Update #42: AD Migration
Refactor to target specific Domain Controllers, with failover.
This commit is contained in:
@@ -15,10 +15,10 @@ namespace Disco.BI.AttachmentBI
|
||||
if (Source != null)
|
||||
{
|
||||
// GDI+ (jpg, png, gif, bmp)
|
||||
if (SourceMimeType.Equals("image/jpeg", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("jpg") ||
|
||||
SourceMimeType.Equals("image/png", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("png") ||
|
||||
SourceMimeType.Equals("image/gif", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("gif") ||
|
||||
SourceMimeType.Equals("image/bmp", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("bmp"))
|
||||
if (SourceMimeType.Equals("image/jpeg", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("jpg") ||
|
||||
SourceMimeType.Equals("image/png", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("png") ||
|
||||
SourceMimeType.Equals("image/gif", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("gif") ||
|
||||
SourceMimeType.Equals("image/bmp", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("bmp"))
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -42,7 +42,7 @@ namespace Disco.BI.AttachmentBI
|
||||
}
|
||||
|
||||
// PDF
|
||||
if (SourceMimeType.Equals("application/pdf", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("pdf"))
|
||||
if (SourceMimeType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("pdf"))
|
||||
{
|
||||
PdfReader pdfReader = new PdfReader(Source);
|
||||
try
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.ClientServices;
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
@@ -295,12 +294,12 @@ namespace Disco.BI.DeviceBI
|
||||
//if (RepoDeviceProfileContext.DistributionType == DeviceProfileConfiguration.DeviceProfileDistributionTypes.OneToOne && RepoDevice.AssignedUser != null)
|
||||
if (RepoDevice.DeviceProfile.DistributionType == DeviceProfile.DistributionTypes.OneToOne && RepoDevice.AssignedUser != null)
|
||||
{
|
||||
ActiveDirectoryUserAccount AssignedUserInfo = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.RetrieveUserAccount(RepoDevice.AssignedUser.UserId);
|
||||
EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.SamAccountName, AssignedUserInfo.Domain, AssignedUserInfo.SecurityIdentifier);
|
||||
ADUserAccount AssignedUserInfo = ActiveDirectory.RetrieveADUserAccount(RepoDevice.AssignedUser.UserId);
|
||||
EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.SamAccountName, AssignedUserInfo.Domain.NetBiosName, AssignedUserInfo.SecurityIdentifier.ToString());
|
||||
response.DeviceAssignedUserUsername = AssignedUserInfo.SamAccountName;
|
||||
response.DeviceAssignedUserDomain = AssignedUserInfo.Domain;
|
||||
response.DeviceAssignedUserDomain = AssignedUserInfo.Domain.NetBiosName;
|
||||
response.DeviceAssignedUserName = AssignedUserInfo.DisplayName;
|
||||
response.DeviceAssignedUserSID = AssignedUserInfo.SecurityIdentifier;
|
||||
response.DeviceAssignedUserSID = AssignedUserInfo.SecurityIdentifier.ToString();
|
||||
}
|
||||
response.DeviceComputerName = RepoDevice.DeviceDomainId;
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 100, "Completed Successfully");
|
||||
@@ -324,23 +323,24 @@ namespace Disco.BI.DeviceBI
|
||||
}
|
||||
public static EnrolResponse Enrol(DiscoDataContext Database, string Username, Models.ClientServices.Enrol Request)
|
||||
{
|
||||
ActiveDirectoryMachineAccount adMachineAccount = null;
|
||||
|
||||
ADMachineAccount adMachineAccount = null;
|
||||
|
||||
EnrolResponse response = new EnrolResponse();
|
||||
|
||||
|
||||
AuthorizationToken authenticatedToken = null;
|
||||
bool isAuthenticated = false;
|
||||
|
||||
ActiveDirectoryDomain domain = null;
|
||||
Lazy<DomainController> domainController = new Lazy<DomainController>(() => {
|
||||
ADDomain domain = null;
|
||||
Lazy<ADDomainController> domainController = new Lazy<ADDomainController>(() =>
|
||||
{
|
||||
if (domain == null)
|
||||
throw new InvalidOperationException("The [domain] variable must be initialized first");
|
||||
return domain.RetrieveWritableDomainController();
|
||||
return domain.GetAvailableDomainController(RequireWritable: true);
|
||||
});
|
||||
|
||||
string sessionId = System.Guid.NewGuid().ToString("B");
|
||||
response.SessionId = sessionId;
|
||||
|
||||
|
||||
EnrolmentLog.LogSessionStarting(sessionId, Request.DeviceSerialNumber, EnrolmentTypes.Normal);
|
||||
EnrolmentLog.LogSessionDeviceInfo(sessionId, Request);
|
||||
|
||||
@@ -362,7 +362,7 @@ namespace Disco.BI.DeviceBI
|
||||
{
|
||||
if (!authenticatedToken.Has(Claims.ComputerAccount))
|
||||
throw new EnrolSafeException(string.Format("Connection not correctly authenticated (SN: {0}; Auth User: {1})", Request.DeviceSerialNumber, authenticatedToken.User.UserId));
|
||||
if (!authenticatedToken.User.UserId.Equals(string.Format("{0}$", Request.DeviceComputerName), System.StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!authenticatedToken.User.UserId.Equals(string.Format("{0}$", Request.DeviceComputerName), System.StringComparison.OrdinalIgnoreCase))
|
||||
throw new EnrolSafeException(string.Format("Connection not correctly authenticated (SN: {0}; Auth User: {1})", Request.DeviceSerialNumber, authenticatedToken.User.UserId));
|
||||
}
|
||||
}
|
||||
@@ -393,16 +393,16 @@ namespace Disco.BI.DeviceBI
|
||||
System.Guid? uuidGuid = null;
|
||||
System.Guid? macAddressGuid = null;
|
||||
if (!string.IsNullOrEmpty(Request.DeviceUUID))
|
||||
uuidGuid = ActiveDirectoryExtensions.NetbootGUIDFromUUID(Request.DeviceUUID);
|
||||
uuidGuid = ADMachineAccount.NetbootGUIDFromUUID(Request.DeviceUUID);
|
||||
if (!string.IsNullOrEmpty(Request.DeviceLanMacAddress))
|
||||
macAddressGuid = ActiveDirectoryExtensions.NetbootGUIDFromMACAddress(Request.DeviceLanMacAddress);
|
||||
|
||||
macAddressGuid = ADMachineAccount.NetbootGUIDFromMACAddress(Request.DeviceLanMacAddress);
|
||||
|
||||
if (domain == null)
|
||||
domain = ActiveDirectory.GetDomainByDnsName(Request.DeviceDNSDomainName);
|
||||
domain = ActiveDirectory.Context.GetDomainByName(Request.DeviceDNSDomainName);
|
||||
|
||||
var requestDeviceId = string.Format(@"{0}\{1}", domain.NetBiosName, Request.DeviceComputerName);
|
||||
|
||||
adMachineAccount = ActiveDirectory.RetrieveMachineAccount(domainController.Value, requestDeviceId, uuidGuid, macAddressGuid);
|
||||
adMachineAccount = domainController.Value.RetrieveADMachineAccount(requestDeviceId, uuidGuid, macAddressGuid);
|
||||
}
|
||||
if (RepoDevice == null)
|
||||
{
|
||||
@@ -468,20 +468,20 @@ namespace Disco.BI.DeviceBI
|
||||
if (RepoDevice.DeviceProfile.ProvisionADAccount)
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 50, "Provisioning an Active Directory Computer Account");
|
||||
|
||||
|
||||
if (string.IsNullOrWhiteSpace(RepoDevice.DeviceProfile.OrganisationalUnit))
|
||||
throw new InvalidOperationException("No Organisational Unit has been set in the device profile");
|
||||
if (domain == null)
|
||||
domain = ActiveDirectory.GetDomainByDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
domain = ActiveDirectory.Context.GetDomainFromDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
|
||||
if (string.IsNullOrEmpty(RepoDevice.DeviceDomainId) || RepoDevice.DeviceProfile.EnforceComputerNameConvention)
|
||||
RepoDevice.DeviceDomainId = RepoDevice.ComputerNameRender(Database, domain);
|
||||
|
||||
string offlineProvisionDiagnosicInfo;
|
||||
EnrolmentLog.LogSessionTaskProvisioningADAccount(sessionId, RepoDevice.SerialNumber, RepoDevice.DeviceDomainId);
|
||||
adMachineAccount = ActiveDirectory.RetrieveMachineAccount(domainController.Value, RepoDevice.DeviceDomainId);
|
||||
|
||||
response.OfflineDomainJoin = ActiveDirectory.OfflineDomainJoinProvision(domain, domainController.Value, RepoDevice.DeviceDomainId, RepoDevice.DeviceProfile.OrganisationalUnit, ref adMachineAccount, out offlineProvisionDiagnosicInfo);
|
||||
adMachineAccount = domainController.Value.RetrieveADMachineAccount(RepoDevice.DeviceDomainId);
|
||||
|
||||
response.OfflineDomainJoin = domainController.Value.OfflineDomainJoinProvision(RepoDevice.DeviceDomainId, RepoDevice.DeviceProfile.OrganisationalUnit, ref adMachineAccount, out offlineProvisionDiagnosicInfo);
|
||||
|
||||
EnrolmentLog.LogSessionDiagnosticInformation(sessionId, offlineProvisionDiagnosicInfo);
|
||||
|
||||
@@ -490,7 +490,7 @@ namespace Disco.BI.DeviceBI
|
||||
if (adMachineAccount != null)
|
||||
{
|
||||
response.DeviceComputerName = adMachineAccount.Name;
|
||||
response.DeviceDomainName = adMachineAccount.Domain;
|
||||
response.DeviceDomainName = adMachineAccount.Domain.NetBiosName;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -509,7 +509,7 @@ namespace Disco.BI.DeviceBI
|
||||
{
|
||||
RepoDevice.DeviceDomainId = adMachineAccount.Name;
|
||||
response.DeviceComputerName = adMachineAccount.Name;
|
||||
response.DeviceDomainName = adMachineAccount.Domain;
|
||||
response.DeviceDomainName = adMachineAccount.Domain.NetBiosName;
|
||||
|
||||
// Enforce Computer Name Convention
|
||||
if (!adMachineAccount.IsCriticalSystemObject && RepoDevice.DeviceProfile.EnforceComputerNameConvention)
|
||||
@@ -517,12 +517,12 @@ namespace Disco.BI.DeviceBI
|
||||
if (string.IsNullOrWhiteSpace(RepoDevice.DeviceProfile.OrganisationalUnit))
|
||||
throw new InvalidOperationException("No Organisational Unit has been set in the device profile");
|
||||
if (domain == null)
|
||||
domain = ActiveDirectory.GetDomainByDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
domain = ActiveDirectory.Context.GetDomainFromDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
|
||||
var calculatedComputerName = RepoDevice.ComputerNameRender(Database, domain);
|
||||
var computerNameSplit = Disco.Services.UserExtensions.SplitUserId(calculatedComputerName);
|
||||
|
||||
if (!Request.DeviceComputerName.Equals(computerNameSplit.Item2, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!Request.DeviceComputerName.Equals(computerNameSplit.Item2, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 50, string.Format("Renaming Device: {0} -> {1}", Request.DeviceComputerName, calculatedComputerName));
|
||||
EnrolmentLog.LogSessionTaskRenamingDevice(sessionId, Request.DeviceComputerName, calculatedComputerName);
|
||||
@@ -533,9 +533,9 @@ namespace Disco.BI.DeviceBI
|
||||
|
||||
// Create New Account
|
||||
string offlineProvisionDiagnosicInfo;
|
||||
|
||||
response.OfflineDomainJoin = ActiveDirectory.OfflineDomainJoinProvision(domain, domainController.Value, RepoDevice.DeviceDomainId, RepoDevice.DeviceProfile.OrganisationalUnit, ref adMachineAccount, out offlineProvisionDiagnosicInfo);
|
||||
|
||||
|
||||
response.OfflineDomainJoin = domainController.Value.OfflineDomainJoinProvision(RepoDevice.DeviceDomainId, RepoDevice.DeviceProfile.OrganisationalUnit, ref adMachineAccount, out offlineProvisionDiagnosicInfo);
|
||||
|
||||
EnrolmentLog.LogSessionDiagnosticInformation(sessionId, offlineProvisionDiagnosicInfo);
|
||||
|
||||
response.RequireReboot = true;
|
||||
@@ -545,14 +545,14 @@ namespace Disco.BI.DeviceBI
|
||||
// Enforce Organisational Unit
|
||||
if (!adMachineAccount.IsCriticalSystemObject && response.OfflineDomainJoin == null && RepoDevice.DeviceProfile.EnforceOrganisationalUnit)
|
||||
{
|
||||
var parentDistinguishedName = adMachineAccount.ParentDistinguishedName();
|
||||
var parentDistinguishedName = adMachineAccount.ParentDistinguishedName;
|
||||
if (string.IsNullOrWhiteSpace(RepoDevice.DeviceProfile.OrganisationalUnit))
|
||||
throw new InvalidOperationException(string.Format("The Organisational Unit for the Device Profile '{0}' [{1}] is not set.", RepoDevice.DeviceProfile.Name, RepoDevice.DeviceProfile.Id));
|
||||
|
||||
if (!parentDistinguishedName.Equals(RepoDevice.DeviceProfile.OrganisationalUnit, StringComparison.InvariantCultureIgnoreCase)) // Custom OU
|
||||
if (!parentDistinguishedName.Equals(RepoDevice.DeviceProfile.OrganisationalUnit, StringComparison.OrdinalIgnoreCase)) // Custom OU
|
||||
{
|
||||
var proposedDomain = ActiveDirectory.GetDomainByDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
var currentDomain = ActiveDirectory.GetDomainByDistinguishedName(parentDistinguishedName);
|
||||
var proposedDomain = ActiveDirectory.Context.GetDomainFromDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
var currentDomain = ActiveDirectory.Context.GetDomainFromDistinguishedName(parentDistinguishedName);
|
||||
if (currentDomain != proposedDomain)
|
||||
throw new NotSupportedException("Unable to move the devices organisational unit when the source and destination domains are different.");
|
||||
if (domain == null)
|
||||
@@ -563,7 +563,6 @@ namespace Disco.BI.DeviceBI
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 65, string.Format("Moving Device Organisational Unit: {0} -> {1}", parentDistinguishedName, RepoDevice.DeviceProfile.OrganisationalUnit));
|
||||
EnrolmentLog.LogSessionTaskMovingDeviceOrganisationUnit(sessionId, parentDistinguishedName, RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
adMachineAccount.MoveOrganisationalUnit(domainController.Value, RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
adMachineAccount = ActiveDirectory.RetrieveMachineAccount(domainController.Value, adMachineAccount.NetBiosId);
|
||||
response.RequireReboot = true;
|
||||
}
|
||||
}
|
||||
@@ -585,14 +584,14 @@ namespace Disco.BI.DeviceBI
|
||||
else
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 80, "Retrieving Active Directory Assigned User Account");
|
||||
ActiveDirectoryUserAccount AssignedUserInfo = Services.Interop.ActiveDirectory.ActiveDirectory.RetrieveUserAccount(RepoDevice.AssignedUser.UserId);
|
||||
EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.SamAccountName, AssignedUserInfo.Domain, AssignedUserInfo.SecurityIdentifier);
|
||||
ADUserAccount AssignedUserInfo = ActiveDirectory.RetrieveADUserAccount(RepoDevice.AssignedUser.UserId);
|
||||
EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.SamAccountName, AssignedUserInfo.Domain.NetBiosName, AssignedUserInfo.SecurityIdentifier.ToString());
|
||||
response.AllowBootstrapperUninstall = true;
|
||||
response.DeviceAssignedUserIsLocalAdmin = RepoDevice.DeviceProfile.AssignedUserLocalAdmin;
|
||||
response.DeviceAssignedUserUsername = AssignedUserInfo.SamAccountName;
|
||||
response.DeviceAssignedUserDomain = AssignedUserInfo.Domain;
|
||||
response.DeviceAssignedUserDomain = AssignedUserInfo.Domain.NetBiosName;
|
||||
response.DeviceAssignedUserName = AssignedUserInfo.DisplayName;
|
||||
response.DeviceAssignedUserSID = AssignedUserInfo.SecurityIdentifier;
|
||||
response.DeviceAssignedUserSID = AssignedUserInfo.SecurityIdentifier.ToString();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -655,4 +654,4 @@ namespace Disco.BI.DeviceBI
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,13 +62,13 @@ namespace Disco.BI.DocumentTemplateBI
|
||||
public string DataScope { get; private set; }
|
||||
public static bool IsDocumentUniqueIdentifier(string UniqueIdentifier)
|
||||
{
|
||||
return UniqueIdentifier.StartsWith("Disco|", System.StringComparison.InvariantCultureIgnoreCase);
|
||||
return UniqueIdentifier.StartsWith("Disco|", System.StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
public DocumentUniqueIdentifier(string TemplateTypeId, string DataId, string CreatorId, DateTime TimeStamp, int? Page = null, string Tag = null)
|
||||
{
|
||||
var creatorId = (string.IsNullOrEmpty(CreatorId) || CreatorId.IndexOf('\\') > -1)
|
||||
? CreatorId
|
||||
: string.Format(@"{0}\{1}", ActiveDirectory.PrimaryDomain.NetBiosName, CreatorId);
|
||||
: string.Format(@"{0}\{1}", ActiveDirectory.Context.PrimaryDomain.NetBiosName, CreatorId);
|
||||
|
||||
this.Tag = Tag;
|
||||
this.TemplateTypeId = TemplateTypeId;
|
||||
@@ -100,7 +100,7 @@ namespace Disco.BI.DocumentTemplateBI
|
||||
{
|
||||
var creatorId = s[4];
|
||||
if (!string.IsNullOrWhiteSpace(creatorId) && creatorId.IndexOf('\\') < 0)
|
||||
creatorId = string.Format(@"{0}\{1}", ActiveDirectory.PrimaryDomain.NetBiosName, creatorId);
|
||||
creatorId = string.Format(@"{0}\{1}", ActiveDirectory.Context.PrimaryDomain.NetBiosName, creatorId);
|
||||
|
||||
this.CreatorId = creatorId;
|
||||
}
|
||||
@@ -193,7 +193,7 @@ namespace Disco.BI.DocumentTemplateBI
|
||||
// Patch for existing documents (before DBv13 - Multi-Domain Support)
|
||||
// Add default domain to User Ids
|
||||
if (this.DataId.IndexOf('\\') < 0)
|
||||
this.DataId = string.Format(@"{0}\{1}", ActiveDirectory.PrimaryDomain.NetBiosName, this.DataId);
|
||||
this.DataId = string.Format(@"{0}\{1}", ActiveDirectory.Context.PrimaryDomain.NetBiosName, this.DataId);
|
||||
|
||||
User u = Database.Users.Find(this.DataId);
|
||||
if (u != null)
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Disco.BI.Expressions.Extensions
|
||||
}
|
||||
public static FileImageExpressionResult JobAttachmentFirstImage(Job Job, DiscoDataContext Database)
|
||||
{
|
||||
var attachment = Job.JobAttachments.FirstOrDefault(ja => ja.MimeType.StartsWith("image/", StringComparison.InvariantCultureIgnoreCase));
|
||||
var attachment = Job.JobAttachments.FirstOrDefault(ja => ja.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase));
|
||||
if (attachment != null)
|
||||
{
|
||||
var filename = attachment.RepositoryFilename(Database);
|
||||
@@ -39,7 +39,7 @@ namespace Disco.BI.Expressions.Extensions
|
||||
}
|
||||
public static FileImageExpressionResult JobAttachmentLastImage(Job Job, DiscoDataContext Database)
|
||||
{
|
||||
var attachment = Job.JobAttachments.LastOrDefault(ja => ja.MimeType.StartsWith("image/", StringComparison.InvariantCultureIgnoreCase));
|
||||
var attachment = Job.JobAttachments.LastOrDefault(ja => ja.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase));
|
||||
if (attachment != null)
|
||||
{
|
||||
var filename = attachment.RepositoryFilename(Database);
|
||||
@@ -52,7 +52,7 @@ namespace Disco.BI.Expressions.Extensions
|
||||
{
|
||||
if (JobAttachment == null)
|
||||
throw new ArgumentNullException("JobAttachment");
|
||||
if (!JobAttachment.MimeType.StartsWith("image/", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!JobAttachment.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
|
||||
throw new ArgumentException("Invalid Image MimeType for Attachment");
|
||||
|
||||
var filename = JobAttachment.RepositoryFilename(Database);
|
||||
@@ -65,7 +65,7 @@ namespace Disco.BI.Expressions.Extensions
|
||||
if (Job.JobAttachments == null)
|
||||
throw new ArgumentException("Job.JobAttachments is null", "Job");
|
||||
|
||||
var attachments = Job.JobAttachments.Where(a => a.MimeType.StartsWith("image/", StringComparison.InvariantCultureIgnoreCase)).ToList();
|
||||
var attachments = Job.JobAttachments.Where(a => a.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
|
||||
if (attachments.Count > 0)
|
||||
{
|
||||
@@ -81,7 +81,7 @@ namespace Disco.BI.Expressions.Extensions
|
||||
if (JobAttachments == null)
|
||||
throw new ArgumentNullException("JobAttachments");
|
||||
|
||||
var attachments = JobAttachments.Cast<JobAttachment>().Where(a => a.MimeType.StartsWith("image/", StringComparison.InvariantCultureIgnoreCase)).ToList();
|
||||
var attachments = JobAttachments.Cast<JobAttachment>().Where(a => a.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
|
||||
if (attachments.Count > 0)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,6 @@ using Disco.Models.Repository;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.IO;
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Services.Users;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
@@ -16,7 +15,7 @@ namespace Disco.BI.Extensions
|
||||
public static class DeviceExtensions
|
||||
{
|
||||
|
||||
public static string ComputerNameRender(this Device device, DiscoDataContext Database, ActiveDirectoryDomain Domain)
|
||||
public static string ComputerNameRender(this Device device, DiscoDataContext Database, ADDomain Domain)
|
||||
{
|
||||
if (Domain == null)
|
||||
throw new ArgumentNullException("Domain");
|
||||
@@ -56,12 +55,12 @@ namespace Disco.BI.Extensions
|
||||
|
||||
public static bool UpdateLastNetworkLogonDate(this Device Device)
|
||||
{
|
||||
return Disco.Services.Interop.ActiveDirectory.Internal.ADUpdateLastNetworkLogonDateJob.UpdateLastNetworkLogonDate(Device);
|
||||
return Disco.Services.Interop.ActiveDirectory.ADTaskUpdateNetworkLogonDates.UpdateLastNetworkLogonDate(Device);
|
||||
}
|
||||
|
||||
public static DeviceAttachment CreateAttachment(this Device Device, DiscoDataContext Database, User CreatorUser, string Filename, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, byte[] PdfThumbnail = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
|
||||
MimeType = Interop.MimeTypes.ResolveMimeType(Filename);
|
||||
|
||||
DeviceAttachment da = new DeviceAttachment()
|
||||
@@ -180,7 +179,7 @@ namespace Disco.BI.Extensions
|
||||
// Update AD Account
|
||||
if (!string.IsNullOrEmpty(d.DeviceDomainId))
|
||||
{
|
||||
var adMachineAccount = ActiveDirectory.RetrieveMachineAccount(d.DeviceDomainId);
|
||||
var adMachineAccount = ActiveDirectory.RetrieveADMachineAccount(d.DeviceDomainId);
|
||||
if (adMachineAccount != null)
|
||||
{
|
||||
adMachineAccount.SetDescription(d);
|
||||
@@ -190,10 +189,10 @@ namespace Disco.BI.Extensions
|
||||
return newDua;
|
||||
}
|
||||
|
||||
public static ActiveDirectoryMachineAccount ActiveDirectoryAccount(this Device Device, params string[] AdditionalProperties)
|
||||
public static ADMachineAccount ActiveDirectoryAccount(this Device Device, params string[] AdditionalProperties)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Device.DeviceDomainId))
|
||||
return ActiveDirectory.RetrieveMachineAccount(Device.DeviceDomainId, AdditionalProperties: AdditionalProperties);
|
||||
return ActiveDirectory.RetrieveADMachineAccount(Device.DeviceDomainId, AdditionalProperties: AdditionalProperties);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Disco.BI.Extensions
|
||||
{
|
||||
public static JobAttachment CreateAttachment(this Job Job, DiscoDataContext Database, User CreatorUser, string Filename, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, byte[] PdfThumbnail = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
|
||||
MimeType = Interop.MimeTypes.ResolveMimeType(Filename);
|
||||
|
||||
JobAttachment ja = new JobAttachment()
|
||||
@@ -177,7 +177,7 @@ namespace Disco.BI.Extensions
|
||||
}
|
||||
foreach (var c in addedComponents)
|
||||
{
|
||||
if (!j.JobComponents.Any(jc => jc.Description.Equals(c.Description, StringComparison.InvariantCultureIgnoreCase)))
|
||||
if (!j.JobComponents.Any(jc => jc.Description.Equals(c.Description, StringComparison.OrdinalIgnoreCase)))
|
||||
{ // Job Component with matching Description doesn't exist.
|
||||
Database.JobComponents.Add(new JobComponent()
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ using Disco.Models.Repository;
|
||||
using Disco.Data.Repository;
|
||||
using System.IO;
|
||||
using Disco.Models.BI.DocumentTemplates;
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
|
||||
namespace Disco.BI.Extensions
|
||||
{
|
||||
@@ -14,7 +14,7 @@ namespace Disco.BI.Extensions
|
||||
{
|
||||
public static UserAttachment CreateAttachment(this User User, DiscoDataContext Database, User CreatorUser, string Filename, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, byte[] PdfThumbnail = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
|
||||
MimeType = Interop.MimeTypes.ResolveMimeType(Filename);
|
||||
|
||||
UserAttachment ua = new UserAttachment()
|
||||
@@ -57,9 +57,9 @@ namespace Disco.BI.Extensions
|
||||
{
|
||||
return u.DeviceUserAssignments.Where(dua => !dua.UnassignedDate.HasValue).ToList();
|
||||
}
|
||||
public static ActiveDirectoryUserAccount ActiveDirectoryAccount(this User User, params string[] AdditionalProperties)
|
||||
public static ADUserAccount ActiveDirectoryAccount(this User User, params string[] AdditionalProperties)
|
||||
{
|
||||
return Disco.Services.Interop.ActiveDirectory.ActiveDirectory.RetrieveUserAccount(User.UserId, AdditionalProperties);
|
||||
return ActiveDirectory.RetrieveADUserAccount(User.UserId, AdditionalProperties);
|
||||
}
|
||||
|
||||
public static bool CanCreateJob(this User u)
|
||||
|
||||
@@ -166,7 +166,7 @@ namespace Disco.BI.Extensions
|
||||
}
|
||||
public static void SaveJpg(this Image Source, int Quality, Stream OutStream)
|
||||
{
|
||||
ImageCodecInfo jpgCodec = ImageCodecInfo.GetImageEncoders().Where(c => c.MimeType.Equals("image/jpeg", StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
|
||||
ImageCodecInfo jpgCodec = ImageCodecInfo.GetImageEncoders().Where(c => c.MimeType.Equals("image/jpeg", StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
|
||||
if (jpgCodec != null)
|
||||
{
|
||||
if (Quality < 0 || Quality > 100)
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.BI.Expressions;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.BI.DocumentTemplates;
|
||||
using System.IO;
|
||||
using iTextSharp.text.pdf;
|
||||
using System.Collections.Concurrent;
|
||||
using Disco.BI.Expressions;
|
||||
using System.Collections;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Models.BI.Expressions;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Users;
|
||||
using iTextSharp.text.pdf;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.BI.Interop.Pdf
|
||||
{
|
||||
@@ -67,7 +67,7 @@ namespace Disco.BI.Interop.Pdf
|
||||
{
|
||||
string dataObjectId = DataObjectsIds[idIndex];
|
||||
if (!dataObjectId.Contains('\\'))
|
||||
dataObjectId = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + dataObjectId;
|
||||
dataObjectId = ActiveDirectory.Context.PrimaryDomain.NetBiosName + @"\" + dataObjectId;
|
||||
|
||||
DataObjects[idIndex] = UserService.GetUser(DataObjectsIds[idIndex], Database, true);
|
||||
if (DataObjects[idIndex] == null)
|
||||
@@ -123,7 +123,7 @@ namespace Disco.BI.Interop.Pdf
|
||||
|
||||
foreach (string pdfFieldKey in pdfStamper.AcroFields.Fields.Keys)
|
||||
{
|
||||
if (pdfFieldKey.Equals("DiscoAttachmentId", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (pdfFieldKey.Equals("DiscoAttachmentId", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
AcroFields.Item fields = pdfStamper.AcroFields.Fields[pdfFieldKey];
|
||||
string fieldValue = dt.UniqueIdentifier(Data, CreatorUser.UserId, TimeStamp);
|
||||
|
||||
@@ -22,8 +22,8 @@ namespace Disco.Client.Interop
|
||||
using (DirectoryEntry member = new DirectoryEntry(memberRef))
|
||||
{
|
||||
var memberPath = member.Path;
|
||||
if (memberPath.Equals(string.Format("WinNT://{0}/{1}", UserDomain, Username), StringComparison.InvariantCultureIgnoreCase) ||
|
||||
memberPath.Equals(string.Format("WinNT://{0}", UserSID), StringComparison.InvariantCultureIgnoreCase))
|
||||
if (memberPath.Equals(string.Format("WinNT://{0}/{1}", UserDomain, Username), StringComparison.OrdinalIgnoreCase) ||
|
||||
memberPath.Equals(string.Format("WinNT://{0}", UserSID), StringComparison.OrdinalIgnoreCase))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Disco.Client.Interop
|
||||
// Determine Primary Adapters
|
||||
|
||||
// Lan
|
||||
PrimaryLanNetworkAdapter = NetworkAdapters.Where(n => !n.IsWLanAdapter && n.NetConnectionId.StartsWith("Local Area Connection", StringComparison.InvariantCultureIgnoreCase)).OrderByDescending(n => n.Speed).FirstOrDefault();
|
||||
PrimaryLanNetworkAdapter = NetworkAdapters.Where(n => !n.IsWLanAdapter && n.NetConnectionId.StartsWith("Local Area Connection", StringComparison.OrdinalIgnoreCase)).OrderByDescending(n => n.Speed).FirstOrDefault();
|
||||
// Might be too restrictive - remove name restriction just in case.
|
||||
if (PrimaryLanNetworkAdapter == null)
|
||||
PrimaryLanNetworkAdapter = NetworkAdapters.Where(n => !n.IsWLanAdapter).OrderByDescending(n => n.Speed).FirstOrDefault();
|
||||
|
||||
@@ -127,9 +127,9 @@ namespace Disco.Client.Interop
|
||||
// Added 2012-11-22 G# - Lenovo IdeaPad Serial SHIM
|
||||
// http://www.discoict.com.au/forum/feature-requests/2012/11/serial-number-detection-on-ideapads.aspx
|
||||
if (string.IsNullOrWhiteSpace(DeviceSerialNumber) ||
|
||||
(DeviceManufacturer.Equals("LENOVO", StringComparison.InvariantCultureIgnoreCase) &&
|
||||
(DeviceModel.Equals("S10-3", StringComparison.InvariantCultureIgnoreCase) // S10-3
|
||||
|| DeviceModel.Equals("2957", StringComparison.InvariantCultureIgnoreCase)))) // S10-2
|
||||
(DeviceManufacturer.Equals("LENOVO", StringComparison.OrdinalIgnoreCase) &&
|
||||
(DeviceModel.Equals("S10-3", StringComparison.OrdinalIgnoreCase) // S10-3
|
||||
|| DeviceModel.Equals("2957", StringComparison.OrdinalIgnoreCase)))) // S10-2
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -74,14 +74,14 @@ namespace Disco.ClientBootstrapper.Interop
|
||||
// Only Copy Certain Files
|
||||
|
||||
// Copy Wireless Certificates
|
||||
if (fileName.StartsWith("WLAN_Cert_Root_", StringComparison.InvariantCultureIgnoreCase) ||
|
||||
fileName.StartsWith("WLAN_Cert_Intermediate_", StringComparison.InvariantCultureIgnoreCase) ||
|
||||
fileName.StartsWith("WLAN_Cert_Personal_", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (fileName.StartsWith("WLAN_Cert_Root_", StringComparison.OrdinalIgnoreCase) ||
|
||||
fileName.StartsWith("WLAN_Cert_Intermediate_", StringComparison.OrdinalIgnoreCase) ||
|
||||
fileName.StartsWith("WLAN_Cert_Personal_", StringComparison.OrdinalIgnoreCase))
|
||||
File.Copy(file, Path.Combine(InstallLocation, fileName));
|
||||
|
||||
// Copy Wireless Profiles
|
||||
if (fileName.StartsWith("WLAN_Profile_", StringComparison.InvariantCultureIgnoreCase) &&
|
||||
fileName.EndsWith(".xml", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (fileName.StartsWith("WLAN_Profile_", StringComparison.OrdinalIgnoreCase) &&
|
||||
fileName.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
|
||||
File.Copy(file, Path.Combine(InstallLocation, fileName));
|
||||
|
||||
}
|
||||
@@ -194,7 +194,7 @@ namespace Disco.ClientBootstrapper.Interop
|
||||
if (string.IsNullOrWhiteSpace(InstallLocation))
|
||||
InstallLocation = Path.Combine(Path.GetPathRoot(Environment.SystemDirectory), "Disco");
|
||||
|
||||
if (InstallLocation.EndsWith(".wim", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (InstallLocation.EndsWith(".wim", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Offline File System (WIM)
|
||||
Program.Status.UpdateStatus("Installing Bootstrapper (Offline)", "Installing", string.Format("Install Location: {0}", InstallLocation));
|
||||
@@ -216,7 +216,7 @@ namespace Disco.ClientBootstrapper.Interop
|
||||
using (var wimImage = wim[i])
|
||||
wimImageInfo.LoadXml(wimImage.ImageInformation);
|
||||
var wimImageInfoName = wimImageInfo.SelectSingleNode("//IMAGE/NAME");
|
||||
if (wimImageInfoName != null && wimImageInfoName.InnerText.Equals(WimImageId, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (wimImageInfoName != null && wimImageInfoName.InnerText.Equals(WimImageId, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
wimImageIndex = i + 1;
|
||||
Program.Status.UpdateStatus(null, "Analysing WIM", string.Format("Found Image Id '{0}' at Index {1}", WimImageId, wimImageIndex));
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Disco.Data.Configuration.Modules
|
||||
}
|
||||
}
|
||||
|
||||
public bool? SearchEntireForest
|
||||
public bool? SearchAllForestServers
|
||||
{
|
||||
get { return GetFromJson<bool?>(null); }
|
||||
set { SetAsJson(value); }
|
||||
|
||||
@@ -423,7 +423,7 @@ DELETE [Users] WHERE [Id]=@IdExisting;";
|
||||
if (System.IO.Directory.Exists(userAttachmentsDirectory))
|
||||
{
|
||||
var files = System.IO.Directory.EnumerateFiles(userAttachmentsDirectory, "*.*", System.IO.SearchOption.AllDirectories)
|
||||
.Where(p => !p.StartsWith(filePrefix, StringComparison.InvariantCultureIgnoreCase) && (p.EndsWith("_thumb.jpg") || p.EndsWith("_file"))).ToList();
|
||||
.Where(p => !p.StartsWith(filePrefix, StringComparison.OrdinalIgnoreCase) && (p.EndsWith("_thumb.jpg") || p.EndsWith("_file"))).ToList();
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.Entity" />
|
||||
<Reference Include="System.DirectoryServices" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
@@ -47,9 +46,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BI\Job\LocationModes.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryDomain.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryOrganisationalUnit.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ActiveDirectorySearchResult.cs" />
|
||||
<Compile Include="Services\Authorization\IAuthorizationToken.cs" />
|
||||
<Compile Include="Services\Authorization\IClaimNavigatorItem.cs" />
|
||||
<Compile Include="Services\Authorization\IRoleToken.cs" />
|
||||
@@ -76,10 +72,6 @@
|
||||
<Compile Include="ClientServices\Enrol.cs" />
|
||||
<Compile Include="ClientServices\WhoAmI.cs" />
|
||||
<Compile Include="ClientServices\WhoAmIResponse.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryMachineAccount.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryGroup.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryUserAccount.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\IActiveDirectoryObject.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Repository\ConfigurationItem.cs" />
|
||||
<Compile Include="Repository\Device\Device.cs" />
|
||||
@@ -172,7 +164,7 @@
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_StartDate="2011/7/1" BuildVersion_DetectChanges="False" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildAction="Both" />
|
||||
<UserProperties BuildVersion_BuildAction="Both" BuildVersion_UseGlobalSettings="False" BuildVersion_DetectChanges="False" BuildVersion_StartDate="2011/7/1" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Models.Interop.ActiveDirectory
|
||||
{
|
||||
public class ActiveDirectoryDomain
|
||||
{
|
||||
public string DnsName { get; private set; }
|
||||
public string NetBiosName { get; private set; }
|
||||
public string DistinguishedName { get; private set; }
|
||||
|
||||
public List<string> SearchContainers { get; private set; }
|
||||
|
||||
public ActiveDirectoryDomain(string DnsName, string NetBiosName, string DistinguishedName, List<string> SearchContainers)
|
||||
{
|
||||
this.DnsName = DnsName;
|
||||
this.NetBiosName = NetBiosName;
|
||||
this.DistinguishedName = DistinguishedName;
|
||||
this.SearchContainers = SearchContainers;
|
||||
}
|
||||
|
||||
public void UpdateSearchContainers(IEnumerable<string> Containers)
|
||||
{
|
||||
this.SearchContainers = Containers.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Disco.Models.Interop.ActiveDirectory
|
||||
{
|
||||
public class ActiveDirectoryGroup : IActiveDirectoryObject
|
||||
{
|
||||
public string Domain { get; set; }
|
||||
public string SamAccountName { get; set; }
|
||||
|
||||
public string DistinguishedName { get; set; }
|
||||
public string SecurityIdentifier { get; set; }
|
||||
public string CommonName { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public string DisplayName { get { return this.Name; } }
|
||||
|
||||
public List<string> MemberOf { get; set; }
|
||||
|
||||
public string NetBiosId { get { return string.Format(@"{0}\{1}", Domain, SamAccountName); } }
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using Disco.Models.Repository;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Disco.Models.Interop.ActiveDirectory
|
||||
{
|
||||
public class ActiveDirectoryMachineAccount : IActiveDirectoryObject
|
||||
{
|
||||
|
||||
public string Domain { get; set; }
|
||||
public string SamAccountName { get; set; }
|
||||
|
||||
public string SecurityIdentifier { get; set; }
|
||||
public string DistinguishedName { get; set; }
|
||||
public string Path { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public string DisplayName { get { return this.Name; } }
|
||||
public string DnsName { get; set; }
|
||||
public Guid NetbootGUID { get; set; }
|
||||
|
||||
public bool IsCriticalSystemObject { get; set; }
|
||||
public Dictionary<string, object[]> LoadedProperties { get; set; }
|
||||
|
||||
public User ToRepositoryUser()
|
||||
{
|
||||
return new User
|
||||
{
|
||||
UserId = this.Domain + "\\" + this.SamAccountName,
|
||||
DisplayName = this.Name
|
||||
};
|
||||
}
|
||||
|
||||
public string NetBiosId { get { return string.Format(@"{0}\{1}", Domain, SamAccountName); } }
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Models.Interop.ActiveDirectory
|
||||
{
|
||||
public class ActiveDirectoryOrganisationalUnit
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Domain { get; set; }
|
||||
public string DistinguishedName { get; set; }
|
||||
public List<ActiveDirectoryOrganisationalUnit> Children { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Models.Interop.ActiveDirectory
|
||||
{
|
||||
public class ActiveDirectorySearchResult
|
||||
{
|
||||
public ActiveDirectoryDomain Domain { get; set; }
|
||||
public string SearchRoot { get; set; }
|
||||
public SearchResult Result { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.Models.Repository;
|
||||
|
||||
namespace Disco.Models.Interop.ActiveDirectory
|
||||
{
|
||||
public class ActiveDirectoryUserAccount : IActiveDirectoryObject
|
||||
{
|
||||
public string Domain { get; set; }
|
||||
public string SamAccountName { get; set; }
|
||||
|
||||
public string DistinguishedName { get; set; }
|
||||
public string SecurityIdentifier { get; set; }
|
||||
public string Path { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public string Email { get; set; }
|
||||
public string Surname { get; set; }
|
||||
public string GivenName { get; set; }
|
||||
public string Phone { get; set; }
|
||||
|
||||
public List<string> Groups { get; set; }
|
||||
|
||||
public Dictionary<string, object[]> LoadedProperties { get; set; }
|
||||
|
||||
public User ToRepositoryUser()
|
||||
{
|
||||
return new User
|
||||
{
|
||||
UserId = this.Domain + "\\" + this.SamAccountName,
|
||||
DisplayName = this.DisplayName,
|
||||
Surname = this.Surname,
|
||||
GivenName = this.GivenName,
|
||||
EmailAddress = this.Email,
|
||||
PhoneNumber = this.Phone,
|
||||
};
|
||||
}
|
||||
|
||||
public string NetBiosId { get { return string.Format(@"{0}\{1}", Domain, SamAccountName); } }
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
|
||||
namespace Disco.Models.Interop.ActiveDirectory
|
||||
{
|
||||
public interface IActiveDirectoryObject
|
||||
{
|
||||
string DistinguishedName { get; set; }
|
||||
string SecurityIdentifier { get; set; }
|
||||
|
||||
string Domain { get; set; }
|
||||
string SamAccountName { get; set; }
|
||||
string NetBiosId { get; }
|
||||
|
||||
string Name { get; set; }
|
||||
string DisplayName { get; }
|
||||
}
|
||||
}
|
||||
@@ -72,6 +72,9 @@ namespace Disco.Models.Repository
|
||||
{
|
||||
get
|
||||
{
|
||||
if (DeviceDomainId == null)
|
||||
return null;
|
||||
|
||||
var index = DeviceDomainId.IndexOf('\\');
|
||||
return index < 0 ? DeviceDomainId : DeviceDomainId.Substring(index + 1);
|
||||
}
|
||||
@@ -82,6 +85,9 @@ namespace Disco.Models.Repository
|
||||
{
|
||||
get
|
||||
{
|
||||
if (DeviceDomainId == null)
|
||||
return null;
|
||||
|
||||
var index = DeviceDomainId.IndexOf('\\');
|
||||
return index < 0 ? null : DeviceDomainId.Substring(0, index);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace Disco.Models.Repository
|
||||
|
||||
public void UpdateSelf(User u)
|
||||
{
|
||||
if (!this.UserId.Equals(u.UserId, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!this.UserId.Equals(u.UserId, StringComparison.OrdinalIgnoreCase))
|
||||
throw new ArgumentException("User Id's do not match", "u");
|
||||
|
||||
if (this.Surname != u.Surname)
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
|
||||
namespace Disco.Services.Authorization
|
||||
{
|
||||
@@ -18,12 +19,12 @@ namespace Disco.Services.Authorization
|
||||
|
||||
#region Token Builders
|
||||
|
||||
public static AuthorizationToken BuildToken(User User, List<string> GroupMembership)
|
||||
public static AuthorizationToken BuildToken(User User, IEnumerable<string> GroupMembership)
|
||||
{
|
||||
return new AuthorizationToken()
|
||||
{
|
||||
User = User,
|
||||
GroupMembership = GroupMembership,
|
||||
GroupMembership = GroupMembership.ToList(),
|
||||
RoleTokens = RoleCache.GetRoleTokens(GroupMembership, User)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
|
||||
namespace Disco.Services.Authorization.Roles
|
||||
{
|
||||
@@ -49,19 +50,19 @@ namespace Disco.Services.Authorization.Roles
|
||||
|
||||
private static IEnumerable<string> GenerateAdministratorSubjectIds(DiscoDataContext Database)
|
||||
{
|
||||
var domainNetBiosName = Interop.ActiveDirectory.ActiveDirectory.PrimaryDomain.NetBiosName;
|
||||
var domainNetBiosName = ActiveDirectory.Context.PrimaryDomain.NetBiosName;
|
||||
var configuredSubjectIds = Database.DiscoConfiguration.Administrators.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Contains(@"\") ? s : string.Format(@"{0}\{1}", domainNetBiosName, s));
|
||||
|
||||
return RequiredAdministratorSubjectIds
|
||||
.Concat(configuredSubjectIds)
|
||||
.Distinct(StringComparer.InvariantCultureIgnoreCase)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.OrderBy(s => s);
|
||||
}
|
||||
public static IEnumerable<string> RequiredAdministratorSubjectIds
|
||||
{
|
||||
get
|
||||
{
|
||||
var domainNetBiosName = Interop.ActiveDirectory.ActiveDirectory.PrimaryDomain.NetBiosName;
|
||||
var domainNetBiosName = ActiveDirectory.Context.PrimaryDomain.NetBiosName;
|
||||
return _RequiredAdministratorSubjectIds.Select(s => string.Format(@"{0}\{1}", domainNetBiosName, s));
|
||||
}
|
||||
}
|
||||
@@ -79,7 +80,7 @@ namespace Disco.Services.Authorization.Roles
|
||||
SubjectIds = SubjectIds
|
||||
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||
.Concat(RequiredAdministratorSubjectIds)
|
||||
.Distinct(StringComparer.InvariantCultureIgnoreCase)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.OrderBy(s => s);
|
||||
|
||||
var subjectIdsString = string.Join(",", SubjectIds);
|
||||
@@ -136,17 +137,15 @@ namespace Disco.Services.Authorization.Roles
|
||||
}
|
||||
internal static RoleToken GetRoleToken(string SecurityGroup)
|
||||
{
|
||||
return _Cache.FirstOrDefault(t => t.SubjectIdHashes.Contains(SecurityGroup.ToLower()));
|
||||
return _Cache.FirstOrDefault(t => t.SubjectIdHashes.Contains(SecurityGroup));
|
||||
}
|
||||
internal static List<IRoleToken> GetRoleTokens(IEnumerable<string> SecurityGroup)
|
||||
{
|
||||
var securityGroups = SecurityGroup.Select(sg => sg.ToLower());
|
||||
|
||||
return _Cache.Where(t => securityGroups.Any(sg => t.SubjectIdHashes.Contains(sg))).Cast<IRoleToken>().ToList();
|
||||
return _Cache.Where(t => SecurityGroup.Any(sg => t.SubjectIdHashes.Contains(sg))).Cast<IRoleToken>().ToList();
|
||||
}
|
||||
internal static List<IRoleToken> GetRoleTokens(IEnumerable<string> SecurityGroup, User User)
|
||||
{
|
||||
var subjectIds = (new string[] { User.UserId }).Concat(SecurityGroup).Select(sg => sg.ToLower());
|
||||
var subjectIds = SecurityGroup.Concat(new string[] { User.UserId });
|
||||
|
||||
return _Cache.Where(t => subjectIds.Any(sg => t.SubjectIdHashes.Contains(sg))).Cast<IRoleToken>().ToList();
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Disco.Services.Authorization.Roles
|
||||
return new RoleToken()
|
||||
{
|
||||
Role = Role,
|
||||
SubjectIdHashes = new HashSet<string>(sg.Select(i => i.ToLower())),
|
||||
SubjectIdHashes = new HashSet<string>(sg.Select(i => i.ToLower()), StringComparer.OrdinalIgnoreCase),
|
||||
SubjectIds = sg.ToList(),
|
||||
Claims = Claims
|
||||
};
|
||||
|
||||
@@ -174,12 +174,29 @@
|
||||
<Compile Include="Authorization\Roles\RoleToken.cs" />
|
||||
<Compile Include="Extensions\DateTimeExtensions.cs" />
|
||||
<Compile Include="Extensions\StringExtensions.cs" />
|
||||
<None Include="Interop\_ActiveDirectory\ActiveDirectory.cs" />
|
||||
<None Include="Interop\_ActiveDirectory\ActiveDirectoryExtensions.cs" />
|
||||
<None Include="Interop\_ActiveDirectory\Internal\ADDiscoverForestServers.cs" />
|
||||
<None Include="Interop\_ActiveDirectory\Internal\ADGroupCache.cs" />
|
||||
<None Include="Interop\_ActiveDirectory\Internal\ADInterop.cs" />
|
||||
<None Include="Interop\_ActiveDirectory\Internal\ADUpdateLastNetworkLogonDateJob.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ActiveDirectory.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryContext.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryExtensions.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\Internal\ADDiscoverForestServers.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\Internal\ADGroupCache.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\Internal\ADInterop.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\Internal\ADUpdateLastNetworkLogonDateJob.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryGroupCache.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADDirectoryEntry.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADDiscoverForestServers.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADDomain.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADDomainController.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADGroup.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADHelpers.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADMachineAccount.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADOrganisationalUnit.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADSearchResult.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADSite.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADTaskUpdateNetworkLogonDates.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADUserAccount.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\IADObject.cs" />
|
||||
<Compile Include="Jobs\JobExtensions.cs" />
|
||||
<Compile Include="Jobs\JobLists\JobTableExtensions.cs" />
|
||||
<Compile Include="Jobs\JobQueues\Cache.cs" />
|
||||
@@ -286,7 +303,7 @@
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties BuildVersion_UseGlobalSettings="False" BuildVersion_DetectChanges="False" BuildVersion_BuildAction="Both" BuildVersion_StartDate="2011/7/1" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" />
|
||||
<UserProperties BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_StartDate="2011/7/1" BuildVersion_BuildAction="Both" BuildVersion_DetectChanges="False" BuildVersion_UseGlobalSettings="False" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public class ADDirectoryEntry : IDisposable
|
||||
{
|
||||
public ADDomain Domain { get; private set; }
|
||||
public ADDomainController DomainController { get; private set; }
|
||||
public DirectoryEntry Entry { get; private set; }
|
||||
|
||||
internal ADDirectoryEntry(ADDomain Domain, ADDomainController DomainController, DirectoryEntry Entry)
|
||||
{
|
||||
if (Domain == null)
|
||||
throw new ArgumentNullException("Domain");
|
||||
if (DomainController == null)
|
||||
throw new ArgumentNullException("DomainController");
|
||||
if (Entry == null)
|
||||
throw new ArgumentNullException("Entry");
|
||||
|
||||
this.Domain = Domain;
|
||||
this.DomainController = DomainController;
|
||||
this.Entry = Entry;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Entry != null)
|
||||
{
|
||||
Entry.Dispose();
|
||||
Entry = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (this.Entry != null)
|
||||
return this.Entry.Path;
|
||||
else
|
||||
return base.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
-8
@@ -7,23 +7,25 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory.Internal
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public class ADDiscoverForestServers : ScheduledTask
|
||||
{
|
||||
public override string TaskName { get { return "Active Directory - Discover Forest Servers"; } }
|
||||
public override bool SingleInstanceTask { get { return true; } }
|
||||
public override bool CancelInitiallySupported { get { return false; } }
|
||||
internal static List<string> ForestServers { get; set; }
|
||||
private static object _scheduleLock = new object();
|
||||
|
||||
protected override void ExecuteTask()
|
||||
{
|
||||
var forestServers = DiscoverForestServers();
|
||||
ADInterop._ForestServers = forestServers;
|
||||
ADDiscoverForestServers.ForestServers = forestServers;
|
||||
|
||||
// Restrict Searching Entire Forest if to many servers
|
||||
using (DiscoDataContext Database = new DiscoDataContext())
|
||||
{
|
||||
var searchEntireForest = Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest;
|
||||
var searchEntireForest = Database.DiscoConfiguration.ActiveDirectory.SearchAllForestServers;
|
||||
|
||||
// Check explicitly configured: No
|
||||
if (!searchEntireForest.HasValue || searchEntireForest.Value)
|
||||
@@ -32,12 +34,12 @@ namespace Disco.Services.Interop.ActiveDirectory.Internal
|
||||
if (forestServers.Count > ActiveDirectory.MaxForestServerSearch)
|
||||
{
|
||||
// Update Database
|
||||
Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest = false;
|
||||
Database.DiscoConfiguration.ActiveDirectory.SearchAllForestServers = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default
|
||||
Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest = true;
|
||||
Database.DiscoConfiguration.ActiveDirectory.SearchAllForestServers = true;
|
||||
}
|
||||
|
||||
Database.SaveChanges();
|
||||
@@ -52,12 +54,59 @@ namespace Disco.Services.Interop.ActiveDirectory.Internal
|
||||
return taskStatus;
|
||||
else
|
||||
{
|
||||
var t = new ADDiscoverForestServers();
|
||||
return t.ScheduleTask();
|
||||
lock (_scheduleLock)
|
||||
{
|
||||
taskStatus = ScheduledTasks.GetTaskStatuses(typeof(ADDiscoverForestServers)).Where(ts => ts.IsRunning).FirstOrDefault();
|
||||
if (taskStatus != null)
|
||||
return taskStatus;
|
||||
else
|
||||
{
|
||||
var t = new ADDiscoverForestServers();
|
||||
return t.ScheduleTask();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static List<string> DiscoverForestServers()
|
||||
public static List<string> LoadForestServersBlocking()
|
||||
{
|
||||
if (ADDiscoverForestServers.ForestServers != null)
|
||||
return ADDiscoverForestServers.ForestServers;
|
||||
|
||||
ScheduledTaskStatus status;
|
||||
lock (_scheduleLock)
|
||||
{
|
||||
if (ADDiscoverForestServers.ForestServers != null)
|
||||
return ADDiscoverForestServers.ForestServers;
|
||||
|
||||
status = ADDiscoverForestServers.ScheduleNow();
|
||||
}
|
||||
|
||||
status.CompletionTask.Wait();
|
||||
return ForestServers;
|
||||
}
|
||||
|
||||
public static Task<List<string>> LoadForestServersAsync()
|
||||
{
|
||||
if (ADDiscoverForestServers.ForestServers != null)
|
||||
return Task.FromResult(ADDiscoverForestServers.ForestServers);
|
||||
|
||||
ScheduledTaskStatus status;
|
||||
lock (_scheduleLock)
|
||||
{
|
||||
if (ADDiscoverForestServers.ForestServers != null)
|
||||
return Task.FromResult(ADDiscoverForestServers.ForestServers);
|
||||
|
||||
status = ADDiscoverForestServers.ScheduleNow();
|
||||
}
|
||||
|
||||
return status.CompletionTask.ContinueWith(t =>
|
||||
{
|
||||
return ADDiscoverForestServers.ForestServers;
|
||||
});
|
||||
}
|
||||
|
||||
private static List<string> DiscoverForestServers()
|
||||
{
|
||||
using (var computerDomain = Domain.GetComputerDomain())
|
||||
{
|
||||
@@ -0,0 +1,383 @@
|
||||
using Disco.Services.Logging;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.DirectoryServices.ActiveDirectory;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public class ADDomain
|
||||
{
|
||||
private const int DomainMaintanceIntervalMinutes = 15;
|
||||
private const int SearchExceptionRetryMax = 4;
|
||||
|
||||
private ActiveDirectoryContext context;
|
||||
private ConcurrentStack<ADDomainController> domainControllers;
|
||||
|
||||
private int domainControllerRoundRobin = -1;
|
||||
private object domainMaintainLock = new object();
|
||||
private DateTime domainMaintenanceNext;
|
||||
|
||||
public Domain Domain { get; private set; }
|
||||
public IEnumerable<ADDomainController> DomainControllers
|
||||
{
|
||||
get
|
||||
{
|
||||
return domainControllers.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public string Name { get; private set; }
|
||||
public string NetBiosName { get; private set; }
|
||||
public string DistinguishedName { get; private set; }
|
||||
public string ConfigurationNamingContext { get; private set; }
|
||||
public SecurityIdentifier SecurityIdentifier { get; private set; }
|
||||
|
||||
public List<string> SearchContainers { get; private set; }
|
||||
|
||||
public ADDomain(ActiveDirectoryContext Context, Domain Domain)
|
||||
{
|
||||
this.context = Context;
|
||||
|
||||
this.Domain = Domain;
|
||||
this.SearchContainers = null;
|
||||
this.domainControllers = null;
|
||||
this.domainMaintenanceNext = DateTime.Now.AddMinutes(DomainMaintanceIntervalMinutes);
|
||||
|
||||
this.Initialize();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
this.Name = Domain.Name;
|
||||
|
||||
var dc = Domain.FindDomainController();
|
||||
|
||||
string ldapPath = string.Format("LDAP://{0}/", dc.Name);
|
||||
|
||||
using (var adRootDSE = new DirectoryEntry(ldapPath + "RootDSE"))
|
||||
{
|
||||
this.DistinguishedName = adRootDSE.Properties["defaultNamingContext"][0].ToString();
|
||||
this.ConfigurationNamingContext = adRootDSE.Properties["configurationNamingContext"][0].ToString();
|
||||
}
|
||||
|
||||
using (var adDomainRoot = new DirectoryEntry(ldapPath + this.DistinguishedName))
|
||||
{
|
||||
this.SecurityIdentifier = new SecurityIdentifier((byte[])(adDomainRoot.Properties["objectSid"][0]), 0);
|
||||
}
|
||||
|
||||
using (var configSearchRoot = new DirectoryEntry(ldapPath + "CN=Partitions," + this.ConfigurationNamingContext))
|
||||
{
|
||||
var configSearchFilter = string.Format("(&(objectcategory=Crossref)(dnsRoot={0})(netBIOSName=*))", this.Name);
|
||||
|
||||
using (var configSearcher = new DirectorySearcher(configSearchRoot, configSearchFilter, new string[] { "NetBIOSName" }, System.DirectoryServices.SearchScope.OneLevel))
|
||||
{
|
||||
SearchResult configResult = configSearcher.FindOne();
|
||||
if (configResult != null)
|
||||
this.NetBiosName = configResult.Properties["NetBIOSName"][0].ToString();
|
||||
else
|
||||
this.NetBiosName = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Domain Controllers
|
||||
|
||||
public IEnumerable<ADDomainController> GetAllReachableDomainControllers()
|
||||
{
|
||||
return this.Domain.FindAllDomainControllers().WhereReachable().Select(dc => new ADDomainController(this.context, dc, this, dc.SiteName == this.context.Site.Name, false));
|
||||
}
|
||||
|
||||
public IEnumerable<ADDomainController> GetReachableSiteDomainControllers()
|
||||
{
|
||||
return this.DomainControllers.Where(dc => dc.IsSiteServer && dc.DomainController.IsReachable());
|
||||
}
|
||||
|
||||
public ADDomainController GetAvailableDomainController(bool RequireWritable = false)
|
||||
{
|
||||
if (this.domainMaintenanceNext < DateTime.Now)
|
||||
MaintainDomainControllers();
|
||||
|
||||
IEnumerable<ADDomainController> availableServers;
|
||||
|
||||
// Try Site Servers first
|
||||
availableServers = AvilableDomainControllers(RequireSiteServer: true, RequireWritable: RequireWritable);
|
||||
|
||||
if (!availableServers.Any())
|
||||
{
|
||||
// No Site Servers available - try all
|
||||
availableServers = AvilableDomainControllers(RequireSiteServer: false, RequireWritable: RequireWritable);
|
||||
|
||||
if (!availableServers.Any())
|
||||
{
|
||||
lock (domainMaintainLock)
|
||||
{
|
||||
availableServers = AvilableDomainControllers(RequireSiteServer: false, RequireWritable: RequireWritable);
|
||||
|
||||
if (!availableServers.Any())
|
||||
return DiscoverAvailableDomainController(RequireWritable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (availableServers.Count())
|
||||
{
|
||||
case 1:
|
||||
// 1 Available DC
|
||||
return availableServers.First();
|
||||
default:
|
||||
// Multiple DCs Available - Round Robin
|
||||
int drr = Interlocked.Increment(ref domainControllerRoundRobin);
|
||||
int dcrrValue = drr % availableServers.Count();
|
||||
|
||||
if (drr > availableServers.Count())
|
||||
domainControllerRoundRobin = -1;
|
||||
|
||||
return availableServers.ElementAt(dcrrValue);
|
||||
}
|
||||
}
|
||||
private IEnumerable<ADDomainController> AvilableDomainControllers(bool RequireSiteServer, bool RequireWritable)
|
||||
{
|
||||
IEnumerable<ADDomainController> query = this.DomainControllers.Where(dc => dc.IsAvailable);
|
||||
if (RequireSiteServer)
|
||||
query = query.Where(dc => dc.IsSiteServer);
|
||||
if (RequireWritable)
|
||||
query = query.Where(dc => dc.IsWritable);
|
||||
|
||||
return query;
|
||||
}
|
||||
private ADDomainController DiscoverAvailableDomainController(bool RequireWritable)
|
||||
{
|
||||
LocatorOptions locatorOptions;
|
||||
if (RequireWritable)
|
||||
locatorOptions = LocatorOptions.ForceRediscovery | LocatorOptions.WriteableRequired;
|
||||
else
|
||||
locatorOptions = LocatorOptions.ForceRediscovery;
|
||||
|
||||
var dc = this.Domain.FindDomainController(locatorOptions);
|
||||
|
||||
var dcName = dc.Name;
|
||||
|
||||
var existingDC = this.DomainControllers.FirstOrDefault(edc => edc.Name == dcName);
|
||||
|
||||
if (existingDC != null)
|
||||
{
|
||||
// DC already in scope
|
||||
|
||||
// Native API indicates writable
|
||||
if (RequireWritable)
|
||||
existingDC.IsWritable = true;
|
||||
|
||||
// Native API indicates it is available
|
||||
existingDC.IsAvailable = true;
|
||||
|
||||
return existingDC;
|
||||
}
|
||||
else
|
||||
{
|
||||
// New DC discovered
|
||||
|
||||
var adDC = new ADDomainController(this.context, dc, this, dc.SiteName == this.context.Site.Name, RequireWritable);
|
||||
|
||||
// Add DC to Available Servers
|
||||
this.domainControllers.Push(adDC);
|
||||
|
||||
return adDC;
|
||||
}
|
||||
}
|
||||
|
||||
private void MaintainDomainControllers()
|
||||
{
|
||||
lock (domainMaintainLock)
|
||||
{
|
||||
var servers = this.domainControllers.ToList();
|
||||
|
||||
var nonSiteServersPresent = servers.Any(s => !s.IsSiteServer);
|
||||
|
||||
if (nonSiteServersPresent)
|
||||
{
|
||||
var siteServersAvailable = servers.Any(s => s.IsSiteServer && s.IsAvailable);
|
||||
var nonSiteServersUnavailable = servers.Any(s => !s.IsSiteServer && !s.IsAvailable);
|
||||
|
||||
if (siteServersAvailable)
|
||||
{
|
||||
// Remove non-site servers
|
||||
UpdateDomainControllers(servers.Where(s => s.IsSiteServer));
|
||||
}
|
||||
else if (nonSiteServersUnavailable)
|
||||
{
|
||||
// Remove unavailable non-site servers
|
||||
UpdateDomainControllers(servers.Where(s => s.IsSiteServer || s.IsAvailable));
|
||||
}
|
||||
}
|
||||
this.domainMaintenanceNext = DateTime.Now.AddMinutes(DomainMaintanceIntervalMinutes);
|
||||
}
|
||||
}
|
||||
|
||||
internal void UpdateDomainControllers(IEnumerable<ADDomainController> DomainControllers)
|
||||
{
|
||||
this.domainControllers = new ConcurrentStack<ADDomainController>(DomainControllers);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public ADDirectoryEntry RetrieveDirectoryEntry(string DistinguishedName, string[] LoadProperties = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(DistinguishedName))
|
||||
throw new ArgumentNullException("DistinguishedName");
|
||||
|
||||
if (!DistinguishedName.EndsWith(this.DistinguishedName, StringComparison.OrdinalIgnoreCase))
|
||||
throw new ArgumentException(string.Format("The Distinguished Name ({0}) isn't a member of this domain [{1}]", DistinguishedName, this.Name), "DistinguishedName");
|
||||
|
||||
var dc = GetAvailableDomainController();
|
||||
|
||||
return dc.RetrieveDirectoryEntry(DistinguishedName, LoadProperties);
|
||||
}
|
||||
|
||||
#region Searching
|
||||
|
||||
public IEnumerable<ADSearchResult> SearchEntireDomain(string LdapFilter, string[] LoadProperties, int? ResultLimit = null)
|
||||
{
|
||||
return SearchInternal(this.DistinguishedName, LdapFilter, LoadProperties, ResultLimit);
|
||||
}
|
||||
|
||||
public IEnumerable<ADSearchResult> SearchScope(string LdapFilter, string[] LoadProperties, int? ResultLimit = null)
|
||||
{
|
||||
var searchScope = this.SearchContainers;
|
||||
|
||||
// No scope set, search entire domain
|
||||
if (searchScope == null)
|
||||
return SearchEntireDomain(LdapFilter, LoadProperties, ResultLimit);
|
||||
|
||||
switch (searchScope.Count)
|
||||
{
|
||||
case 0: // Ignore domain
|
||||
return Enumerable.Empty<ADSearchResult>();
|
||||
|
||||
case 1: // Single-search
|
||||
return SearchInternal(searchScope[0], LdapFilter, LoadProperties, ResultLimit);
|
||||
|
||||
default: // Multi-search - Parallelize
|
||||
|
||||
var queryTasks = searchScope.Select(scope =>
|
||||
Task<IEnumerable<ADSearchResult>>.Factory.StartNew(() =>
|
||||
SearchInternal(scope, LdapFilter, LoadProperties, ResultLimit))).ToArray();
|
||||
|
||||
// Block
|
||||
Task.WaitAll(queryTasks);
|
||||
|
||||
var results = queryTasks.SelectMany(t => t.Result);
|
||||
if (ResultLimit.HasValue)
|
||||
results = results.Take(ResultLimit.Value);
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
internal IEnumerable<ADSearchResult> SearchInternal(string SearchRoot, string LdapFilter, string[] LoadProperties, int? ResultLimit)
|
||||
{
|
||||
if (string.IsNullOrEmpty(SearchRoot))
|
||||
throw new ArgumentNullException("SearchRoot");
|
||||
if (string.IsNullOrEmpty(LdapFilter))
|
||||
throw new ArgumentNullException("LdapFilter");
|
||||
if (ResultLimit.HasValue && ResultLimit.Value < 1)
|
||||
throw new ArgumentOutOfRangeException("ResultLimit", "The ResultLimit must be 1 or greater");
|
||||
|
||||
// Search with recovery
|
||||
var exceptionCount = 0;
|
||||
Queue<Exception> exceptions = null;
|
||||
do
|
||||
{
|
||||
var domainController = GetAvailableDomainController();
|
||||
|
||||
try
|
||||
{
|
||||
return domainController.SearchInternal(SearchRoot, LdapFilter, LoadProperties, ResultLimit);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (exceptions == null)
|
||||
exceptions = new Queue<Exception>(SearchExceptionRetryMax);
|
||||
|
||||
exceptions.Enqueue(ex);
|
||||
exceptionCount++;
|
||||
|
||||
// Set offline for DomainControllerUnavailableMinutes
|
||||
domainController.IsAvailable = false;
|
||||
SystemLog.LogWarning(string.Format("A domain controller [{0}] is offline. It will be retried after {1}. Error: {2} [{3}]", domainController.Name, domainController.AvailableWhen.Value.ToShortTimeString(), ex.Message, ex.GetType().Name));
|
||||
}
|
||||
} while (exceptionCount < SearchExceptionRetryMax);
|
||||
|
||||
throw new AggregateException(
|
||||
new Exception[] { new Exception(string.Format("Unable to perform Active Directory Search after {0} attempts", exceptionCount)) }
|
||||
.Concat(exceptions));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
internal void UpdateSearchContainers(List<string> Containers)
|
||||
{
|
||||
this.SearchContainers = Containers ?? new List<string>();
|
||||
}
|
||||
internal void UpdateSearchEntireDomain()
|
||||
{
|
||||
this.SearchContainers = null;
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
public string DefaultComputerContainer
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Format("CN=Computers,{0}", this.DistinguishedName);
|
||||
}
|
||||
}
|
||||
|
||||
public string FriendlyDistinguishedNamePath(string DistinguishedName)
|
||||
{
|
||||
if (!DistinguishedName.EndsWith(this.DistinguishedName, StringComparison.OrdinalIgnoreCase))
|
||||
throw new ArgumentException(string.Format("The Distinguished Name [{0}] doesn't exist within this domain [{1}]", DistinguishedName, this.DistinguishedName));
|
||||
|
||||
StringBuilder name = new StringBuilder();
|
||||
|
||||
name.Append('[').Append(this.NetBiosName).Append(']');
|
||||
|
||||
var subDN = DistinguishedName.Substring(0, DistinguishedName.Length - this.DistinguishedName.Length);
|
||||
var subDNComponents = subDN.Split(',');
|
||||
|
||||
subDNComponents
|
||||
.Where(c => !string.IsNullOrWhiteSpace(c))
|
||||
.Reverse()
|
||||
.Select(c => c.Substring(c.IndexOf('=') + 1))
|
||||
.ToList()
|
||||
.ForEach(c => name.Append(" > ").Append(c));
|
||||
|
||||
return name.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0} [{1}]", this.Name, this.NetBiosName);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || !(obj is ADDomain))
|
||||
return false;
|
||||
else
|
||||
return this.DistinguishedName == ((ADDomain)obj).DistinguishedName;
|
||||
}
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this.DistinguishedName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,424 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.DirectoryServices;
|
||||
using System.DirectoryServices.ActiveDirectory;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public class ADDomainController
|
||||
{
|
||||
private const string LdapPathTemplate = @"LDAP://{0}/{1}";
|
||||
private ActiveDirectoryContext context;
|
||||
|
||||
public DomainController DomainController { get; private set; }
|
||||
public ADDomain Domain { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public string SiteName { get; private set; }
|
||||
|
||||
public bool IsSiteServer { get; private set; }
|
||||
public bool IsWritable { get; internal set; }
|
||||
public DateTime? AvailableWhen { get; private set; }
|
||||
|
||||
public bool IsAvailable
|
||||
{
|
||||
get
|
||||
{
|
||||
var aw = AvailableWhen;
|
||||
if (aw.HasValue && aw.Value < DateTime.Now)
|
||||
AvailableWhen = null;
|
||||
|
||||
return !aw.HasValue;
|
||||
}
|
||||
internal set
|
||||
{
|
||||
if (value)
|
||||
AvailableWhen = null;
|
||||
else
|
||||
AvailableWhen = DateTime.Now.AddMinutes(ActiveDirectory.DomainControllerUnavailableMinutes);
|
||||
}
|
||||
}
|
||||
|
||||
public ADDomainController(ActiveDirectoryContext Context, DomainController DomainController, ADDomain Domain, bool IsSiteServer, bool IsWritable)
|
||||
{
|
||||
this.context = Context;
|
||||
|
||||
this.Domain = Domain;
|
||||
this.DomainController = DomainController;
|
||||
|
||||
this.Name = DomainController.Name;
|
||||
this.SiteName = DomainController.SiteName;
|
||||
|
||||
this.IsSiteServer = IsSiteServer;
|
||||
this.IsWritable = IsWritable;
|
||||
|
||||
this.AvailableWhen = null;
|
||||
}
|
||||
|
||||
public ADDirectoryEntry RetrieveDirectoryEntry(string DistinguishedName, string[] LoadProperties = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(DistinguishedName))
|
||||
throw new ArgumentNullException("DistinguishedName");
|
||||
|
||||
if (!DistinguishedName.EndsWith(this.Domain.DistinguishedName, StringComparison.OrdinalIgnoreCase))
|
||||
throw new ArgumentException(string.Format("The Distinguished Name ({0}) isn't a member of this domain [{1}]", DistinguishedName, this.Domain.Name), "DistinguishedName");
|
||||
|
||||
var entry = new DirectoryEntry(string.Format(LdapPathTemplate, this.Name, DistinguishedName));
|
||||
|
||||
if (LoadProperties != null)
|
||||
entry.RefreshCache(LoadProperties);
|
||||
|
||||
return new ADDirectoryEntry(this.Domain, this, entry);
|
||||
}
|
||||
|
||||
#region Searching
|
||||
public IEnumerable<ADSearchResult> SearchEntireDomain(string LdapFilter, string[] LoadProperties, int? ResultLimit = null)
|
||||
{
|
||||
return SearchInternal(Domain.DistinguishedName, LdapFilter, LoadProperties, ResultLimit);
|
||||
}
|
||||
|
||||
public IEnumerable<ADSearchResult> SearchScope(string LdapFilter, string[] LoadProperties, int? ResultLimit = null)
|
||||
{
|
||||
var searchScope = this.Domain.SearchContainers;
|
||||
|
||||
// No scope set, search entire domain
|
||||
if (searchScope == null)
|
||||
return SearchEntireDomain(LdapFilter, LoadProperties, ResultLimit);
|
||||
|
||||
// Ignore domain
|
||||
if (searchScope.Count == 0)
|
||||
return Enumerable.Empty<ADSearchResult>();
|
||||
|
||||
// Multi-search
|
||||
var results = searchScope.SelectMany(scope => SearchInternal(scope, LdapFilter, LoadProperties, ResultLimit));
|
||||
if (ResultLimit.HasValue)
|
||||
results = results.Take(ResultLimit.Value);
|
||||
return results;
|
||||
}
|
||||
|
||||
internal IEnumerable<ADSearchResult> SearchInternal(string SearchRoot, string LdapFilter, string[] LoadProperties, int? ResultLimit)
|
||||
{
|
||||
if (string.IsNullOrEmpty(SearchRoot))
|
||||
throw new ArgumentNullException("SearchRoot");
|
||||
if (string.IsNullOrEmpty(LdapFilter))
|
||||
throw new ArgumentNullException("LdapFilter");
|
||||
if (ResultLimit.HasValue && ResultLimit.Value < 1)
|
||||
throw new ArgumentOutOfRangeException("ResultLimit", "The ResultLimit must be 1 or greater");
|
||||
|
||||
using (ADDirectoryEntry rootEntry = this.RetrieveDirectoryEntry(SearchRoot))
|
||||
{
|
||||
using (DirectorySearcher searcher = new DirectorySearcher(rootEntry.Entry, LdapFilter, LoadProperties, System.DirectoryServices.SearchScope.Subtree))
|
||||
{
|
||||
searcher.PageSize = 500;
|
||||
|
||||
if (ResultLimit.HasValue)
|
||||
searcher.SizeLimit = ResultLimit.Value;
|
||||
|
||||
return searcher.FindAll().Cast<SearchResult>().Select(result => new ADSearchResult(Domain, this, SearchRoot, LdapFilter, result));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region AD Objects
|
||||
|
||||
#region User Accounts
|
||||
public ADUserAccount RetrieveADUserAccount(string Id, string[] AdditionalProperties = null)
|
||||
{
|
||||
string[] loadProperites = (AdditionalProperties != null && AdditionalProperties.Length > 0)
|
||||
? ADUserAccount.LoadProperties.Concat(AdditionalProperties).ToArray()
|
||||
: ADUserAccount.LoadProperties;
|
||||
|
||||
var result = RetrieveBySamAccountName(Id, ADUserAccount.LdapSamAccountNameFilterTemplate, loadProperites);
|
||||
|
||||
if (result == null)
|
||||
return null;
|
||||
else
|
||||
return result.AsADUserAccount(false, AdditionalProperties);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Machine Accounts
|
||||
public ADMachineAccount RetrieveADMachineAccount(string Id, System.Guid? UUIDNetbootGUID, System.Guid? MacAddressNetbootGUID, string[] AdditionalProperties = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Id))
|
||||
throw new ArgumentNullException("Id");
|
||||
|
||||
// Add $ identifier for machine accounts
|
||||
if (!Id.EndsWith("$"))
|
||||
Id += "$";
|
||||
|
||||
string[] loadProperites = (AdditionalProperties != null && AdditionalProperties.Length > 0)
|
||||
? ADMachineAccount.LoadProperties.Concat(AdditionalProperties).ToArray()
|
||||
: ADMachineAccount.LoadProperties;
|
||||
|
||||
ADSearchResult adResult;
|
||||
|
||||
adResult = RetrieveBySamAccountName(Id, ADMachineAccount.LdapSamAccountNameFilterTemplate, loadProperites);
|
||||
if (adResult == null && (UUIDNetbootGUID.HasValue || MacAddressNetbootGUID.HasValue))
|
||||
{
|
||||
string ldapFilter;
|
||||
if (UUIDNetbootGUID.HasValue && MacAddressNetbootGUID.HasValue)
|
||||
{
|
||||
ldapFilter = string.Format(ADMachineAccount.LdapNetbootGuidDoubleFilterTemplate, UUIDNetbootGUID.Value.ToLdapQueryFormat(), MacAddressNetbootGUID.Value.ToLdapQueryFormat());
|
||||
}
|
||||
else if (UUIDNetbootGUID.HasValue)
|
||||
{
|
||||
ldapFilter = string.Format(ADMachineAccount.LdapNetbootGuidSingleFilterTemplate, UUIDNetbootGUID.Value.ToLdapQueryFormat());
|
||||
}
|
||||
else // MacAddressNetbootGUID.HasValue
|
||||
{
|
||||
ldapFilter = string.Format(ADMachineAccount.LdapNetbootGuidSingleFilterTemplate, MacAddressNetbootGUID.Value.ToLdapQueryFormat());
|
||||
}
|
||||
adResult = this.SearchEntireDomain(ldapFilter, loadProperites, ActiveDirectory.SingleSearchResult).FirstOrDefault();
|
||||
}
|
||||
|
||||
if (adResult != null)
|
||||
return adResult.AsADMachineAccount(AdditionalProperties);
|
||||
else
|
||||
return null; // Not Found
|
||||
}
|
||||
public ADMachineAccount RetrieveADMachineAccount(string Id, string[] AdditionalProperties = null)
|
||||
{
|
||||
return RetrieveADMachineAccount(Id, null, null, AdditionalProperties);
|
||||
}
|
||||
public ADMachineAccount RetrieveADMachineAccount(string Id, System.Guid? NetbootGUID, string[] AdditionalProperties = null)
|
||||
{
|
||||
return RetrieveADMachineAccount(Id, NetbootGUID, null, AdditionalProperties);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Groups
|
||||
public ADGroup RetrieveADGroup(string Id)
|
||||
{
|
||||
var result = RetrieveBySamAccountName(Id, ADGroup.LdapSamAccountNameFilterTemplate, ADGroup.LoadProperties);
|
||||
|
||||
if (result == null)
|
||||
return null;
|
||||
else
|
||||
return result.AsADGroup();
|
||||
}
|
||||
public ADGroup RetrieveADGroupByDistinguishedName(string DistinguishedName)
|
||||
{
|
||||
using (var groupEntry = this.RetrieveDirectoryEntry(DistinguishedName, ADGroup.LoadProperties))
|
||||
{
|
||||
if (groupEntry == null)
|
||||
return null;
|
||||
|
||||
return groupEntry.AsADGroup();
|
||||
}
|
||||
}
|
||||
public ADGroup RetrieveADGroupWithSecurityIdentifier(SecurityIdentifier SecurityIdentifier)
|
||||
{
|
||||
if (SecurityIdentifier == null)
|
||||
throw new ArgumentNullException("SecurityIdentifier");
|
||||
if (!SecurityIdentifier.IsEqualDomainSid(this.Domain.SecurityIdentifier))
|
||||
throw new ArgumentException(string.Format("The specified Security Identifier [{0}] does not belong to this domain [{1}]", SecurityIdentifier.ToString(), this.Domain.Name), "SecurityIdentifier");
|
||||
|
||||
var sidBinaryString = SecurityIdentifier.ToBinaryString();
|
||||
|
||||
string ldapFilter = string.Format(ADGroup.LdapSecurityIdentifierFilterTemplate, sidBinaryString);
|
||||
|
||||
var result = this.SearchEntireDomain(ldapFilter, ADGroup.LoadProperties, ActiveDirectory.SingleSearchResult).FirstOrDefault();
|
||||
if (result == null)
|
||||
return null;
|
||||
else
|
||||
return result.AsADGroup();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Object
|
||||
private const string ObjectLdapSamAccountNameFilter = "(&(|(objectCategory=Person)(objectCategory=Computer)(objectCategory=Group))(sAMAccountName={0}))";
|
||||
private static readonly string[] ObjectLoadProperties = { "objectCategory" };
|
||||
private static readonly string[] ObjectLoadPropertiesAll = ObjectLoadProperties.Concat(ADUserAccount.LoadProperties).Concat(ADMachineAccount.LoadProperties).Concat(ADGroup.LoadProperties).Distinct().ToArray();
|
||||
|
||||
public IADObject RetrieveADObject(string Id, bool Quick)
|
||||
{
|
||||
var result = RetrieveBySamAccountName(Id, ObjectLdapSamAccountNameFilter, ObjectLoadPropertiesAll);
|
||||
|
||||
if (result == null)
|
||||
return null;
|
||||
else
|
||||
{
|
||||
var objectCategory = result.Value<string>("objectCategory");
|
||||
objectCategory = objectCategory.Substring(0, objectCategory.IndexOf(',')).ToLower();
|
||||
switch (objectCategory)
|
||||
{
|
||||
case "cn=person":
|
||||
return result.AsADUserAccount(Quick, null);
|
||||
case "cn=computer":
|
||||
return result.AsADMachineAccount(null);
|
||||
case "cn=group":
|
||||
return result.AsADGroup();
|
||||
default:
|
||||
throw new InvalidOperationException("Unexpected objectCategory");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Organisational Units
|
||||
private const string OrganisationalUnitsLdapFilter = "(objectCategory=organizationalUnit)";
|
||||
private static readonly string[] OrganisationalUnitsLoadProperties = { "name", "distinguishedName" };
|
||||
|
||||
public List<ADOrganisationalUnit> RetrieveADOrganisationalUnitStructure()
|
||||
{
|
||||
Dictionary<string, List<ADOrganisationalUnit>> resultTree = new Dictionary<string, List<ADOrganisationalUnit>>();
|
||||
|
||||
var unsortedOrganisationalUnits = this.SearchEntireDomain(OrganisationalUnitsLdapFilter, OrganisationalUnitsLoadProperties)
|
||||
.Select(r => r.AsADOrganisationalUnit()).ToList();
|
||||
|
||||
var indexedOrganisationalUnits = unsortedOrganisationalUnits.ToDictionary(k => k.DistinguishedName);
|
||||
|
||||
var indexedChildren = unsortedOrganisationalUnits
|
||||
.GroupBy(ou => ou.DistinguishedName.Substring(ou.DistinguishedName.IndexOf(',') + 1))
|
||||
.ToDictionary(g => g.Key, g => g.ToList());
|
||||
|
||||
// Link Children
|
||||
foreach (var ouChildren in indexedChildren)
|
||||
{
|
||||
ADOrganisationalUnit ouParent;
|
||||
if (indexedOrganisationalUnits.TryGetValue(ouChildren.Key, out ouParent))
|
||||
{
|
||||
ouParent.Children = ouChildren.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return indexedChildren[Domain.DistinguishedName];
|
||||
}
|
||||
#endregion
|
||||
|
||||
private ADSearchResult RetrieveBySamAccountName(string Id, string LdapFilterTemplate, string[] LoadProperties)
|
||||
{
|
||||
var splitId = UserExtensions.SplitUserId(Id);
|
||||
|
||||
if (!this.Domain.NetBiosName.Equals(splitId.Item1, StringComparison.OrdinalIgnoreCase))
|
||||
throw new ArgumentException(string.Format("The Id [{0}] is invalid for this domain [{1}]", Id, this.Domain.Name), "Id");
|
||||
|
||||
var ldapFilter = string.Format(LdapFilterTemplate, splitId.Item2);
|
||||
|
||||
return this.SearchEntireDomain(ldapFilter, LoadProperties, ActiveDirectory.SingleSearchResult).FirstOrDefault();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Actions
|
||||
public bool IsReachable()
|
||||
{
|
||||
using (Ping p = new Ping())
|
||||
{
|
||||
var pr = p.Send(this.Name, 1000);
|
||||
return (pr.Status == IPStatus.Success);
|
||||
}
|
||||
}
|
||||
|
||||
public string OfflineDomainJoinProvision(string ComputerSamAccountName, string OrganisationalUnit, ref ADMachineAccount MachineAccount, out string DiagnosticInformation)
|
||||
{
|
||||
if (MachineAccount != null && MachineAccount.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", MachineAccount.DistinguishedName));
|
||||
|
||||
if (!this.IsWritable)
|
||||
throw new InvalidOperationException(string.Format("The domain controller [{0}] is not writable. This action (Offline Domain Join Provision) requires a writable domain controller.", this.Name));
|
||||
|
||||
StringBuilder diagnosticInfo = new StringBuilder();
|
||||
string DJoinResult = null;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(ComputerSamAccountName))
|
||||
ComputerSamAccountName = ComputerSamAccountName.TrimEnd('$');
|
||||
if (!string.IsNullOrWhiteSpace(ComputerSamAccountName) && ComputerSamAccountName.Contains('\\'))
|
||||
ComputerSamAccountName = ComputerSamAccountName.Substring(ComputerSamAccountName.IndexOf('\\') + 1);
|
||||
if (string.IsNullOrWhiteSpace(ComputerSamAccountName) || ComputerSamAccountName.Length > 24)
|
||||
throw new System.ArgumentException("Invalid Computer Name; > 0 and <= 24", "ComputerName");
|
||||
|
||||
// Ensure Specified OU Exists
|
||||
if (!string.IsNullOrEmpty(OrganisationalUnit))
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var deOU = this.RetrieveDirectoryEntry(OrganisationalUnit, new string[] { "distinguishedName" }))
|
||||
{
|
||||
if (deOU == null)
|
||||
throw new Exception(string.Format("OU's Directory Entry couldn't be found at [{0}]", OrganisationalUnit));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ArgumentException(string.Format("An error occurred while trying to locate the specified OU: {0}", OrganisationalUnit), "OrganisationalUnit", ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (MachineAccount != null)
|
||||
MachineAccount.DeleteAccount(this);
|
||||
|
||||
string tempFileName = System.IO.Path.GetTempFileName();
|
||||
string argumentOU = (!string.IsNullOrWhiteSpace(OrganisationalUnit)) ? string.Format(" /MACHINEOU \"{0}\"", OrganisationalUnit) : string.Empty;
|
||||
string arguments = string.Format("/PROVISION /DOMAIN \"{0}\" /DCNAME \"{1}\" /MACHINE \"{2}\"{3} /REUSE /SAVEFILE \"{4}\"",
|
||||
this.Domain.Name,
|
||||
this.Name,
|
||||
ComputerSamAccountName,
|
||||
argumentOU,
|
||||
tempFileName
|
||||
);
|
||||
ProcessStartInfo commandStarter = new ProcessStartInfo("DJOIN.EXE", arguments)
|
||||
{
|
||||
CreateNoWindow = true,
|
||||
ErrorDialog = false,
|
||||
LoadUserProfile = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false
|
||||
};
|
||||
diagnosticInfo.AppendFormat("{0} {1}", "DJOIN.EXE", arguments);
|
||||
diagnosticInfo.AppendLine();
|
||||
|
||||
string stdOutput;
|
||||
string stdError;
|
||||
using (Process commandProc = Process.Start(commandStarter))
|
||||
{
|
||||
commandProc.WaitForExit(20000);
|
||||
stdOutput = commandProc.StandardOutput.ReadToEnd();
|
||||
stdError = commandProc.StandardError.ReadToEnd();
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(stdOutput))
|
||||
diagnosticInfo.AppendLine(stdOutput);
|
||||
if (!string.IsNullOrWhiteSpace(stdError))
|
||||
diagnosticInfo.AppendLine(stdError);
|
||||
|
||||
if (System.IO.File.Exists(tempFileName))
|
||||
{
|
||||
DJoinResult = System.Convert.ToBase64String(System.IO.File.ReadAllBytes(tempFileName));
|
||||
System.IO.File.Delete(tempFileName);
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(DJoinResult))
|
||||
throw new System.InvalidOperationException(string.Format("Domain Join Unsuccessful{0}Error: {1}{0}Output: {2}", System.Environment.NewLine, stdError, stdOutput));
|
||||
|
||||
DiagnosticInformation = diagnosticInfo.ToString();
|
||||
|
||||
// Reload Machine Account
|
||||
MachineAccount = this.RetrieveADMachineAccount(string.Format(@"{0}\{1}", this.Domain.NetBiosName, ComputerSamAccountName), (MachineAccount == null ? null : MachineAccount.LoadedProperties.Keys.ToArray()));
|
||||
|
||||
return DJoinResult;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.Name;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || !(obj is ADDomainController))
|
||||
return false;
|
||||
else
|
||||
return this.Name == ((ADDomainController)obj).Name;
|
||||
}
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public class ADGroup : IADObject
|
||||
{
|
||||
internal static readonly string[] LoadProperties = { "name", "distinguishedName", "sAMAccountName", "objectSid", "memberOf" };
|
||||
internal const string LdapSearchFilterTemplate = "(&(objectCategory=Group)(|(sAMAccountName=*{0}*)(name=*{0}*)(cn=*{0}*)))";
|
||||
internal const string LdapSamAccountNameFilterTemplate = "(&(objectCategory=Group)(sAMAccountName={0}))";
|
||||
internal const string LdapSecurityIdentifierFilterTemplate = "(&(objectCategory=Group)(objectSid={0}))";
|
||||
|
||||
public ADDomain Domain { get; private set; }
|
||||
|
||||
public string DistinguishedName { get; private set; }
|
||||
public SecurityIdentifier SecurityIdentifier { get; private set; }
|
||||
|
||||
public string Id { get { return string.Format(@"{0}\{1}", Domain.NetBiosName, SamAccountName); } }
|
||||
public string SamAccountName { get; private set; }
|
||||
|
||||
public string Name { get; private set; }
|
||||
public string DisplayName { get { return this.Name; } }
|
||||
|
||||
public List<string> MemberOf { get; private set; }
|
||||
|
||||
private ADGroup(ADDomain Domain, string DistinguishedName, SecurityIdentifier SecurityIdentifier, string SamAccountName, string Name, List<string> MemberOf)
|
||||
{
|
||||
this.Domain = Domain;
|
||||
this.DistinguishedName = DistinguishedName;
|
||||
this.SecurityIdentifier = SecurityIdentifier;
|
||||
this.SamAccountName = SamAccountName;
|
||||
this.Name = Name;
|
||||
this.MemberOf = MemberOf;
|
||||
}
|
||||
|
||||
public static ADGroup FromSearchResult(ADSearchResult SearchResult)
|
||||
{
|
||||
if (SearchResult == null)
|
||||
throw new ArgumentNullException("SearchResult");
|
||||
|
||||
var name = SearchResult.Value<string>("name");
|
||||
var distinguishedName = SearchResult.Value<string>("distinguishedName");
|
||||
var sAMAccountName = SearchResult.Value<string>("sAMAccountName");
|
||||
var objectSid = new SecurityIdentifier(SearchResult.Value<byte[]>("objectSid"), 0);
|
||||
var memberOf = SearchResult.Values<string>("memberOf").ToList();
|
||||
|
||||
return new ADGroup(SearchResult.Domain, distinguishedName, objectSid, sAMAccountName, name, memberOf);
|
||||
}
|
||||
|
||||
public static ADGroup FromDirectoryEntry(ADDirectoryEntry DirectoryEntry)
|
||||
{
|
||||
if (DirectoryEntry == null)
|
||||
throw new ArgumentNullException("DirectoryEntry");
|
||||
|
||||
var properties = DirectoryEntry.Entry.Properties;
|
||||
|
||||
var name = properties.Value<string>("name");
|
||||
var distinguishedName = properties.Value<string>("distinguishedName");
|
||||
var sAMAccountName = properties.Value<string>("sAMAccountName");
|
||||
var objectSid = new SecurityIdentifier(properties.Value<byte[]>("objectSid"), 0);
|
||||
var memberOf = properties.Values<string>("memberOf").ToList();
|
||||
|
||||
return new ADGroup(DirectoryEntry.Domain, distinguishedName, objectSid, sAMAccountName, name, memberOf);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.Id;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || !(obj is ADGroup))
|
||||
return false;
|
||||
else
|
||||
return this.DistinguishedName == ((ADGroup)obj).DistinguishedName;
|
||||
}
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this.DistinguishedName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
internal static class ADHelpers
|
||||
{
|
||||
internal static byte[] ToBytes(this SecurityIdentifier Sid)
|
||||
{
|
||||
var sidBytes = new byte[Sid.BinaryLength];
|
||||
|
||||
Sid.GetBinaryForm(sidBytes, 0);
|
||||
|
||||
return sidBytes;
|
||||
}
|
||||
|
||||
internal static SecurityIdentifier BuildPrimaryGroupSid(SecurityIdentifier UserSid, int PrimaryGroupId)
|
||||
{
|
||||
var groupSid = UserSid.ToBytes();
|
||||
|
||||
int ridOffset = groupSid.Length - 4;
|
||||
int groupId = PrimaryGroupId;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
groupSid[ridOffset + i] = (byte)(groupId & 0xFF);
|
||||
groupId >>= 8;
|
||||
}
|
||||
|
||||
return new SecurityIdentifier(groupSid, 0);
|
||||
}
|
||||
|
||||
internal static string ToBinaryString(this SecurityIdentifier Sid)
|
||||
{
|
||||
StringBuilder escapedSid = new StringBuilder();
|
||||
|
||||
foreach (var sidByte in Sid.ToBytes())
|
||||
{
|
||||
escapedSid.Append('\\');
|
||||
escapedSid.Append(sidByte.ToString("x2"));
|
||||
}
|
||||
|
||||
return escapedSid.ToString();
|
||||
}
|
||||
|
||||
internal static string EscapeLdapQuery(string query)
|
||||
{
|
||||
return query.Replace("*", "\\2a").Replace("(", "\\28").Replace(")", "\\29").Replace("\\", "\\5c").Replace("NUL", "\\00").Replace("/", "\\2f");
|
||||
}
|
||||
|
||||
internal static string ToLdapQueryFormat(this System.Guid g)
|
||||
{
|
||||
checked
|
||||
{
|
||||
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
||||
byte[] array = g.ToByteArray();
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
byte b = array[i];
|
||||
sb.Append("\\");
|
||||
sb.Append(b.ToString("X2"));
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
using Disco.Models.Repository;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public class ADMachineAccount : IADObject
|
||||
{
|
||||
internal static readonly string[] LoadProperties = { "name", "distinguishedName", "sAMAccountName", "objectSid", "dNSHostName", "netbootGUID", "isCriticalSystemObject" };
|
||||
internal const string LdapSamAccountNameFilterTemplate = "(&(objectCategory=computer)(sAMAccountName={0}))";
|
||||
internal const string LdapNetbootGuidSingleFilterTemplate = "(&(objectCategory=computer)(netbootGUID={0}))";
|
||||
internal const string LdapNetbootGuidDoubleFilterTemplate = "(&(objectCategory=computer)(|(netbootGUID={0})(netbootGUID={1})))";
|
||||
|
||||
public ADDomain Domain { get; private set; }
|
||||
|
||||
public string DistinguishedName { get; private set; }
|
||||
public SecurityIdentifier SecurityIdentifier { get; private set; }
|
||||
public string Id { get { return string.Format(@"{0}\{1}", Domain.NetBiosName, SamAccountName); } }
|
||||
|
||||
public string SamAccountName { get; private set; }
|
||||
|
||||
public string Name { get; private set; }
|
||||
public string DisplayName { get { return this.Name; } }
|
||||
|
||||
public string DnsName { get; private set; }
|
||||
public Guid NetbootGUID { get; private set; }
|
||||
|
||||
public bool IsCriticalSystemObject { get; private set; }
|
||||
public Dictionary<string, object[]> LoadedProperties { get; private set; }
|
||||
|
||||
public string ParentDistinguishedName
|
||||
{
|
||||
get
|
||||
{
|
||||
return DistinguishedName.Substring(DistinguishedName.IndexOf(',') + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private ADMachineAccount(ADDomain Domain, string DistinguishedName, SecurityIdentifier SecurityIdentifier, string SamAccountName, string Name, string DnsName, Guid NetbootGUID, bool IsCriticalSystemObject, Dictionary<string, object[]> LoadedProperties)
|
||||
{
|
||||
this.Domain = Domain;
|
||||
this.DistinguishedName = DistinguishedName;
|
||||
this.SecurityIdentifier = SecurityIdentifier;
|
||||
this.SamAccountName = SamAccountName;
|
||||
this.Name = Name;
|
||||
this.DnsName = DnsName;
|
||||
this.NetbootGUID = NetbootGUID;
|
||||
this.IsCriticalSystemObject = IsCriticalSystemObject;
|
||||
this.LoadedProperties = LoadedProperties;
|
||||
}
|
||||
|
||||
public static ADMachineAccount FromSearchResult(ADSearchResult SearchResult, string[] AdditionalProperties)
|
||||
{
|
||||
if (SearchResult == null)
|
||||
throw new ArgumentNullException("SearchResult");
|
||||
|
||||
string name = SearchResult.Value<string>("name");
|
||||
string sAMAccountName = SearchResult.Value<string>("sAMAccountName");
|
||||
string distinguishedName = SearchResult.Value<string>("distinguishedName");
|
||||
var objectSid = new SecurityIdentifier(SearchResult.Value<byte[]>("objectSid"), 0);
|
||||
|
||||
var dNSName = SearchResult.Value<string>("dNSHostName");
|
||||
if (dNSName == null)
|
||||
dNSName = string.Format("{0}.{1}", sAMAccountName.TrimEnd('$'), SearchResult.Domain.Name);
|
||||
|
||||
bool isCriticalSystemObject = SearchResult.Value<bool>("isCriticalSystemObject");
|
||||
|
||||
var netbootGUID = default(Guid);
|
||||
byte[] netbootGuidBytes = SearchResult.Value<byte[]>("netbootGUID");
|
||||
if (netbootGuidBytes != null)
|
||||
netbootGUID = new Guid(netbootGuidBytes);
|
||||
|
||||
// Additional Properties
|
||||
Dictionary<string, object[]> additionalProperties;
|
||||
if (AdditionalProperties != null)
|
||||
additionalProperties = AdditionalProperties
|
||||
.Select(p => Tuple.Create(p, SearchResult.Values<object>(p).ToArray()))
|
||||
.ToDictionary(t => t.Item1, t => t.Item2);
|
||||
else
|
||||
{
|
||||
additionalProperties = new Dictionary<string, object[]>();
|
||||
}
|
||||
|
||||
return new ADMachineAccount(
|
||||
SearchResult.Domain,
|
||||
distinguishedName,
|
||||
objectSid,
|
||||
sAMAccountName,
|
||||
name,
|
||||
dNSName,
|
||||
netbootGUID,
|
||||
isCriticalSystemObject,
|
||||
additionalProperties);
|
||||
}
|
||||
|
||||
public User ToRepositoryUser()
|
||||
{
|
||||
return new User
|
||||
{
|
||||
UserId = this.Id,
|
||||
DisplayName = this.Name
|
||||
};
|
||||
}
|
||||
|
||||
public object GetPropertyValue(string PropertyName, int Index = 0)
|
||||
{
|
||||
switch (PropertyName.ToLower())
|
||||
{
|
||||
case "name":
|
||||
return this.Name;
|
||||
case "samaccountname":
|
||||
return this.SamAccountName;
|
||||
case "distinguishedname":
|
||||
return this.DistinguishedName;
|
||||
case "objectsid":
|
||||
return this.SecurityIdentifier.ToString();
|
||||
case "netbootguid":
|
||||
return this.NetbootGUID;
|
||||
default:
|
||||
object[] adProperty;
|
||||
if (this.LoadedProperties.TryGetValue(PropertyName, out adProperty) && Index <= adProperty.Length)
|
||||
return adProperty[Index];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#region Actions
|
||||
|
||||
public void DeleteAccount(ADDomainController WritableDomainController)
|
||||
{
|
||||
if (this.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account [{0}] is a Critical System Active Directory Object and Disco refuses to modify it", this.DistinguishedName));
|
||||
|
||||
if (!WritableDomainController.IsWritable)
|
||||
throw new InvalidOperationException(string.Format("The domain controller [{0}] is not writable. This action (Offline Domain Join Provision) requires a writable domain controller.", this.Name));
|
||||
|
||||
using (ADDirectoryEntry entry = WritableDomainController.RetrieveDirectoryEntry(this.DistinguishedName))
|
||||
{
|
||||
entry.Entry.DeleteTree();
|
||||
}
|
||||
}
|
||||
public void DeleteAccount()
|
||||
{
|
||||
this.DeleteAccount(Domain.GetAvailableDomainController(RequireWritable: true));
|
||||
}
|
||||
|
||||
private void SetNetbootGUID(ADDomainController WritableDomainController, System.Guid updatedNetbootGUID)
|
||||
{
|
||||
if (this.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", this.DistinguishedName));
|
||||
|
||||
using (var deAccount = WritableDomainController.RetrieveDirectoryEntry(this.DistinguishedName))
|
||||
{
|
||||
var netbootGUIDProp = deAccount.Entry.Properties["netbootGUID"];
|
||||
bool flag = netbootGUIDProp.Count > 0;
|
||||
if (flag)
|
||||
{
|
||||
netbootGUIDProp.Clear();
|
||||
}
|
||||
netbootGUIDProp.Add(updatedNetbootGUID.ToByteArray());
|
||||
deAccount.Entry.CommitChanges();
|
||||
}
|
||||
}
|
||||
public void SetDescription(ADDomainController WritableDomainController, string Description)
|
||||
{
|
||||
using (var deAccount = WritableDomainController.RetrieveDirectoryEntry(this.DistinguishedName))
|
||||
{
|
||||
var descriptionProp = deAccount.Entry.Properties["description"];
|
||||
if (descriptionProp.Count > 0)
|
||||
{
|
||||
descriptionProp.Clear();
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Description))
|
||||
{
|
||||
descriptionProp.Add(Description);
|
||||
}
|
||||
deAccount.Entry.CommitChanges();
|
||||
}
|
||||
}
|
||||
public void SetDescription(string Description)
|
||||
{
|
||||
this.SetDescription(Domain.GetAvailableDomainController(RequireWritable: true), Description);
|
||||
}
|
||||
|
||||
public void SetDescription(ADDomainController WritableDomainController, Device Device)
|
||||
{
|
||||
System.Text.StringBuilder descriptionBuilder = new System.Text.StringBuilder();
|
||||
|
||||
if (Device.AssignedUserId != null)
|
||||
{
|
||||
descriptionBuilder.Append(Device.AssignedUser.UserId).Append(" (").Append(Device.AssignedUser.DisplayName).Append("); ");
|
||||
}
|
||||
|
||||
if (Device.DeviceModelId.HasValue)
|
||||
{
|
||||
descriptionBuilder.Append(Device.DeviceModel.Description).Append("; ");
|
||||
}
|
||||
|
||||
descriptionBuilder.Append(Device.DeviceProfile.Description).Append(";");
|
||||
|
||||
string description = descriptionBuilder.ToString().Trim();
|
||||
if (description.Length > 1024)
|
||||
description = description.Substring(0, 1024);
|
||||
|
||||
this.SetDescription(WritableDomainController, description);
|
||||
}
|
||||
public void SetDescription(Device Device)
|
||||
{
|
||||
this.SetDescription(Domain.GetAvailableDomainController(RequireWritable: true), Device);
|
||||
}
|
||||
|
||||
public void DisableAccount(ADDomainController WritableDomainController)
|
||||
{
|
||||
if (this.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", this.DistinguishedName));
|
||||
|
||||
using (var deAccount = WritableDomainController.RetrieveDirectoryEntry(this.DistinguishedName))
|
||||
{
|
||||
int accountControl = (int)deAccount.Entry.Properties["userAccountControl"][0];
|
||||
int updatedAccountControl = (accountControl | 2);
|
||||
if (accountControl != updatedAccountControl)
|
||||
{
|
||||
deAccount.Entry.Properties["userAccountControl"][0] = updatedAccountControl;
|
||||
deAccount.Entry.CommitChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
public void DisableAccount()
|
||||
{
|
||||
this.DisableAccount(Domain.GetAvailableDomainController(RequireWritable: true));
|
||||
}
|
||||
|
||||
public void EnableAccount(ADDomainController WritableDomainController)
|
||||
{
|
||||
if (this.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", this.DistinguishedName));
|
||||
|
||||
using (var deAccount = WritableDomainController.RetrieveDirectoryEntry(this.DistinguishedName))
|
||||
{
|
||||
int accountControl = (int)deAccount.Entry.Properties["userAccountControl"][0];
|
||||
if ((accountControl & 2) == 2)
|
||||
{
|
||||
int updatedAccountControl = (accountControl ^ 2);
|
||||
deAccount.Entry.Properties["userAccountControl"][0] = updatedAccountControl;
|
||||
deAccount.Entry.CommitChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
public void EnableAccount()
|
||||
{
|
||||
this.EnableAccount(Domain.GetAvailableDomainController(RequireWritable: true));
|
||||
}
|
||||
|
||||
public bool UpdateNetbootGUID(ADDomainController WritableDomainController, string UUID, string MACAddress)
|
||||
{
|
||||
if (this.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", this.DistinguishedName));
|
||||
|
||||
Guid netbootGUID = Guid.Empty;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(UUID))
|
||||
{
|
||||
netbootGUID = NetbootGUIDFromUUID(UUID);
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(MACAddress))
|
||||
{
|
||||
netbootGUID = NetbootGUIDFromMACAddress(MACAddress);
|
||||
}
|
||||
|
||||
if (netbootGUID != System.Guid.Empty && netbootGUID != this.NetbootGUID)
|
||||
{
|
||||
this.SetNetbootGUID(WritableDomainController, netbootGUID);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public void UpdateNetbootGUID(string UUID, string MACAddress)
|
||||
{
|
||||
this.UpdateNetbootGUID(Domain.GetAvailableDomainController(RequireWritable: true), UUID, MACAddress);
|
||||
}
|
||||
public static System.Guid NetbootGUIDFromUUID(string UUID)
|
||||
{
|
||||
return new Guid(UUID);
|
||||
}
|
||||
public static System.Guid NetbootGUIDFromMACAddress(string MACAddress)
|
||||
{
|
||||
string strippedMACAddress = MACAddress.Trim().Replace(":", string.Empty).Replace("-", string.Empty);
|
||||
bool flag = strippedMACAddress.Length == 12;
|
||||
System.Guid NetbootGUIDFromMACAddress;
|
||||
if (flag)
|
||||
{
|
||||
System.Guid guid = new System.Guid(string.Format("00000000-0000-0000-0000-{0}", strippedMACAddress));
|
||||
NetbootGUIDFromMACAddress = guid;
|
||||
}
|
||||
else
|
||||
{
|
||||
NetbootGUIDFromMACAddress = System.Guid.Empty;
|
||||
}
|
||||
return NetbootGUIDFromMACAddress;
|
||||
}
|
||||
|
||||
public void MoveOrganisationalUnit(ADDomainController WritableDomainController, string NewOrganisationUnit)
|
||||
{
|
||||
if (this.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", this.DistinguishedName));
|
||||
|
||||
var parentDistinguishedName = this.ParentDistinguishedName;
|
||||
|
||||
if (parentDistinguishedName != null && !parentDistinguishedName.Equals(NewOrganisationUnit, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// If no OU provided, place in default Computers container
|
||||
if (string.IsNullOrWhiteSpace(NewOrganisationUnit))
|
||||
NewOrganisationUnit = Domain.DefaultComputerContainer;
|
||||
|
||||
if (!NewOrganisationUnit.EndsWith(Domain.DistinguishedName, StringComparison.OrdinalIgnoreCase))
|
||||
throw new InvalidOperationException(string.Format("Unable to move AD Account from one domain [{0}] to another [{1}].", this.DistinguishedName, NewOrganisationUnit));
|
||||
|
||||
using (ADDirectoryEntry ou = WritableDomainController.RetrieveDirectoryEntry(NewOrganisationUnit))
|
||||
{
|
||||
using (ADDirectoryEntry i = WritableDomainController.RetrieveDirectoryEntry(this.DistinguishedName))
|
||||
{
|
||||
i.Entry.UsePropertyCache = false;
|
||||
i.Entry.MoveTo(ou.Entry);
|
||||
|
||||
// Update Distinguished Name
|
||||
this.DistinguishedName = i.Entry.Properties["distinguishedName"][0].ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void MoveOrganisationalUnit(string NewOrganisationUnit)
|
||||
{
|
||||
this.MoveOrganisationalUnit(Domain.GetAvailableDomainController(RequireWritable: true), NewOrganisationUnit);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.Id;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || !(obj is ADMachineAccount))
|
||||
return false;
|
||||
else
|
||||
return this.DistinguishedName == ((ADMachineAccount)obj).DistinguishedName;
|
||||
}
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this.DistinguishedName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public class ADOrganisationalUnit
|
||||
{
|
||||
public ADDomain Domain { get; private set; }
|
||||
public string DistinguishedName { get; private set; }
|
||||
|
||||
public string Name { get; private set; }
|
||||
public List<ADOrganisationalUnit> Children { get; internal set; }
|
||||
|
||||
private ADOrganisationalUnit(ADDomain Domain, string DistinguishedName, string Name, List<ADOrganisationalUnit> Children)
|
||||
{
|
||||
this.Domain = Domain;
|
||||
this.DistinguishedName = DistinguishedName;
|
||||
this.Name = Name;
|
||||
this.Children = Children;
|
||||
}
|
||||
|
||||
public static ADOrganisationalUnit FromSearchResult(ADSearchResult SearchResult)
|
||||
{
|
||||
string distinguishedName = SearchResult.Value<string>("distinguishedName");
|
||||
string name = SearchResult.Value<string>("name");
|
||||
|
||||
return new ADOrganisationalUnit(SearchResult.Domain, distinguishedName, name, null);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.Name;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || !(obj is ADOrganisationalUnit))
|
||||
return false;
|
||||
else
|
||||
return this.DistinguishedName == ((ADOrganisationalUnit)obj).DistinguishedName;
|
||||
}
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this.DistinguishedName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public class ADSearchResult
|
||||
{
|
||||
private SearchResult _result;
|
||||
|
||||
public ADDomain Domain { get; private set; }
|
||||
public ADDomainController DomainController { get; private set; }
|
||||
|
||||
public string SearchPath { get; private set; }
|
||||
public string LdapFilter { get; private set; }
|
||||
public string LdapPath { get; private set; }
|
||||
public string DistinguishedName { get; private set; }
|
||||
|
||||
public ADSearchResult(ADDomain Domain, ADDomainController DomainController, string SearchPath, string LdapFilter, SearchResult Result)
|
||||
{
|
||||
this._result = Result;
|
||||
this.Domain = Domain;
|
||||
this.DomainController = DomainController;
|
||||
this.SearchPath = SearchPath;
|
||||
this.LdapFilter = LdapFilter;
|
||||
|
||||
this.LdapPath = _result.Path;
|
||||
this.DistinguishedName = Value<string>("dn");
|
||||
}
|
||||
|
||||
public bool Contains(string PropertyName)
|
||||
{
|
||||
return _result.Properties.Contains(PropertyName);
|
||||
}
|
||||
|
||||
public T Value<T>(string PropertyName)
|
||||
{
|
||||
var p = Values<T>(PropertyName);
|
||||
return p.FirstOrDefault();
|
||||
}
|
||||
|
||||
public IEnumerable<T> Values<T>(string PropertyName)
|
||||
{
|
||||
var p = _result.Properties[PropertyName];
|
||||
return p.OfType<T>();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.LdapPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices.ActiveDirectory;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public class ADSite
|
||||
{
|
||||
private ActiveDirectoryContext context;
|
||||
|
||||
public ActiveDirectorySite Site { get; private set; }
|
||||
|
||||
public string Name { get; private set; }
|
||||
|
||||
public List<ADDomainController> DomainControllers { get; private set; }
|
||||
|
||||
public ADSite(ActiveDirectoryContext Context, ActiveDirectorySite Site)
|
||||
{
|
||||
this.context = Context;
|
||||
|
||||
this.Site = Site;
|
||||
|
||||
this.Name = Site.Name;
|
||||
this.DomainControllers = null;
|
||||
}
|
||||
|
||||
internal void UpdateDomainControllers(IEnumerable<ADDomainController> DomainControllers)
|
||||
{
|
||||
this.DomainControllers = DomainControllers.ToList();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.Name;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || !(obj is ADSite))
|
||||
return false;
|
||||
else
|
||||
return this.Name == ((ADSite)obj).Name;
|
||||
}
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Logging;
|
||||
using Disco.Services.Tasks;
|
||||
using Quartz;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.DirectoryServices.ActiveDirectory;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public class ADTaskUpdateNetworkLogonDates : ScheduledTask
|
||||
{
|
||||
|
||||
public override string TaskName { get { return "Active Directory - Update Last Network Logon Dates Task"; } }
|
||||
public override bool SingleInstanceTask { get { return true; } }
|
||||
public override bool CancelInitiallySupported { get { return false; } }
|
||||
|
||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
||||
{
|
||||
// ActiveDirectoryUpdateLastNetworkLogonDateJob @ 11:30pm
|
||||
TriggerBuilder triggerBuilder = TriggerBuilder.Create().
|
||||
WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(23, 30));
|
||||
|
||||
this.ScheduleTask(triggerBuilder);
|
||||
}
|
||||
|
||||
protected override void ExecuteTask()
|
||||
{
|
||||
int changeCount;
|
||||
|
||||
this.Status.UpdateStatus(1, "Starting", "Connecting to the Database and initializing the environment");
|
||||
using (DiscoDataContext database = new DiscoDataContext())
|
||||
{
|
||||
UpdateLastNetworkLogonDates(database, this.Status);
|
||||
this.Status.UpdateStatus(95, "Updating Database", "Writing last network logon dates to the Database");
|
||||
changeCount = database.SaveChanges();
|
||||
this.Status.Finished(string.Format("{0} Device last network logon dates updated", changeCount), "/Config/SystemConfig");
|
||||
}
|
||||
|
||||
SystemLog.LogInformation(new string[]
|
||||
{
|
||||
"Updated LastNetworkLogon Device Property for Device/s",
|
||||
changeCount.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
public static ScheduledTaskStatus ScheduleImmediately()
|
||||
{
|
||||
var existingTask = ScheduledTasks.GetTaskStatuses(typeof(ADTaskUpdateNetworkLogonDates)).Where(s => s.IsRunning).FirstOrDefault();
|
||||
if (existingTask != null)
|
||||
return existingTask;
|
||||
|
||||
var instance = new ADTaskUpdateNetworkLogonDates();
|
||||
return instance.ScheduleTask();
|
||||
}
|
||||
|
||||
public static bool UpdateLastNetworkLogonDate(Device Device)
|
||||
{
|
||||
const string ldapFilterTemplate = "(&(objectCategory=Computer)(sAMAccountName={0}))";
|
||||
string[] ldapProperties = new string[] { "lastLogon", "lastLogonTimestamp" };
|
||||
|
||||
System.DateTime? lastLogon = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(Device.DeviceDomainId))
|
||||
{
|
||||
var context = ActiveDirectory.Context;
|
||||
var deviceSamAccountName = UserExtensions.SplitUserId(Device.DeviceDomainId).Item2 + "$";
|
||||
var ldapFilter = string.Format(ldapFilterTemplate, ADHelpers.EscapeLdapQuery(deviceSamAccountName));
|
||||
|
||||
var domain = context.GetDomainFromId(Device.DeviceDomainId);
|
||||
IEnumerable<ADDomainController> domainControllers;
|
||||
|
||||
if (context.SearchAllForestServers)
|
||||
domainControllers = domain.GetAllReachableDomainControllers();
|
||||
else
|
||||
domainControllers = domain.GetReachableSiteDomainControllers();
|
||||
|
||||
lastLogon = domainControllers.Select(dc =>
|
||||
{
|
||||
var result = dc.SearchEntireDomain(ldapFilter, ldapProperties, ActiveDirectory.SingleSearchResult).FirstOrDefault();
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
long lastLogonValue = default(long);
|
||||
long lastLogonTimestampValue = default(long);
|
||||
|
||||
lastLogonValue = result.Value<long>("lastLogon");
|
||||
lastLogonTimestampValue = result.Value<long>("lastLogonTimestamp");
|
||||
|
||||
long highedValue = Math.Max(lastLogonValue, lastLogonTimestampValue);
|
||||
|
||||
if (highedValue > 0)
|
||||
return (DateTime?)new DateTime((DateTime.FromFileTime(highedValue).Ticks / 10000000L) * 10000000L);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}).Where(dt => dt.HasValue).Max();
|
||||
}
|
||||
|
||||
if (lastLogon.HasValue &&
|
||||
(
|
||||
!Device.LastNetworkLogonDate.HasValue
|
||||
|| Device.LastNetworkLogonDate.Value < lastLogon
|
||||
))
|
||||
{
|
||||
Device.LastNetworkLogonDate = lastLogon;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void UpdateLastNetworkLogonDates(DiscoDataContext Database, ScheduledTaskStatus status)
|
||||
{
|
||||
var context = ActiveDirectory.Context;
|
||||
const string ldapFilter = "(objectCategory=Computer)";
|
||||
string[] ldapProperties = new string[] { "sAMAccountName", "lastLogon" };
|
||||
|
||||
status.UpdateStatus(2, "Initializing", "Determining Domains and Available Domain Controllers");
|
||||
|
||||
// Determine Domain Scopes to Query
|
||||
var domainQueries = context.Domains
|
||||
.Select(d => Tuple.Create(d, d.SearchContainers ?? new List<string>() { d.DistinguishedName }))
|
||||
.Where(d => d.Item2.Count > 0);
|
||||
|
||||
// Determine Domain Controllers to Query
|
||||
IEnumerable<Tuple<ADDomain, ADDomainController, List<string>>> serverQueries;
|
||||
if (context.SearchAllForestServers)
|
||||
serverQueries = domainQueries.SelectMany(q => q.Item1.GetAllReachableDomainControllers(), (q, dc) => Tuple.Create(q.Item1, dc, q.Item2));
|
||||
else
|
||||
serverQueries = domainQueries.SelectMany(q => q.Item1.GetReachableSiteDomainControllers(), (q, dc) => Tuple.Create(q.Item1, dc, q.Item2));
|
||||
|
||||
var scopedQueries = serverQueries.SelectMany(q => q.Item3, (q, scope) => Tuple.Create(q.Item1, q.Item2, scope)).ToList();
|
||||
|
||||
var queries = Enumerable.Range(0, scopedQueries.Count).Select(i =>
|
||||
{
|
||||
var q = scopedQueries[i];
|
||||
return Tuple.Create(i, q.Item1, q.Item2, q.Item3);
|
||||
});
|
||||
|
||||
var queryResults = queries.SelectMany(q =>
|
||||
{
|
||||
var queryIndex = q.Item1;
|
||||
var domain = q.Item2;
|
||||
var domainController = q.Item3;
|
||||
var searchRoot = q.Item4;
|
||||
|
||||
// Update Status
|
||||
double progress = 5 + (queryIndex * (90 / scopedQueries.Count));
|
||||
status.UpdateStatus(progress, string.Format("Querying Domain [{0}] using controller [{1}]", domain.NetBiosName, domainController.Name), string.Format("Searching: {0}", searchRoot));
|
||||
|
||||
// Perform Query
|
||||
var directoryResults = domainController.SearchInternal(searchRoot, ldapFilter, ldapProperties, null);
|
||||
|
||||
return directoryResults.Select(result =>
|
||||
{
|
||||
var samAccountName = result.Value<string>("sAMAccountName");
|
||||
|
||||
long lastLogonValue = default(long);
|
||||
long lastLogonTimestampValue = default(long);
|
||||
|
||||
lastLogonValue = result.Value<long>("lastLogon");
|
||||
lastLogonTimestampValue = result.Value<long>("lastLogonTimestamp");
|
||||
|
||||
long highedValue = Math.Max(lastLogonValue, lastLogonTimestampValue);
|
||||
|
||||
if (highedValue > 0)
|
||||
{
|
||||
var computerName = string.Format(@"{0}\{1}", domain.NetBiosName, samAccountName.TrimEnd('$'));
|
||||
var lastLogon = new DateTime((DateTime.FromFileTime(highedValue).Ticks / 10000000L) * 10000000L);
|
||||
return Tuple.Create(computerName, lastLogon);
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}).Where(i => i != null).ToList();
|
||||
|
||||
}).GroupBy(r => r.Item1, StringComparer.OrdinalIgnoreCase).ToDictionary(g => g.Key.ToUpper(), g => g.Max(i => i.Item2));
|
||||
|
||||
status.UpdateStatus(90, "Processing Results", "Processing last network logon dates and looking for updates");
|
||||
|
||||
foreach (Device device in Database.Devices.Where(device => device.DeviceDomainId != null))
|
||||
{
|
||||
DateTime lastLogonDate;
|
||||
if (queryResults.TryGetValue(device.DeviceDomainId.ToUpper(), out lastLogonDate))
|
||||
{
|
||||
if (!device.LastNetworkLogonDate.HasValue)
|
||||
device.LastNetworkLogonDate = lastLogonDate;
|
||||
else
|
||||
{
|
||||
// Change accuracy to the second
|
||||
lastLogonDate = new DateTime((lastLogonDate.Ticks / 10000000L) * 10000000L);
|
||||
|
||||
if (device.LastNetworkLogonDate.Value < lastLogonDate)
|
||||
device.LastNetworkLogonDate = lastLogonDate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
using Disco.Models.Repository;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public class ADUserAccount : IADObject
|
||||
{
|
||||
internal const string LdapSamAccountNameFilterTemplate = "(&(objectCategory=Person)(sAMAccountName={0}))";
|
||||
internal const string LdapSearchFilterTemplate = "(&(objectCategory=Person)(objectClass=user)(|(sAMAccountName=*{0}*)(displayName=*{0}*)))";
|
||||
internal static readonly string[] LoadProperties = { "name", "distinguishedName", "sAMAccountName", "objectSid", "displayName", "sn", "givenName", "memberOf", "primaryGroupID", "mail", "telephoneNumber" };
|
||||
internal static readonly string[] QuickLoadProperties = { "name", "distinguishedName", "sAMAccountName", "objectSid", "displayName", "sn", "givenName", "mail", "telephoneNumber" };
|
||||
|
||||
|
||||
public ADDomain Domain { get; private set; }
|
||||
|
||||
public string DistinguishedName { get; private set; }
|
||||
public SecurityIdentifier SecurityIdentifier { get; private set; }
|
||||
|
||||
public string Id { get { return string.Format(@"{0}\{1}", Domain.NetBiosName, SamAccountName); } }
|
||||
public string SamAccountName { get; private set; }
|
||||
|
||||
public string Name { get; private set; }
|
||||
public string DisplayName { get; private set; }
|
||||
|
||||
public string Surname { get; private set; }
|
||||
public string GivenName { get; private set; }
|
||||
public string Email { get; private set; }
|
||||
public string Phone { get; private set; }
|
||||
|
||||
public List<ADGroup> Groups { get; private set; }
|
||||
|
||||
public Dictionary<string, object[]> LoadedProperties { get; private set; }
|
||||
|
||||
private ADUserAccount(ADDomain Domain, string DistinguishedName, SecurityIdentifier SecurityIdentifier, string SamAccountName,
|
||||
string Name, string DisplayName, string Surname, string GivenName, string Email, string Phone,
|
||||
List<ADGroup> Groups, Dictionary<string, object[]> LoadedProperties)
|
||||
{
|
||||
this.Domain = Domain;
|
||||
this.DistinguishedName = DistinguishedName;
|
||||
this.SecurityIdentifier = SecurityIdentifier;
|
||||
this.SamAccountName = SamAccountName;
|
||||
this.Name = Name;
|
||||
this.DisplayName = DisplayName;
|
||||
this.Surname = Surname;
|
||||
this.GivenName = GivenName;
|
||||
this.Email = Email;
|
||||
this.Phone = Phone;
|
||||
this.Groups = Groups;
|
||||
this.LoadedProperties = LoadedProperties;
|
||||
}
|
||||
|
||||
public static ADUserAccount FromSearchResult(ADSearchResult SearchResult, bool Quick, string[] AdditionalProperties)
|
||||
{
|
||||
if (SearchResult == null)
|
||||
throw new ArgumentNullException("SearchResult");
|
||||
|
||||
string name = SearchResult.Value<string>("name");
|
||||
string sAMAccountName = SearchResult.Value<string>("sAMAccountName");
|
||||
string distinguishedName = SearchResult.Value<string>("distinguishedName");
|
||||
var objectSid = new SecurityIdentifier(SearchResult.Value<byte[]>("objectSid"), 0);
|
||||
|
||||
var displayName = SearchResult.Value<string>("displayName") ?? sAMAccountName;
|
||||
var surname = SearchResult.Value<string>("sn");
|
||||
string givenName = SearchResult.Value<string>("givenName");
|
||||
string email = SearchResult.Value<string>("mail");
|
||||
string phone = SearchResult.Value<string>("telephoneNumber");
|
||||
|
||||
List<ADGroup> groups = null;
|
||||
// Don't load Groups when doing a quick search
|
||||
if (!Quick)
|
||||
{
|
||||
int primaryGroupID = (int)SearchResult.Value<int>("primaryGroupID");
|
||||
var primaryGroupSid = ADHelpers.BuildPrimaryGroupSid(objectSid, primaryGroupID);
|
||||
var memberGroups = SearchResult.Values<string>("memberOf");
|
||||
|
||||
var primaryGroup = ActiveDirectory.GroupCache.GetGroup(primaryGroupSid);
|
||||
|
||||
var groupDistinguishedNames =
|
||||
new string[] { primaryGroup.DistinguishedName }
|
||||
.Concat(memberGroups);
|
||||
|
||||
groups = ActiveDirectory.GroupCache.GetRecursiveGroups(groupDistinguishedNames).ToList();
|
||||
}
|
||||
|
||||
// Additional Properties
|
||||
Dictionary<string, object[]> additionalProperties;
|
||||
if (AdditionalProperties != null)
|
||||
additionalProperties = AdditionalProperties
|
||||
.Select(p => Tuple.Create(p, SearchResult.Values<object>(p).ToArray()))
|
||||
.ToDictionary(t => t.Item1, t => t.Item2);
|
||||
else
|
||||
{
|
||||
additionalProperties = new Dictionary<string, object[]>();
|
||||
}
|
||||
|
||||
return new ADUserAccount(
|
||||
SearchResult.Domain,
|
||||
distinguishedName,
|
||||
objectSid,
|
||||
sAMAccountName,
|
||||
name,
|
||||
displayName,
|
||||
surname,
|
||||
givenName,
|
||||
email,
|
||||
phone,
|
||||
groups,
|
||||
additionalProperties);
|
||||
}
|
||||
|
||||
public object GetPropertyValue(string PropertyName, int Index = 0)
|
||||
{
|
||||
switch (PropertyName.ToLower())
|
||||
{
|
||||
case "name":
|
||||
return this.Name;
|
||||
case "samaccountname":
|
||||
return this.SamAccountName;
|
||||
case "distinguishedname":
|
||||
return this.DistinguishedName;
|
||||
case "objectsid":
|
||||
return this.SecurityIdentifier.ToString();
|
||||
case "sn":
|
||||
return this.Surname;
|
||||
case "givenname":
|
||||
return this.GivenName;
|
||||
case "mail":
|
||||
return this.Email;
|
||||
case "telephonenumber":
|
||||
return this.Phone;
|
||||
default:
|
||||
object[] adProperty;
|
||||
if (this.LoadedProperties.TryGetValue(PropertyName, out adProperty) && Index <= adProperty.Length)
|
||||
return adProperty[Index];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public User ToRepositoryUser()
|
||||
{
|
||||
return new User
|
||||
{
|
||||
UserId = this.Id,
|
||||
DisplayName = this.DisplayName,
|
||||
Surname = this.Surname,
|
||||
GivenName = this.GivenName,
|
||||
EmailAddress = this.Email,
|
||||
PhoneNumber = this.Phone,
|
||||
};
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.Id;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || !(obj is ADUserAccount))
|
||||
return false;
|
||||
else
|
||||
return this.DistinguishedName == ((ADUserAccount)obj).DistinguishedName;
|
||||
}
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this.DistinguishedName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,595 +1,226 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Services.Interop.ActiveDirectory.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.DirectoryServices.ActiveDirectory;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public static class ActiveDirectory
|
||||
{
|
||||
private const int SingleSearchResult = 1;
|
||||
public const int SingleSearchResult = 1;
|
||||
public const int DefaultSearchResultLimit = 30;
|
||||
public const int MaxForestServerSearch = 30;
|
||||
public const int DomainControllerUnavailableMinutes = 10;
|
||||
|
||||
private static ActiveDirectoryContext context;
|
||||
private static ActiveDirectoryGroupCache groupCache;
|
||||
private static object contextInitializingLock = new object();
|
||||
|
||||
public static void Initialize(DiscoDataContext Database)
|
||||
{
|
||||
ADInterop.Initialize(Database);
|
||||
}
|
||||
public static void UpdateSearchContainers(DiscoDataContext Database, List<string> Containers)
|
||||
{
|
||||
ADInterop.UpdateSearchContainers(Database, Containers);
|
||||
}
|
||||
public static bool UpdateSearchEntireForest(DiscoDataContext Database, bool SearchEntireForest)
|
||||
{
|
||||
return ADInterop.UpdateSearchEntireForest(Database, SearchEntireForest);
|
||||
}
|
||||
|
||||
public static ActiveDirectoryDomain PrimaryDomain
|
||||
{
|
||||
get
|
||||
lock (contextInitializingLock)
|
||||
{
|
||||
return ADInterop.PrimaryDomain;
|
||||
}
|
||||
}
|
||||
public static IEnumerable<ActiveDirectoryDomain> Domains
|
||||
{
|
||||
get
|
||||
{
|
||||
return ADInterop.Domains.ToList();
|
||||
context = new ActiveDirectoryContext(Database);
|
||||
groupCache = new ActiveDirectoryGroupCache();
|
||||
}
|
||||
}
|
||||
|
||||
public static ActiveDirectorySite Site
|
||||
public static ActiveDirectoryContext Context
|
||||
{
|
||||
get
|
||||
{
|
||||
return ADInterop.Site;
|
||||
}
|
||||
}
|
||||
|
||||
public static ActiveDirectoryDomain GetDomainByDistinguishedName(string DistinguishedName)
|
||||
{
|
||||
return ADInterop.GetDomainByDistinguishedName(DistinguishedName);
|
||||
}
|
||||
|
||||
public static ActiveDirectoryDomain GetDomainByNetBiosName(string NetBiosName)
|
||||
{
|
||||
return ADInterop.GetDomainByNetBiosName(NetBiosName);
|
||||
}
|
||||
|
||||
public static ActiveDirectoryDomain GetDomainByDnsName(string DnsName)
|
||||
{
|
||||
return ADInterop.GetDomainByDnsName(DnsName);
|
||||
}
|
||||
|
||||
public static ActiveDirectoryDomain GetDomainFromId(string Id)
|
||||
{
|
||||
return ADInterop.GetDomainFromId(Id);
|
||||
}
|
||||
|
||||
public static List<string> LoadForestServers()
|
||||
{
|
||||
return ADInterop.LoadForestServers();
|
||||
}
|
||||
|
||||
public static Task<List<string>> LoadForestServersAsync()
|
||||
{
|
||||
return ADInterop.LoadForestServersAsync();
|
||||
}
|
||||
|
||||
public static bool SearchEntireForest
|
||||
{
|
||||
get
|
||||
{
|
||||
return ADInterop.SearchEntireForest;
|
||||
}
|
||||
}
|
||||
|
||||
#region Machine Account
|
||||
private static readonly string[] MachineLoadProperties = { "name", "distinguishedName", "sAMAccountName", "objectSid", "dNSHostName", "netbootGUID", "isCriticalSystemObject" };
|
||||
|
||||
public static ActiveDirectoryMachineAccount RetrieveMachineAccount(DomainController DomainController, string Id, params string[] AdditionalProperties)
|
||||
{
|
||||
return RetrieveMachineAccount(DomainController, Id, (System.Guid?)null, (System.Guid?)null, AdditionalProperties);
|
||||
}
|
||||
public static ActiveDirectoryMachineAccount RetrieveMachineAccount(string Id, params string[] AdditionalProperties)
|
||||
{
|
||||
return RetrieveMachineAccount(Id, (System.Guid?)null, (System.Guid?)null, AdditionalProperties);
|
||||
}
|
||||
public static ActiveDirectoryMachineAccount RetrieveMachineAccount(DomainController DomainController, string Id, System.Guid? UUIDNetbootGUID, params string[] AdditionalProperties)
|
||||
{
|
||||
return RetrieveMachineAccount(DomainController, Id, UUIDNetbootGUID, (System.Guid?)null, AdditionalProperties);
|
||||
}
|
||||
public static ActiveDirectoryMachineAccount RetrieveMachineAccount(string Id, System.Guid? UUIDNetbootGUID, params string[] AdditionalProperties)
|
||||
{
|
||||
return RetrieveMachineAccount(Id, UUIDNetbootGUID, (System.Guid?)null, AdditionalProperties);
|
||||
}
|
||||
public static ActiveDirectoryMachineAccount RetrieveMachineAccount(string Id, System.Guid? UUIDNetbootGUID, System.Guid? MacAddressNetbootGUID, params string[] AdditionalProperties)
|
||||
{
|
||||
return RetrieveMachineAccount(null, Id, UUIDNetbootGUID, MacAddressNetbootGUID, AdditionalProperties);
|
||||
}
|
||||
public static ActiveDirectoryMachineAccount RetrieveMachineAccount(DomainController DomainController, string Id, System.Guid? UUIDNetbootGUID, System.Guid? MacAddressNetbootGUID, params string[] AdditionalProperties)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Id))
|
||||
throw new ArgumentNullException("Id");
|
||||
|
||||
// Add $ identifier for machine accounts
|
||||
if (!Id.EndsWith("$"))
|
||||
Id += "$";
|
||||
|
||||
const string ldapFilterTemplate = "(&(objectCategory=computer)(sAMAccountName={0}))";
|
||||
const string ldapNetbootGuidFilterTemplate = "(&(objectCategory=computer)(netbootGUID={0}))";
|
||||
|
||||
string[] loadProperites = (AdditionalProperties != null && AdditionalProperties.Length > 0)
|
||||
? MachineLoadProperties.Concat(AdditionalProperties).ToArray()
|
||||
: MachineLoadProperties;
|
||||
|
||||
ActiveDirectorySearchResult adResult;
|
||||
|
||||
var splitId = UserExtensions.SplitUserId(Id);
|
||||
var ldapSamAccountFilter = string.Format(ldapFilterTemplate, splitId.Item2);
|
||||
var domain = ADInterop.GetDomainFromId(Id);
|
||||
|
||||
adResult = ADInterop.SearchAll(domain, DomainController, ldapSamAccountFilter, SingleSearchResult, loadProperites).FirstOrDefault();
|
||||
if (adResult == null && (UUIDNetbootGUID.HasValue || MacAddressNetbootGUID.HasValue))
|
||||
{
|
||||
|
||||
if (UUIDNetbootGUID.HasValue)
|
||||
if (context == null)
|
||||
{
|
||||
var ldapFilter = string.Format(ldapNetbootGuidFilterTemplate, ADInterop.FormatGuidForLdapQuery(UUIDNetbootGUID.Value));
|
||||
adResult = ADInterop.SearchAll(domain, DomainController, ldapFilter, SingleSearchResult, loadProperites).FirstOrDefault();
|
||||
lock (contextInitializingLock)
|
||||
{
|
||||
if (context == null)
|
||||
throw new InvalidOperationException("Active Directory interoperability hasn't been initialized");
|
||||
}
|
||||
}
|
||||
if (adResult == null && MacAddressNetbootGUID.HasValue)
|
||||
{
|
||||
var ldapFilter = string.Format(ldapNetbootGuidFilterTemplate, ADInterop.FormatGuidForLdapQuery(MacAddressNetbootGUID.Value));
|
||||
adResult = ADInterop.SearchAll(domain, DomainController, ldapFilter, SingleSearchResult, loadProperites).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
if (adResult != null)
|
||||
return adResult.AsMachineAccount(AdditionalProperties);
|
||||
return context;
|
||||
}
|
||||
}
|
||||
public static ActiveDirectoryGroupCache GroupCache
|
||||
{
|
||||
get
|
||||
{
|
||||
if (groupCache == null)
|
||||
{
|
||||
lock (contextInitializingLock)
|
||||
{
|
||||
if (groupCache == null)
|
||||
throw new InvalidOperationException("Active Directory interoperability hasn't been initialized");
|
||||
}
|
||||
}
|
||||
|
||||
return groupCache;
|
||||
}
|
||||
}
|
||||
|
||||
#region User Accounts
|
||||
|
||||
public static ADUserAccount RetrieveADUserAccount(string Id, params string[] AdditionalProperties)
|
||||
{
|
||||
var domain = Context.GetDomainFromId(Id);
|
||||
return domain.GetAvailableDomainController().RetrieveADUserAccount(Id, AdditionalProperties);
|
||||
}
|
||||
|
||||
public static IEnumerable<ADUserAccount> SearchADUserAccounts(string Term, bool Quick, int? ResultLimit = ActiveDirectory.DefaultSearchResultLimit, params string[] AdditionalProperties)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Term))
|
||||
throw new ArgumentNullException("Term");
|
||||
|
||||
ADDomain searchDomain;
|
||||
var term = RelevantSearchTerm(Term, out searchDomain);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(term))
|
||||
return Enumerable.Empty<ADUserAccount>();
|
||||
|
||||
var ldapFilter = string.Format(ADUserAccount.LdapSearchFilterTemplate, ADHelpers.EscapeLdapQuery(term));
|
||||
|
||||
IEnumerable<ADSearchResult> searchResults;
|
||||
if (searchDomain != null)
|
||||
searchResults = searchDomain.SearchScope(ldapFilter, ADGroup.LoadProperties, ResultLimit);
|
||||
else
|
||||
return null; // Not Found
|
||||
}
|
||||
searchResults = Context.SearchScope(ldapFilter, ADGroup.LoadProperties, ResultLimit);
|
||||
|
||||
private static ActiveDirectoryMachineAccount AsMachineAccount(this ActiveDirectorySearchResult item, string[] AdditionalProperties)
|
||||
{
|
||||
string name = item.Result.Properties["name"][0].ToString();
|
||||
string sAMAccountName = item.Result.Properties["sAMAccountName"][0].ToString();
|
||||
string distinguishedName = item.Result.Properties["distinguishedName"][0].ToString();
|
||||
string objectSid = ADInterop.ConvertBytesToSDDLString((byte[])item.Result.Properties["objectSid"][0]);
|
||||
|
||||
var dNSNameProperty = item.Result.Properties["dNSHostName"];
|
||||
string dNSName = null;
|
||||
if (dNSNameProperty.Count > 0)
|
||||
dNSName = dNSNameProperty[0].ToString();
|
||||
else
|
||||
dNSName = string.Format("{0}.{1}", sAMAccountName.TrimEnd('$'), item.Domain.DnsName);
|
||||
|
||||
bool isCriticalSystemObject = (bool)item.Result.Properties["isCriticalSystemObject"][0];
|
||||
|
||||
System.Guid netbootGUIDResult = default(System.Guid);
|
||||
ResultPropertyValueCollection netbootGUIDProp = item.Result.Properties["netbootGUID"];
|
||||
if (netbootGUIDProp.Count > 0)
|
||||
{
|
||||
netbootGUIDResult = new System.Guid((byte[])netbootGUIDProp[0]);
|
||||
}
|
||||
|
||||
// Additional Properties
|
||||
Dictionary<string, object[]> additionalProperties = new Dictionary<string, object[]>();
|
||||
if (AdditionalProperties != null)
|
||||
foreach (string propertyName in AdditionalProperties)
|
||||
{
|
||||
var property = item.Result.Properties[propertyName];
|
||||
var propertyValues = new List<object>();
|
||||
for (int index = 0; index < property.Count; index++)
|
||||
propertyValues.Add(property[index]);
|
||||
additionalProperties.Add(propertyName, propertyValues.ToArray());
|
||||
}
|
||||
|
||||
return new ActiveDirectoryMachineAccount
|
||||
{
|
||||
Name = name,
|
||||
DistinguishedName = distinguishedName,
|
||||
SamAccountName = sAMAccountName,
|
||||
SecurityIdentifier = objectSid,
|
||||
NetbootGUID = netbootGUIDResult,
|
||||
Path = item.Result.Path,
|
||||
Domain = item.Domain.NetBiosName,
|
||||
DnsName = dNSName,
|
||||
IsCriticalSystemObject = isCriticalSystemObject,
|
||||
LoadedProperties = additionalProperties
|
||||
};
|
||||
}
|
||||
|
||||
public static string OfflineDomainJoinProvision(ActiveDirectoryDomain Domain, DomainController DomainController, string ComputerName, string OrganisationalUnit, ref ActiveDirectoryMachineAccount MachineAccount, out string DiagnosticInformation)
|
||||
{
|
||||
const string ldapFilterTemplate = "(&(objectCategory=computer)(sAMAccountName={0}))";
|
||||
|
||||
if (MachineAccount != null && MachineAccount.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", MachineAccount.DistinguishedName));
|
||||
|
||||
if (MachineAccount != null)
|
||||
MachineAccount.DeleteAccount(DomainController);
|
||||
|
||||
var computerId = UserExtensions.SplitUserId(ComputerName);
|
||||
|
||||
var offlineJoinResult = ADInterop.OfflineDomainJoinProvision(Domain, DomainController, computerId.Item2, OrganisationalUnit, out DiagnosticInformation);
|
||||
|
||||
// Reload newly created Account
|
||||
string[] loadAdditionalProperties = (MachineAccount != null && MachineAccount.LoadedProperties != null && MachineAccount.LoadedProperties.Count > 0)
|
||||
? MachineAccount.LoadedProperties.Keys.ToArray()
|
||||
: null;
|
||||
|
||||
MachineAccount = null;
|
||||
|
||||
string[] loadProperites = (loadAdditionalProperties != null)
|
||||
? MachineLoadProperties.Concat(loadAdditionalProperties).ToArray()
|
||||
: MachineLoadProperties;
|
||||
|
||||
var ldapSamAccountName = computerId.Item2.EndsWith("$") ? computerId.Item2 : computerId.Item2 + "$";
|
||||
var ldapFilter = string.Format(ldapFilterTemplate, ldapSamAccountName);
|
||||
var ldapResult = ADInterop.SearchAll(Domain, DomainController, ldapFilter, 1, loadProperites).FirstOrDefault();
|
||||
|
||||
if (ldapResult != null)
|
||||
MachineAccount = ldapResult.AsMachineAccount(loadAdditionalProperties);
|
||||
|
||||
return offlineJoinResult;
|
||||
return searchResults.Select(result => result.AsADUserAccount(Quick, AdditionalProperties));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region User Account
|
||||
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)
|
||||
#region Machine Accounts
|
||||
public static ADMachineAccount RetrieveADMachineAccount(string Id, params string[] AdditionalProperties)
|
||||
{
|
||||
const string ldapFilter = "(&(objectCategory=Person)(sAMAccountName={0}))";
|
||||
|
||||
string[] loadProperites = (AdditionalProperties != null && AdditionalProperties.Length > 0)
|
||||
? UserLoadProperties.Concat(AdditionalProperties).ToArray()
|
||||
: UserLoadProperties;
|
||||
|
||||
return SearchBySamAccountName(Id, ldapFilter, loadProperites).Select(result => result.AsUserAccount(false, AdditionalProperties)).FirstOrDefault();
|
||||
var domain = Context.GetDomainFromId(Id);
|
||||
return domain.GetAvailableDomainController().RetrieveADMachineAccount(Id, AdditionalProperties);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectoryUserAccount> SearchUserAccounts(string Term, params string[] AdditionalProperties)
|
||||
public static ADMachineAccount RetrieveADMachineAccount(string Id, System.Guid? NetbootGUID, params string[] AdditionalProperties)
|
||||
{
|
||||
return SearchUserAccounts(Term, false, AdditionalProperties);
|
||||
var domain = Context.GetDomainFromId(Id);
|
||||
return domain.GetAvailableDomainController().RetrieveADMachineAccount(Id, NetbootGUID, AdditionalProperties);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectoryUserAccount> SearchUserAccounts(string Term, bool Quick, params string[] AdditionalProperties)
|
||||
public static ADMachineAccount RetrieveADMachineAccount(string Id, System.Guid? UUIDNetbootGUID, System.Guid? MacAddressNetbootGUID, params string[] AdditionalProperties)
|
||||
{
|
||||
const int resultLimit = 30; // Default Search Limit
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Term))
|
||||
throw new ArgumentNullException("Term");
|
||||
|
||||
// Apply Domain Restriction
|
||||
ActiveDirectoryDomain searchDomain = null;
|
||||
Term = ApplySearchTermDomainRestriction(Term, out searchDomain);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Term))
|
||||
return Enumerable.Empty<ActiveDirectoryUserAccount>();
|
||||
|
||||
string ldapFilter = string.Format("(&(objectCategory=Person)(objectClass=user)(|(sAMAccountName=*{0}*)(displayName=*{0}*)))", ADInterop.EscapeLdapQuery(Term));
|
||||
|
||||
string[] loadProperites = Quick
|
||||
? UserQuickLoadProperties
|
||||
: UserLoadProperties;
|
||||
|
||||
if (AdditionalProperties != null && AdditionalProperties.Length > 0)
|
||||
loadProperites.Concat(AdditionalProperties).ToArray();
|
||||
|
||||
IEnumerable<ActiveDirectorySearchResult> searchResults;
|
||||
if (searchDomain == null)
|
||||
searchResults = ADInterop.SearchScope(ldapFilter, resultLimit, loadProperites);
|
||||
else
|
||||
searchResults = ADInterop.SearchScope(searchDomain, ldapFilter, resultLimit, loadProperites);
|
||||
|
||||
return searchResults.Select(result => result.AsUserAccount(Quick, AdditionalProperties));
|
||||
}
|
||||
|
||||
private static ActiveDirectoryUserAccount AsUserAccount(this ActiveDirectorySearchResult item, bool Quick, string[] AdditionalProperties)
|
||||
{
|
||||
string name = item.Result.Properties["name"][0].ToString();
|
||||
string username = item.Result.Properties["sAMAccountName"][0].ToString();
|
||||
string distinguishedName = item.Result.Properties["distinguishedName"][0].ToString();
|
||||
byte[] objectSid = (byte[])item.Result.Properties["objectSid"][0];
|
||||
string objectSidSDDL = ADInterop.ConvertBytesToSDDLString(objectSid);
|
||||
List<string> groups = null;
|
||||
|
||||
ResultPropertyValueCollection displayNameProp = item.Result.Properties["displayName"];
|
||||
string displayName = username;
|
||||
if (displayNameProp.Count > 0)
|
||||
displayName = displayNameProp[0].ToString();
|
||||
string surname = null;
|
||||
ResultPropertyValueCollection surnameProp = item.Result.Properties["sn"];
|
||||
if (surnameProp.Count > 0)
|
||||
surname = surnameProp[0].ToString();
|
||||
string givenName = null;
|
||||
ResultPropertyValueCollection givenNameProp = item.Result.Properties["givenName"];
|
||||
if (givenNameProp.Count > 0)
|
||||
givenName = givenNameProp[0].ToString();
|
||||
string email = null;
|
||||
ResultPropertyValueCollection emailProp = item.Result.Properties["mail"];
|
||||
if (emailProp.Count > 0)
|
||||
email = emailProp[0].ToString();
|
||||
string phone = null;
|
||||
ResultPropertyValueCollection phoneProp = item.Result.Properties["telephoneNumber"];
|
||||
if (phoneProp.Count > 0)
|
||||
phone = phoneProp[0].ToString();
|
||||
|
||||
// Don't load Groups when doing a quick search
|
||||
if (!Quick)
|
||||
{
|
||||
int primaryGroupID = (int)item.Result.Properties["primaryGroupID"][0];
|
||||
string primaryGroupSid = ADInterop.ConvertBytesToSDDLString(ADInterop.BuildPrimaryGroupSid(objectSid, primaryGroupID));
|
||||
var groupDistinguishedNames = item.Result.Properties["memberOf"].Cast<string>().ToList();
|
||||
groupDistinguishedNames.Add(ADGroupCache.GetGroupsDistinguishedNameForSecurityIdentifier(primaryGroupSid));
|
||||
groups = ADGroupCache.GetGroups(groupDistinguishedNames).ToList();
|
||||
}
|
||||
|
||||
// Additional Properties
|
||||
Dictionary<string, object[]> additionalProperties = new Dictionary<string, object[]>();
|
||||
if (AdditionalProperties != null && AdditionalProperties.Length > 0)
|
||||
foreach (string propertyName in AdditionalProperties)
|
||||
{
|
||||
var property = item.Result.Properties[propertyName];
|
||||
var propertyValues = new List<object>();
|
||||
for (int index = 0; index < property.Count; index++)
|
||||
propertyValues.Add(property[index]);
|
||||
additionalProperties.Add(propertyName, propertyValues.ToArray());
|
||||
}
|
||||
|
||||
return new ActiveDirectoryUserAccount
|
||||
{
|
||||
Domain = item.Domain.NetBiosName,
|
||||
Name = name,
|
||||
Surname = surname,
|
||||
GivenName = givenName,
|
||||
Email = email,
|
||||
Phone = phone,
|
||||
DistinguishedName = distinguishedName,
|
||||
SamAccountName = username,
|
||||
DisplayName = displayName,
|
||||
SecurityIdentifier = objectSidSDDL,
|
||||
Groups = groups,
|
||||
Path = item.Result.Path,
|
||||
LoadedProperties = additionalProperties
|
||||
};
|
||||
var domain = Context.GetDomainFromId(Id);
|
||||
return domain.GetAvailableDomainController().RetrieveADMachineAccount(Id, UUIDNetbootGUID, MacAddressNetbootGUID, AdditionalProperties);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Groups
|
||||
private static readonly string[] GroupLoadProperties = { "name", "distinguishedName", "cn", "sAMAccountName", "objectSid", "memberOf" };
|
||||
|
||||
public static ActiveDirectoryGroup RetrieveGroup(string Id)
|
||||
public static ADGroup RetrieveADGroup(string Id)
|
||||
{
|
||||
const string ldapFilter = "(&(objectCategory=Group)(objectSid={0}))";
|
||||
|
||||
return SearchBySamAccountName(Id, ldapFilter, GroupLoadProperties).Select(result => result.AsGroup()).FirstOrDefault();
|
||||
var domain = Context.GetDomainFromId(Id);
|
||||
return domain.GetAvailableDomainController().RetrieveADGroup(Id);
|
||||
}
|
||||
public static ActiveDirectoryGroup RetrieveGroupWithDistinguishedName(string DistinguishedName)
|
||||
public static ADGroup RetrieveADGroupByDistinguishedName(string DistinguishedName)
|
||||
{
|
||||
ActiveDirectoryDomain domain;
|
||||
|
||||
using (var groupEntry = ADInterop.RetrieveDirectoryEntry(DistinguishedName, out domain))
|
||||
{
|
||||
if (groupEntry == null)
|
||||
return null;
|
||||
|
||||
return groupEntry.AsGroup(domain);
|
||||
}
|
||||
var domain = Context.GetDomainFromDistinguishedName(DistinguishedName);
|
||||
return domain.GetAvailableDomainController().RetrieveADGroupByDistinguishedName(DistinguishedName);
|
||||
}
|
||||
public static ActiveDirectoryGroup RetrieveGroupWithSecurityIdentifier(string SecurityIdentifier)
|
||||
public static ADGroup RetrieveADGroupWithSecurityIdentifier(SecurityIdentifier SecurityIdentifier)
|
||||
{
|
||||
const int resultLimit = 1;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(SecurityIdentifier))
|
||||
throw new ArgumentNullException("SecurityIdentifier");
|
||||
|
||||
var sidBytes = ADInterop.ConvertSDDLStringToBytes(SecurityIdentifier);
|
||||
var sidBinaryString = ADInterop.ConvertBytesToBinarySidString(sidBytes);
|
||||
|
||||
string ldapFilter = string.Format("(&(objectCategory=Group)(objectSid={0}))", sidBinaryString);
|
||||
|
||||
return ADInterop.SearchAll(ldapFilter, resultLimit, null).Select(result => result.AsGroup()).FirstOrDefault();
|
||||
var domain = Context.GetDomainFromSecurityIdentifier(SecurityIdentifier);
|
||||
return domain.GetAvailableDomainController().RetrieveADGroupWithSecurityIdentifier(SecurityIdentifier);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectoryGroup> SearchGroups(string Term)
|
||||
{
|
||||
const int resultLimit = 30; // Default Search Limit
|
||||
|
||||
public static IEnumerable<ADGroup> SearchADGroups(string Term, int? ResultLimit = ActiveDirectory.DefaultSearchResultLimit)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Term))
|
||||
throw new ArgumentNullException("Term");
|
||||
|
||||
// Apply Domain Restriction
|
||||
ActiveDirectoryDomain searchDomain = null;
|
||||
Term = ApplySearchTermDomainRestriction(Term, out searchDomain);
|
||||
ADDomain searchDomain;
|
||||
var term = RelevantSearchTerm(Term, out searchDomain);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Term))
|
||||
return Enumerable.Empty<ActiveDirectoryGroup>();
|
||||
if (string.IsNullOrWhiteSpace(term))
|
||||
return Enumerable.Empty<ADGroup>();
|
||||
|
||||
string ldapFilter = string.Format("(&(objectCategory=Group)(|(sAMAccountName=*{0}*)(name=*{0}*)(cn=*{0}*)))", ADInterop.EscapeLdapQuery(Term));
|
||||
var ldapFilter= string.Format(ADGroup.LdapSearchFilterTemplate, ADHelpers.EscapeLdapQuery(term));
|
||||
|
||||
IEnumerable<ActiveDirectorySearchResult> searchResults;
|
||||
if (searchDomain == null)
|
||||
searchResults = ADInterop.SearchScope(ldapFilter, resultLimit, GroupLoadProperties);
|
||||
IEnumerable<ADSearchResult> searchResults;
|
||||
if (searchDomain != null)
|
||||
searchResults = searchDomain.SearchScope(ldapFilter, ADGroup.LoadProperties, ResultLimit);
|
||||
else
|
||||
searchResults = ADInterop.SearchScope(searchDomain, ldapFilter, resultLimit, GroupLoadProperties);
|
||||
searchResults = Context.SearchScope(ldapFilter, ADGroup.LoadProperties, ResultLimit);
|
||||
|
||||
return searchResults.Select(result => result.AsGroup());
|
||||
return searchResults.Select(result => result.AsADGroup());
|
||||
}
|
||||
|
||||
private static ActiveDirectoryGroup AsGroup(this ActiveDirectorySearchResult item)
|
||||
{
|
||||
var name = (string)item.Result.Properties["name"][0];
|
||||
var distinguishedName = (string)item.Result.Properties["distinguishedName"][0];
|
||||
var cn = (string)item.Result.Properties["cn"][0];
|
||||
var sAMAccountName = (string)item.Result.Properties["sAMAccountName"][0];
|
||||
var objectSid = ADInterop.ConvertBytesToSDDLString((byte[])item.Result.Properties["objectSid"][0]);
|
||||
var memberOf = item.Result.Properties["memberOf"].Cast<string>().ToList();
|
||||
#endregion
|
||||
|
||||
return new ActiveDirectoryGroup()
|
||||
{
|
||||
Domain = item.Domain.NetBiosName,
|
||||
Name = name,
|
||||
DistinguishedName = distinguishedName,
|
||||
CommonName = cn,
|
||||
SamAccountName = sAMAccountName,
|
||||
SecurityIdentifier = objectSid,
|
||||
MemberOf = memberOf
|
||||
};
|
||||
}
|
||||
private static ActiveDirectoryGroup AsGroup(this DirectoryEntry item, ActiveDirectoryDomain Domain)
|
||||
#region Organisational Units
|
||||
public static IEnumerable<Tuple<ADDomain, List<ADOrganisationalUnit>>> RetrieveADOrganisationalUnitStructure()
|
||||
{
|
||||
var name = (string)item.Properties["name"][0];
|
||||
var distinguishedName = (string)item.Properties["distinguishedName"][0];
|
||||
var cn = (string)item.Properties["cn"][0];
|
||||
var sAMAccountName = (string)item.Properties["sAMAccountName"][0];
|
||||
var objectSid = ADInterop.ConvertBytesToSDDLString((byte[])item.Properties["objectSid"][0]);
|
||||
var memberOf = item.Properties["memberOf"].Cast<string>().ToList();
|
||||
|
||||
return new ActiveDirectoryGroup()
|
||||
{
|
||||
Domain = Domain.NetBiosName,
|
||||
Name = name,
|
||||
DistinguishedName = distinguishedName,
|
||||
CommonName = cn,
|
||||
SamAccountName = sAMAccountName,
|
||||
SecurityIdentifier = objectSid,
|
||||
MemberOf = memberOf
|
||||
};
|
||||
return Context.Domains
|
||||
.Select(d => d.GetAvailableDomainController())
|
||||
.Select(dc => Tuple.Create(dc.Domain, dc.RetrieveADOrganisationalUnitStructure()));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Object
|
||||
private static readonly string[] ObjectLoadProperties = { "objectCategory" };
|
||||
private static readonly string[] ObjectLoadPropertiesAll = ObjectLoadProperties.Concat(UserLoadProperties).Concat(MachineLoadProperties).Concat(GroupLoadProperties).Distinct().ToArray();
|
||||
|
||||
public static IActiveDirectoryObject RetrieveObject(string Id, bool Quick)
|
||||
#region Objects
|
||||
public static IADObject RetrieveADObject(string Id, bool Quick)
|
||||
{
|
||||
const string ldapFilter = "(&(|(objectCategory=Person)(objectCategory=Computer)(objectCategory=Group))(sAMAccountName={0}))";
|
||||
|
||||
return SearchBySamAccountName(Id, ldapFilter, ObjectLoadPropertiesAll)
|
||||
.Select<ActiveDirectorySearchResult, IActiveDirectoryObject>(result =>
|
||||
{
|
||||
var objectCategory = (string)result.Result.Properties["objectCategory"][0];
|
||||
objectCategory = objectCategory.Substring(0, objectCategory.IndexOf(',')).ToLower();
|
||||
switch (objectCategory)
|
||||
{
|
||||
case "cn=person":
|
||||
return result.AsUserAccount(Quick, null);
|
||||
case "cn=computer":
|
||||
return result.AsMachineAccount(null);
|
||||
case "cn=group":
|
||||
return result.AsGroup();
|
||||
default:
|
||||
throw new InvalidOperationException("Unexpected objectCategory");
|
||||
}
|
||||
}).FirstOrDefault();
|
||||
var domain = Context.GetDomainFromId(Id);
|
||||
return domain.GetAvailableDomainController().RetrieveADObject(Id, Quick);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Organisation Units
|
||||
#region Actions
|
||||
|
||||
public static List<ActiveDirectoryOrganisationalUnit> RetrieveOrganisationalUnitStructure(ActiveDirectoryDomain Domain)
|
||||
public static string OfflineDomainJoinProvision(string ComputerSamAccountName, string OrganisationalUnit, ref ADMachineAccount MachineAccount, out string DiagnosticInformation)
|
||||
{
|
||||
using (DirectoryEntry domainRoot = ADInterop.RetrieveDirectoryEntry(Domain.DistinguishedName, out Domain))
|
||||
{
|
||||
return ActiveDirectory.RetrieveOrganisationalUnitStructureInternal(Domain, domainRoot);
|
||||
}
|
||||
}
|
||||
private static List<ActiveDirectoryOrganisationalUnit> RetrieveOrganisationalUnitStructureInternal(ActiveDirectoryDomain Domain, DirectoryEntry Container)
|
||||
{
|
||||
Dictionary<string, List<ActiveDirectoryOrganisationalUnit>> resultTree = new Dictionary<string, List<ActiveDirectoryOrganisationalUnit>>();
|
||||
var domain = Context.GetDomainFromDistinguishedName(OrganisationalUnit);
|
||||
var writableDomainController = domain.GetAvailableDomainController(RequireWritable: true);
|
||||
|
||||
using (DirectorySearcher adSearcher = new DirectorySearcher(Container, "(objectCategory=organizationalUnit)", new string[]
|
||||
{
|
||||
"name",
|
||||
"distinguishedName"
|
||||
}, SearchScope.Subtree))
|
||||
{
|
||||
adSearcher.PageSize = 500;
|
||||
|
||||
using (SearchResultCollection adResults = adSearcher.FindAll())
|
||||
{
|
||||
resultTree = adResults.Cast<SearchResult>().Select(adResult =>
|
||||
{
|
||||
string i = adResult.Properties["name"][0].ToString();
|
||||
string dn = adResult.Properties["distinguishedName"][0].ToString();
|
||||
return new ActiveDirectoryOrganisationalUnit
|
||||
{
|
||||
Domain = Domain.NetBiosName,
|
||||
Name = i,
|
||||
DistinguishedName = dn,
|
||||
};
|
||||
}).GroupBy(ou => ou.DistinguishedName.Substring(ou.DistinguishedName.IndexOf(',') + 1)).ToDictionary(g => g.Key, g => g.ToList());
|
||||
}
|
||||
}
|
||||
|
||||
// Build Tree
|
||||
var results = resultTree[Domain.DistinguishedName];
|
||||
foreach (var child in results)
|
||||
RetrieveOrganisationalUnitStructureChildrenInternal(child, resultTree);
|
||||
|
||||
return results;
|
||||
}
|
||||
private static void RetrieveOrganisationalUnitStructureChildrenInternal(ActiveDirectoryOrganisationalUnit OrganisationalUnit, Dictionary<string, List<ActiveDirectoryOrganisationalUnit>> ResultTree)
|
||||
{
|
||||
List<ActiveDirectoryOrganisationalUnit> children;
|
||||
|
||||
if (ResultTree.TryGetValue(OrganisationalUnit.DistinguishedName, out children))
|
||||
{
|
||||
foreach (var child in children)
|
||||
RetrieveOrganisationalUnitStructureChildrenInternal(child, ResultTree);
|
||||
|
||||
OrganisationalUnit.Children = children;
|
||||
}
|
||||
return writableDomainController.OfflineDomainJoinProvision(ComputerSamAccountName, OrganisationalUnit, ref MachineAccount, out DiagnosticInformation);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
private static IEnumerable<ActiveDirectorySearchResult> SearchBySamAccountName(string Id, string LdapFilterTemplate, string[] LoadProperties)
|
||||
private static string RelevantSearchTerm(string Term, out ADDomain Domain)
|
||||
{
|
||||
var splitId = UserExtensions.SplitUserId(Id);
|
||||
var ldapFilter = string.Format(LdapFilterTemplate, splitId.Item2);
|
||||
var domains = ADInterop.GetDomainFromId(Id);
|
||||
Domain = null;
|
||||
|
||||
return ADInterop.SearchAll(domains, ldapFilter, SingleSearchResult, LoadProperties);
|
||||
}
|
||||
|
||||
private static string ApplySearchTermDomainRestriction(string Term, out ActiveDirectoryDomain Domain)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Term))
|
||||
throw new ArgumentNullException("Term");
|
||||
return null;
|
||||
|
||||
var domainIndex = Term.IndexOf('\\');
|
||||
if (domainIndex >= 0)
|
||||
var term = Term.Trim();
|
||||
|
||||
var domainSeperatorIndex = term.IndexOf('\\');
|
||||
|
||||
if (domainSeperatorIndex >= 0)
|
||||
{
|
||||
var domain = Term.Substring(0, domainIndex);
|
||||
// Domain Search Restriction
|
||||
|
||||
if (!ADInterop.TryGetDomainByNetBiosName(domain, out Domain))
|
||||
return null; // Domain not found - invalid search
|
||||
|
||||
if (Term.Length > (domainIndex + 1))
|
||||
return Term.Substring(domainIndex + 1);
|
||||
if (term.Length > domainSeperatorIndex + 1)
|
||||
{
|
||||
var netbiosName = term.Substring(0, domainSeperatorIndex);
|
||||
if (Context.TryGetDomainByNetBiosName(netbiosName, out Domain))
|
||||
{
|
||||
return term.Substring(domainSeperatorIndex + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null; // Unknown Domain
|
||||
}
|
||||
}
|
||||
else
|
||||
return null; // Domain only, no Term
|
||||
}
|
||||
else
|
||||
{
|
||||
Domain = null;
|
||||
return Term;
|
||||
{
|
||||
return null; // No term to search, only Domain
|
||||
}
|
||||
}
|
||||
|
||||
return term;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,308 @@
|
||||
using Disco.Data.Repository;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.DirectoryServices.ActiveDirectory;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public class ActiveDirectoryContext
|
||||
{
|
||||
public ADSite Site { get; private set; }
|
||||
public ADDomain PrimaryDomain { get; private set; }
|
||||
public List<ADDomain> Domains { get; private set; }
|
||||
|
||||
public List<string> ForestServers
|
||||
{
|
||||
get
|
||||
{
|
||||
return ADDiscoverForestServers.LoadForestServersBlocking();
|
||||
}
|
||||
}
|
||||
|
||||
private bool _SearchAllForestServers { get; set; }
|
||||
public bool SearchAllForestServers
|
||||
{
|
||||
get
|
||||
{
|
||||
var fs = ADDiscoverForestServers.ForestServers;
|
||||
if (fs != null && fs.Count > ActiveDirectory.MaxForestServerSearch)
|
||||
return false; // Never
|
||||
|
||||
return _SearchAllForestServers;
|
||||
}
|
||||
}
|
||||
|
||||
#region Contructor/Initializing
|
||||
|
||||
internal ActiveDirectoryContext(DiscoDataContext Database)
|
||||
{
|
||||
Initialize(Database);
|
||||
}
|
||||
|
||||
private void Initialize(DiscoDataContext Database)
|
||||
{
|
||||
// Search Entire Forest (default: true)
|
||||
this._SearchAllForestServers = Database.DiscoConfiguration.ActiveDirectory.SearchAllForestServers ?? true;
|
||||
|
||||
// Determine Site
|
||||
var computerSite = ActiveDirectorySite.GetComputerSite();
|
||||
this.Site = new ADSite(this, computerSite);
|
||||
|
||||
// Determine Domains
|
||||
var computerDomain = Domain.GetComputerDomain();
|
||||
this.Domains = computerDomain.Forest.Domains
|
||||
.Cast<Domain>()
|
||||
.Select(d => new ADDomain(this, d))
|
||||
.ToList();
|
||||
this.PrimaryDomain = this.Domains.Where(d => d.Name == computerDomain.Name).First();
|
||||
|
||||
// Determine Search Scope Containers
|
||||
ReinitializeSearchContainers(Database.DiscoConfiguration.ActiveDirectory.SearchContainers);
|
||||
|
||||
// Determine Domain Controllers
|
||||
var siteDomainControllers = computerSite.Servers
|
||||
.OfType<DomainController>()
|
||||
.Where(dc => dc.IsReachable())
|
||||
.Select(dc => new ADDomainController(this, dc, GetDomainByName(dc.Domain.Name), IsSiteServer: true, IsWritable: false));
|
||||
|
||||
Site.UpdateDomainControllers(siteDomainControllers);
|
||||
this.Domains.ForEach(domain => domain.UpdateDomainControllers(siteDomainControllers.Where(dc => dc.Domain == domain)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Domain Getters
|
||||
|
||||
public bool TryGetDomainFromDistinguishedName(string DistinguishedName, out ADDomain Domain)
|
||||
{
|
||||
// Find closest match
|
||||
Domain = this.Domains.Where(d => DistinguishedName.EndsWith(d.DistinguishedName, StringComparison.OrdinalIgnoreCase))
|
||||
.OrderByDescending(d => d.DistinguishedName.Length).FirstOrDefault();
|
||||
|
||||
return (Domain != null);
|
||||
}
|
||||
public ADDomain GetDomainFromDistinguishedName(string DistinguishedName)
|
||||
{
|
||||
ADDomain domain;
|
||||
if (!TryGetDomainFromDistinguishedName(DistinguishedName, out domain))
|
||||
throw new ArgumentException(string.Format("The distinguished name is from an unknown domain: [{0}]", DistinguishedName), "DistinguishedName");
|
||||
return domain;
|
||||
}
|
||||
|
||||
public bool TryGetDomainByNetBiosName(string NetBiosName, out ADDomain Domain)
|
||||
{
|
||||
Domain = this.Domains.FirstOrDefault(d => d.NetBiosName.Equals(NetBiosName, StringComparison.OrdinalIgnoreCase));
|
||||
return (Domain != null);
|
||||
}
|
||||
public ADDomain GetDomainByNetBiosName(string NetBiosName)
|
||||
{
|
||||
ADDomain domain;
|
||||
if (!TryGetDomainByNetBiosName(NetBiosName, out domain))
|
||||
throw new ArgumentException(string.Format("The domain for specified NetBios name is unknown [{0}]", NetBiosName), "NetBiosName");
|
||||
return domain;
|
||||
}
|
||||
|
||||
public bool TryGetDomainByName(string Name, out ADDomain Domain)
|
||||
{
|
||||
Domain = this.Domains.FirstOrDefault(d => d.Name.Equals(Name, StringComparison.OrdinalIgnoreCase));
|
||||
return (Domain != null);
|
||||
}
|
||||
public ADDomain GetDomainByName(string Name)
|
||||
{
|
||||
ADDomain domain;
|
||||
if (!TryGetDomainByName(Name, out domain))
|
||||
throw new ArgumentException(string.Format("The domain for specified DNS name is unknown [{0}]", Name), "Name");
|
||||
return domain;
|
||||
}
|
||||
|
||||
public bool TryGetDomainFromSecurityIdentifier(SecurityIdentifier SecurityIdentifier, out ADDomain Domain)
|
||||
{
|
||||
Domain = this.Domains.FirstOrDefault(d => d.SecurityIdentifier.IsEqualDomainSid(SecurityIdentifier));
|
||||
return (Domain != null);
|
||||
}
|
||||
public ADDomain GetDomainFromSecurityIdentifier(SecurityIdentifier SecurityIdentifier)
|
||||
{
|
||||
ADDomain domain;
|
||||
if (!TryGetDomainFromSecurityIdentifier(SecurityIdentifier, out domain))
|
||||
throw new ArgumentException(string.Format("The domain for specified Security Identifier is unknown [{0}]", SecurityIdentifier.ToString()), "SecurityIdentifier");
|
||||
return domain;
|
||||
}
|
||||
|
||||
public bool TryGetDomainFromId(string Id, out ADDomain Domain)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Id))
|
||||
throw new ArgumentNullException("Id");
|
||||
|
||||
var idSplit = UserExtensions.SplitUserId(Id);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(idSplit.Item1))
|
||||
throw new ArgumentException(string.Format("The Id must include the Domain [{0}]", Id), "Id");
|
||||
|
||||
return TryGetDomainByNetBiosName(idSplit.Item1, out Domain);
|
||||
}
|
||||
public ADDomain GetDomainFromId(string Id)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Id))
|
||||
throw new ArgumentNullException("Id");
|
||||
|
||||
var idSplit = UserExtensions.SplitUserId(Id);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(idSplit.Item1))
|
||||
throw new ArgumentException(string.Format("The Id must include the Domain [{0}]", Id), "Id");
|
||||
|
||||
return GetDomainByNetBiosName(idSplit.Item1);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public ADDirectoryEntry RetrieveDirectoryEntry(string DistinguishedName, string[] LoadProperties = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(DistinguishedName))
|
||||
throw new ArgumentNullException("DistinguishedName");
|
||||
|
||||
var d = GetDomainFromDistinguishedName(DistinguishedName);
|
||||
var dc = d.GetAvailableDomainController();
|
||||
|
||||
return dc.RetrieveDirectoryEntry(DistinguishedName, LoadProperties);
|
||||
}
|
||||
|
||||
#region Searching
|
||||
|
||||
public IEnumerable<ADSearchResult> SearchEntireForest(string LdapFilter, string[] LoadProperties, int? ResultLimit = null)
|
||||
{
|
||||
var queries = this.Domains.Select(d => Tuple.Create(d, d.DistinguishedName));
|
||||
|
||||
return SearchInternal(queries, LdapFilter, LoadProperties, ResultLimit);
|
||||
}
|
||||
|
||||
public IEnumerable<ADSearchResult> SearchScope(string LdapFilter, string[] LoadProperties, int? ResultLimit = null)
|
||||
{
|
||||
var queries = this.Domains.SelectMany(
|
||||
d => d.SearchContainers ?? new List<string>() { d.DistinguishedName },
|
||||
(d, scope) => Tuple.Create(d, scope));
|
||||
|
||||
return SearchInternal(queries, LdapFilter, LoadProperties, ResultLimit);
|
||||
}
|
||||
|
||||
internal IEnumerable<ADSearchResult> SearchInternal(IEnumerable<Tuple<ADDomain, string>> Queries, string LdapFilter, string[] LoadProperties, int? ResultLimit)
|
||||
{
|
||||
var queries = Queries.ToList();
|
||||
|
||||
switch (queries.Count)
|
||||
{
|
||||
case 0: // Nothing Queried
|
||||
return Enumerable.Empty<ADSearchResult>();
|
||||
|
||||
case 1: // Single-search
|
||||
var querySingle = queries[0];
|
||||
return querySingle.Item1.SearchInternal(querySingle.Item2, LdapFilter, LoadProperties, ResultLimit);
|
||||
|
||||
default: // Multi-search - Parallelize
|
||||
|
||||
var queryTasks = queries.Select(query =>
|
||||
Task<IEnumerable<ADSearchResult>>.Factory.StartNew(() =>
|
||||
query.Item1.SearchInternal(query.Item2, LdapFilter, LoadProperties, ResultLimit))).ToArray();
|
||||
|
||||
// Block
|
||||
Task.WaitAll(queryTasks);
|
||||
|
||||
var results = queryTasks.SelectMany(t => t.Result);
|
||||
if (ResultLimit.HasValue)
|
||||
results = results.Take(ResultLimit.Value);
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Configuration
|
||||
|
||||
public bool UpdateSearchAllForestServers(DiscoDataContext Database, bool SearchAllForestServers)
|
||||
{
|
||||
if (SearchAllForestServers == false)
|
||||
{
|
||||
Database.DiscoConfiguration.ActiveDirectory.SearchAllForestServers = false;
|
||||
this._SearchAllForestServers = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
var forestServers = ADDiscoverForestServers.LoadForestServersBlocking();
|
||||
if (forestServers.Count <= ActiveDirectory.MaxForestServerSearch)
|
||||
{
|
||||
Database.DiscoConfiguration.ActiveDirectory.SearchAllForestServers = true;
|
||||
this._SearchAllForestServers = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Database.DiscoConfiguration.ActiveDirectory.SearchAllForestServers = false;
|
||||
this._SearchAllForestServers = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSearchContainers(DiscoDataContext Database, IEnumerable<string> Containers)
|
||||
{
|
||||
Dictionary<string, List<string>> searchContainers = null;
|
||||
|
||||
if (Containers != null)
|
||||
{
|
||||
searchContainers = Containers
|
||||
.Where(c => !string.IsNullOrWhiteSpace(c))
|
||||
.Distinct()
|
||||
.Select(c =>
|
||||
{
|
||||
ADDomain d;
|
||||
if (TryGetDomainFromDistinguishedName(c, out d))
|
||||
return Tuple.Create(d, c);
|
||||
else
|
||||
return null;
|
||||
}).Where(i => i != null)
|
||||
.GroupBy(i => i.Item1)
|
||||
.ToDictionary(g => g.Key.Name.ToLower(), g => g.Select(i => i.Item2).ToList());
|
||||
}
|
||||
|
||||
if (searchContainers == null || searchContainers.Count == 0)
|
||||
{
|
||||
Database.DiscoConfiguration.ActiveDirectory.SearchContainers = null;
|
||||
ReinitializeSearchContainers(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
Database.DiscoConfiguration.ActiveDirectory.SearchContainers = searchContainers;
|
||||
ReinitializeSearchContainers(searchContainers);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReinitializeSearchContainers(Dictionary<string, List<string>> Containers)
|
||||
{
|
||||
if (Containers == null)
|
||||
{
|
||||
// No search restrictions (search entire domain)
|
||||
foreach (var domain in this.Domains)
|
||||
domain.UpdateSearchEntireDomain();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Restrict search containers
|
||||
var searchContainerDomains = Containers.Join(this.Domains, ok => ok.Key, ik => ik.Name, (o, i) => Tuple.Create(o, i), StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var domainContainers in searchContainerDomains)
|
||||
domainContainers.Item2.UpdateSearchContainers(domainContainers.Item1.Value);
|
||||
|
||||
// Ignore domains without configured containers
|
||||
var unconfiguredContainers = this.Domains.Except(searchContainerDomains.Select(sc => sc.Item2));
|
||||
foreach (var domain in unconfiguredContainers)
|
||||
domain.UpdateSearchContainers(new List<string>());
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,4 @@
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Interop.ActiveDirectory.Internal;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.DirectoryServices.ActiveDirectory;
|
||||
@@ -16,23 +13,7 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
#region Domain/Directory Extensions
|
||||
|
||||
public static DomainController RetrieveWritableDomainController(this ActiveDirectoryDomain domain)
|
||||
{
|
||||
return ADInterop.RetrieveWritableDomainController(domain);
|
||||
}
|
||||
|
||||
public static IEnumerable<DomainController> RetrieveReachableDomainControllers(this ActiveDirectorySite site, ActiveDirectoryDomain domain)
|
||||
{
|
||||
return site.Servers.OfType<DomainController>().Where(dc => dc.Reachable() && dc.Domain.Name.Equals(domain.DnsName));
|
||||
}
|
||||
|
||||
public static IEnumerable<DomainController> RetrieveReachableDomainControllers(this ActiveDirectoryDomain domain)
|
||||
{
|
||||
var d = Domain.GetDomain(new DirectoryContext(DirectoryContextType.Domain, domain.DnsName));
|
||||
return d.FindAllDomainControllers().OfType<DomainController>().Where(dc => dc.Reachable());
|
||||
}
|
||||
|
||||
public static bool Reachable(this DirectoryServer ds)
|
||||
public static bool IsReachable(this DirectoryServer ds)
|
||||
{
|
||||
using (Ping p = new Ping())
|
||||
{
|
||||
@@ -41,351 +22,82 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetFriendlyOrganisationalUnitName(this ActiveDirectoryDomain domain, string DistinguishedName)
|
||||
public static IEnumerable<DomainController> WhereReachable(this DomainControllerCollection domainControllers)
|
||||
{
|
||||
if (!DistinguishedName.EndsWith(domain.DistinguishedName, StringComparison.InvariantCultureIgnoreCase))
|
||||
throw new ArgumentException(string.Format("The Distinguished Name [{0}] doesn't exist within this domain [{1}]", DistinguishedName, domain.DistinguishedName));
|
||||
|
||||
StringBuilder name = new StringBuilder();
|
||||
|
||||
name.Append('[').Append(domain.NetBiosName).Append(']');
|
||||
|
||||
var subDN = DistinguishedName.Substring(0, DistinguishedName.Length - domain.DistinguishedName.Length);
|
||||
var subDNComponents = subDN.Split(',');
|
||||
|
||||
subDNComponents
|
||||
.Where(c => !string.IsNullOrWhiteSpace(c))
|
||||
.Reverse()
|
||||
.Select(c => c.Substring(c.IndexOf('=') + 1))
|
||||
.ToList()
|
||||
.ForEach(c => name.Append(" > ").Append(c));
|
||||
|
||||
return name.ToString();
|
||||
return domainControllers.Cast<DomainController>().Where(dc => dc.IsReachable());
|
||||
}
|
||||
|
||||
public static string GetDefaultComputerContainer(this ActiveDirectoryDomain domain)
|
||||
public static IEnumerable<ADDomainController> WhereReachable(this IEnumerable<ADDomainController> domainControllers)
|
||||
{
|
||||
return string.Format("CN=Computers,{0}", domain.DistinguishedName);
|
||||
return domainControllers.Where(dc => dc.DomainController.IsReachable());
|
||||
}
|
||||
|
||||
// Directory Entry Properties (Generic Helpers)
|
||||
public static T Value<T>(this PropertyCollection properties, string PropertyName)
|
||||
{
|
||||
var p = properties.Values<T>(PropertyName);
|
||||
return p.FirstOrDefault();
|
||||
}
|
||||
public static IEnumerable<T> Values<T>(this PropertyCollection properties, string PropertyName)
|
||||
{
|
||||
var p = properties[PropertyName];
|
||||
return p.OfType<T>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region User Account Extensions
|
||||
public static object GetPropertyValue(this ActiveDirectoryUserAccount account, string PropertyName, int Index = 0)
|
||||
#region ADObject Builders
|
||||
|
||||
// User Accounts
|
||||
public static ADUserAccount AsADUserAccount(this ADSearchResult SearchResult, bool Quick, string[] AdditionalProperties)
|
||||
{
|
||||
switch (PropertyName.ToLower())
|
||||
{
|
||||
case "name":
|
||||
return account.Name;
|
||||
case "samaccountname":
|
||||
return account.SamAccountName;
|
||||
case "distinguishedname":
|
||||
return account.DistinguishedName;
|
||||
case "objectsid":
|
||||
return account.SecurityIdentifier;
|
||||
case "sn":
|
||||
return account.Surname;
|
||||
case "givenname":
|
||||
return account.GivenName;
|
||||
case "mail":
|
||||
return account.Email;
|
||||
case "telephonenumber":
|
||||
return account.Phone;
|
||||
default:
|
||||
object[] adProperty;
|
||||
if (account.LoadedProperties.TryGetValue(PropertyName, out adProperty) && Index <= adProperty.Length)
|
||||
return adProperty[Index];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
return ADUserAccount.FromSearchResult(SearchResult, Quick, AdditionalProperties);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Machine Account Extensions
|
||||
|
||||
public static void DeleteAccount(this ActiveDirectoryMachineAccount account, DomainController DomainController)
|
||||
public static IEnumerable<ADUserAccount> AsADUserAccounts(this IEnumerable<ADSearchResult> SearchResults, bool Quick, string[] AdditionalProperties)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
using (DirectoryEntry deAccount = DomainController.RetrieveDirectoryEntry(account.DistinguishedName))
|
||||
{
|
||||
deAccount.DeleteObjectRecursive();
|
||||
}
|
||||
}
|
||||
public static void DeleteAccount(this ActiveDirectoryMachineAccount account)
|
||||
{
|
||||
var domain = account.GetDomain();
|
||||
|
||||
using (var domainController = domain.RetrieveWritableDomainController())
|
||||
{
|
||||
account.DeleteAccount(domainController);
|
||||
}
|
||||
return SearchResults.Select(sr => ADUserAccount.FromSearchResult(sr, Quick, AdditionalProperties));
|
||||
}
|
||||
|
||||
private static void SetNetbootGUID(this ActiveDirectoryMachineAccount account, DomainController DomainController, System.Guid updatedNetbootGUID)
|
||||
// Machine Accounts
|
||||
public static ADMachineAccount AsADMachineAccount(this ADSearchResult SearchResult, string[] AdditionalProperties)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
using (DirectoryEntry deAccount = DomainController.RetrieveDirectoryEntry(account.DistinguishedName))
|
||||
{
|
||||
PropertyValueCollection netbootGUIDProp = deAccount.Properties["netbootGUID"];
|
||||
bool flag = netbootGUIDProp.Count > 0;
|
||||
if (flag)
|
||||
{
|
||||
netbootGUIDProp.Clear();
|
||||
}
|
||||
netbootGUIDProp.Add(updatedNetbootGUID.ToByteArray());
|
||||
deAccount.CommitChanges();
|
||||
}
|
||||
return ADMachineAccount.FromSearchResult(SearchResult, AdditionalProperties);
|
||||
}
|
||||
public static void SetDescription(this ActiveDirectoryMachineAccount account, DomainController DomainController, string Description)
|
||||
public static IEnumerable<ADMachineAccount> AsADMachineAccounts(this IEnumerable<ADSearchResult> SearchResults, string[] AdditionalProperties)
|
||||
{
|
||||
using (DirectoryEntry deAccount = DomainController.RetrieveDirectoryEntry(account.DistinguishedName))
|
||||
{
|
||||
PropertyValueCollection descriptionProp = deAccount.Properties["description"];
|
||||
if (descriptionProp.Count > 0)
|
||||
{
|
||||
descriptionProp.Clear();
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Description))
|
||||
{
|
||||
descriptionProp.Add(Description);
|
||||
}
|
||||
deAccount.CommitChanges();
|
||||
}
|
||||
}
|
||||
public static void SetDescription(this ActiveDirectoryMachineAccount account, string Description)
|
||||
{
|
||||
var domain = account.GetDomain();
|
||||
|
||||
using (var domainController = domain.RetrieveWritableDomainController())
|
||||
{
|
||||
account.SetDescription(domainController, Description);
|
||||
}
|
||||
return SearchResults.Select(sr => ADMachineAccount.FromSearchResult(sr, AdditionalProperties));
|
||||
}
|
||||
|
||||
public static void SetDescription(this ActiveDirectoryMachineAccount account, DomainController DomainController, Device Device)
|
||||
// Groups
|
||||
public static ADGroup AsADGroup(this ADSearchResult SearchResult)
|
||||
{
|
||||
System.Text.StringBuilder descriptionBuilder = new System.Text.StringBuilder();
|
||||
|
||||
if (Device.AssignedUserId != null)
|
||||
{
|
||||
descriptionBuilder.Append(Device.AssignedUser.UserId).Append(" (").Append(Device.AssignedUser.DisplayName).Append("); ");
|
||||
}
|
||||
|
||||
if (Device.DeviceModelId.HasValue)
|
||||
{
|
||||
descriptionBuilder.Append(Device.DeviceModel.Description).Append("; ");
|
||||
}
|
||||
|
||||
descriptionBuilder.Append(Device.DeviceProfile.Description).Append(";");
|
||||
|
||||
string description = descriptionBuilder.ToString().Trim();
|
||||
if (description.Length > 1024)
|
||||
description = description.Substring(0, 1024);
|
||||
|
||||
account.SetDescription(DomainController, description);
|
||||
return ADGroup.FromSearchResult(SearchResult);
|
||||
}
|
||||
public static void SetDescription(this ActiveDirectoryMachineAccount account, Device Device)
|
||||
public static IEnumerable<ADGroup> AsADGroups(this IEnumerable<ADSearchResult> SearchResults)
|
||||
{
|
||||
var domain = account.GetDomain();
|
||||
|
||||
using (var domainController = domain.RetrieveWritableDomainController())
|
||||
{
|
||||
account.SetDescription(domainController, Device);
|
||||
}
|
||||
return SearchResults.Select(sr => ADGroup.FromSearchResult(sr));
|
||||
}
|
||||
public static ADGroup AsADGroup(this ADDirectoryEntry DirectoryEntry)
|
||||
{
|
||||
return ADGroup.FromDirectoryEntry(DirectoryEntry);
|
||||
}
|
||||
public static IEnumerable<ADGroup> AsADGroups(this IEnumerable<ADDirectoryEntry> DirectoryEntries)
|
||||
{
|
||||
return DirectoryEntries.Select(de => ADGroup.FromDirectoryEntry(de));
|
||||
}
|
||||
|
||||
public static void DisableAccount(this ActiveDirectoryMachineAccount account, DomainController DomainController)
|
||||
// Organisational Units
|
||||
public static ADOrganisationalUnit AsADOrganisationalUnit(this ADSearchResult SearchResult)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
using (DirectoryEntry deAccount = DomainController.RetrieveDirectoryEntry(account.DistinguishedName))
|
||||
{
|
||||
int accountControl = (int)deAccount.Properties["userAccountControl"][0];
|
||||
int updatedAccountControl = (accountControl | 2);
|
||||
if (accountControl != updatedAccountControl)
|
||||
{
|
||||
deAccount.Properties["userAccountControl"][0] = updatedAccountControl;
|
||||
deAccount.CommitChanges();
|
||||
}
|
||||
}
|
||||
return ADOrganisationalUnit.FromSearchResult(SearchResult);
|
||||
}
|
||||
public static void DisableAccount(this ActiveDirectoryMachineAccount account)
|
||||
public static IEnumerable<ADOrganisationalUnit> AsADOrganisationalUnit(this IEnumerable<ADSearchResult> SearchResults)
|
||||
{
|
||||
var domain = account.GetDomain();
|
||||
|
||||
using (var domainController = domain.RetrieveWritableDomainController())
|
||||
{
|
||||
account.DisableAccount(domainController);
|
||||
}
|
||||
}
|
||||
public static void EnableAccount(this ActiveDirectoryMachineAccount account, DomainController DomainController)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
using (DirectoryEntry deAccount = DomainController.RetrieveDirectoryEntry(account.DistinguishedName))
|
||||
{
|
||||
int accountControl = (int)deAccount.Properties["userAccountControl"][0];
|
||||
if ((accountControl & 2) == 2)
|
||||
{
|
||||
int updatedAccountControl = (accountControl ^ 2);
|
||||
deAccount.Properties["userAccountControl"][0] = updatedAccountControl;
|
||||
deAccount.CommitChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void EnableAccount(this ActiveDirectoryMachineAccount account)
|
||||
{
|
||||
var domain = account.GetDomain();
|
||||
|
||||
using (var domainController = domain.RetrieveWritableDomainController())
|
||||
{
|
||||
account.EnableAccount(domainController);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool UpdateNetbootGUID(this ActiveDirectoryMachineAccount account, DomainController DomainController, string UUID, string MACAddress)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
Guid netbootGUID = Guid.Empty;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(UUID))
|
||||
{
|
||||
netbootGUID = ActiveDirectoryExtensions.NetbootGUIDFromUUID(UUID);
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(MACAddress))
|
||||
{
|
||||
netbootGUID = ActiveDirectoryExtensions.NetbootGUIDFromMACAddress(MACAddress);
|
||||
}
|
||||
|
||||
if (netbootGUID != System.Guid.Empty && netbootGUID != account.NetbootGUID)
|
||||
{
|
||||
account.SetNetbootGUID(DomainController, netbootGUID);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public static bool UpdateNetbootGUID(this ActiveDirectoryMachineAccount account, string UUID, string MACAddress)
|
||||
{
|
||||
var domain = account.GetDomain();
|
||||
|
||||
using (var domainController = domain.RetrieveWritableDomainController())
|
||||
{
|
||||
return account.UpdateNetbootGUID(domainController, UUID, MACAddress);
|
||||
}
|
||||
}
|
||||
public static System.Guid NetbootGUIDFromMACAddress(string MACAddress)
|
||||
{
|
||||
string strippedMACAddress = MACAddress.Trim().Replace(":", string.Empty).Replace("-", string.Empty);
|
||||
bool flag = strippedMACAddress.Length == 12;
|
||||
System.Guid NetbootGUIDFromMACAddress;
|
||||
if (flag)
|
||||
{
|
||||
System.Guid guid = new System.Guid(string.Format("00000000-0000-0000-0000-{0}", strippedMACAddress));
|
||||
NetbootGUIDFromMACAddress = guid;
|
||||
}
|
||||
else
|
||||
{
|
||||
NetbootGUIDFromMACAddress = System.Guid.Empty;
|
||||
}
|
||||
return NetbootGUIDFromMACAddress;
|
||||
}
|
||||
public static System.Guid NetbootGUIDFromUUID(string UUID)
|
||||
{
|
||||
System.Guid result = new System.Guid(UUID);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static object GetPropertyValue(this ActiveDirectoryMachineAccount account, string PropertyName, int Index = 0)
|
||||
{
|
||||
switch (PropertyName.ToLower())
|
||||
{
|
||||
case "name":
|
||||
return account.Name;
|
||||
case "samaccountname":
|
||||
return account.SamAccountName;
|
||||
case "distinguishedname":
|
||||
return account.DistinguishedName;
|
||||
case "objectsid":
|
||||
return account.SecurityIdentifier;
|
||||
case "netbootguid":
|
||||
return account.NetbootGUID;
|
||||
default:
|
||||
object[] adProperty;
|
||||
if (account.LoadedProperties.TryGetValue(PropertyName, out adProperty) && Index <= adProperty.Length)
|
||||
return adProperty[Index];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static IPStatus PingComputer(this ActiveDirectoryMachineAccount account, int Timeout = 2000)
|
||||
{
|
||||
using (var p = new Ping())
|
||||
{
|
||||
PingReply reply = p.Send(account.DnsName, Timeout);
|
||||
return reply.Status;
|
||||
}
|
||||
}
|
||||
|
||||
public static void MoveOrganisationalUnit(this ActiveDirectoryMachineAccount account, DomainController DomainController, string NewOrganisationUnit)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
var parentDistinguishedName = account.ParentDistinguishedName();
|
||||
|
||||
if (parentDistinguishedName != null && !parentDistinguishedName.Equals(NewOrganisationUnit, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
var domain = account.GetDomain();
|
||||
|
||||
// If no OU provided, place in default Computers container
|
||||
if (string.IsNullOrWhiteSpace(NewOrganisationUnit))
|
||||
NewOrganisationUnit = domain.GetDefaultComputerContainer();
|
||||
|
||||
if (!NewOrganisationUnit.EndsWith(domain.DistinguishedName, StringComparison.InvariantCultureIgnoreCase))
|
||||
throw new InvalidOperationException(string.Format("Unable to move AD Account from one domain [{0}] to another [{1}].", account.DistinguishedName, NewOrganisationUnit));
|
||||
|
||||
using (DirectoryEntry ou = DomainController.RetrieveDirectoryEntry(NewOrganisationUnit))
|
||||
{
|
||||
using (DirectoryEntry i = DomainController.RetrieveDirectoryEntry(account.DistinguishedName))
|
||||
{
|
||||
i.UsePropertyCache = false;
|
||||
i.MoveTo(ou);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string ParentDistinguishedName(this ActiveDirectoryMachineAccount account)
|
||||
{
|
||||
// Determine Parent
|
||||
if (!string.IsNullOrWhiteSpace(account.DistinguishedName))
|
||||
return account.DistinguishedName.Substring(account.DistinguishedName.IndexOf(",") + 1);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ActiveDirectoryDomain GetDomain(this ActiveDirectoryMachineAccount account)
|
||||
{
|
||||
var domain = ActiveDirectory.GetDomainByNetBiosName(account.Domain);
|
||||
|
||||
if (domain == null)
|
||||
throw new InvalidOperationException(string.Format("Unable to find Domain [{0}] for account [{1}]", account.Domain, account.Name));
|
||||
else
|
||||
return domain;
|
||||
return SearchResults.Select(sr => ADOrganisationalUnit.FromSearchResult(sr));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public class ActiveDirectoryGroupCache
|
||||
{
|
||||
private ConcurrentDictionary<SecurityIdentifier, Tuple<ADGroup, DateTime>> securityIdentifierCache;
|
||||
private ConcurrentDictionary<string, Tuple<ADGroup, DateTime>> distinguishedNameCache;
|
||||
private const long CacheTimeoutTicks = 6000000000; // 10 Minutes
|
||||
|
||||
private const int CacheCleanIntervalMinutes = 15;
|
||||
private DateTime cacheCleanNext;
|
||||
private object cacheCleanLock = new object();
|
||||
private Task cacheCleanTask;
|
||||
|
||||
public ActiveDirectoryGroupCache()
|
||||
{
|
||||
this.securityIdentifierCache = new ConcurrentDictionary<SecurityIdentifier, Tuple<ADGroup, DateTime>>();
|
||||
this.distinguishedNameCache = new ConcurrentDictionary<string, Tuple<ADGroup, DateTime>>(StringComparer.OrdinalIgnoreCase);
|
||||
cacheCleanNext = DateTime.Now.AddMinutes(CacheCleanIntervalMinutes);
|
||||
}
|
||||
|
||||
public ADGroup GetGroup(string DistinguishedName)
|
||||
{
|
||||
// Check Cache
|
||||
Tuple<ADGroup, DateTime> groupRecord = TryDistinguishedNameCache(DistinguishedName);
|
||||
|
||||
if (groupRecord == null)
|
||||
{
|
||||
// Load from AD
|
||||
var group = ActiveDirectory.RetrieveADGroupByDistinguishedName(DistinguishedName);
|
||||
SetValue(group);
|
||||
|
||||
return group;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return from Cache
|
||||
return groupRecord.Item1;
|
||||
}
|
||||
}
|
||||
public ADGroup GetGroup(SecurityIdentifier SecurityIdentifier)
|
||||
{
|
||||
// Check Cache
|
||||
Tuple<ADGroup, DateTime> groupRecord = TrySecurityIdentifierCache(SecurityIdentifier);
|
||||
|
||||
if (groupRecord == null)
|
||||
{
|
||||
// Load from AD
|
||||
var group = ActiveDirectory.RetrieveADGroupWithSecurityIdentifier(SecurityIdentifier);
|
||||
SetValue(group);
|
||||
|
||||
return group;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return from Cache
|
||||
return groupRecord.Item1;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<ADGroup> GetRecursiveGroups(IEnumerable<string> DistinguishedNames)
|
||||
{
|
||||
List<ADGroup> groups = new List<ADGroup>();
|
||||
|
||||
foreach (var distinguishedName in DistinguishedNames)
|
||||
foreach (var group in GetGroupsRecursive(distinguishedName, new Stack<ADGroup>()))
|
||||
if (!groups.Contains(group))
|
||||
{
|
||||
groups.Add(group);
|
||||
yield return group;
|
||||
}
|
||||
}
|
||||
public IEnumerable<ADGroup> GetRecursiveGroups(string DistinguishedName)
|
||||
{
|
||||
foreach (var group in GetGroupsRecursive(DistinguishedName, new Stack<ADGroup>()))
|
||||
yield return group;
|
||||
}
|
||||
private IEnumerable<ADGroup> GetGroupsRecursive(string DistinguishedName, Stack<ADGroup> RecursiveTree)
|
||||
{
|
||||
var group = GetGroup(DistinguishedName);
|
||||
|
||||
if (group != null && !RecursiveTree.Contains(group))
|
||||
{
|
||||
yield return group;
|
||||
|
||||
if (group.MemberOf != null)
|
||||
{
|
||||
RecursiveTree.Push(group);
|
||||
|
||||
foreach (var parentDistinguishedName in group.MemberOf)
|
||||
foreach (var parentGroup in GetGroupsRecursive(parentDistinguishedName, RecursiveTree))
|
||||
yield return parentGroup;
|
||||
|
||||
RecursiveTree.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Tuple<ADGroup, DateTime> TryDistinguishedNameCache(string DistinguishedName)
|
||||
{
|
||||
Tuple<ADGroup, DateTime> groupRecord;
|
||||
if (distinguishedNameCache.TryGetValue(DistinguishedName, out groupRecord))
|
||||
{
|
||||
if (groupRecord.Item2 > DateTime.Now)
|
||||
return groupRecord;
|
||||
else
|
||||
{
|
||||
if (distinguishedNameCache.TryRemove(DistinguishedName, out groupRecord))
|
||||
securityIdentifierCache.TryRemove(groupRecord.Item1.SecurityIdentifier, out groupRecord);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private Tuple<ADGroup, DateTime> TrySecurityIdentifierCache(SecurityIdentifier SecurityIdentifier)
|
||||
{
|
||||
Tuple<ADGroup, DateTime> groupRecord;
|
||||
if (securityIdentifierCache.TryGetValue(SecurityIdentifier, out groupRecord))
|
||||
{
|
||||
if (groupRecord.Item2 > DateTime.Now)
|
||||
return groupRecord;
|
||||
else
|
||||
{
|
||||
if (securityIdentifierCache.TryRemove(SecurityIdentifier, out groupRecord))
|
||||
distinguishedNameCache.TryRemove(groupRecord.Item1.DistinguishedName, out groupRecord);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool SetValue(ADGroup Group)
|
||||
{
|
||||
Tuple<ADGroup, DateTime> groupRecord = Tuple.Create(Group, DateTime.Now.AddTicks(CacheTimeoutTicks));
|
||||
Tuple<ADGroup, DateTime> oldGroupRecord;
|
||||
|
||||
var distinguishedName = Group.DistinguishedName;
|
||||
var securityIdentifier = Group.SecurityIdentifier;
|
||||
|
||||
if (distinguishedNameCache.ContainsKey(distinguishedName))
|
||||
{
|
||||
if (distinguishedNameCache.TryGetValue(distinguishedName, out oldGroupRecord))
|
||||
{
|
||||
distinguishedNameCache.TryUpdate(distinguishedName, groupRecord, oldGroupRecord);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
distinguishedNameCache.TryAdd(distinguishedName, groupRecord);
|
||||
}
|
||||
|
||||
if (securityIdentifierCache.ContainsKey(securityIdentifier))
|
||||
{
|
||||
if (securityIdentifierCache.TryGetValue(securityIdentifier, out oldGroupRecord))
|
||||
{
|
||||
securityIdentifierCache.TryUpdate(securityIdentifier, groupRecord, oldGroupRecord);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
securityIdentifierCache.TryAdd(securityIdentifier, groupRecord);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Stale Cache Clean
|
||||
|
||||
private void EnsureCleanCache()
|
||||
{
|
||||
if (cacheCleanTask == null && cacheCleanNext < DateTime.Now)
|
||||
{
|
||||
lock (cacheCleanLock)
|
||||
{
|
||||
if (cacheCleanTask == null && cacheCleanNext < DateTime.Now)
|
||||
{
|
||||
cacheCleanTask = Task.Factory.StartNew(CleanCache);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CleanCache()
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
// Clean Cache
|
||||
var dnKeys = distinguishedNameCache.Keys.ToArray();
|
||||
foreach (var dnKey in dnKeys)
|
||||
{
|
||||
Tuple<ADGroup, DateTime> groupRecord;
|
||||
if (distinguishedNameCache.TryGetValue(dnKey, out groupRecord))
|
||||
{
|
||||
if (groupRecord.Item2 <= now)
|
||||
{
|
||||
distinguishedNameCache.TryRemove(dnKey, out groupRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean SID Cache
|
||||
var siKeys = securityIdentifierCache.Keys.ToArray();
|
||||
foreach (var siKey in siKeys)
|
||||
{
|
||||
Tuple<ADGroup, DateTime> groupRecord;
|
||||
if (securityIdentifierCache.TryGetValue(siKey, out groupRecord))
|
||||
{
|
||||
if (groupRecord.Item2 <= now)
|
||||
{
|
||||
securityIdentifierCache.TryRemove(siKey, out groupRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule Next Clean
|
||||
cacheCleanNext = now.AddMinutes(CacheCleanIntervalMinutes);
|
||||
cacheCleanTask = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
using System.Security.Principal;
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public interface IADObject
|
||||
{
|
||||
ADDomain Domain { get; }
|
||||
|
||||
string DistinguishedName { get; }
|
||||
SecurityIdentifier SecurityIdentifier { get; }
|
||||
|
||||
string Id { get; }
|
||||
string SamAccountName { get; }
|
||||
|
||||
string Name { get; }
|
||||
string DisplayName { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,226 +0,0 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Services.Tasks;
|
||||
using Quartz;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory.Internal
|
||||
{
|
||||
public class ADGroupCache : ScheduledTask
|
||||
{
|
||||
private static ConcurrentDictionary<string, Tuple<ActiveDirectoryGroup, DateTime>> _SecurityIdentifierCache = new ConcurrentDictionary<string, Tuple<ActiveDirectoryGroup, DateTime>>();
|
||||
private static ConcurrentDictionary<string, Tuple<ActiveDirectoryGroup, DateTime>> _DistinguishedNameCache = new ConcurrentDictionary<string, Tuple<ActiveDirectoryGroup, DateTime>>();
|
||||
private const long CacheTimeoutTicks = 6000000000; // 10 Minutes
|
||||
|
||||
public static IEnumerable<string> GetGroups(IEnumerable<string> DistinguishedNames)
|
||||
{
|
||||
List<ActiveDirectoryGroup> groups = new List<ActiveDirectoryGroup>();
|
||||
|
||||
foreach (var distinguishedName in DistinguishedNames)
|
||||
foreach (var group in GetGroupsRecursive(distinguishedName, new Stack<ActiveDirectoryGroup>()))
|
||||
if (!groups.Contains(group))
|
||||
{
|
||||
groups.Add(group);
|
||||
yield return group.NetBiosId;
|
||||
}
|
||||
}
|
||||
public static IEnumerable<string> GetGroups(string DistinguishedName)
|
||||
{
|
||||
foreach (var group in GetGroupsRecursive(DistinguishedName, new Stack<ActiveDirectoryGroup>()))
|
||||
yield return group.NetBiosId;
|
||||
}
|
||||
public static string GetGroupsDistinguishedNameForSecurityIdentifier(string SecurityIdentifier)
|
||||
{
|
||||
var group = GetGroupBySecurityIdentifier(SecurityIdentifier);
|
||||
if (group == null)
|
||||
return null;
|
||||
else
|
||||
return group.DistinguishedName;
|
||||
}
|
||||
private static IEnumerable<ActiveDirectoryGroup> GetGroupsRecursive(string DistinguishedName, Stack<ActiveDirectoryGroup> RecursiveTree)
|
||||
{
|
||||
var group = GetGroup(DistinguishedName);
|
||||
|
||||
if (group != null && !RecursiveTree.Contains(group))
|
||||
{
|
||||
yield return group;
|
||||
|
||||
if (group.MemberOf != null)
|
||||
{
|
||||
RecursiveTree.Push(group);
|
||||
|
||||
foreach (var parentDistinguishedName in group.MemberOf)
|
||||
foreach (var parentGroup in GetGroupsRecursive(parentDistinguishedName, RecursiveTree))
|
||||
yield return parentGroup;
|
||||
|
||||
RecursiveTree.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ActiveDirectoryGroup GetGroup(string DistinguishedName)
|
||||
{
|
||||
// Check Cache
|
||||
Tuple<ActiveDirectoryGroup, DateTime> groupRecord = TryCache(DistinguishedName);
|
||||
|
||||
if (groupRecord == null)
|
||||
{
|
||||
// Load from AD
|
||||
var group = ActiveDirectory.RetrieveGroupWithDistinguishedName(DistinguishedName);
|
||||
SetValue(group);
|
||||
|
||||
return group;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return from Cache
|
||||
return groupRecord.Item1;
|
||||
}
|
||||
}
|
||||
private static ActiveDirectoryGroup GetGroupBySecurityIdentifier(string SecurityIdentifier)
|
||||
{
|
||||
// Check Cache
|
||||
Tuple<ActiveDirectoryGroup, DateTime> groupRecord = TrySecurityIdentifierCache(SecurityIdentifier);
|
||||
|
||||
if (groupRecord == null)
|
||||
{
|
||||
// Load from AD
|
||||
var group = ActiveDirectory.RetrieveGroupWithSecurityIdentifier(SecurityIdentifier);
|
||||
SetValue(group);
|
||||
|
||||
return group;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return from Cache
|
||||
return groupRecord.Item1;
|
||||
}
|
||||
}
|
||||
|
||||
private static Tuple<ActiveDirectoryGroup, DateTime> TryCache(string DistinguishedName)
|
||||
{
|
||||
string distinguishedName = DistinguishedName.ToLower();
|
||||
Tuple<ActiveDirectoryGroup, DateTime> groupRecord;
|
||||
if (_DistinguishedNameCache.TryGetValue(distinguishedName, out groupRecord))
|
||||
{
|
||||
if (groupRecord.Item2 > DateTime.Now)
|
||||
return groupRecord;
|
||||
else
|
||||
{
|
||||
if (_DistinguishedNameCache.TryRemove(distinguishedName, out groupRecord))
|
||||
_SecurityIdentifierCache.TryRemove(groupRecord.Item1.SecurityIdentifier, out groupRecord);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static Tuple<ActiveDirectoryGroup, DateTime> TrySecurityIdentifierCache(string SecurityIdentifier)
|
||||
{
|
||||
Tuple<ActiveDirectoryGroup, DateTime> groupRecord;
|
||||
if (_SecurityIdentifierCache.TryGetValue(SecurityIdentifier, out groupRecord))
|
||||
{
|
||||
if (groupRecord.Item2 > DateTime.Now)
|
||||
return groupRecord;
|
||||
else
|
||||
{
|
||||
if (_SecurityIdentifierCache.TryRemove(SecurityIdentifier, out groupRecord))
|
||||
_DistinguishedNameCache.TryRemove(groupRecord.Item1.DistinguishedName.ToLower(), out groupRecord);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static bool SetValue(ActiveDirectoryGroup Group)
|
||||
{
|
||||
Tuple<ActiveDirectoryGroup, DateTime> groupRecord = new Tuple<ActiveDirectoryGroup, DateTime>(Group, DateTime.Now.AddTicks(CacheTimeoutTicks));
|
||||
Tuple<ActiveDirectoryGroup, DateTime> oldGroupRecord;
|
||||
|
||||
string key = Group.DistinguishedName.ToLower();
|
||||
if (_DistinguishedNameCache.ContainsKey(key))
|
||||
{
|
||||
if (_DistinguishedNameCache.TryGetValue(key, out oldGroupRecord))
|
||||
{
|
||||
_DistinguishedNameCache.TryUpdate(key, groupRecord, oldGroupRecord);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_DistinguishedNameCache.TryAdd(key, groupRecord);
|
||||
}
|
||||
|
||||
string securityIdentifier = Group.SecurityIdentifier;
|
||||
if (_SecurityIdentifierCache.ContainsKey(securityIdentifier))
|
||||
{
|
||||
if (_SecurityIdentifierCache.TryGetValue(securityIdentifier, out oldGroupRecord))
|
||||
{
|
||||
_SecurityIdentifierCache.TryUpdate(securityIdentifier, groupRecord, oldGroupRecord);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_SecurityIdentifierCache.TryAdd(securityIdentifier, groupRecord);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void CleanStaleCache()
|
||||
{
|
||||
// Clean Cache
|
||||
var groupKeys = _DistinguishedNameCache.Keys.ToArray();
|
||||
foreach (string groupKey in groupKeys)
|
||||
{
|
||||
Tuple<ActiveDirectoryGroup, DateTime> groupRecord;
|
||||
if (_DistinguishedNameCache.TryGetValue(groupKey, out groupRecord))
|
||||
{
|
||||
if (groupRecord.Item2 <= DateTime.Now)
|
||||
{
|
||||
_DistinguishedNameCache.TryRemove(groupKey, out groupRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean SID Cache
|
||||
groupKeys = _SecurityIdentifierCache.Keys.ToArray();
|
||||
foreach (string groupKey in groupKeys)
|
||||
{
|
||||
Tuple<ActiveDirectoryGroup, DateTime> groupRecord;
|
||||
if (_SecurityIdentifierCache.TryGetValue(groupKey, out groupRecord))
|
||||
{
|
||||
if (groupRecord.Item2 <= DateTime.Now)
|
||||
{
|
||||
_SecurityIdentifierCache.TryRemove(groupKey, out groupRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string TaskName { get { return "AD Group Cache - Clean Stale Cache"; } }
|
||||
|
||||
public override bool SingleInstanceTask { get { return true; } }
|
||||
public override bool CancelInitiallySupported { get { return false; } }
|
||||
public override bool LogExceptionsOnly { get { return true; } }
|
||||
|
||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
||||
{
|
||||
// Run @ every 15mins
|
||||
|
||||
// Next 15min interval
|
||||
DateTime now = DateTime.Now;
|
||||
int mins = (15 - (now.Minute % 15));
|
||||
if (mins < 10)
|
||||
mins += 15;
|
||||
DateTimeOffset startAt = new DateTimeOffset(now).AddMinutes(mins).AddSeconds(now.Second * -1).AddMilliseconds(now.Millisecond * -1);
|
||||
|
||||
TriggerBuilder triggerBuilder = TriggerBuilder.Create().StartAt(startAt).
|
||||
WithSchedule(SimpleScheduleBuilder.RepeatMinutelyForever(15));
|
||||
|
||||
this.ScheduleTask(triggerBuilder);
|
||||
}
|
||||
|
||||
protected override void ExecuteTask()
|
||||
{
|
||||
CleanStaleCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,682 +0,0 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Services.Tasks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.DirectoryServices;
|
||||
using System.DirectoryServices.ActiveDirectory;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory.Internal
|
||||
{
|
||||
internal static class ADInterop
|
||||
{
|
||||
public static List<ActiveDirectoryDomain> Domains { get; private set; }
|
||||
public static ActiveDirectoryDomain PrimaryDomain { get; private set; }
|
||||
public static ActiveDirectorySite Site { get; private set; }
|
||||
internal static List<string> _ForestServers { get; set; }
|
||||
private static bool _SearchEntireForest { get; set; }
|
||||
private static bool _Initialized = false;
|
||||
private static object _InitializeLock = new object();
|
||||
|
||||
#region Initialization
|
||||
|
||||
public static void Initialize(DiscoDataContext Database)
|
||||
{
|
||||
if (!_Initialized)
|
||||
{
|
||||
lock (_InitializeLock)
|
||||
{
|
||||
if (!_Initialized)
|
||||
{
|
||||
_SearchEntireForest = Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest ?? true; // Default True
|
||||
|
||||
using (var computerDomain = Domain.GetComputerDomain())
|
||||
{
|
||||
PrimaryDomain = GetDomainInternal(computerDomain, Database);
|
||||
|
||||
Domains = computerDomain.Forest.Domains.Cast<Domain>().Select(d =>
|
||||
{
|
||||
if (d.Name == PrimaryDomain.DnsName)
|
||||
return PrimaryDomain;
|
||||
else
|
||||
return GetDomainInternal(d, Database);
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
Site = ActiveDirectorySite.GetComputerSite();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ActiveDirectoryDomain GetDomainInternal(Domain d, DiscoDataContext Database)
|
||||
{
|
||||
string ldapPath = string.Format("LDAP://{0}/", d.Name);
|
||||
string defaultNamingContext;
|
||||
string configurationNamingContext;
|
||||
string netBiosName;
|
||||
|
||||
using (var adRootDSE = new DirectoryEntry(ldapPath + "RootDSE"))
|
||||
{
|
||||
defaultNamingContext = adRootDSE.Properties["defaultNamingContext"][0].ToString();
|
||||
configurationNamingContext = adRootDSE.Properties["configurationNamingContext"][0].ToString();
|
||||
}
|
||||
|
||||
using (var configSearchRoot = new DirectoryEntry(ldapPath + "CN=Partitions," + configurationNamingContext))
|
||||
{
|
||||
var configSearchFilter = string.Format("(&(objectcategory=Crossref)(dnsRoot={0})(netBIOSName=*))", d.Name);
|
||||
var configSearchLoadProperites = new string[] { "NetBIOSName" };
|
||||
|
||||
using (var configSearcher = new DirectorySearcher(configSearchRoot, configSearchFilter, configSearchLoadProperites, System.DirectoryServices.SearchScope.OneLevel))
|
||||
{
|
||||
SearchResult configResult = configSearcher.FindOne();
|
||||
|
||||
if (configResult != null)
|
||||
netBiosName = configResult.Properties["NetBIOSName"][0].ToString();
|
||||
else
|
||||
netBiosName = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Search Containers
|
||||
var searchContainersAll = Database.DiscoConfiguration.ActiveDirectory.SearchContainers;
|
||||
List<string> searchContainers = null;
|
||||
|
||||
if (searchContainersAll == null || searchContainersAll.Count == 0 || !searchContainersAll.TryGetValue(d.Name.ToLower(), out searchContainers))
|
||||
searchContainers = new List<string>() { defaultNamingContext }; // No search constraints set - search entire tree
|
||||
|
||||
return new ActiveDirectoryDomain(d.Name, netBiosName, defaultNamingContext, searchContainers);
|
||||
}
|
||||
|
||||
public static void UpdateSearchContainers(DiscoDataContext Database, IEnumerable<string> Containers)
|
||||
{
|
||||
Dictionary<string, List<string>> searchContainers = null;
|
||||
|
||||
if (Containers != null)
|
||||
{
|
||||
searchContainers = Containers
|
||||
.Where(c => !string.IsNullOrWhiteSpace(c))
|
||||
.Distinct()
|
||||
.Select(c =>
|
||||
{
|
||||
ActiveDirectoryDomain d;
|
||||
if (TryGetDomainByDistinguishedName(c, out d))
|
||||
return Tuple.Create(d, c);
|
||||
else
|
||||
return null;
|
||||
}).Where(i => i != null)
|
||||
.GroupBy(i => i.Item1)
|
||||
.ToDictionary(g => g.Key.DnsName.ToLower(), g => g.Select(i => i.Item2).ToList());
|
||||
}
|
||||
|
||||
if (searchContainers == null || searchContainers.Count == 0)
|
||||
{
|
||||
Database.DiscoConfiguration.ActiveDirectory.SearchContainers = null;
|
||||
|
||||
// No search constraints set - search entire tree
|
||||
Domains.ForEach(d => d.UpdateSearchContainers(new string[] { d.DistinguishedName }));
|
||||
}
|
||||
else
|
||||
{
|
||||
Database.DiscoConfiguration.ActiveDirectory.SearchContainers = searchContainers;
|
||||
|
||||
Domains.ForEach(d =>
|
||||
{
|
||||
List<string> domainContainers;
|
||||
if (searchContainers.TryGetValue(d.DnsName.ToLower(), out domainContainers))
|
||||
d.UpdateSearchContainers(domainContainers);
|
||||
else
|
||||
d.UpdateSearchContainers(Enumerable.Empty<string>());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static bool UpdateSearchEntireForest(DiscoDataContext Database, bool SearchEntireForest)
|
||||
{
|
||||
if (SearchEntireForest == false)
|
||||
{
|
||||
Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest = false;
|
||||
ADInterop._SearchEntireForest = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
var forestServers = LoadForestServers();
|
||||
if (forestServers.Count <= ActiveDirectory.MaxForestServerSearch)
|
||||
{
|
||||
Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest = true;
|
||||
ADInterop._SearchEntireForest = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest = false;
|
||||
ADInterop._SearchEntireForest = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Domain Getters
|
||||
|
||||
public static bool TryGetDomainByDistinguishedName(string DistinguishedName, out ActiveDirectoryDomain Domain)
|
||||
{
|
||||
// Find closest match
|
||||
Domain = ADInterop.Domains.Where(d => DistinguishedName.EndsWith(d.DistinguishedName, StringComparison.InvariantCultureIgnoreCase))
|
||||
.OrderByDescending(d => d.DistinguishedName.Length).FirstOrDefault();
|
||||
|
||||
return (Domain != null);
|
||||
}
|
||||
public static ActiveDirectoryDomain GetDomainByDistinguishedName(string DistinguishedName)
|
||||
{
|
||||
ActiveDirectoryDomain domain;
|
||||
if (!TryGetDomainByDistinguishedName(DistinguishedName, out domain))
|
||||
throw new ArgumentException(string.Format("The domain is unknown distinguished name: [{0}]", DistinguishedName), "Id");
|
||||
return domain;
|
||||
}
|
||||
|
||||
public static bool TryGetDomainByNetBiosName(string NetBiosName, out ActiveDirectoryDomain Domain)
|
||||
{
|
||||
Domain = ADInterop.Domains.FirstOrDefault(d => d.NetBiosName.Equals(NetBiosName, StringComparison.InvariantCultureIgnoreCase));
|
||||
return (Domain != null);
|
||||
}
|
||||
public static ActiveDirectoryDomain GetDomainByNetBiosName(string NetBiosName)
|
||||
{
|
||||
ActiveDirectoryDomain domain;
|
||||
if (!TryGetDomainByNetBiosName(NetBiosName, out domain))
|
||||
throw new ArgumentException(string.Format("The specified domain is unknown [{0}]", NetBiosName), "Id");
|
||||
return domain;
|
||||
}
|
||||
|
||||
public static bool TryGetDomainByDnsName(string DnsName, out ActiveDirectoryDomain Domain)
|
||||
{
|
||||
Domain = ADInterop.Domains.FirstOrDefault(d => d.DnsName.Equals(DnsName, StringComparison.InvariantCultureIgnoreCase));
|
||||
return (Domain != null);
|
||||
}
|
||||
public static ActiveDirectoryDomain GetDomainByDnsName(string DnsName)
|
||||
{
|
||||
ActiveDirectoryDomain domain;
|
||||
if (!TryGetDomainByDnsName(DnsName, out domain))
|
||||
throw new ArgumentException(string.Format("The specified domain is unknown [{0}]", DnsName), "Id");
|
||||
return domain;
|
||||
}
|
||||
|
||||
public static bool TryGetDomainFromId(string Id, out ActiveDirectoryDomain Domain)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Id))
|
||||
throw new ArgumentNullException("Id");
|
||||
|
||||
var idSplit = UserExtensions.SplitUserId(Id);
|
||||
|
||||
if (idSplit.Item1 == null)
|
||||
throw new ArgumentException(string.Format("The Id must include the Domain [{0}]", Id), "Id");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(idSplit.Item1))
|
||||
throw new ArgumentException(string.Format("The Id Domain was empty [{0}]", Id), "Id");
|
||||
if (string.IsNullOrWhiteSpace(idSplit.Item2))
|
||||
throw new ArgumentException(string.Format("The Id Name was empty [{0}]", Id), "Id");
|
||||
|
||||
return TryGetDomainByNetBiosName(idSplit.Item1, out Domain);
|
||||
}
|
||||
public static ActiveDirectoryDomain GetDomainFromId(string Id)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Id))
|
||||
throw new ArgumentNullException("Id");
|
||||
|
||||
var idSplit = UserExtensions.SplitUserId(Id);
|
||||
|
||||
if (idSplit.Item1 == null)
|
||||
throw new ArgumentException(string.Format("The Id must include the Domain [{0}]", Id), "Id");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(idSplit.Item1))
|
||||
throw new ArgumentException(string.Format("The Id Domain was empty [{0}]", Id), "Id");
|
||||
if (string.IsNullOrWhiteSpace(idSplit.Item2))
|
||||
throw new ArgumentException(string.Format("The Id Name was empty [{0}]", Id), "Id");
|
||||
|
||||
return GetDomainByNetBiosName(idSplit.Item1);
|
||||
}
|
||||
|
||||
public static List<string> LoadForestServers()
|
||||
{
|
||||
if (_ForestServers == null)
|
||||
{
|
||||
lock (_InitializeLock)
|
||||
{
|
||||
if (_ForestServers == null)
|
||||
{
|
||||
var status = ADDiscoverForestServers.ScheduleNow();
|
||||
status.CompletionTask.Wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
return _ForestServers;
|
||||
}
|
||||
public static Task<List<string>> LoadForestServersAsync()
|
||||
{
|
||||
if (_ForestServers != null)
|
||||
return Task.FromResult(_ForestServers);
|
||||
|
||||
lock (_InitializeLock)
|
||||
{
|
||||
if (_ForestServers != null)
|
||||
return Task.FromResult(_ForestServers);
|
||||
|
||||
// Invoke Scheduled Task
|
||||
var status = ADDiscoverForestServers.ScheduleNow();
|
||||
|
||||
return status.CompletionTask.ContinueWith(t =>
|
||||
{
|
||||
return ADInterop._ForestServers.ToList();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static bool SearchEntireForest
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_ForestServers != null && _ForestServers.Count > ActiveDirectory.MaxForestServerSearch)
|
||||
return false; // Never
|
||||
|
||||
return _SearchEntireForest;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Searching
|
||||
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(string LdapFilter, string[] LoadProperties)
|
||||
{
|
||||
return SearchAll(Domains, LdapFilter, LoadProperties);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(string LdapFilter, int ResultLimit, string[] LoadProperties)
|
||||
{
|
||||
return SearchAll(Domains, LdapFilter, ResultLimit, LoadProperties);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(IEnumerable<Tuple<ActiveDirectoryDomain, DomainController>> DomainsWithController, string LdapFilter, string[] LoadProperties)
|
||||
{
|
||||
return SearchAll(DomainsWithController, LdapFilter, null, LoadProperties);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(IEnumerable<ActiveDirectoryDomain> Domains, string LdapFilter, string[] LoadProperties)
|
||||
{
|
||||
return SearchAll(Domains, LdapFilter, null, LoadProperties);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(ActiveDirectoryDomain Domain, DomainController DomainController, string LdapFilter, string[] LoadProperties)
|
||||
{
|
||||
return SearchAll(Domain, DomainController, LdapFilter, null, LoadProperties);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(ActiveDirectoryDomain Domain, string LdapFilter, string[] LoadProperties)
|
||||
{
|
||||
return SearchAll(Domain, LdapFilter, null, LoadProperties);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(IEnumerable<ActiveDirectoryDomain> Domains, string LdapFilter, int? ResultLimit, string[] LoadProperties)
|
||||
{
|
||||
if (Domains == null || Domains.Count() == 0)
|
||||
return Enumerable.Empty<ActiveDirectorySearchResult>();
|
||||
|
||||
var queries = Domains.Select(d => Tuple.Create(d, (DomainController)null)).ToList();
|
||||
|
||||
return SearchAll(queries, LdapFilter, ResultLimit, LoadProperties);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(IEnumerable<Tuple<ActiveDirectoryDomain, DomainController>> DomainsWithController, string LdapFilter, int? ResultLimit, string[] LoadProperties)
|
||||
{
|
||||
var queries = DomainsWithController.ToList();
|
||||
|
||||
IEnumerable<ActiveDirectorySearchResult> results;
|
||||
|
||||
switch (queries.Count)
|
||||
{
|
||||
case 0:
|
||||
results = Enumerable.Empty<ActiveDirectorySearchResult>();
|
||||
break;
|
||||
case 1:
|
||||
var singleQuery = queries.First();
|
||||
results = SearchDomain(singleQuery.Item1, singleQuery.Item2, null, LdapFilter, ResultLimit, LoadProperties);
|
||||
break;
|
||||
default:
|
||||
var taskFactory = new TaskFactory<IEnumerable<ActiveDirectorySearchResult>>();
|
||||
var tasks = queries
|
||||
.Select(query =>
|
||||
taskFactory.StartNew(() =>
|
||||
SearchDomain(query.Item1, query.Item2, null, LdapFilter, ResultLimit, LoadProperties))
|
||||
).ToArray();
|
||||
Task.WaitAll(tasks);
|
||||
results = tasks.SelectMany(t => t.Result);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ResultLimit.HasValue)
|
||||
results = results.Take(ResultLimit.Value);
|
||||
|
||||
return results.ToList();
|
||||
}
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(ActiveDirectoryDomain Domain, string LdapFilter, int? ResultLimit, string[] LoadProperties)
|
||||
{
|
||||
return SearchAll(Domain, null, LdapFilter, ResultLimit, LoadProperties);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(ActiveDirectoryDomain Domain, DomainController DomainController, string LdapFilter, int? ResultLimit, string[] LoadProperties)
|
||||
{
|
||||
return SearchDomain(Domain, DomainController, null, LdapFilter, ResultLimit, LoadProperties);
|
||||
}
|
||||
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(string LdapFilter, string[] LoadProperties)
|
||||
{
|
||||
return SearchScope(Domains, LdapFilter, LoadProperties);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(string LdapFilter, int ResultLimit, string[] LoadProperties)
|
||||
{
|
||||
return SearchScope(Domains, LdapFilter, ResultLimit, LoadProperties);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(IEnumerable<ActiveDirectoryDomain> Domains, string LdapFilter, string[] LoadProperties)
|
||||
{
|
||||
return SearchScope(Domains, LdapFilter, null, LoadProperties);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(IEnumerable<Tuple<ActiveDirectoryDomain, DomainController>> DomainsWithController, string LdapFilter, string[] LoadProperties)
|
||||
{
|
||||
return SearchScope(DomainsWithController, LdapFilter, null, LoadProperties);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(ActiveDirectoryDomain Domain, string LdapFilter, string[] LoadProperties)
|
||||
{
|
||||
return SearchScope(Domain, LdapFilter, null, LoadProperties);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(ActiveDirectoryDomain Domain, DomainController DomainController, string LdapFilter, string[] LoadProperties)
|
||||
{
|
||||
return SearchScope(Domain, DomainController, LdapFilter, null, LoadProperties);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(IEnumerable<ActiveDirectoryDomain> Domains, string LdapFilter, int? ResultLimit, string[] LoadProperties)
|
||||
{
|
||||
return SearchScope(Domains.Select(d => Tuple.Create(d, (DomainController)null)), LdapFilter, ResultLimit, LoadProperties);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(ActiveDirectoryDomain Domain, string LdapFilter, int? ResultLimit, string[] LoadProperties)
|
||||
{
|
||||
return SearchScope(Domain, null, LdapFilter, ResultLimit, LoadProperties);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(ActiveDirectoryDomain Domain, DomainController DomainController, string LdapFilter, int? ResultLimit, string[] LoadProperties)
|
||||
{
|
||||
if (Domain.SearchContainers == null || Domain.SearchContainers.Count == 0)
|
||||
return Enumerable.Empty<ActiveDirectorySearchResult>();
|
||||
|
||||
var query = new List<Tuple<ActiveDirectoryDomain, DomainController>>() {
|
||||
Tuple.Create(Domain, DomainController)
|
||||
};
|
||||
|
||||
return SearchScope(query, LdapFilter, ResultLimit, LoadProperties);
|
||||
}
|
||||
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(IEnumerable<Tuple<ActiveDirectoryDomain, DomainController>> DomainsWithController, string LdapFilter, int? ResultLimit, string[] LoadProperties)
|
||||
{
|
||||
var queries = DomainsWithController.SelectMany(d => d.Item1.SearchContainers, (d, sc) => Tuple.Create(d.Item1, d.Item2, sc)).ToList();
|
||||
|
||||
IEnumerable<ActiveDirectorySearchResult> results;
|
||||
|
||||
switch (queries.Count)
|
||||
{
|
||||
case 0:
|
||||
results = Enumerable.Empty<ActiveDirectorySearchResult>();
|
||||
break;
|
||||
case 1:
|
||||
var singleQuery = queries.First();
|
||||
results = SearchDomain(singleQuery.Item1, singleQuery.Item2, singleQuery.Item3, LdapFilter, ResultLimit, LoadProperties);
|
||||
break;
|
||||
default:
|
||||
var taskFactory = new TaskFactory<IEnumerable<ActiveDirectorySearchResult>>();
|
||||
var tasks = queries
|
||||
.Select(query =>
|
||||
taskFactory.StartNew(() =>
|
||||
SearchDomain(query.Item1, query.Item2, query.Item3, LdapFilter, ResultLimit, LoadProperties).ToList())
|
||||
).ToArray();
|
||||
Task.WaitAll(tasks);
|
||||
results = tasks.SelectMany(t => t.Result);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ResultLimit.HasValue)
|
||||
results = results.Take(ResultLimit.Value);
|
||||
|
||||
return results.ToList();
|
||||
}
|
||||
|
||||
private static IEnumerable<ActiveDirectorySearchResult> SearchDomain(ActiveDirectoryDomain Domain, DomainController DomainController, string SearchRoot, string LdapFilter, int? ResultLimit, string[] LoadProperties)
|
||||
{
|
||||
string ldapServer;
|
||||
if (DomainController != null)
|
||||
{
|
||||
ldapServer = DomainController.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
var domainDC = Site.RetrieveReachableDomainControllers(Domain).FirstOrDefault();
|
||||
if (domainDC != null)
|
||||
ldapServer = domainDC.Name;
|
||||
else
|
||||
ldapServer = Domain.DnsName;
|
||||
}
|
||||
string searchRoot = SearchRoot ?? Domain.DistinguishedName;
|
||||
string ldapPath = string.Format(@"LDAP://{0}/{1}", ldapServer, searchRoot);
|
||||
|
||||
using (DirectoryEntry rootEntry = new DirectoryEntry(ldapPath))
|
||||
{
|
||||
using (DirectorySearcher searcher = new DirectorySearcher(rootEntry, LdapFilter, LoadProperties, System.DirectoryServices.SearchScope.Subtree))
|
||||
{
|
||||
searcher.PageSize = 500;
|
||||
|
||||
if (ResultLimit.HasValue)
|
||||
searcher.SizeLimit = ResultLimit.Value;
|
||||
return searcher.FindAll().Cast<SearchResult>().Select(result => new ActiveDirectorySearchResult()
|
||||
{
|
||||
Domain = Domain,
|
||||
SearchRoot = searchRoot,
|
||||
Result = result,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public static string OfflineDomainJoinProvision(ActiveDirectoryDomain Domain, DomainController DomainController, string ComputerSamAccountName, string OrganisationalUnit, out string DiagnosticInformation)
|
||||
{
|
||||
StringBuilder diagnosticInfo = new StringBuilder();
|
||||
string DJoinResult = null;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(ComputerSamAccountName))
|
||||
ComputerSamAccountName = ComputerSamAccountName.TrimEnd('$');
|
||||
if (string.IsNullOrWhiteSpace(ComputerSamAccountName) || ComputerSamAccountName.Length > 24)
|
||||
throw new System.ArgumentException("Invalid Computer Name; > 0 and <= 24", "ComputerName");
|
||||
|
||||
// Ensure Specified OU Exists
|
||||
if (!string.IsNullOrEmpty(OrganisationalUnit))
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var deOU = DomainController.RetrieveDirectoryEntry(OrganisationalUnit))
|
||||
{
|
||||
if (deOU == null)
|
||||
throw new Exception(string.Format("OU's Directory Entry couldn't be found at [{0}]", OrganisationalUnit));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ArgumentException(string.Format("An error occurred while trying to locate the specified OU: {0}", OrganisationalUnit), "OrganisationalUnit", ex);
|
||||
}
|
||||
}
|
||||
|
||||
string tempFileName = System.IO.Path.GetTempFileName();
|
||||
string argumentOU = (!string.IsNullOrWhiteSpace(OrganisationalUnit)) ? string.Format(" /MACHINEOU \"{0}\"", OrganisationalUnit) : string.Empty;
|
||||
string arguments = string.Format("/PROVISION /DOMAIN \"{0}\" /DCNAME \"{1}\" /MACHINE \"{2}\"{3} /REUSE /SAVEFILE \"{4}\"",
|
||||
Domain.DnsName,
|
||||
DomainController.Name,
|
||||
ComputerSamAccountName,
|
||||
argumentOU,
|
||||
tempFileName
|
||||
);
|
||||
ProcessStartInfo commandStarter = new ProcessStartInfo("DJOIN.EXE", arguments)
|
||||
{
|
||||
CreateNoWindow = true,
|
||||
ErrorDialog = false,
|
||||
LoadUserProfile = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false
|
||||
};
|
||||
diagnosticInfo.AppendFormat("{0} {1}", "DJOIN.EXE", arguments);
|
||||
diagnosticInfo.AppendLine();
|
||||
|
||||
string stdOutput;
|
||||
string stdError;
|
||||
using (Process commandProc = Process.Start(commandStarter))
|
||||
{
|
||||
commandProc.WaitForExit(20000);
|
||||
stdOutput = commandProc.StandardOutput.ReadToEnd();
|
||||
stdError = commandProc.StandardError.ReadToEnd();
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(stdOutput))
|
||||
diagnosticInfo.AppendLine(stdOutput);
|
||||
if (!string.IsNullOrWhiteSpace(stdError))
|
||||
diagnosticInfo.AppendLine(stdError);
|
||||
|
||||
if (System.IO.File.Exists(tempFileName))
|
||||
{
|
||||
DJoinResult = System.Convert.ToBase64String(System.IO.File.ReadAllBytes(tempFileName));
|
||||
System.IO.File.Delete(tempFileName);
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(DJoinResult))
|
||||
throw new System.InvalidOperationException(string.Format("Domain Join Unsuccessful{0}Error: {1}{0}Output: {2}", System.Environment.NewLine, stdError, stdOutput));
|
||||
|
||||
DiagnosticInformation = diagnosticInfo.ToString();
|
||||
|
||||
return DJoinResult;
|
||||
}
|
||||
|
||||
public static DirectoryEntry RetrieveDirectoryEntry(string DistinguishedName, out ActiveDirectoryDomain Domain)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(DistinguishedName))
|
||||
throw new ArgumentNullException("DistinguishedName");
|
||||
|
||||
// Find Domain
|
||||
var domain = GetDomainByDistinguishedName(DistinguishedName);
|
||||
|
||||
if (domain == null)
|
||||
throw new ArgumentException(string.Format("Unknown domain for DistinguishedName: {0}", DistinguishedName), "DistinguishedName");
|
||||
|
||||
var domainDC = Site.RetrieveReachableDomainControllers(domain).FirstOrDefault();
|
||||
var ldapServer = domainDC != null ? domainDC.Name : domain.DnsName;
|
||||
|
||||
Domain = domain;
|
||||
|
||||
return new DirectoryEntry(string.Format(@"LDAP://{0}/{1}", ldapServer, DistinguishedName));
|
||||
}
|
||||
|
||||
public static DomainController RetrieveWritableDomainController(this ActiveDirectoryDomain domain)
|
||||
{
|
||||
var adContext = new DirectoryContext(DirectoryContextType.Domain, domain.DnsName);
|
||||
using (var adDomain = Domain.GetDomain(adContext))
|
||||
{
|
||||
return adDomain.FindDomainController(LocatorOptions.WriteableRequired);
|
||||
}
|
||||
}
|
||||
|
||||
public static DirectoryEntry RetrieveDirectoryEntry(this DomainController domainController, string DistinguishedName)
|
||||
{
|
||||
return new DirectoryEntry(string.Format(@"LDAP://{0}/{1}", domainController.Name, DistinguishedName));
|
||||
}
|
||||
|
||||
public static void DeleteObjectRecursive(this DirectoryEntry directoryEntry)
|
||||
{
|
||||
DeleteObjectRecursiveInternal(directoryEntry);
|
||||
|
||||
using (var deParent = directoryEntry.Parent)
|
||||
{
|
||||
deParent.Children.Remove(directoryEntry);
|
||||
}
|
||||
}
|
||||
private static void DeleteObjectRecursiveInternal(DirectoryEntry directoryEntry)
|
||||
{
|
||||
List<DirectoryEntry> children = directoryEntry.Children.Cast<DirectoryEntry>().ToList();
|
||||
|
||||
foreach (var child in children)
|
||||
{
|
||||
DeleteObjectRecursive(child);
|
||||
directoryEntry.Children.Remove(child);
|
||||
child.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
internal static string ConvertBytesToSDDLString(byte[] SID)
|
||||
{
|
||||
SecurityIdentifier sID = new SecurityIdentifier(SID, 0);
|
||||
|
||||
return sID.ToString();
|
||||
}
|
||||
|
||||
internal static byte[] ConvertSDDLStringToBytes(string SidSsdlString)
|
||||
{
|
||||
SecurityIdentifier sID = new SecurityIdentifier(SidSsdlString);
|
||||
|
||||
var sidBytes = new byte[sID.BinaryLength];
|
||||
|
||||
sID.GetBinaryForm(sidBytes, 0);
|
||||
|
||||
return sidBytes;
|
||||
}
|
||||
|
||||
internal static byte[] BuildPrimaryGroupSid(byte[] UserSID, int PrimaryGroupId)
|
||||
{
|
||||
var groupSid = (byte[])UserSID.Clone();
|
||||
|
||||
int ridOffset = groupSid.Length - 4;
|
||||
int groupId = PrimaryGroupId;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
groupSid[ridOffset + i] = (byte)(groupId & 0xFF);
|
||||
groupId >>= 8;
|
||||
}
|
||||
|
||||
return groupSid;
|
||||
}
|
||||
|
||||
internal static string ConvertBytesToBinarySidString(byte[] SID)
|
||||
{
|
||||
StringBuilder escapedSid = new StringBuilder();
|
||||
|
||||
foreach (var sidByte in SID)
|
||||
{
|
||||
escapedSid.Append('\\');
|
||||
escapedSid.Append(sidByte.ToString("x2"));
|
||||
}
|
||||
|
||||
return escapedSid.ToString();
|
||||
}
|
||||
|
||||
internal static string EscapeLdapQuery(string query)
|
||||
{
|
||||
return query.Replace("*", "\\2a").Replace("(", "\\28").Replace(")", "\\29").Replace("\\", "\\5c").Replace("NUL", "\\00").Replace("/", "\\2f");
|
||||
}
|
||||
internal static string FormatGuidForLdapQuery(System.Guid g)
|
||||
{
|
||||
checked
|
||||
{
|
||||
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
||||
byte[] array = g.ToByteArray();
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
byte b = array[i];
|
||||
sb.Append("\\");
|
||||
sb.Append(b.ToString("X2"));
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,231 +0,0 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Logging;
|
||||
using Disco.Services.Tasks;
|
||||
using Quartz;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.DirectoryServices.ActiveDirectory;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory.Internal
|
||||
{
|
||||
public class ADUpdateLastNetworkLogonDateJob : ScheduledTask
|
||||
{
|
||||
|
||||
public override string TaskName { get { return "Active Directory - Update Last Network Logon Dates Task"; } }
|
||||
public override bool SingleInstanceTask { get { return true; } }
|
||||
public override bool CancelInitiallySupported { get { return false; } }
|
||||
|
||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
||||
{
|
||||
// ActiveDirectoryUpdateLastNetworkLogonDateJob @ 11:30pm
|
||||
TriggerBuilder triggerBuilder = TriggerBuilder.Create().
|
||||
WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(23, 30));
|
||||
|
||||
this.ScheduleTask(triggerBuilder);
|
||||
}
|
||||
|
||||
protected override void ExecuteTask()
|
||||
{
|
||||
int changeCount;
|
||||
|
||||
this.Status.UpdateStatus(1, "Starting", "Connecting to the Database and initializing the environment");
|
||||
using (DiscoDataContext database = new DiscoDataContext())
|
||||
{
|
||||
UpdateLastNetworkLogonDates(database, this.Status);
|
||||
this.Status.UpdateStatus(95, "Updating Database", "Writing last network logon dates to the Database");
|
||||
changeCount = database.SaveChanges();
|
||||
this.Status.Finished(string.Format("{0} Device last network logon dates updated", changeCount), "/Config/SystemConfig");
|
||||
}
|
||||
|
||||
SystemLog.LogInformation(new string[]
|
||||
{
|
||||
"Updated LastNetworkLogon Device Property for Device/s",
|
||||
changeCount.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
public static ScheduledTaskStatus ScheduleImmediately()
|
||||
{
|
||||
var existingTask = ScheduledTasks.GetTaskStatuses(typeof(ADUpdateLastNetworkLogonDateJob)).Where(s => s.IsRunning).FirstOrDefault();
|
||||
if (existingTask != null)
|
||||
return existingTask;
|
||||
|
||||
var instance = new ADUpdateLastNetworkLogonDateJob();
|
||||
return instance.ScheduleTask();
|
||||
}
|
||||
|
||||
public static bool UpdateLastNetworkLogonDate(Device Device)
|
||||
{
|
||||
const string ldapFilterTemplate = "(&(objectCategory=Computer)(sAMAccountName={0}))";
|
||||
string[] ldapProperties = new string[] { "lastLogon", "lastLogonTimestamp" };
|
||||
|
||||
System.DateTime? lastLogon = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(Device.DeviceDomainId))
|
||||
{
|
||||
var deviceSamAccountName = UserExtensions.SplitUserId(Device.DeviceDomainId).Item2 + "$";
|
||||
var ldapFilter = string.Format(ldapFilterTemplate, ADInterop.EscapeLdapQuery(deviceSamAccountName));
|
||||
|
||||
var domain = ADInterop.GetDomainFromId(Device.DeviceDomainId);
|
||||
IEnumerable<DomainController> domainControllers;
|
||||
|
||||
if (ADInterop.SearchEntireForest)
|
||||
domainControllers = domain.RetrieveReachableDomainControllers();
|
||||
else
|
||||
domainControllers = ADInterop.Site.RetrieveReachableDomainControllers(domain);
|
||||
|
||||
lastLogon = domainControllers.Select(dc =>
|
||||
{
|
||||
using (var directoryRoot = dc.RetrieveDirectoryEntry(domain.DistinguishedName))
|
||||
{
|
||||
using (var directorySearcher = new DirectorySearcher(directoryRoot, ldapFilter, ldapProperties, SearchScope.Subtree))
|
||||
{
|
||||
var directoryResult = directorySearcher.FindOne();
|
||||
|
||||
if (directoryResult != null)
|
||||
{
|
||||
long lastLogonValue = default(long);
|
||||
long lastLogonTimestampValue = default(long);
|
||||
|
||||
var lastLogonProperty = directoryResult.Properties["lastLogon"];
|
||||
if (lastLogonProperty != null && lastLogonProperty.Count > 0)
|
||||
lastLogonValue = (long)lastLogonProperty[0];
|
||||
var lastLogonTimestampProperty = directoryResult.Properties["lastLogonTimestamp"];
|
||||
if (lastLogonTimestampProperty != null && lastLogonTimestampProperty.Count > 0)
|
||||
lastLogonTimestampValue = (long)lastLogonTimestampProperty[0];
|
||||
|
||||
long highedValue = Math.Max(lastLogonValue, lastLogonTimestampValue);
|
||||
|
||||
if (highedValue > 0)
|
||||
return (DateTime?)new DateTime((DateTime.FromFileTime(highedValue).Ticks / 10000000L) * 10000000L);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}).Where(dt => dt.HasValue).Max();
|
||||
}
|
||||
|
||||
if (lastLogon.HasValue &&
|
||||
(
|
||||
!Device.LastNetworkLogonDate.HasValue
|
||||
|| Device.LastNetworkLogonDate.Value < lastLogon
|
||||
))
|
||||
{
|
||||
Device.LastNetworkLogonDate = lastLogon;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void UpdateLastNetworkLogonDates(DiscoDataContext Database, ScheduledTaskStatus status)
|
||||
{
|
||||
const string ldapFilter = "(objectCategory=Computer)";
|
||||
string[] ldapProperties = new string[] { "sAMAccountName", "lastLogon" };
|
||||
|
||||
status.UpdateStatus(2, "Initializing", "Determining Domains and Available Domain Controllers");
|
||||
|
||||
// Determine Domain Controllers to Query
|
||||
IEnumerable<Tuple<ActiveDirectoryDomain, DomainController>> domainControllers;
|
||||
if (ADInterop.SearchEntireForest)
|
||||
domainControllers = ADInterop.Domains.SelectMany(d => d.RetrieveReachableDomainControllers(), (d, dc) => Tuple.Create(d, dc));
|
||||
else
|
||||
domainControllers = ADInterop.Domains.SelectMany(d => ADInterop.Site.RetrieveReachableDomainControllers(d), (d, dc) => Tuple.Create(d, dc));
|
||||
|
||||
// Determine Queries
|
||||
var requiredRueries = domainControllers
|
||||
.Where(s => s.Item1.SearchContainers != null && s.Item1.SearchContainers.Count > 0)
|
||||
.SelectMany(s => s.Item1.SearchContainers, (s, c) => Tuple.Create(s.Item1, s.Item2, c)).ToList();
|
||||
|
||||
var queries = Enumerable.Range(0, requiredRueries.Count).Select(i =>
|
||||
{
|
||||
var q = requiredRueries[i];
|
||||
return Tuple.Create(i, q.Item1, q.Item2, q.Item3);
|
||||
});
|
||||
|
||||
var queryResults = queries.SelectMany(q =>
|
||||
{
|
||||
var queryIndex = q.Item1;
|
||||
var domain = q.Item2;
|
||||
var domainController = q.Item3;
|
||||
var searchRoot = q.Item4;
|
||||
|
||||
// Update Status
|
||||
double progress = 5 + (queryIndex * (90 / requiredRueries.Count));
|
||||
status.UpdateStatus(progress, string.Format("Querying Domain [{0}] using controller [{1}]", domain.NetBiosName, domainController.Name), string.Format("Searching: {0}", searchRoot));
|
||||
|
||||
// Perform Query
|
||||
using (var directoryRoot = domainController.RetrieveDirectoryEntry(searchRoot))
|
||||
{
|
||||
using (var directorySearcher = new DirectorySearcher(directoryRoot, ldapFilter, ldapProperties, SearchScope.Subtree))
|
||||
{
|
||||
directorySearcher.PageSize = 500;
|
||||
|
||||
var directoryResults = directorySearcher.FindAll();
|
||||
|
||||
if (directoryResults != null)
|
||||
{
|
||||
return directoryResults.Cast<SearchResult>().Select(result =>
|
||||
{
|
||||
var samAccountProperity = result.Properties["sAMAccountName"];
|
||||
|
||||
|
||||
long lastLogonValue = default(long);
|
||||
long lastLogonTimestampValue = default(long);
|
||||
|
||||
var lastLogonProperty = result.Properties["lastLogon"];
|
||||
if (lastLogonProperty != null && lastLogonProperty.Count > 0)
|
||||
lastLogonValue = (long)lastLogonProperty[0];
|
||||
var lastLogonTimestampProperty = result.Properties["lastLogonTimestamp"];
|
||||
if (lastLogonTimestampProperty != null && lastLogonTimestampProperty.Count > 0)
|
||||
lastLogonTimestampValue = (long)lastLogonTimestampProperty[0];
|
||||
|
||||
long highedValue = Math.Max(lastLogonValue, lastLogonTimestampValue);
|
||||
|
||||
if (highedValue > 0)
|
||||
{
|
||||
var computerName = string.Format(@"{0}\{1}", domain.NetBiosName, samAccountProperity[0].ToString().TrimEnd('$'));
|
||||
var lastLogon = new DateTime((DateTime.FromFileTime(highedValue).Ticks / 10000000L) * 10000000L);
|
||||
return Tuple.Create(computerName, lastLogon);
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}).Where(i => i != null).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Enumerable.Empty<Tuple<string, DateTime>>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}).GroupBy(r => r.Item1, StringComparer.InvariantCultureIgnoreCase).ToDictionary(g => g.Key.ToUpper(), g => g.Max(i => i.Item2));
|
||||
|
||||
status.UpdateStatus(90, "Processing Results", "Processing last network logon dates and looking for updates");
|
||||
|
||||
foreach (Device device in Database.Devices.Where(device => device.DeviceDomainId != null))
|
||||
{
|
||||
DateTime lastLogonDate;
|
||||
if (queryResults.TryGetValue(device.DeviceDomainId.ToUpper(), out lastLogonDate))
|
||||
{
|
||||
if (!device.LastNetworkLogonDate.HasValue)
|
||||
device.LastNetworkLogonDate = lastLogonDate;
|
||||
else
|
||||
{
|
||||
// Change accuracy to the second
|
||||
lastLogonDate = new DateTime((lastLogonDate.Ticks / 10000000L) * 10000000L);
|
||||
|
||||
if (device.LastNetworkLogonDate.Value < lastLogonDate)
|
||||
device.LastNetworkLogonDate = lastLogonDate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -274,12 +274,12 @@ namespace Disco.Services
|
||||
Location = i,
|
||||
References = o.ToList()
|
||||
},
|
||||
StringComparer.InvariantCultureIgnoreCase);
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
public static IEnumerable<JobLocationReference> JobLocationReferences(this IEnumerable<JobTableStatusItemModel> Items)
|
||||
{
|
||||
return Items.Where(i => !string.IsNullOrWhiteSpace(i.DeviceHeldLocation) && i.DeviceHeld.HasValue && !i.DeviceReturnedDate.HasValue)
|
||||
.GroupBy(i => i.DeviceHeldLocation, StringComparer.InvariantCultureIgnoreCase)
|
||||
.GroupBy(i => i.DeviceHeldLocation, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(i => new JobLocationReference()
|
||||
{
|
||||
Location = i.Key,
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace Disco.Services.Logging
|
||||
var appDomain = AppDomain.CurrentDomain;
|
||||
|
||||
var logModuleTypes = (from a in appDomain.GetAssemblies()
|
||||
where !a.GlobalAssemblyCache && !a.IsDynamic && a.FullName.StartsWith("Disco.", StringComparison.InvariantCultureIgnoreCase)
|
||||
where !a.GlobalAssemblyCache && !a.IsDynamic && a.FullName.StartsWith("Disco.", StringComparison.OrdinalIgnoreCase)
|
||||
from type in a.GetTypes()
|
||||
where typeof(LogBase).IsAssignableFrom(type) && !type.IsAbstract
|
||||
select type);
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Disco.Services.Plugins.Features.WarrantyProvider
|
||||
public static PluginFeatureManifest FindPluginFeature(string PluginIdOrWarrantyProviderId)
|
||||
{
|
||||
var defs = Plugins.GetPluginFeatures(typeof(WarrantyProviderFeature));
|
||||
var def = defs.FirstOrDefault(d => d.PluginManifest.Id.Equals(PluginIdOrWarrantyProviderId, StringComparison.InvariantCultureIgnoreCase));
|
||||
var def = defs.FirstOrDefault(d => d.PluginManifest.Id.Equals(PluginIdOrWarrantyProviderId, StringComparison.OrdinalIgnoreCase));
|
||||
if (def != null)
|
||||
return def;
|
||||
else
|
||||
@@ -36,7 +36,7 @@ namespace Disco.Services.Plugins.Features.WarrantyProvider
|
||||
{
|
||||
using (var providerInstance = d.CreateInstance<WarrantyProviderFeature>())
|
||||
{
|
||||
if (providerInstance.WarrantyProviderId != null && providerInstance.WarrantyProviderId.Equals(PluginIdOrWarrantyProviderId, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (providerInstance.WarrantyProviderId != null && providerInstance.WarrantyProviderId.Equals(PluginIdOrWarrantyProviderId, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return d;
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace Disco.Services.Plugins
|
||||
|
||||
// Check for Compatibility
|
||||
var compatibilityData = Plugins.LoadCompatibilityData(database);
|
||||
var pluginCompatibility = compatibilityData.Plugins.FirstOrDefault(i => i.Id.Equals(packageManifest.Id, StringComparison.InvariantCultureIgnoreCase) && packageManifest.Version == Version.Parse(i.Version));
|
||||
var pluginCompatibility = compatibilityData.Plugins.FirstOrDefault(i => i.Id.Equals(packageManifest.Id, StringComparison.OrdinalIgnoreCase) && packageManifest.Version == Version.Parse(i.Version));
|
||||
if (pluginCompatibility != null && !pluginCompatibility.Compatible)
|
||||
throw new InvalidOperationException(string.Format("The plugin [{0} v{1}] is not compatible: {2}", packageManifest.Id, packageManifest.VersionFormatted, pluginCompatibility.Reason));
|
||||
|
||||
|
||||
@@ -240,7 +240,7 @@ namespace Disco.Services.Plugins
|
||||
|
||||
foreach (string referenceFilename in Directory.EnumerateFiles(pluginLocation, "*.dll", SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
if (!referenceFilename.Equals(assembly.Location, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!referenceFilename.Equals(assembly.Location, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Ignore Excluded Assemblies
|
||||
if (!PluginExcludedAssemblies.Contains(Path.GetFileNameWithoutExtension(referenceFilename)))
|
||||
|
||||
@@ -302,7 +302,7 @@ namespace Disco.Services.Plugins
|
||||
foreach (var serverItem in serverData.Plugins)
|
||||
{
|
||||
var serverItemVersion = Version.Parse(serverItem.Version);
|
||||
var localItem = localItems.FirstOrDefault(i => i.Id.Equals(serverItem.Id, StringComparison.InvariantCultureIgnoreCase) && serverItemVersion == localItemVersions[i]);
|
||||
var localItem = localItems.FirstOrDefault(i => i.Id.Equals(serverItem.Id, StringComparison.OrdinalIgnoreCase) && serverItemVersion == localItemVersions[i]);
|
||||
if (localItem != null)
|
||||
joinedItems.Remove(localItem);
|
||||
|
||||
@@ -373,7 +373,7 @@ namespace Disco.Services.Plugins
|
||||
if (pluginManifest != null)
|
||||
{
|
||||
// Check Version Compatibility
|
||||
var pluginCompatibility = compatibilityData.Value.Plugins.FirstOrDefault(i => i.Id.Equals(pluginManifest.Id, StringComparison.InvariantCultureIgnoreCase) && pluginManifest.Version == Version.Parse(i.Version));
|
||||
var pluginCompatibility = compatibilityData.Value.Plugins.FirstOrDefault(i => i.Id.Equals(pluginManifest.Id, StringComparison.OrdinalIgnoreCase) && pluginManifest.Version == Version.Parse(i.Version));
|
||||
if (pluginCompatibility != null && !pluginCompatibility.Compatible)
|
||||
throw new InvalidOperationException(string.Format("The plugin [{0} v{1}] is not compatible: {2}", pluginManifest.Id, pluginManifest.VersionFormatted, pluginCompatibility.Reason));
|
||||
|
||||
@@ -496,7 +496,7 @@ namespace Disco.Services.Plugins
|
||||
// Check Compatibility
|
||||
if (CompatibilityData == null)
|
||||
CompatibilityData = LoadCompatibilityData(Database);
|
||||
var pluginCompatibility = CompatibilityData.Plugins.FirstOrDefault(i => i.Id.Equals(packageManifest.Id, StringComparison.InvariantCultureIgnoreCase) && packageManifest.Version == Version.Parse(i.Version));
|
||||
var pluginCompatibility = CompatibilityData.Plugins.FirstOrDefault(i => i.Id.Equals(packageManifest.Id, StringComparison.OrdinalIgnoreCase) && packageManifest.Version == Version.Parse(i.Version));
|
||||
if (pluginCompatibility != null && !pluginCompatibility.Compatible)
|
||||
throw new InvalidOperationException(string.Format("The plugin [{0} v{1}] is not compatible: {2}", packageManifest.Id, packageManifest.VersionFormatted, pluginCompatibility.Reason));
|
||||
|
||||
@@ -595,7 +595,7 @@ namespace Disco.Services.Plugins
|
||||
|
||||
public static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
|
||||
{
|
||||
if (args.RequestingAssembly != null && args.RequestingAssembly.Location.StartsWith(PluginPath, StringComparison.InvariantCultureIgnoreCase) && _PluginManifests != null)
|
||||
if (args.RequestingAssembly != null && args.RequestingAssembly.Location.StartsWith(PluginPath, StringComparison.OrdinalIgnoreCase) && _PluginManifests != null)
|
||||
{
|
||||
// Try best guess first
|
||||
PluginManifest requestingPlugin = _PluginManifests.Values.Where(p => p.Type.Assembly == args.RequestingAssembly).FirstOrDefault();
|
||||
|
||||
@@ -235,7 +235,7 @@ namespace Disco.Services.Plugins
|
||||
{
|
||||
// Check for Compatibility
|
||||
var compatibilityData = Plugins.LoadCompatibilityData(database);
|
||||
var pluginCompatibility = compatibilityData.Plugins.FirstOrDefault(i => i.Id.Equals(updateManifest.Id, StringComparison.InvariantCultureIgnoreCase) && updateManifest.Version == Version.Parse(i.Version));
|
||||
var pluginCompatibility = compatibilityData.Plugins.FirstOrDefault(i => i.Id.Equals(updateManifest.Id, StringComparison.OrdinalIgnoreCase) && updateManifest.Version == Version.Parse(i.Version));
|
||||
if (pluginCompatibility != null && !pluginCompatibility.Compatible)
|
||||
throw new InvalidOperationException(string.Format("The plugin [{0} v{1}] is not compatible: {2}", updateManifest.Id, updateManifest.VersionFormatted, pluginCompatibility.Reason));
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Models.Services.Jobs.JobLists;
|
||||
using Disco.Models.Services.Searching;
|
||||
@@ -171,7 +170,7 @@ namespace Disco.Services.Searching
|
||||
|
||||
public static List<User> SearchUsersUpstream(string Term, int? LimitCount = null)
|
||||
{
|
||||
IEnumerable<ActiveDirectoryUserAccount> matches = ActiveDirectory.SearchUserAccounts(Term, Quick: true);
|
||||
IEnumerable<ADUserAccount> matches = ActiveDirectory.SearchADUserAccounts(Term, Quick: true);
|
||||
|
||||
if (LimitCount.HasValue)
|
||||
matches = matches.Take(LimitCount.Value);
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Disco.Services
|
||||
{
|
||||
public static bool IsInPrimaryDomain(this User u)
|
||||
{
|
||||
return u.Domain.Equals(Disco.Services.Interop.ActiveDirectory.ActiveDirectory.PrimaryDomain.NetBiosName, StringComparison.InvariantCultureIgnoreCase);
|
||||
return u.Domain.Equals(ActiveDirectory.Context.PrimaryDomain.NetBiosName, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public static string FriendlyId(this User u)
|
||||
@@ -23,8 +23,8 @@ namespace Disco.Services
|
||||
public static string FriendlyUserId(string UserId)
|
||||
{
|
||||
var splitUserId = SplitUserId(UserId);
|
||||
|
||||
if (splitUserId.Item1 != null && splitUserId.Item1.Equals(ActiveDirectory.PrimaryDomain.NetBiosName, StringComparison.InvariantCultureIgnoreCase))
|
||||
|
||||
if (splitUserId.Item1 != null && splitUserId.Item1.Equals(ActiveDirectory.Context.PrimaryDomain.NetBiosName, StringComparison.OrdinalIgnoreCase))
|
||||
return splitUserId.Item2;
|
||||
else
|
||||
return UserId;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Authorization.Roles;
|
||||
@@ -206,9 +205,9 @@ namespace Disco.Services.Users
|
||||
Cache.FlushCache();
|
||||
}
|
||||
|
||||
internal static IEnumerable<ActiveDirectoryUserAccount> SearchUsers(DiscoDataContext Database, string Term)
|
||||
internal static IEnumerable<ADUserAccount> SearchUsers(DiscoDataContext Database, string Term)
|
||||
{
|
||||
var adImportedUsers = ActiveDirectory.SearchUserAccounts(Term, Quick: true);
|
||||
var adImportedUsers = ActiveDirectory.SearchADUserAccounts(Term, Quick: true);
|
||||
foreach (var adU in adImportedUsers.Select(adU => adU.ToRepositoryUser()))
|
||||
{
|
||||
var existingUser = Database.Users.Find(adU.UserId);
|
||||
@@ -230,7 +229,7 @@ namespace Disco.Services.Users
|
||||
if (UserId.EndsWith("$"))
|
||||
{
|
||||
// Machine Account
|
||||
var adAccount = ActiveDirectory.RetrieveMachineAccount(UserId);
|
||||
var adAccount = ActiveDirectory.RetrieveADMachineAccount(UserId);
|
||||
|
||||
if (adAccount == null)
|
||||
return null;
|
||||
@@ -244,10 +243,10 @@ namespace Disco.Services.Users
|
||||
{
|
||||
// User Account
|
||||
|
||||
ActiveDirectoryUserAccount adAccount;
|
||||
ADUserAccount adAccount;
|
||||
try
|
||||
{
|
||||
adAccount = ActiveDirectory.RetrieveUserAccount(UserId);
|
||||
adAccount = ActiveDirectory.RetrieveADUserAccount(UserId);
|
||||
|
||||
if (adAccount == null)
|
||||
throw new ArgumentException(string.Format("Invalid Username: '{0}'; User not found in Active Directory", UserId), "Username");
|
||||
@@ -280,7 +279,7 @@ namespace Disco.Services.Users
|
||||
}
|
||||
Database.SaveChanges();
|
||||
|
||||
var token = AuthorizationToken.BuildToken(user, adAccount.Groups);
|
||||
var token = AuthorizationToken.BuildToken(user, adAccount.Groups.Select(g => g.Id));
|
||||
|
||||
return new Tuple<User, AuthorizationToken>(user, token);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Authorization.Roles;
|
||||
@@ -16,7 +15,6 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
[DiscoAuthorize(Claims.DiscoAdminAccount)]
|
||||
public partial class AuthorizationRoleController : AuthorizedDatabaseController
|
||||
{
|
||||
|
||||
#region Properties
|
||||
|
||||
const string pName = "name";
|
||||
@@ -111,14 +109,15 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
var subjects = Subjects
|
||||
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||
.Select(s => s.Trim())
|
||||
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveObject(s, Quick: true)))
|
||||
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveADObject(s, Quick: true)))
|
||||
.Where(s => s.Item2 is ADUserAccount || s.Item2 is ADGroup)
|
||||
.ToList();
|
||||
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
|
||||
|
||||
if (invalidSubjects.Count > 0)
|
||||
throw new ArgumentException(string.Format("Subjects not found: {0}", string.Join(", ", invalidSubjects)), "Subjects");
|
||||
|
||||
var proposedSubjects = subjects.Select(s => s.Item2.NetBiosId).OrderBy(s => s).ToArray();
|
||||
var proposedSubjects = subjects.Select(s => s.Item2.Id).OrderBy(s => s).ToArray();
|
||||
var currentSubjects = AuthorizationRole.SubjectIds == null ? new string[0] : AuthorizationRole.SubjectIds.Split(',');
|
||||
removedSubjects = currentSubjects.Except(proposedSubjects).ToArray();
|
||||
addedSubjects = proposedSubjects.Except(currentSubjects).ToArray();
|
||||
@@ -249,14 +248,15 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
var subjects = Subjects
|
||||
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||
.Select(s => s.Trim())
|
||||
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveObject(s, Quick: true)))
|
||||
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveADObject(s, Quick: true)))
|
||||
.Where(s => s.Item2 is ADUserAccount || s.Item2 is ADGroup)
|
||||
.ToList();
|
||||
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
|
||||
|
||||
if (invalidSubjects.Count > 0)
|
||||
throw new ArgumentException(string.Format("Subjects not found: {0}", string.Join(", ", invalidSubjects)), "Subjects");
|
||||
|
||||
proposedSubjects = subjects.Select(s => s.Item2.NetBiosId).OrderBy(s => s).ToArray();
|
||||
proposedSubjects = subjects.Select(s => s.Item2.Id).OrderBy(s => s).ToArray();
|
||||
var currentSubjects = UserService.AdministratorSubjectIds;
|
||||
removedSubjects = currentSubjects.Except(proposedSubjects).ToArray();
|
||||
addedSubjects = proposedSubjects.Except(currentSubjects).ToArray();
|
||||
@@ -275,31 +275,5 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public virtual ActionResult SearchSubjects(string term)
|
||||
{
|
||||
var groupResults = ActiveDirectory.SearchGroups(term).Cast<IActiveDirectoryObject>();
|
||||
var userResults = ActiveDirectory.SearchUserAccounts(term).Cast<IActiveDirectoryObject>();
|
||||
|
||||
var results = groupResults.Concat(userResults).OrderBy(r => r.SamAccountName)
|
||||
.Select(r => Models.AuthorizationRole.SubjectItem.FromActiveDirectoryObject(r)).ToList();
|
||||
|
||||
return Json(results, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
public virtual ActionResult Subject(string Id)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Id))
|
||||
return Json(null, JsonRequestBehavior.AllowGet);
|
||||
else if (!Id.Contains(@"\"))
|
||||
Id = string.Format(@"{0}\{1}", ActiveDirectory.PrimaryDomain.NetBiosName, Id);
|
||||
|
||||
var subject = ActiveDirectory.RetrieveObject(Id, Quick: true);
|
||||
|
||||
if (subject == null || !(subject is ActiveDirectoryUserAccount || subject is ActiveDirectoryGroup))
|
||||
return Json(null, JsonRequestBehavior.AllowGet);
|
||||
else
|
||||
return Json(Models.AuthorizationRole.SubjectItem.FromActiveDirectoryObject(subject), JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
// Update AD Account
|
||||
if (!string.IsNullOrEmpty(device.DeviceDomainId) && device.DeviceDomainId.Length <= 24)
|
||||
{
|
||||
var adMachineAccount = ActiveDirectory.RetrieveMachineAccount(device.DeviceDomainId);
|
||||
var adMachineAccount = ActiveDirectory.RetrieveADMachineAccount(device.DeviceDomainId);
|
||||
if (adMachineAccount != null)
|
||||
adMachineAccount.SetDescription(device);
|
||||
}
|
||||
@@ -410,7 +410,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
var thumbPath = da.RepositoryThumbnailFilename(Database);
|
||||
if (System.IO.File.Exists(thumbPath))
|
||||
{
|
||||
if (thumbPath.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (thumbPath.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
|
||||
return File(thumbPath, "image/png");
|
||||
else
|
||||
return File(thumbPath, "image/jpg");
|
||||
@@ -433,7 +433,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
if (file.ContentLength > 0)
|
||||
{
|
||||
var contentType = file.ContentType;
|
||||
if (string.IsNullOrEmpty(contentType) || contentType.Equals("unknown/unknown", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (string.IsNullOrEmpty(contentType) || contentType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
|
||||
contentType = BI.Interop.MimeTypes.ResolveMimeType(file.FileName);
|
||||
|
||||
var da = new Disco.Models.Repository.DeviceAttachment()
|
||||
@@ -501,7 +501,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
var da = Database.DeviceAttachments.Include("TechUser").Where(m => m.Id == id).FirstOrDefault();
|
||||
if (da != null)
|
||||
{
|
||||
if (da.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (da.TechUserId.Equals(CurrentUser.UserId, StringComparison.OrdinalIgnoreCase))
|
||||
Authorization.RequireAny(Claims.Device.Actions.RemoveAnyAttachments, Claims.Device.Actions.RemoveOwnAttachments);
|
||||
else
|
||||
Authorization.Require(Claims.Device.Actions.RemoveAnyAttachments);
|
||||
|
||||
@@ -246,7 +246,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateOrganisationalUnit(Disco.Models.Repository.DeviceProfile deviceProfile, string OrganisationalUnit)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(OrganisationalUnit))
|
||||
OrganisationalUnit = ActiveDirectory.PrimaryDomain.GetDefaultComputerContainer();
|
||||
OrganisationalUnit = ActiveDirectory.Context.PrimaryDomain.DefaultComputerContainer;
|
||||
|
||||
if (OrganisationalUnit != deviceProfile.OrganisationalUnit)
|
||||
{
|
||||
|
||||
@@ -531,7 +531,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
// Enforce Restricted List Mode
|
||||
var value = DeviceHeldLocation.Trim();
|
||||
|
||||
if (!Database.DiscoConfiguration.JobPreferences.LocationList.Contains(value, StringComparer.InvariantCultureIgnoreCase))
|
||||
if (!Database.DiscoConfiguration.JobPreferences.LocationList.Contains(value, StringComparer.OrdinalIgnoreCase))
|
||||
throw new ArgumentException("The location was not found in the list (Mode: Restricted List)");
|
||||
}
|
||||
|
||||
@@ -545,7 +545,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateFlags(Job job, string Flags)
|
||||
{
|
||||
// Only User Management Job Supports Flags at the moment
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.UMgmt, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.UMgmt, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for User Management Jobs");
|
||||
}
|
||||
@@ -602,7 +602,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateNonWarrantyIsInsuranceClaim(Job job, string IsInsuranceClaim)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -641,7 +641,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private Models.Job._DateChangeModel UpdateNonWarrantyAccountingChargeRequired(Job job, string AccountingChargeRequiredDate)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -675,7 +675,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private Models.Job._DateChangeModel UpdateNonWarrantyAccountingChargeAdded(Job job, string AccountingChargeAddedDate)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -709,7 +709,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private Models.Job._DateChangeModel UpdateNonWarrantyAccountingChargePaid(Job job, string AccountingChargePaidDate)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -743,7 +743,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private Models.Job._DateChangeModel UpdateNonWarrantyPurchaseOrderRaised(Job job, string PurchaseOrderRaisedDate)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -786,7 +786,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private Models.Job._DateChangeModel UpdateNonWarrantyPurchaseOrderSent(Job job, string PurchaseOrderSentDate)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -820,7 +820,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private Models.Job._DateChangeModel UpdateNonWarrantyInvoiceReceived(Job job, string InvoiceReceivedDate)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -855,7 +855,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateNonWarrantyRepairerName(Job job, string RepairerName)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -873,7 +873,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateNonWarrantyRepairerLoggedDate(Job job, string RepairerLoggedDate)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -884,7 +884,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RepairerLoggedDate.Equals("Now", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (RepairerLoggedDate.Equals("Now", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
job.JobMetaNonWarranty.RepairerLoggedDate = DateTime.Now;
|
||||
}
|
||||
@@ -906,7 +906,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateNonWarrantyRepairerReference(Job job, string RepairerReference)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -924,7 +924,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateNonWarrantyRepairerCompletedDate(Job job, string RepairerCompletedDate)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -935,7 +935,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RepairerCompletedDate.Equals("Now", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (RepairerCompletedDate.Equals("Now", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
job.JobMetaNonWarranty.RepairerCompletedDate = DateTime.Now;
|
||||
}
|
||||
@@ -962,7 +962,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private Models.Job._DateChangeModel UpdateInsuranceClaimFormSentDate(Job job, string ClaimFormSentDate)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -973,7 +973,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ClaimFormSentDate.Equals("Now", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (ClaimFormSentDate.Equals("Now", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
job.JobMetaInsurance.ClaimFormSentDate = DateTime.Now;
|
||||
}
|
||||
@@ -1004,7 +1004,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateInsuranceDateOfPurchase(Job job, string DateOfPurchase)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -1028,7 +1028,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateInsuranceOtherInterestedParties(Job job, string OtherInterestedParties)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -1047,7 +1047,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateInsuranceRecoverReduceAction(Job job, string RecoverReduceAction)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -1066,7 +1066,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateInsurancePoliceNotifiedCrimeReportNo(Job job, string PoliceNotifiedCrimeReportNo)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -1085,7 +1085,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateInsurancePoliceNotifiedDate(Job job, string PoliceNotifiedDate)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -1109,7 +1109,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateInsurancePoliceNotifiedStation(Job job, string PoliceNotifiedStation)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -1128,7 +1128,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateInsurancePoliceNotified(Job job, string PoliceNotified)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -1146,7 +1146,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateInsurancePropertyLastSeenDate(Job job, string PropertyLastSeenDate)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -1173,7 +1173,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateInsuranceBurglaryTheftMethodOfEntry(Job job, string BurglaryTheftMethodOfEntry)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -1192,7 +1192,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateInsuranceWitnessesNamesAddresses(Job job, string WitnessesNamesAddresses)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -1211,7 +1211,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateInsuranceThirdPartyCausedWhy(Job job, string ThirdPartyCausedWhy)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -1230,7 +1230,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateInsuranceThirdPartyCausedName(Job job, string ThirdPartyCausedName)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -1249,7 +1249,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateInsuranceThirdPartyCaused(Job job, string ThirdPartyCaused)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -1267,7 +1267,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateInsuranceDescription(Job job, string Description)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -1286,7 +1286,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateInsuranceEventLocation(Job job, string EventLocation)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -1305,7 +1305,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateInsuranceLossOrDamageDate(Job job, string LossOrDamageDate)
|
||||
{
|
||||
// Validate Is NonWarranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HNWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware NonWarranty Jobs");
|
||||
}
|
||||
@@ -1334,7 +1334,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateWarrantyExternalName(Job job, string ExternalName)
|
||||
{
|
||||
// Validate Is Warranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware Warranty Jobs");
|
||||
}
|
||||
@@ -1353,7 +1353,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateWarrantyExternalLoggedDate(Job job, string ExternalLoggedDate)
|
||||
{
|
||||
// Validate Is Warranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware Warranty Jobs");
|
||||
}
|
||||
@@ -1380,7 +1380,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateWarrantyExternalReference(Job job, string ExternalReference)
|
||||
{
|
||||
// Validate Is Warranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware Warranty Jobs");
|
||||
}
|
||||
@@ -1399,7 +1399,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
private void UpdateWarrantyExternalCompletedDate(Job job, string ExternalCompletedDate)
|
||||
{
|
||||
// Validate Is Warranty Job
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HWar, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!job.JobTypeId.Equals(JobType.JobTypeIds.HWar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new Exception("This property can only be set for Hardware Warranty Jobs");
|
||||
}
|
||||
@@ -1410,7 +1410,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ExternalCompletedDate.Equals("Now", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (ExternalCompletedDate.Equals("Now", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
job.JobMetaWarranty.ExternalCompletedDate = DateTime.Now;
|
||||
}
|
||||
@@ -1876,7 +1876,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
var jl = Database.JobLogs.Find(id);
|
||||
if (jl != null)
|
||||
{
|
||||
if (jl.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (jl.TechUserId.Equals(CurrentUser.UserId, StringComparison.OrdinalIgnoreCase))
|
||||
Authorization.RequireAny(Claims.Job.Actions.RemoveAnyLogs, Claims.Job.Actions.RemoveOwnLogs);
|
||||
else
|
||||
Authorization.Require(Claims.Job.Actions.RemoveAnyLogs);
|
||||
@@ -1921,7 +1921,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
var thumbFileInfo = new FileInfo(thumbPath);
|
||||
if (thumbFileInfo.Exists && thumbFileInfo.Length > 0)
|
||||
{
|
||||
if (thumbPath.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (thumbPath.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
|
||||
return File(thumbPath, "image/png");
|
||||
else
|
||||
return File(thumbPath, "image/jpg");
|
||||
@@ -1944,7 +1944,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
if (file.ContentLength > 0)
|
||||
{
|
||||
var contentType = file.ContentType;
|
||||
if (string.IsNullOrEmpty(contentType) || contentType.Equals("unknown/unknown", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (string.IsNullOrEmpty(contentType) || contentType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
|
||||
contentType = BI.Interop.MimeTypes.ResolveMimeType(file.FileName);
|
||||
|
||||
var ja = new Disco.Models.Repository.JobAttachment()
|
||||
@@ -2012,7 +2012,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
var ja = Database.JobAttachments.Include("TechUser").Where(m => m.Id == id).FirstOrDefault();
|
||||
if (ja != null)
|
||||
{
|
||||
if (ja.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (ja.TechUserId.Equals(CurrentUser.UserId, StringComparison.OrdinalIgnoreCase))
|
||||
Authorization.RequireAny(Claims.Job.Actions.RemoveAnyAttachments, Claims.Job.Actions.RemoveOwnAttachments);
|
||||
else
|
||||
Authorization.Require(Claims.Job.Actions.RemoveAnyAttachments);
|
||||
@@ -2148,7 +2148,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
{
|
||||
case Disco.Models.BI.Job.LocationModes.Unrestricted:
|
||||
var jobDateThreshold = DateTime.Now.AddYears(-1);
|
||||
locations = Database.Jobs.Where(j => (j.OpenedDate > jobDateThreshold || !j.ClosedDate.HasValue) && j.DeviceHeldLocation != null).Select(j => j.DeviceHeldLocation).Distinct().OrderBy(l => l).ToList().Where(l => !string.IsNullOrWhiteSpace(l)).Select(l => l.Trim()).Distinct(StringComparer.InvariantCultureIgnoreCase).OrderBy(l => l).ToList();
|
||||
locations = Database.Jobs.Where(j => (j.OpenedDate > jobDateThreshold || !j.ClosedDate.HasValue) && j.DeviceHeldLocation != null).Select(j => j.DeviceHeldLocation).Distinct().OrderBy(l => l).ToList().Where(l => !string.IsNullOrWhiteSpace(l)).Select(l => l.Trim()).Distinct(StringComparer.OrdinalIgnoreCase).OrderBy(l => l).ToList();
|
||||
break;
|
||||
case Disco.Models.BI.Job.LocationModes.OptionalList:
|
||||
case Disco.Models.BI.Job.LocationModes.RestrictedList:
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
var list = LocationList
|
||||
.Where(i => !string.IsNullOrWhiteSpace(i))
|
||||
.Select(i => i.Trim())
|
||||
.Distinct(StringComparer.InvariantCultureIgnoreCase)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.OrderBy(i => i);
|
||||
|
||||
Database.DiscoConfiguration.JobPreferences.LocationList = list.ToList();
|
||||
@@ -93,7 +93,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
list = list
|
||||
.Where(l => !string.IsNullOrWhiteSpace(l))
|
||||
.Select(l => l.Trim())
|
||||
.Distinct(StringComparer.InvariantCultureIgnoreCase)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.OrderBy(i => i);
|
||||
|
||||
Database.DiscoConfiguration.JobPreferences.LocationList = list.ToList();
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Jobs.JobQueues;
|
||||
using Disco.Services.Web;
|
||||
@@ -291,14 +290,15 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
var subjects = Subjects
|
||||
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||
.Select(s => s.Trim())
|
||||
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveObject(s, Quick: true)))
|
||||
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveADObject(s, Quick: true)))
|
||||
.Where(s => s.Item2 is ADUserAccount || s.Item2 is ADGroup)
|
||||
.ToList();
|
||||
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
|
||||
|
||||
if (invalidSubjects.Count > 0)
|
||||
throw new ArgumentException(string.Format("Subjects not found: {0}", string.Join(", ", invalidSubjects)), "Subjects");
|
||||
|
||||
var proposedSubjects = subjects.Select(s => s.Item2.NetBiosId).OrderBy(s => s).ToArray();
|
||||
var proposedSubjects = subjects.Select(s => s.Item2.Id).OrderBy(s => s).ToArray();
|
||||
|
||||
subjectIds = string.Join(",", proposedSubjects);
|
||||
|
||||
@@ -370,28 +370,5 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
[DiscoAuthorize(Claims.Config.JobQueue.Configure)]
|
||||
public virtual ActionResult SearchSubjects(string term)
|
||||
{
|
||||
var groupResults = ActiveDirectory.SearchGroups(term).Cast<IActiveDirectoryObject>();
|
||||
var userResults = ActiveDirectory.SearchUserAccounts(term).Cast<IActiveDirectoryObject>();
|
||||
|
||||
var results = groupResults.Concat(userResults).OrderBy(r => r.SamAccountName)
|
||||
.Select(r => Models.JobQueue.SubjectItem.FromActiveDirectoryObject(r)).ToList();
|
||||
|
||||
return Json(results, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
[DiscoAuthorize(Claims.Config.JobQueue.Configure)]
|
||||
public virtual ActionResult Subject(string Id)
|
||||
{
|
||||
var subject = ActiveDirectory.RetrieveObject(Id, Quick: true);
|
||||
|
||||
if (subject == null || !(subject is ActiveDirectoryUserAccount || subject is ActiveDirectoryGroup))
|
||||
return Json(null, JsonRequestBehavior.AllowGet);
|
||||
else
|
||||
return Json(Models.JobQueue.SubjectItem.FromActiveDirectoryObject(subject), JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Data.Configuration;
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Web;
|
||||
@@ -20,7 +19,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
[DiscoAuthorize(Claims.Config.System.Show)]
|
||||
public virtual ActionResult UpdateLastNetworkLogonDates()
|
||||
{
|
||||
var taskStatus = Disco.Services.Interop.ActiveDirectory.Internal.ADUpdateLastNetworkLogonDateJob.ScheduleImmediately();
|
||||
var taskStatus = Disco.Services.Interop.ActiveDirectory.ADTaskUpdateNetworkLogonDates.ScheduleImmediately();
|
||||
|
||||
return RedirectToAction(MVC.Config.Logging.TaskStatus(taskStatus.SessionId));
|
||||
}
|
||||
@@ -126,7 +125,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
|
||||
if (Image != null && Image.ContentLength > 0)
|
||||
{
|
||||
if (Image.ContentType.StartsWith("image/", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (Image.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Database.DiscoConfiguration.OrganisationLogo = Image.InputStream;
|
||||
|
||||
@@ -227,7 +226,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
[DiscoAuthorize(Claims.Config.System.ConfigureActiveDirectory)]
|
||||
public virtual ActionResult UpdateActiveDirectorySearchScope(List<string> Containers, bool redirect = false)
|
||||
{
|
||||
ActiveDirectory.UpdateSearchContainers(Database, Containers);
|
||||
ActiveDirectory.Context.UpdateSearchContainers(Database, Containers);
|
||||
Database.SaveChanges();
|
||||
|
||||
if (redirect)
|
||||
@@ -237,17 +236,17 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
}
|
||||
|
||||
[DiscoAuthorize(Claims.Config.System.ConfigureActiveDirectory)]
|
||||
public virtual ActionResult UpdateActiveDirectorySearchEntireForest(bool SearchEntireForest, bool redirect = false)
|
||||
public virtual ActionResult UpdateActiveDirectorySearchAllForestServers(bool SearchAllForestServers, bool redirect = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = ActiveDirectory.UpdateSearchEntireForest(Database, SearchEntireForest);
|
||||
var result = ActiveDirectory.Context.UpdateSearchAllForestServers(Database, SearchAllForestServers);
|
||||
|
||||
Database.SaveChanges();
|
||||
|
||||
if (!result)
|
||||
{
|
||||
var forestServers = ActiveDirectory.LoadForestServers();
|
||||
var forestServers = ActiveDirectory.Context.ForestServers;
|
||||
if (forestServers.Count > ActiveDirectory.MaxForestServerSearch)
|
||||
throw new InvalidOperationException(string.Format("This forest contains more than the Max Forest Server Search restriction ({0})", ActiveDirectory.MaxForestServerSearch));
|
||||
else
|
||||
@@ -271,8 +270,8 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
[DiscoAuthorizeAny(Claims.Config.System.ConfigureActiveDirectory, Claims.Config.DeviceProfile.Configure)]
|
||||
public virtual ActionResult DomainOrganisationalUnits()
|
||||
{
|
||||
var domainOUs = ActiveDirectory.Domains
|
||||
.Select(d => new Models.System.DomainOrganisationalUnitsModel() { Domain = d, OrganisationalUnits = ActiveDirectory.RetrieveOrganisationalUnitStructure(d) })
|
||||
var domainOUs = ActiveDirectory.RetrieveADOrganisationalUnitStructure()
|
||||
.Select(d => new Models.System.DomainOrganisationalUnitsModel() { Domain = d.Item1, OrganisationalUnits = d.Item2})
|
||||
.Select(ous => ous.ToFancyTreeNode()).ToList();
|
||||
|
||||
return new JsonResult()
|
||||
@@ -283,6 +282,29 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
};
|
||||
}
|
||||
|
||||
[DiscoAuthorizeAny(Claims.DiscoAdminAccount, Claims.Config.JobQueue.Configure)]
|
||||
public virtual ActionResult SearchSubjects(string term)
|
||||
{
|
||||
var groupResults = ActiveDirectory.SearchADGroups(term).Cast<IADObject>();
|
||||
var userResults = ActiveDirectory.SearchADUserAccounts(term, true).Cast<IADObject>();
|
||||
|
||||
var results = groupResults.Concat(userResults).OrderBy(r => r.SamAccountName)
|
||||
.Select(r => Models.Shared.SubjectDescriptorModel.FromActiveDirectoryObject(r)).ToList();
|
||||
|
||||
return Json(results, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
[DiscoAuthorizeAny(Claims.DiscoAdminAccount, Claims.Config.JobQueue.Configure)]
|
||||
public virtual ActionResult Subject(string Id)
|
||||
{
|
||||
var subject = ActiveDirectory.RetrieveADObject(Id, Quick: true);
|
||||
|
||||
if (subject == null)
|
||||
return Json(null, JsonRequestBehavior.AllowGet);
|
||||
else
|
||||
return Json(Models.Shared.SubjectDescriptorModel.FromActiveDirectoryObject(subject), JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Proxy Settings
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
var thumbPath = ua.RepositoryThumbnailFilename(Database);
|
||||
if (System.IO.File.Exists(thumbPath))
|
||||
{
|
||||
if (thumbPath.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (thumbPath.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
|
||||
return File(thumbPath, "image/png");
|
||||
else
|
||||
return File(thumbPath, "image/jpg");
|
||||
@@ -65,7 +65,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
public virtual ActionResult AttachmentUpload(string id, string Domain, string Comments)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Domain))
|
||||
id = ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + id;
|
||||
id = ActiveDirectory.Context.PrimaryDomain.NetBiosName + @"\" + id;
|
||||
else
|
||||
id = Domain + @"\" + id;
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
if (file.ContentLength > 0)
|
||||
{
|
||||
var contentType = file.ContentType;
|
||||
if (string.IsNullOrEmpty(contentType) || contentType.Equals("unknown/unknown", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (string.IsNullOrEmpty(contentType) || contentType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
|
||||
contentType = BI.Interop.MimeTypes.ResolveMimeType(file.FileName);
|
||||
|
||||
var ua = new Disco.Models.Repository.UserAttachment()
|
||||
@@ -127,7 +127,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
public virtual ActionResult Attachments(string id, string Domain)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Domain))
|
||||
id = ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + id;
|
||||
id = ActiveDirectory.Context.PrimaryDomain.NetBiosName + @"\" + id;
|
||||
else
|
||||
id = Domain + @"\" + id;
|
||||
|
||||
@@ -151,7 +151,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
var ua = Database.UserAttachments.Include("TechUser").Where(m => m.Id == id).FirstOrDefault();
|
||||
if (ua != null)
|
||||
{
|
||||
if (ua.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (ua.TechUserId.Equals(CurrentUser.UserId, StringComparison.OrdinalIgnoreCase))
|
||||
Authorization.RequireAny(Claims.User.Actions.RemoveAnyAttachments, Claims.User.Actions.RemoveOwnAttachments);
|
||||
else
|
||||
Authorization.Require(Claims.User.Actions.RemoveAnyAttachments);
|
||||
@@ -174,7 +174,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
throw new ArgumentNullException("AttachmentTypeId");
|
||||
|
||||
if (string.IsNullOrEmpty(Domain))
|
||||
id = ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + id;
|
||||
id = ActiveDirectory.Context.PrimaryDomain.NetBiosName + @"\" + id;
|
||||
else
|
||||
id = Domain + @"\" + id;
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Disco.Web.Areas.API.Models.AuthorizationRole
|
||||
{
|
||||
public class SubjectItem
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Type { get; set; }
|
||||
|
||||
public static SubjectItem FromActiveDirectoryObject(IActiveDirectoryObject ADObject)
|
||||
{
|
||||
return new Models.AuthorizationRole.SubjectItem()
|
||||
{
|
||||
Id = ADObject.NetBiosId,
|
||||
Name = ADObject.DisplayName,
|
||||
Type = ADObject is ActiveDirectoryGroup ? "group" : "user"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Disco.Web.Areas.API.Models.JobQueue
|
||||
{
|
||||
public class SubjectItem
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Type { get; set; }
|
||||
|
||||
public static SubjectItem FromActiveDirectoryObject(IActiveDirectoryObject ADObject)
|
||||
{
|
||||
return new Models.JobQueue.SubjectItem()
|
||||
{
|
||||
Id = ADObject.NetBiosId,
|
||||
Name = ADObject.DisplayName,
|
||||
Type = ADObject is ActiveDirectoryGroup ? "group" : "user"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Disco.Web.Areas.API.Models.Shared
|
||||
{
|
||||
public class SubjectDescriptorModel
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Type { get; set; }
|
||||
|
||||
public bool IsGroup { get; set; }
|
||||
public bool IsUserAccount { get; set; }
|
||||
public bool IsMachineAccount { get; set; }
|
||||
|
||||
public static SubjectDescriptorModel FromActiveDirectoryObject(IADObject ADObject)
|
||||
{
|
||||
var item = new SubjectDescriptorModel()
|
||||
{
|
||||
Id = ADObject.Id,
|
||||
Name = ADObject.DisplayName
|
||||
};
|
||||
|
||||
if (ADObject is ADUserAccount)
|
||||
{
|
||||
item.IsUserAccount = true;
|
||||
item.Type = "user";
|
||||
}
|
||||
else if (ADObject is ADGroup)
|
||||
{
|
||||
item.IsGroup = true;
|
||||
item.Type = "group";
|
||||
}
|
||||
else if (ADObject is ADMachineAccount)
|
||||
{
|
||||
item.IsMachineAccount = true;
|
||||
item.Type = "machine";
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Type = "unknown";
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,14 @@
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using Disco.Web.Models.Shared;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Disco.Web.Areas.API.Models.System
|
||||
{
|
||||
public class DomainOrganisationalUnitsModel
|
||||
{
|
||||
public ActiveDirectoryDomain Domain { get; set; }
|
||||
public List<ActiveDirectoryOrganisationalUnit> OrganisationalUnits { get; set; }
|
||||
public ADDomain Domain { get; set; }
|
||||
public List<ADOrganisationalUnit> OrganisationalUnits { get; set; }
|
||||
|
||||
public FancyTreeNode ToFancyTreeNode()
|
||||
{
|
||||
@@ -21,13 +19,13 @@ namespace Disco.Web.Areas.API.Models.System
|
||||
key = Domain.DistinguishedName,
|
||||
title = Domain.NetBiosName,
|
||||
folder = true,
|
||||
tooltip = Domain.DnsName,
|
||||
tooltip = Domain.Name,
|
||||
children = children,
|
||||
unselectable = false,
|
||||
expanded = true
|
||||
};
|
||||
}
|
||||
private FancyTreeNode OrganisationalUnitToFancyTreeNode(ActiveDirectoryOrganisationalUnit OrganisationalUnit)
|
||||
private FancyTreeNode OrganisationalUnitToFancyTreeNode(ADOrganisationalUnit OrganisationalUnit)
|
||||
{
|
||||
FancyTreeNode[] children = OrganisationalUnit.Children == null
|
||||
? null
|
||||
|
||||
@@ -6,6 +6,7 @@ using Disco.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Plugins.Features.UIExtension;
|
||||
using Disco.Services.Users;
|
||||
using Disco.Services.Web;
|
||||
using Disco.Web.Areas.API.Models.Shared;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -27,10 +28,10 @@ namespace Disco.Web.Areas.Config.Controllers
|
||||
throw new ArgumentException("Invalid Authorization Role Id");
|
||||
|
||||
var token = RoleToken.FromAuthorizationRole(ar);
|
||||
var subjects = token.SubjectIds == null ? new List<Models.AuthorizationRole.SubjectDescriptorModel>() :
|
||||
token.SubjectIds.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId, Quick: true))
|
||||
var subjects = token.SubjectIds == null ? new List<SubjectDescriptorModel>() :
|
||||
token.SubjectIds.Select(subjectId => ActiveDirectory.RetrieveADObject(subjectId, Quick: true))
|
||||
.Where(item => item != null)
|
||||
.Select(item => Models.AuthorizationRole.SubjectDescriptorModel.FromActiveDirectoryObject(item))
|
||||
.Select(item => SubjectDescriptorModel.FromActiveDirectoryObject(item))
|
||||
.OrderBy(item => item.Name).ToList();
|
||||
|
||||
var m = new Models.AuthorizationRole.ShowModel()
|
||||
@@ -53,9 +54,9 @@ namespace Disco.Web.Areas.Config.Controllers
|
||||
.Select(ar => RoleToken.FromAuthorizationRole(ar)).Cast<IRoleToken>().ToList();
|
||||
|
||||
var administratorSubjects = UserService.AdministratorSubjectIds
|
||||
.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId, Quick: true))
|
||||
.Select(subjectId => ActiveDirectory.RetrieveADObject(subjectId, Quick: true))
|
||||
.Where(item => item != null)
|
||||
.Select(item => Models.AuthorizationRole.SubjectDescriptorModel.FromActiveDirectoryObject(item))
|
||||
.Select(item => SubjectDescriptorModel.FromActiveDirectoryObject(item))
|
||||
.OrderBy(item => item.Name).ToList();
|
||||
|
||||
var m = new Models.AuthorizationRole.IndexModel()
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace Disco.Web.Areas.Config.Controllers
|
||||
ComputerNameTemplate = DeviceProfile.DefaultComputerNameTemplate,
|
||||
ProvisionADAccount = true,
|
||||
DistributionType = DeviceProfile.DistributionTypes.OneToMany,
|
||||
OrganisationalUnit = ActiveDirectory.PrimaryDomain.GetDefaultComputerContainer()
|
||||
OrganisationalUnit = ActiveDirectory.Context.PrimaryDomain.DefaultComputerContainer
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using Disco.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Jobs.JobQueues;
|
||||
using Disco.Services.Plugins.Features.UIExtension;
|
||||
using Disco.Services.Web;
|
||||
using Disco.Web.Areas.API.Models.Shared;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -28,10 +29,10 @@ namespace Disco.Web.Areas.Config.Controllers
|
||||
throw new ArgumentException("Invalid Job Queue Id");
|
||||
|
||||
var token = JobQueueToken.FromJobQueue(jq);
|
||||
var subjects = token.SubjectIds == null ? new List<Models.JobQueue.ShowModel.SubjectDescriptor>() :
|
||||
token.SubjectIds.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId, Quick: true))
|
||||
var subjects = token.SubjectIds == null ? new List<SubjectDescriptorModel>() :
|
||||
token.SubjectIds.Select(subjectId => ActiveDirectory.RetrieveADObject(subjectId, Quick: true))
|
||||
.Where(item => item != null)
|
||||
.Select(item => Models.JobQueue.ShowModel.SubjectDescriptor.FromActiveDirectoryObject(item))
|
||||
.Select(item => SubjectDescriptorModel.FromActiveDirectoryObject(item))
|
||||
.OrderBy(item => item.Name).ToList();
|
||||
|
||||
var totalJobCount = Database.JobQueueJobs.Where(jqj => jqj.JobQueueId == id.Value).Select(jqj => jqj.Job).Distinct().Count();
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Web;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.UI.Config.AuthorizationRole;
|
||||
using Disco.Models.Services.Authorization;
|
||||
using Disco.Web.Areas.API.Models.Shared;
|
||||
|
||||
namespace Disco.Web.Areas.Config.Models.AuthorizationRole
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Disco.Models.Services.Authorization;
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Models.UI.Config.AuthorizationRole;
|
||||
using Disco.Web.Areas.API.Models.Shared;
|
||||
using Disco.Web.Models.Shared;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
|
||||
namespace Disco.Web.Areas.Config.Models.AuthorizationRole
|
||||
{
|
||||
public class SubjectDescriptorModel
|
||||
{
|
||||
public bool IsGroup { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Id { get; set; }
|
||||
|
||||
public static SubjectDescriptorModel FromActiveDirectoryObject(IActiveDirectoryObject ADObject)
|
||||
{
|
||||
var item = new SubjectDescriptorModel()
|
||||
{
|
||||
Id = ADObject.NetBiosId,
|
||||
Name = ADObject.DisplayName
|
||||
};
|
||||
|
||||
if (ADObject is ActiveDirectoryGroup)
|
||||
item.IsGroup = true;
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using Disco.Services.Plugins;
|
||||
using Disco.Models.UI.Config.DeviceProfile;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
|
||||
namespace Disco.Web.Areas.Config.Models.DeviceProfile
|
||||
{
|
||||
@@ -15,6 +16,23 @@ namespace Disco.Web.Areas.Config.Models.DeviceProfile
|
||||
public Disco.Models.BI.Config.OrganisationAddress DefaultOrganisationAddress { get; set; }
|
||||
public List<Disco.Models.BI.Config.OrganisationAddress> OrganisationAddresses { get; set; }
|
||||
|
||||
public string FriendlyOrganisationalUnitName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(this.DeviceProfile.OrganisationalUnit))
|
||||
{
|
||||
var domain = ActiveDirectory.Context.PrimaryDomain;
|
||||
return domain.FriendlyDistinguishedNamePath(domain.DefaultComputerContainer);
|
||||
}
|
||||
else
|
||||
{
|
||||
var domain = ActiveDirectory.Context.GetDomainFromDistinguishedName(this.DeviceProfile.OrganisationalUnit);
|
||||
return domain.FriendlyDistinguishedNamePath(this.DeviceProfile.OrganisationalUnit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<PluginFeatureManifest> CertificateProviders { get; set; }
|
||||
|
||||
public int DeviceCount { get; set; }
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Models.Services.Jobs.JobQueues;
|
||||
using Disco.Models.Services.Jobs.JobQueues;
|
||||
using Disco.Models.UI.Config.JobQueue;
|
||||
using System;
|
||||
using Disco.Web.Areas.API.Models.Shared;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Disco.Web.Areas.Config.Models.JobQueue
|
||||
{
|
||||
@@ -12,28 +9,7 @@ namespace Disco.Web.Areas.Config.Models.JobQueue
|
||||
{
|
||||
public IJobQueueToken Token { get; set; }
|
||||
|
||||
public List<SubjectDescriptor> Subjects { get; set; }
|
||||
|
||||
public class SubjectDescriptor
|
||||
{
|
||||
public bool IsGroup { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Id { get; set; }
|
||||
|
||||
public static SubjectDescriptor FromActiveDirectoryObject(IActiveDirectoryObject ADObject)
|
||||
{
|
||||
var item = new SubjectDescriptor()
|
||||
{
|
||||
Id = ADObject.NetBiosId,
|
||||
Name = ADObject.DisplayName
|
||||
};
|
||||
|
||||
if (ADObject is ActiveDirectoryGroup)
|
||||
item.IsGroup = true;
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
public List<SubjectDescriptorModel> Subjects { get; set; }
|
||||
|
||||
public int OpenJobCount { get; set; }
|
||||
public int TotalJobCount { get; set; }
|
||||
@@ -41,6 +17,5 @@ namespace Disco.Web.Areas.Config.Models.JobQueue
|
||||
public List<Disco.Models.Repository.JobType> JobTypes { get; set; }
|
||||
|
||||
public bool CanDelete { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ using System.Data.SqlClient;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.BI.Interop.Community;
|
||||
using Disco.Services.Tasks;
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using System.DirectoryServices.ActiveDirectory;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
|
||||
@@ -77,14 +76,14 @@ namespace Disco.Web.Areas.Config.Models.SystemConfig
|
||||
|
||||
#region Active Directory
|
||||
|
||||
[Display(Name="Search Entire Forest")]
|
||||
public bool ADSearchEntireForest { get; set; }
|
||||
[Display(Name="Search All Forest Servers")]
|
||||
public bool ADSearchAllForestServers { get; set; }
|
||||
|
||||
public ActiveDirectoryDomain ADPrimaryDomain { get; set; }
|
||||
public List<ActiveDirectoryDomain> ADAdditionalDomains { get; set; }
|
||||
public ActiveDirectorySite ADSite { get; set; }
|
||||
public List<Tuple<DirectoryServer, bool>> ADSiteServers { get; set; }
|
||||
public List<Tuple<string, ActiveDirectoryDomain, string>> ADSearchContainers { get; set; }
|
||||
public List<ADDomain> ADDomains { get; set; }
|
||||
public ADDomain ADPrimaryDomain { get; set; }
|
||||
public ADSite ADSite { get; set; }
|
||||
public List<ADDomainController> ADServers { get; set; }
|
||||
public List<Tuple<string, ADDomain, string>> ADSearchContainers { get; set; }
|
||||
public List<string> ADForestServers { get; set; }
|
||||
|
||||
#endregion
|
||||
@@ -119,28 +118,28 @@ namespace Disco.Web.Areas.Config.Models.SystemConfig
|
||||
};
|
||||
|
||||
// AD
|
||||
m.ADPrimaryDomain = ActiveDirectory.PrimaryDomain;
|
||||
m.ADAdditionalDomains = ActiveDirectory.Domains.Where(d => d != m.ADPrimaryDomain).ToList();
|
||||
m.ADSite = ActiveDirectory.Site;
|
||||
m.ADSiteServers = m.ADSite.Servers.Cast<DirectoryServer>().Select(s => Tuple.Create(s, s.Reachable())).ToList();
|
||||
m.ADDomains = ActiveDirectory.Context.Domains.ToList();
|
||||
m.ADPrimaryDomain = ActiveDirectory.Context.PrimaryDomain;
|
||||
m.ADSite = ActiveDirectory.Context.Site;
|
||||
m.ADServers = ActiveDirectory.Context.Domains.SelectMany(d => d.DomainControllers).ToList();
|
||||
var configSearchContainers = config.ActiveDirectory.SearchContainers;
|
||||
m.ADSearchContainers = configSearchContainers == null ? null : configSearchContainers.SelectMany(d => d.Value, (k, c) =>
|
||||
{
|
||||
var domain = ActiveDirectory.GetDomainByDnsName(k.Key);
|
||||
return Tuple.Create(c, domain, domain.GetFriendlyOrganisationalUnitName(c));
|
||||
var domain = ActiveDirectory.Context.GetDomainByName(k.Key);
|
||||
return Tuple.Create(c, domain, domain.FriendlyDistinguishedNamePath(c));
|
||||
}).ToList();
|
||||
|
||||
var loadForestServersTask = ActiveDirectory.LoadForestServersAsync();
|
||||
var loadForestServersTask = ADDiscoverForestServers.LoadForestServersAsync();
|
||||
if (loadForestServersTask.Wait(TimeSpan.FromSeconds(1)))
|
||||
{
|
||||
m.ADForestServers = loadForestServersTask.Result;
|
||||
var configValue = config.ActiveDirectory.SearchEntireForest ?? true;
|
||||
m.ADSearchEntireForest = configValue && m.ADForestServers.Count <= ActiveDirectory.MaxForestServerSearch;
|
||||
var configValue = config.ActiveDirectory.SearchAllForestServers ?? true;
|
||||
m.ADSearchAllForestServers = configValue && m.ADForestServers.Count <= ActiveDirectory.MaxForestServerSearch;
|
||||
}
|
||||
else
|
||||
{
|
||||
m.ADForestServers = null;
|
||||
m.ADSearchEntireForest = config.ActiveDirectory.SearchEntireForest ?? true;
|
||||
m.ADSearchAllForestServers = config.ActiveDirectory.SearchAllForestServers ?? true;
|
||||
}
|
||||
|
||||
return m;
|
||||
|
||||
@@ -90,7 +90,7 @@ else
|
||||
|
||||
textAdd.watermark('Search Subjects')
|
||||
.autocomplete({
|
||||
source: '@(Url.Action(MVC.API.AuthorizationRole.SearchSubjects()))',
|
||||
source: '@(Url.Action(MVC.API.System.SearchSubjects()))',
|
||||
minLength: 2,
|
||||
focus: function (e, ui) {
|
||||
textAdd.val(ui.item.Id);
|
||||
@@ -148,32 +148,37 @@ else
|
||||
var id = textAdd.val();
|
||||
|
||||
$.ajax({
|
||||
url: '@Url.Action(MVC.API.AuthorizationRole.Subject())',
|
||||
url: '@Url.Action(MVC.API.System.Subject())',
|
||||
method: 'post',
|
||||
data: { Id: id }
|
||||
}).done(function (response) {
|
||||
if (response) {
|
||||
if (list.find('li[data-subjectid="' + response.Id.replace('\\', '\\\\') + '"]').length == 0) {
|
||||
if (response.IsGroup || response.IsUserAccount) {
|
||||
if (list.find('li[data-subjectid="' + response.Id.replace('\\', '\\\\') + '"]').length == 0) {
|
||||
|
||||
var liIcon = $('<i>').addClass('fa fa-lg');
|
||||
if (response.Type === 'user')
|
||||
liIcon.addClass('fa-user');
|
||||
else
|
||||
liIcon.addClass('fa-users');
|
||||
var liIcon = $('<i>').addClass('fa fa-lg');
|
||||
if (response.Type === 'user')
|
||||
liIcon.addClass('fa-user');
|
||||
else
|
||||
liIcon.addClass('fa-users');
|
||||
|
||||
var li = $('<li>')
|
||||
.append(liIcon)
|
||||
.append($('<span>').text(response.Id == response.Name ? response.Id : response.Name + ' [' + response.Id + ']'))
|
||||
.append($('<i>').addClass('fa fa-times-circle remove'))
|
||||
.addClass(response.Type)
|
||||
.attr('data-subjectid', response.Id)
|
||||
.attr('data-subjectstatus', 'new');
|
||||
var li = $('<li>')
|
||||
.append(liIcon)
|
||||
.append($('<span>').text(response.Id == response.Name ? response.Id : response.Name + ' [' + response.Id + ']'))
|
||||
.append($('<i>').addClass('fa fa-times-circle remove'))
|
||||
.addClass(response.Type)
|
||||
.attr('data-subjectid', response.Id)
|
||||
.attr('data-subjectstatus', 'new');
|
||||
|
||||
list.append(li);
|
||||
list.append(li);
|
||||
|
||||
updateNoSubjects();
|
||||
} else {
|
||||
alert('That subject has already been added');
|
||||
updateNoSubjects();
|
||||
} else {
|
||||
alert('That subject has already been added');
|
||||
}
|
||||
}
|
||||
else {
|
||||
alert(response.Name + ' ['+response.Id+'] is a ' + response.Type + '. Only users and groups can be added.');
|
||||
}
|
||||
} else {
|
||||
alert('Unknown Id');
|
||||
|
||||
@@ -385,7 +385,7 @@ WriteLiteral(@"></form>
|
||||
|
||||
|
||||
#line 93 "..\..\Areas\Config\Views\AuthorizationRole\Index.cshtml"
|
||||
Write(Url.Action(MVC.API.AuthorizationRole.SearchSubjects()));
|
||||
Write(Url.Action(MVC.API.System.SearchSubjects()));
|
||||
|
||||
|
||||
#line default
|
||||
@@ -417,42 +417,47 @@ WriteLiteral("\',\r\n minLength: 2,\r\n
|
||||
|
||||
|
||||
#line 151 "..\..\Areas\Config\Views\AuthorizationRole\Index.cshtml"
|
||||
Write(Url.Action(MVC.API.AuthorizationRole.Subject()));
|
||||
Write(Url.Action(MVC.API.System.Subject()));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\',\r\n method: \'post\',\r\n data: { Id: id }\r\n " +
|
||||
" }).done(function (response) {\r\n if (response) {\r\n " +
|
||||
" if (list.find(\'li[data-subjectid=\"\' + response.Id.replace(\'\\\\\', \'\\\\\\\\\') + " +
|
||||
"\'\"]\').length == 0) {\r\n\r\n var liIcon = $(\'<i>\').addClass(\'" +
|
||||
"fa fa-lg\');\r\n if (response.Type === \'user\')\r\n " +
|
||||
" liIcon.addClass(\'fa-user\');\r\n else\r\n " +
|
||||
" liIcon.addClass(\'fa-users\');\r\n\r\n v" +
|
||||
"ar li = $(\'<li>\')\r\n .append(liIcon)\r\n " +
|
||||
" .append($(\'<span>\').text(response.Id == response.Name ? response.Id " +
|
||||
": response.Name + \' [\' + response.Id + \']\'))\r\n .appen" +
|
||||
"d($(\'<i>\').addClass(\'fa fa-times-circle remove\'))\r\n ." +
|
||||
"addClass(response.Type)\r\n .attr(\'data-subjectid\', res" +
|
||||
"ponse.Id)\r\n .attr(\'data-subjectstatus\', \'new\');\r\n\r\n " +
|
||||
" list.append(li);\r\n\r\n updateNoSubjec" +
|
||||
"ts();\r\n } else {\r\n alert(\'That subject" +
|
||||
" has already been added\');\r\n }\r\n } else {\r\n " +
|
||||
" alert(\'Unknown Id\');\r\n }\r\n }).fail(fu" +
|
||||
"nction (jqXHR, textStatus, errorThrown) {\r\n alert(\'Error: \' + err" +
|
||||
"orThrown);\r\n });\r\n return false;\r\n }\r\n\r\n " +
|
||||
" function updateNoSubjects() {\r\n if (list.find(\'li:visible\').leng" +
|
||||
"th > 0)\r\n noSubjects.hide();\r\n else\r\n n" +
|
||||
"oSubjects.show();\r\n }\r\n\r\n function saveChanges() {\r\n va" +
|
||||
"r form = $(\'#Config_AuthRoles_Subjects_Update_Dialog_Form\').empty();\r\n\r\n " +
|
||||
" list.find(\'li[data-subjectstatus!=\"removed\"]\').each(function () {\r\n " +
|
||||
" var subjectId = $(this).attr(\'data-subjectid\');\r\n\r\n form.a" +
|
||||
"ppend($(\'<input>\').attr({\r\n \'name\': \'Subjects\',\r\n " +
|
||||
" \'type\': \'hidden\'\r\n }).val(subjectId));\r\n\r\n })." +
|
||||
"get();\r\n\r\n form.submit();\r\n\r\n dialog.dialog(\"disable\");\r\n " +
|
||||
" dialog.dialog(\"option\", \"buttons\", null);\r\n }\r\n\r\n $(fun" +
|
||||
"ction () {\r\n $(\'#Config_AuthRoles_UpdateAdministrators\').click(showDi" +
|
||||
"alog);\r\n });\r\n\r\n })();\r\n</script>\r\n<!-- #endregion -->\r\n<div");
|
||||
" if (response.IsGroup || response.IsUserAccount) {\r\n " +
|
||||
" if (list.find(\'li[data-subjectid=\"\' + response.Id.replace(\'\\\\\', \'\\\\\\\\\') + \'\"]\')" +
|
||||
".length == 0) {\r\n\r\n var liIcon = $(\'<i>\').addClass(\'f" +
|
||||
"a fa-lg\');\r\n if (response.Type === \'user\')\r\n " +
|
||||
" liIcon.addClass(\'fa-user\');\r\n " +
|
||||
"else\r\n liIcon.addClass(\'fa-users\');\r\n\r\n " +
|
||||
" var li = $(\'<li>\')\r\n .append(li" +
|
||||
"Icon)\r\n .append($(\'<span>\').text(response.Id == r" +
|
||||
"esponse.Name ? response.Id : response.Name + \' [\' + response.Id + \']\'))\r\n " +
|
||||
" .append($(\'<i>\').addClass(\'fa fa-times-circle remove\'))" +
|
||||
"\r\n .addClass(response.Type)\r\n " +
|
||||
" .attr(\'data-subjectid\', response.Id)\r\n " +
|
||||
" .attr(\'data-subjectstatus\', \'new\');\r\n\r\n list.append" +
|
||||
"(li);\r\n\r\n updateNoSubjects();\r\n " +
|
||||
" } else {\r\n alert(\'That subject has already been add" +
|
||||
"ed\');\r\n }\r\n }\r\n els" +
|
||||
"e {\r\n alert(response.Name + \' [\'+response.Id+\'] is a \' + " +
|
||||
"response.Type + \'. Only users and groups can be added.\');\r\n }" +
|
||||
"\r\n } else {\r\n alert(\'Unknown Id\');\r\n " +
|
||||
" }\r\n }).fail(function (jqXHR, textStatus, errorThrown) {\r\n " +
|
||||
" alert(\'Error: \' + errorThrown);\r\n });\r\n retu" +
|
||||
"rn false;\r\n }\r\n\r\n function updateNoSubjects() {\r\n i" +
|
||||
"f (list.find(\'li:visible\').length > 0)\r\n noSubjects.hide();\r\n " +
|
||||
" else\r\n noSubjects.show();\r\n }\r\n\r\n function " +
|
||||
"saveChanges() {\r\n var form = $(\'#Config_AuthRoles_Subjects_Update_Dia" +
|
||||
"log_Form\').empty();\r\n\r\n list.find(\'li[data-subjectstatus!=\"removed\"]\'" +
|
||||
").each(function () {\r\n var subjectId = $(this).attr(\'data-subject" +
|
||||
"id\');\r\n\r\n form.append($(\'<input>\').attr({\r\n \'n" +
|
||||
"ame\': \'Subjects\',\r\n \'type\': \'hidden\'\r\n }).val(" +
|
||||
"subjectId));\r\n\r\n }).get();\r\n\r\n form.submit();\r\n\r\n " +
|
||||
" dialog.dialog(\"disable\");\r\n dialog.dialog(\"option\", \"buttons\", nul" +
|
||||
"l);\r\n }\r\n\r\n $(function () {\r\n $(\'#Config_AuthRoles_Upda" +
|
||||
"teAdministrators\').click(showDialog);\r\n });\r\n\r\n })();\r\n</script>\r\n<!--" +
|
||||
" #endregion -->\r\n<div");
|
||||
|
||||
WriteLiteral(" class=\"actionBar\"");
|
||||
|
||||
@@ -467,7 +472,7 @@ WriteLiteral(" class=\"button\"");
|
||||
WriteLiteral(">Update Disco Administrators [");
|
||||
|
||||
|
||||
#line 221 "..\..\Areas\Config\Views\AuthorizationRole\Index.cshtml"
|
||||
#line 226 "..\..\Areas\Config\Views\AuthorizationRole\Index.cshtml"
|
||||
Write(Model.AdministratorSubjects.Count);
|
||||
|
||||
|
||||
@@ -478,7 +483,7 @@ WriteLiteral("]</a>\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 222 "..\..\Areas\Config\Views\AuthorizationRole\Index.cshtml"
|
||||
#line 227 "..\..\Areas\Config\Views\AuthorizationRole\Index.cshtml"
|
||||
Write(Html.ActionLinkButton("Create Authorization Role", MVC.Config.AuthorizationRole.Create()));
|
||||
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
|
||||
textAdd.watermark('Search Subjects')
|
||||
.autocomplete({
|
||||
source: '@(Url.Action(MVC.API.AuthorizationRole.SearchSubjects()))',
|
||||
source: '@(Url.Action(MVC.API.System.SearchSubjects()))',
|
||||
minLength: 2,
|
||||
focus: function (e, ui) {
|
||||
textAdd.val(ui.item.Id);
|
||||
@@ -169,32 +169,36 @@
|
||||
var id = textAdd.val();
|
||||
|
||||
$.ajax({
|
||||
url: '@Url.Action(MVC.API.AuthorizationRole.Subject())',
|
||||
url: '@Url.Action(MVC.API.System.Subject())',
|
||||
method: 'post',
|
||||
data: { Id: id }
|
||||
}).done(function(response){
|
||||
if (response){
|
||||
if (list.find('li[data-subjectid="'+response.Id.replace('\\', '\\\\')+'"]').length == 0){
|
||||
if (response.IsGroup || response.IsUserAccount) {
|
||||
if (list.find('li[data-subjectid="'+response.Id.replace('\\', '\\\\')+'"]').length == 0){
|
||||
|
||||
var liIcon = $('<i>').addClass('fa fa-lg');
|
||||
if (response.Type === 'user')
|
||||
liIcon.addClass('fa-user');
|
||||
else
|
||||
liIcon.addClass('fa-users');
|
||||
var liIcon = $('<i>').addClass('fa fa-lg');
|
||||
if (response.Type === 'user')
|
||||
liIcon.addClass('fa-user');
|
||||
else
|
||||
liIcon.addClass('fa-users');
|
||||
|
||||
var li = $('<li>')
|
||||
.append(liIcon)
|
||||
.append($('<span>').text(response.Id == response.Name ? response.Id : response.Name + ' [' + response.Id + ']'))
|
||||
.append($('<i>').addClass('fa fa-times-circle remove'))
|
||||
.addClass(response.Type)
|
||||
.attr('data-subjectid', response.Id)
|
||||
.attr('data-subjectstatus', 'new');
|
||||
var li = $('<li>')
|
||||
.append(liIcon)
|
||||
.append($('<span>').text(response.Id == response.Name ? response.Id : response.Name + ' [' + response.Id + ']'))
|
||||
.append($('<i>').addClass('fa fa-times-circle remove'))
|
||||
.addClass(response.Type)
|
||||
.attr('data-subjectid', response.Id)
|
||||
.attr('data-subjectstatus', 'new');
|
||||
|
||||
list.append(li);
|
||||
list.append(li);
|
||||
|
||||
updateNoSubjects();
|
||||
updateNoSubjects();
|
||||
}else{
|
||||
alert('That subject has already been added');
|
||||
}
|
||||
}else{
|
||||
alert('That subject has already been added');
|
||||
alert(response.Name + ' ['+response.Id+'] is a ' + response.Type + '. Only users and groups can be added.');
|
||||
}
|
||||
}else{
|
||||
alert('Unknown Id');
|
||||
|
||||
@@ -500,7 +500,7 @@ WriteLiteral("></form>\r\n </div>\r\n <scr
|
||||
|
||||
|
||||
#line 115 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
|
||||
Write(Url.Action(MVC.API.AuthorizationRole.SearchSubjects()));
|
||||
Write(Url.Action(MVC.API.System.SearchSubjects()));
|
||||
|
||||
|
||||
#line default
|
||||
@@ -544,7 +544,7 @@ WriteLiteral("\',\r\n minLength: 2,\r
|
||||
|
||||
|
||||
#line 172 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
|
||||
Write(Url.Action(MVC.API.AuthorizationRole.Subject()));
|
||||
Write(Url.Action(MVC.API.System.Subject()));
|
||||
|
||||
|
||||
#line default
|
||||
@@ -552,49 +552,54 @@ WriteLiteral("\',\r\n minLength: 2,\r
|
||||
WriteLiteral("\',\r\n method: \'post\',\r\n " +
|
||||
" data: { Id: id }\r\n }).done(function(r" +
|
||||
"esponse){\r\n if (response){\r\n " +
|
||||
" if (list.find(\'li[data-subjectid=\"\'+response.Id.replace(\'" +
|
||||
"\\\\\', \'\\\\\\\\\')+\'\"]\').length == 0){\r\n \r\n" +
|
||||
" var liIcon = $(\'<i>\').addClass(\'fa f" +
|
||||
"a-lg\');\r\n if (response.Type === \'user" +
|
||||
"\')\r\n liIcon.addClass(\'fa-user\');\r" +
|
||||
"\n else\r\n " +
|
||||
" liIcon.addClass(\'fa-users\');\r\n\r\n " +
|
||||
" var li = $(\'<li>\')\r\n " +
|
||||
" .append(liIcon)\r\n .append($(\'<" +
|
||||
"span>\').text(response.Id == response.Name ? response.Id : response.Name + \' [\' " +
|
||||
"+ response.Id + \']\'))\r\n .append($" +
|
||||
"(\'<i>\').addClass(\'fa fa-times-circle remove\'))\r\n " +
|
||||
" .addClass(response.Type)\r\n " +
|
||||
" .attr(\'data-subjectid\', response.Id)\r\n " +
|
||||
" .attr(\'data-subjectstatus\', \'new\');\r\n\r\n " +
|
||||
" list.append(li);\r\n\r\n " +
|
||||
" updateNoSubjects(); \r\n " +
|
||||
" }else{\r\n aler" +
|
||||
"t(\'That subject has already been added\');\r\n " +
|
||||
" }\r\n }else{\r\n " +
|
||||
" alert(\'Unknown Id\');\r\n }\r\n " +
|
||||
" }).fail(function(jqXHR, textStatus, errorThrown){\r\n " +
|
||||
" alert(\'Error: \' + errorThrown);\r\n " +
|
||||
" });\r\n }\r\n\r\n " +
|
||||
" function updateNoSubjects(){\r\n if (list.find" +
|
||||
"(\'li:visible\').length > 0)\r\n noSubjects.hide(" +
|
||||
");\r\n else\r\n no" +
|
||||
"Subjects.show();\r\n }\r\n\r\n f" +
|
||||
"unction saveChanges(){\r\n var form = $(\'#Config_Au" +
|
||||
"thRoles_Subjects_Update_Dialog_Form\').empty();\r\n\r\n " +
|
||||
" list.find(\'li[data-subjectstatus!=\"removed\"]\').each(function(){\r\n " +
|
||||
" var subjectId = $(this).attr(\'data-subjectid\');\r\n " +
|
||||
" \r\n form.append($(" +
|
||||
"\'<input>\').attr({\r\n \'name\': \'Subjects\',\r\n" +
|
||||
" \'type\': \'hidden\'\r\n " +
|
||||
" }).val(subjectId));\r\n\r\n }).get();\r\n" +
|
||||
"\r\n form.submit();\r\n\r\n " +
|
||||
" dialog.dialog(\"disable\");\r\n dialog.dialog(\"op" +
|
||||
"tion\", \"buttons\", null);\r\n }\r\n\r\n " +
|
||||
" $(function(){\r\n $(\'#Config_AuthRoles_Subje" +
|
||||
"cts_Update\').click(showDialog);\r\n });\r\n\r\n " +
|
||||
" })();\r\n </script>\r\n </div>\r\n " +
|
||||
" </td>\r\n </tr>\r\n <tr>\r\n <td");
|
||||
" if (response.IsGroup || response.IsUserAccount) {\r\n " +
|
||||
" if (list.find(\'li[data-subjectid=\"\'+respon" +
|
||||
"se.Id.replace(\'\\\\\', \'\\\\\\\\\')+\'\"]\').length == 0){\r\n " +
|
||||
" \r\n var liIcon = $(\'<" +
|
||||
"i>\').addClass(\'fa fa-lg\');\r\n if (" +
|
||||
"response.Type === \'user\')\r\n l" +
|
||||
"iIcon.addClass(\'fa-user\');\r\n else" +
|
||||
"\r\n liIcon.addClass(\'fa-users\'" +
|
||||
");\r\n\r\n var li = $(\'<li>\')\r\n " +
|
||||
" .append(liIcon)\r\n " +
|
||||
" .append($(\'<span>\').text(response.Id == respo" +
|
||||
"nse.Name ? response.Id : response.Name + \' [\' + response.Id + \']\'))\r\n " +
|
||||
" .append($(\'<i>\').addClass(\'fa fa-times" +
|
||||
"-circle remove\'))\r\n .addClass" +
|
||||
"(response.Type)\r\n .attr(\'data" +
|
||||
"-subjectid\', response.Id)\r\n ." +
|
||||
"attr(\'data-subjectstatus\', \'new\');\r\n\r\n " +
|
||||
" list.append(li);\r\n\r\n update" +
|
||||
"NoSubjects(); \r\n " +
|
||||
" }else{\r\n alert" +
|
||||
"(\'That subject has already been added\');\r\n " +
|
||||
" }\r\n }else{\r\n " +
|
||||
" alert(response.Name + \' [\'+response.Id+\'] is a \' + response" +
|
||||
".Type + \'. Only users and groups can be added.\');\r\n " +
|
||||
" }\r\n }else{\r\n " +
|
||||
" alert(\'Unknown Id\');\r\n }\r\n " +
|
||||
" }).fail(function(jqXHR, textStatus, errorThrown){" +
|
||||
"\r\n alert(\'Error: \' + errorThrown);\r\n " +
|
||||
" });\r\n }\r\n\r\n " +
|
||||
" function updateNoSubjects(){\r\n if (l" +
|
||||
"ist.find(\'li:visible\').length > 0)\r\n noSubjec" +
|
||||
"ts.hide();\r\n else\r\n " +
|
||||
" noSubjects.show();\r\n }\r\n\r\n " +
|
||||
" function saveChanges(){\r\n var form = $(\'#C" +
|
||||
"onfig_AuthRoles_Subjects_Update_Dialog_Form\').empty();\r\n\r\n " +
|
||||
" list.find(\'li[data-subjectstatus!=\"removed\"]\').each(function(){\r\n " +
|
||||
" var subjectId = $(this).attr(\'data-subjectid\');\r\n" +
|
||||
" \r\n form.a" +
|
||||
"ppend($(\'<input>\').attr({\r\n \'name\': \'Subj" +
|
||||
"ects\',\r\n \'type\': \'hidden\'\r\n " +
|
||||
" }).val(subjectId));\r\n\r\n })." +
|
||||
"get();\r\n\r\n form.submit();\r\n\r\n " +
|
||||
" dialog.dialog(\"disable\");\r\n dialog.di" +
|
||||
"alog(\"option\", \"buttons\", null);\r\n }\r\n\r\n " +
|
||||
" $(function(){\r\n $(\'#Config_AuthRol" +
|
||||
"es_Subjects_Update\').click(showDialog);\r\n });\r\n\r\n " +
|
||||
" })();\r\n </script>\r\n </div>" +
|
||||
"\r\n </td>\r\n </tr>\r\n <tr>\r\n <td");
|
||||
|
||||
WriteLiteral(" colspan=\"2\"");
|
||||
|
||||
@@ -613,7 +618,7 @@ WriteLiteral(" class=\"button small disabled\"");
|
||||
WriteLiteral(">Save Changes</a>");
|
||||
|
||||
|
||||
#line 247 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
|
||||
#line 251 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
|
||||
Write(AjaxHelpers.AjaxLoader());
|
||||
|
||||
|
||||
@@ -623,7 +628,7 @@ WriteLiteral("\r\n </div>\r\n <script>\r\n
|
||||
"(){\r\n var claimNodes = ");
|
||||
|
||||
|
||||
#line 251 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
|
||||
#line 255 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
|
||||
Write(new HtmlString(Newtonsoft.Json.JsonConvert.SerializeObject(Model.ClaimNavigatorFancyTreeNodes)));
|
||||
|
||||
|
||||
@@ -662,7 +667,7 @@ WriteLiteral(@";
|
||||
url: '");
|
||||
|
||||
|
||||
#line 281 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
|
||||
#line 285 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
|
||||
Write(Url.Action(MVC.API.AuthorizationRole.UpdateClaims(Model.Token.Role.Id)));
|
||||
|
||||
|
||||
@@ -702,7 +707,7 @@ WriteLiteral(">\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 307 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
|
||||
#line 311 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
|
||||
Write(Html.ActionLinkButton("Delete", MVC.API.AuthorizationRole.Delete(Model.Token.Role.Id, true), "Config_AuthRoles_Actions_Delete_Button"));
|
||||
|
||||
|
||||
|
||||
@@ -523,24 +523,15 @@
|
||||
<td>@if (canConfig)
|
||||
{
|
||||
<div id="DeviceProfile_OrganisationalUnit" class="code" data-value="@Model.DeviceProfile.OrganisationalUnit">
|
||||
@if (string.IsNullOrEmpty(Model.DeviceProfile.OrganisationalUnit))
|
||||
{
|
||||
<span>{Default Computers Container}</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
var domain = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.GetDomainByDistinguishedName(Model.DeviceProfile.OrganisationalUnit);
|
||||
|
||||
<span>
|
||||
@Disco.Services.Interop.ActiveDirectory.ActiveDirectoryExtensions.GetFriendlyOrganisationalUnitName(domain, Model.DeviceProfile.OrganisationalUnit)
|
||||
</span>
|
||||
}
|
||||
<span>
|
||||
@Model.FriendlyOrganisationalUnitName
|
||||
</span>
|
||||
</div>
|
||||
<a id="changeOrganisationalUnit" href="#" class="button small">Change</a>@AjaxHelpers.AjaxLoader()
|
||||
<div id="dialogOrganisationalUnit" title="Organisational Unit" class="dialog">
|
||||
<div id="dialogOrganisationalUnit_Loading">
|
||||
@AjaxHelpers.AjaxLoader() Loading Organisational Units
|
||||
</div>
|
||||
@AjaxHelpers.AjaxLoader() Loading Organisational Units
|
||||
</div>
|
||||
<div id="treeOrganisationalUnit" class="organisationalUnitTree">
|
||||
</div>
|
||||
</div>
|
||||
@@ -660,18 +651,9 @@
|
||||
else
|
||||
{
|
||||
<div id="displayOrganisationalUnit" class="code">
|
||||
@if (string.IsNullOrEmpty(Model.DeviceProfile.OrganisationalUnit))
|
||||
{
|
||||
<span>{Default Computers Container}</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
var domain = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.GetDomainByDistinguishedName(Model.DeviceProfile.OrganisationalUnit);
|
||||
|
||||
<span>
|
||||
@Disco.Services.Interop.ActiveDirectory.ActiveDirectoryExtensions.GetFriendlyOrganisationalUnitName(domain, Model.DeviceProfile.OrganisationalUnit)
|
||||
</span>
|
||||
}
|
||||
<span>
|
||||
@Model.FriendlyOrganisationalUnitName
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
<div style="margin-top: 8px;">
|
||||
|
||||
@@ -1597,56 +1597,18 @@ WriteLiteral(" data-value=\"");
|
||||
#line hidden
|
||||
WriteLiteral("\"");
|
||||
|
||||
WriteLiteral(">\r\n");
|
||||
WriteLiteral(">\r\n <span>\r\n");
|
||||
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 526 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 526 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
if (string.IsNullOrEmpty(Model.DeviceProfile.OrganisationalUnit))
|
||||
{
|
||||
#line 527 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
Write(Model.FriendlyOrganisationalUnitName);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <span>{Default Computers Container}</span>\r\n");
|
||||
|
||||
|
||||
#line 529 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
var domain = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.GetDomainByDistinguishedName(Model.DeviceProfile.OrganisationalUnit);
|
||||
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <span>\r\n");
|
||||
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 535 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
Write(Disco.Services.Interop.ActiveDirectory.ActiveDirectoryExtensions.GetFriendlyOrganisationalUnitName(domain, Model.DeviceProfile.OrganisationalUnit));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n </span>\r\n");
|
||||
|
||||
|
||||
#line 537 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
}
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" </div>\r\n");
|
||||
WriteLiteral("\r\n </span>\r\n </div>\r\n");
|
||||
|
||||
WriteLiteral(" <a");
|
||||
|
||||
@@ -1659,20 +1621,20 @@ WriteLiteral(" class=\"button small\"");
|
||||
WriteLiteral(">Change</a>");
|
||||
|
||||
|
||||
#line 539 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 530 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 539 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 530 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
Write(AjaxHelpers.AjaxLoader());
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 539 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 530 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
|
||||
|
||||
|
||||
@@ -1692,17 +1654,17 @@ WriteLiteral(" id=\"dialogOrganisationalUnit_Loading\"");
|
||||
|
||||
WriteLiteral(">\r\n");
|
||||
|
||||
WriteLiteral(" ");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 542 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
Write(AjaxHelpers.AjaxLoader());
|
||||
#line 533 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
Write(AjaxHelpers.AjaxLoader());
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" Loading Organisational Units\r\n </div>\r\n " +
|
||||
" <div");
|
||||
WriteLiteral(" Loading Organisational Units\r\n </div>\r\n <d" +
|
||||
"iv");
|
||||
|
||||
WriteLiteral(" id=\"treeOrganisationalUnit\"");
|
||||
|
||||
@@ -1717,7 +1679,7 @@ WriteLiteral(" type=\"text/javascript\"");
|
||||
WriteLiteral(">\r\n $(function () {\r\n var ouSetUrl = \'");
|
||||
|
||||
|
||||
#line 549 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 540 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
Write(Url.Action(MVC.API.DeviceProfile.UpdateOrganisationalUnit(Model.DeviceProfile.Id, null, true)));
|
||||
|
||||
|
||||
@@ -1759,7 +1721,7 @@ WriteLiteral("\';\r\n var ouValue = $(\'#DeviceProfile_Or
|
||||
" $ouTree.css(\'height\', \'100%\');\r\n\r\n $.getJSON(\'");
|
||||
|
||||
|
||||
#line 599 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 590 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
Write(Url.Action(MVC.API.System.DomainOrganisationalUnits()));
|
||||
|
||||
|
||||
@@ -1806,7 +1768,7 @@ WriteLiteral("\', null, function (data) {\r\n
|
||||
" </script>\r\n");
|
||||
|
||||
|
||||
#line 659 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 650 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1820,59 +1782,21 @@ WriteLiteral(" id=\"displayOrganisationalUnit\"");
|
||||
|
||||
WriteLiteral(" class=\"code\"");
|
||||
|
||||
WriteLiteral(">\r\n");
|
||||
WriteLiteral(">\r\n <span>\r\n");
|
||||
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 663 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 663 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
if (string.IsNullOrEmpty(Model.DeviceProfile.OrganisationalUnit))
|
||||
{
|
||||
#line 655 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
Write(Model.FriendlyOrganisationalUnitName);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <span>{Default Computers Container}</span>\r\n");
|
||||
WriteLiteral("\r\n </span>\r\n </div>\r\n");
|
||||
|
||||
|
||||
#line 666 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
var domain = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.GetDomainByDistinguishedName(Model.DeviceProfile.OrganisationalUnit);
|
||||
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <span>\r\n");
|
||||
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 672 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
Write(Disco.Services.Interop.ActiveDirectory.ActiveDirectoryExtensions.GetFriendlyOrganisationalUnitName(domain, Model.DeviceProfile.OrganisationalUnit));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n </span>\r\n");
|
||||
|
||||
|
||||
#line 674 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
}
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" </div>\r\n");
|
||||
|
||||
|
||||
#line 676 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 658 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -1885,13 +1809,13 @@ WriteLiteral(" style=\"margin-top: 8px;\"");
|
||||
WriteLiteral(">\r\n");
|
||||
|
||||
|
||||
#line 678 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 660 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 678 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 660 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
if (canConfig)
|
||||
{
|
||||
|
||||
@@ -1907,7 +1831,7 @@ WriteLiteral(" type=\"checkbox\"");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 680 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 662 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
Write(Model.DeviceProfile.EnforceOrganisationalUnit ? new MvcHtmlString("checked=\"checked\" ") : new MvcHtmlString(string.Empty));
|
||||
|
||||
|
||||
@@ -1928,7 +1852,7 @@ WriteLiteral(@">
|
||||
$.getJSON('");
|
||||
|
||||
|
||||
#line 687 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 669 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
Write(Url.Action(MVC.API.DeviceProfile.UpdateEnforceOrganisationalUnit(Model.DeviceProfile.Id)));
|
||||
|
||||
|
||||
@@ -1948,7 +1872,7 @@ WriteLiteral(@"', data, function (response, result) {
|
||||
");
|
||||
|
||||
|
||||
#line 698 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 680 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1965,7 +1889,7 @@ WriteLiteral(" type=\"checkbox\"");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 701 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 683 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
Write(Model.DeviceProfile.EnforceOrganisationalUnit ? new MvcHtmlString("checked=\"checked\" ") : new MvcHtmlString(string.Empty));
|
||||
|
||||
|
||||
@@ -1974,7 +1898,7 @@ WriteLiteral(" ");
|
||||
WriteLiteral(" disabled=\"disabled\" />\r\n");
|
||||
|
||||
|
||||
#line 702 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 684 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -1990,7 +1914,7 @@ WriteLiteral(">\r\n Enforce Organisational Unit\r\n
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 706 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 688 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
Write(AjaxHelpers.AjaxLoader());
|
||||
|
||||
|
||||
@@ -2000,7 +1924,7 @@ WriteLiteral("\r\n </div>\r\n </td>\r\n </tr>\r
|
||||
"\n");
|
||||
|
||||
|
||||
#line 712 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 694 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
if (canDelete)
|
||||
{
|
||||
|
||||
@@ -2055,7 +1979,7 @@ WriteLiteral(@">
|
||||
");
|
||||
|
||||
|
||||
#line 748 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 730 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -2068,13 +1992,13 @@ WriteLiteral(" class=\"actionBar\"");
|
||||
WriteLiteral(">\r\n");
|
||||
|
||||
|
||||
#line 750 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 732 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 750 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 732 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
if (canDelete)
|
||||
{
|
||||
|
||||
@@ -2082,14 +2006,14 @@ WriteLiteral(">\r\n");
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 752 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 734 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
Write(Html.ActionLinkButton("Delete", MVC.API.DeviceProfile.Delete(Model.DeviceProfile.Id, true), "buttonDelete"));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 752 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 734 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
|
||||
}
|
||||
|
||||
@@ -2099,7 +2023,7 @@ WriteLiteral(">\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 754 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 736 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
if (Authorization.Has(Claims.Device.Actions.Export))
|
||||
{
|
||||
|
||||
@@ -2107,14 +2031,14 @@ WriteLiteral(" ");
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 756 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 738 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
Write(Html.ActionLinkButton("Export Devices", MVC.API.DeviceProfile.ExportDevices(Model.DeviceProfile.Id)));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 756 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 738 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
|
||||
}
|
||||
|
||||
@@ -2124,7 +2048,7 @@ WriteLiteral(" ");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 758 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 740 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
if (Authorization.Has(Claims.Device.Search))
|
||||
{
|
||||
|
||||
@@ -2132,14 +2056,14 @@ WriteLiteral(" ");
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 760 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 742 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
Write(Html.ActionLinkButton("View Devices", MVC.Search.Query(Model.DeviceProfile.Id.ToString(), "DeviceProfile")));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 760 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
#line 742 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml"
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -369,7 +369,7 @@
|
||||
|
||||
textAdd.watermark('Search Subjects')
|
||||
.autocomplete({
|
||||
source: '@(Url.Action(MVC.API.JobQueue.SearchSubjects()))',
|
||||
source: '@(Url.Action(MVC.API.System.SearchSubjects()))',
|
||||
minLength: 2,
|
||||
focus: function (e, ui) {
|
||||
textAdd.val(ui.item.Id);
|
||||
@@ -428,32 +428,36 @@
|
||||
var id = textAdd.val();
|
||||
|
||||
$.ajax({
|
||||
url: '@Url.Action(MVC.API.JobQueue.Subject())',
|
||||
url: '@Url.Action(MVC.API.System.Subject())',
|
||||
method: 'post',
|
||||
data: { Id: id }
|
||||
}).done(function (response) {
|
||||
if (response) {
|
||||
if (list.find('li[data-subjectid="' + response.Id + '"]').filter('[data-status!="removed"]').length == 0) {
|
||||
if (response.IsGroup || response.IsUserAccount) {
|
||||
if (list.find('li[data-subjectid="' + response.Id + '"]').filter('[data-status!="removed"]').length == 0) {
|
||||
|
||||
var liIcon = $('<i>').addClass('fa fa-lg');
|
||||
if (response.Type === 'user')
|
||||
liIcon.addClass('fa-user');
|
||||
else
|
||||
liIcon.addClass('fa-users');
|
||||
var liIcon = $('<i>').addClass('fa fa-lg');
|
||||
if (response.Type === 'user')
|
||||
liIcon.addClass('fa-user');
|
||||
else
|
||||
liIcon.addClass('fa-users');
|
||||
|
||||
var li = $('<li>')
|
||||
.append(liIcon)
|
||||
.append($('<span>').text(response.Id == response.Name ? response.Id : response.Name + ' [' + response.Id + ']'))
|
||||
.append($('<i>').addClass('fa fa-times-circle remove'))
|
||||
.addClass(response.Type)
|
||||
.attr('data-subjectid', response.Id)
|
||||
.attr('data-subjectstatus', 'new');
|
||||
var li = $('<li>')
|
||||
.append(liIcon)
|
||||
.append($('<span>').text(response.Id == response.Name ? response.Id : response.Name + ' [' + response.Id + ']'))
|
||||
.append($('<i>').addClass('fa fa-times-circle remove'))
|
||||
.addClass(response.Type)
|
||||
.attr('data-subjectid', response.Id)
|
||||
.attr('data-subjectstatus', 'new');
|
||||
|
||||
list.append(li);
|
||||
list.append(li);
|
||||
|
||||
updateNoSubjects();
|
||||
updateNoSubjects();
|
||||
} else {
|
||||
alert('That subject has already been added');
|
||||
}
|
||||
} else {
|
||||
alert('That subject has already been added');
|
||||
alert(response.Name + ' [' + response.Id + '] is a ' + response.Type + '. Only users and groups can be added.');
|
||||
}
|
||||
} else {
|
||||
alert('Unknown Id');
|
||||
|
||||
@@ -1321,7 +1321,7 @@ WriteLiteral("></form>\r\n </div>\r\n
|
||||
|
||||
|
||||
#line 372 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
Write(Url.Action(MVC.API.JobQueue.SearchSubjects()));
|
||||
Write(Url.Action(MVC.API.System.SearchSubjects()));
|
||||
|
||||
|
||||
#line default
|
||||
@@ -1368,7 +1368,7 @@ WriteLiteral("\',\r\n minLength:
|
||||
|
||||
|
||||
#line 431 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
Write(Url.Action(MVC.API.JobQueue.Subject()));
|
||||
Write(Url.Action(MVC.API.System.Subject()));
|
||||
|
||||
|
||||
#line default
|
||||
@@ -1376,53 +1376,58 @@ WriteLiteral("\',\r\n minLength:
|
||||
WriteLiteral("\',\r\n method: \'post\',\r\n " +
|
||||
" data: { Id: id }\r\n }).don" +
|
||||
"e(function (response) {\r\n if (response) {" +
|
||||
"\r\n if (list.find(\'li[data-subjectid=\"" +
|
||||
"\' + response.Id + \'\"]\').filter(\'[data-status!=\"removed\"]\').length == 0) {\r\n\r\n " +
|
||||
" var liIcon = $(\'<i>\').addClass(\'fa " +
|
||||
"fa-lg\');\r\n if (response.Type === " +
|
||||
"\'user\')\r\n liIcon.addClass(\'fa" +
|
||||
"-user\');\r\n else\r\n " +
|
||||
" liIcon.addClass(\'fa-users\');\r\n\r\n " +
|
||||
" var li = $(\'<li>\')\r\n " +
|
||||
" .append(liIcon)\r\n " +
|
||||
" .append($(\'<span>\').text(response.Id == response.Name ? respons" +
|
||||
"e.Id : response.Name + \' [\' + response.Id + \']\'))\r\n " +
|
||||
" .append($(\'<i>\').addClass(\'fa fa-times-circle remove\'))\r\n" +
|
||||
" .addClass(response.Type)\r\n " +
|
||||
" .attr(\'data-subjectid\', respon" +
|
||||
"se.Id)\r\n .attr(\'data-subjects" +
|
||||
"tatus\', \'new\');\r\n\r\n list.append(l" +
|
||||
"i);\r\n\r\n updateNoSubjects();\r\n " +
|
||||
" } else {\r\n " +
|
||||
" alert(\'That subject has already been added\');\r\n " +
|
||||
" }\r\n } else {" +
|
||||
"\r\n alert(\'Unknown Id\');\r\n " +
|
||||
" }\r\n }).fail(funct" +
|
||||
"ion (jqXHR, textStatus, errorThrown) {\r\n " +
|
||||
"alert(\'Error: \' + errorThrown);\r\n });\r\n " +
|
||||
" }\r\n\r\n function upda" +
|
||||
"teNoSubjects() {\r\n if (list.find(\'li:visible\'" +
|
||||
").length > 0)\r\n noSubjects.hide();\r\n " +
|
||||
" else\r\n noS" +
|
||||
"ubjects.show();\r\n }\r\n\r\n " +
|
||||
" function saveChanges() {\r\n var form = $" +
|
||||
"(\'#Config_JobQueues_Subjects_Update_Dialog_Form\').empty();\r\n\r\n " +
|
||||
" list.find(\'li[data-subjectstatus!=\"removed\"]\').each(function (" +
|
||||
") {\r\n var subjectId = $(this).attr(\'data-" +
|
||||
"subjectid\');\r\n\r\n form.append($(\'<input>\')" +
|
||||
".attr({\r\n \'name\': \'Subjects\',\r\n " +
|
||||
" \'type\': \'hidden\'\r\n " +
|
||||
" }).val(subjectId));\r\n\r\n }).ge" +
|
||||
"t();\r\n\r\n form.submit();\r\n\r\n " +
|
||||
" dialog.dialog(\"disable\");\r\n " +
|
||||
" dialog.dialog(\"option\", \"buttons\", null);\r\n }\r\n\r" +
|
||||
"\n $(function () {\r\n " +
|
||||
" $(\'#Config_JobQueues_Subjects_Update\').click(showDialog);\r\n " +
|
||||
" });\r\n\r\n })();\r\n " +
|
||||
" </script>\r\n </div>\r\n");
|
||||
"\r\n if (response.IsGroup || response.I" +
|
||||
"sUserAccount) {\r\n if (list.find(\'" +
|
||||
"li[data-subjectid=\"\' + response.Id + \'\"]\').filter(\'[data-status!=\"removed\"]\').le" +
|
||||
"ngth == 0) {\r\n\r\n var liIcon =" +
|
||||
" $(\'<i>\').addClass(\'fa fa-lg\');\r\n " +
|
||||
" if (response.Type === \'user\')\r\n " +
|
||||
" liIcon.addClass(\'fa-user\');\r\n " +
|
||||
" else\r\n liIco" +
|
||||
"n.addClass(\'fa-users\');\r\n\r\n v" +
|
||||
"ar li = $(\'<li>\')\r\n .appe" +
|
||||
"nd(liIcon)\r\n .append($(\'<" +
|
||||
"span>\').text(response.Id == response.Name ? response.Id : response.Name + \' [\' +" +
|
||||
" response.Id + \']\'))\r\n .a" +
|
||||
"ppend($(\'<i>\').addClass(\'fa fa-times-circle remove\'))\r\n " +
|
||||
" .addClass(response.Type)\r\n " +
|
||||
" .attr(\'data-subjectid\', response.Id)\r\n " +
|
||||
" .attr(\'data-subjectstatus\', \'new\'" +
|
||||
");\r\n\r\n list.append(li);\r\n\r\n " +
|
||||
" updateNoSubjects();\r\n " +
|
||||
" } else {\r\n " +
|
||||
" alert(\'That subject has already been added\');\r\n " +
|
||||
" }\r\n " +
|
||||
" } else {\r\n alert(response.Name" +
|
||||
" + \' [\' + response.Id + \'] is a \' + response.Type + \'. Only users and groups can" +
|
||||
" be added.\');\r\n }\r\n " +
|
||||
" } else {\r\n aler" +
|
||||
"t(\'Unknown Id\');\r\n }\r\n " +
|
||||
" }).fail(function (jqXHR, textStatus, errorThrown) {\r\n " +
|
||||
" alert(\'Error: \' + errorThrown);\r\n " +
|
||||
" });\r\n }\r\n\r\n " +
|
||||
" function updateNoSubjects() {\r\n " +
|
||||
" if (list.find(\'li:visible\').length > 0)\r\n " +
|
||||
" noSubjects.hide();\r\n else\r\n " +
|
||||
" noSubjects.show();\r\n }" +
|
||||
"\r\n\r\n function saveChanges() {\r\n " +
|
||||
" var form = $(\'#Config_JobQueues_Subjects_Update_Dialog_Form\')." +
|
||||
"empty();\r\n\r\n list.find(\'li[data-subjectstatus" +
|
||||
"!=\"removed\"]\').each(function () {\r\n var s" +
|
||||
"ubjectId = $(this).attr(\'data-subjectid\');\r\n\r\n " +
|
||||
" form.append($(\'<input>\').attr({\r\n " +
|
||||
" \'name\': \'Subjects\',\r\n \'type\': \'hid" +
|
||||
"den\'\r\n }).val(subjectId));\r\n\r\n " +
|
||||
" }).get();\r\n\r\n form.s" +
|
||||
"ubmit();\r\n\r\n dialog.dialog(\"disable\");\r\n " +
|
||||
" dialog.dialog(\"option\", \"buttons\", null);\r\n " +
|
||||
" }\r\n\r\n $(function () {\r\n" +
|
||||
" $(\'#Config_JobQueues_Subjects_Update\').click" +
|
||||
"(showDialog);\r\n });\r\n\r\n " +
|
||||
" })();\r\n </script>\r\n </div>\r\n");
|
||||
|
||||
|
||||
#line 499 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 503 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -1432,13 +1437,13 @@ WriteLiteral(" </td>\r\n </tr>\r\n <tr>\r\n
|
||||
" Jobs:</th>\r\n <td>\r\n <div>\r\n");
|
||||
|
||||
|
||||
#line 506 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 510 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 506 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 510 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
if (Model.Token.JobQueue.JobSubTypes.Count > 0)
|
||||
{
|
||||
|
||||
@@ -1448,13 +1453,13 @@ WriteLiteral(" </td>\r\n </tr>\r\n <tr>\r\n
|
||||
WriteLiteral(" <ul>\r\n");
|
||||
|
||||
|
||||
#line 509 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 513 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 509 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 513 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
foreach (var jobType in Model.Token.JobQueue.JobSubTypes.GroupBy(jst => jst.JobType).OrderBy(jtg => jtg.Key.Description))
|
||||
{
|
||||
|
||||
@@ -1466,7 +1471,7 @@ WriteLiteral(" <li>\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 512 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 516 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
Write(jobType.Key.Description);
|
||||
|
||||
|
||||
@@ -1475,13 +1480,13 @@ WriteLiteral(" ");
|
||||
WriteLiteral("\r\n <ul>\r\n");
|
||||
|
||||
|
||||
#line 514 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 518 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 514 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 518 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
if (jobType.Count() == Model.JobTypes.FirstOrDefault(jt => jt.Id == jobType.Key.Id).JobSubTypes.Count)
|
||||
{
|
||||
|
||||
@@ -1495,7 +1500,7 @@ WriteLiteral(" class=\"smallMessage\"");
|
||||
WriteLiteral(">[All Sub Types]</span></li>\r\n");
|
||||
|
||||
|
||||
#line 517 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 521 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1508,7 +1513,7 @@ WriteLiteral(">[All Sub Types]</span></li>\r\n");
|
||||
WriteLiteral(" <li>");
|
||||
|
||||
|
||||
#line 522 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 526 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
Write(jobSubType.Description);
|
||||
|
||||
|
||||
@@ -1517,7 +1522,7 @@ WriteLiteral(" <li>");
|
||||
WriteLiteral("</li>\r\n");
|
||||
|
||||
|
||||
#line 523 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 527 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1528,7 +1533,7 @@ WriteLiteral(" </ul>\r\n
|
||||
"\n");
|
||||
|
||||
|
||||
#line 527 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 531 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -1537,7 +1542,7 @@ WriteLiteral(" </ul>\r\n
|
||||
WriteLiteral(" </ul>\r\n");
|
||||
|
||||
|
||||
#line 529 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 533 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1552,7 +1557,7 @@ WriteLiteral("<None>");
|
||||
WriteLiteral("\r\n");
|
||||
|
||||
|
||||
#line 533 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 537 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -1561,13 +1566,13 @@ WriteLiteral("\r\n");
|
||||
WriteLiteral(" </div>\r\n");
|
||||
|
||||
|
||||
#line 535 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 539 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 535 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 539 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
if (canConfig)
|
||||
{
|
||||
|
||||
@@ -1595,13 +1600,13 @@ WriteLiteral(" title=\"Job Queue Automatic Types\"");
|
||||
WriteLiteral(">\r\n");
|
||||
|
||||
|
||||
#line 539 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 543 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 539 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 543 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
using (Html.BeginForm(MVC.API.JobQueue.UpdateJobSubTypes(Model.Token.JobQueue.Id, null, true)))
|
||||
{
|
||||
var selectedTypes = Model.Token.JobQueue.JobSubTypes.Select(jst => jst.JobType).Distinct().ToList();
|
||||
@@ -1613,15 +1618,15 @@ WriteLiteral(">\r\n");
|
||||
#line hidden
|
||||
WriteLiteral(" <div");
|
||||
|
||||
WriteAttribute("id", Tuple.Create(" id=\"", 28527), Tuple.Create("\"", 28549)
|
||||
, Tuple.Create(Tuple.Create("", 28532), Tuple.Create("trJobType", 28532), true)
|
||||
WriteAttribute("id", Tuple.Create(" id=\"", 28953), Tuple.Create("\"", 28975)
|
||||
, Tuple.Create(Tuple.Create("", 28958), Tuple.Create("trJobType", 28958), true)
|
||||
|
||||
#line 544 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 28541), Tuple.Create<System.Object, System.Int32>(jt.Id
|
||||
#line 548 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 28967), Tuple.Create<System.Object, System.Int32>(jt.Id
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 28541), false)
|
||||
, 28967), false)
|
||||
);
|
||||
|
||||
WriteLiteral(" class=\"jobTypes\"");
|
||||
@@ -1629,35 +1634,35 @@ WriteLiteral(" class=\"jobTypes\"");
|
||||
WriteLiteral(">\r\n <h4>\r\n <inp" +
|
||||
"ut");
|
||||
|
||||
WriteAttribute("id", Tuple.Create(" id=\"", 28650), Tuple.Create("\"", 28669)
|
||||
, Tuple.Create(Tuple.Create("", 28655), Tuple.Create("Types_", 28655), true)
|
||||
WriteAttribute("id", Tuple.Create(" id=\"", 29076), Tuple.Create("\"", 29095)
|
||||
, Tuple.Create(Tuple.Create("", 29081), Tuple.Create("Types_", 29081), true)
|
||||
|
||||
#line 546 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 28661), Tuple.Create<System.Object, System.Int32>(jt.Id
|
||||
#line 550 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 29087), Tuple.Create<System.Object, System.Int32>(jt.Id
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 28661), false)
|
||||
, 29087), false)
|
||||
);
|
||||
|
||||
WriteLiteral(" class=\"jobType\"");
|
||||
|
||||
WriteLiteral(" type=\"checkbox\"");
|
||||
|
||||
WriteAttribute("value", Tuple.Create(" value=\"", 28702), Tuple.Create("\"", 28718)
|
||||
WriteAttribute("value", Tuple.Create(" value=\"", 29128), Tuple.Create("\"", 29144)
|
||||
|
||||
#line 546 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 28710), Tuple.Create<System.Object, System.Int32>(jt.Id
|
||||
#line 550 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 29136), Tuple.Create<System.Object, System.Int32>(jt.Id
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 28710), false)
|
||||
, 29136), false)
|
||||
);
|
||||
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 546 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 550 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
Write(selectedTypes.Contains(jt) ? "checked=\"checked\"" : null);
|
||||
|
||||
|
||||
@@ -1665,21 +1670,21 @@ WriteLiteral(" ");
|
||||
#line hidden
|
||||
WriteLiteral(" /><label");
|
||||
|
||||
WriteAttribute("for", Tuple.Create(" for=\"", 28789), Tuple.Create("\"", 28809)
|
||||
, Tuple.Create(Tuple.Create("", 28795), Tuple.Create("Types_", 28795), true)
|
||||
WriteAttribute("for", Tuple.Create(" for=\"", 29215), Tuple.Create("\"", 29235)
|
||||
, Tuple.Create(Tuple.Create("", 29221), Tuple.Create("Types_", 29221), true)
|
||||
|
||||
#line 546 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 28801), Tuple.Create<System.Object, System.Int32>(jt.Id
|
||||
#line 550 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 29227), Tuple.Create<System.Object, System.Int32>(jt.Id
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 28801), false)
|
||||
, 29227), false)
|
||||
);
|
||||
|
||||
WriteLiteral(">");
|
||||
|
||||
|
||||
#line 546 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 550 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
Write(jt.Description);
|
||||
|
||||
|
||||
@@ -1687,15 +1692,15 @@ WriteLiteral(">");
|
||||
#line hidden
|
||||
WriteLiteral("</label></h4>\r\n <div");
|
||||
|
||||
WriteAttribute("id", Tuple.Create(" id=\"", 28877), Tuple.Create("\"", 28899)
|
||||
, Tuple.Create(Tuple.Create("", 28882), Tuple.Create("SubTypes_", 28882), true)
|
||||
WriteAttribute("id", Tuple.Create(" id=\"", 29303), Tuple.Create("\"", 29325)
|
||||
, Tuple.Create(Tuple.Create("", 29308), Tuple.Create("SubTypes_", 29308), true)
|
||||
|
||||
#line 547 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 28891), Tuple.Create<System.Object, System.Int32>(jt.Id
|
||||
#line 551 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 29317), Tuple.Create<System.Object, System.Int32>(jt.Id
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 28891), false)
|
||||
, 29317), false)
|
||||
);
|
||||
|
||||
WriteLiteral(" class=\"jobSubTypes\"");
|
||||
@@ -1705,7 +1710,7 @@ WriteLiteral(">\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 548 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 552 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
Write(CommonHelpers.CheckboxBulkSelect(string.Format("CheckboxBulkSelect_{0}", jt.Id), "div"));
|
||||
|
||||
|
||||
@@ -1716,7 +1721,7 @@ WriteLiteral("\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 549 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 553 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
Write(CommonHelpers.CheckBoxList("JobSubTypes", jt.JobSubTypes.OrderBy(jst => jst.Description).ToSelectListItems(Model.Token.JobQueue.JobSubTypes), 2));
|
||||
|
||||
|
||||
@@ -1726,7 +1731,7 @@ WriteLiteral("\r\n </div>\r\n
|
||||
"");
|
||||
|
||||
|
||||
#line 552 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 556 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1774,7 +1779,7 @@ WriteLiteral(" <script>\r\n (function
|
||||
" })();\r\n </script>\r\n");
|
||||
|
||||
|
||||
#line 617 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 621 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -1795,7 +1800,7 @@ WriteLiteral("></i> When jobs of these types are created, they will automat
|
||||
" </table>\r\n</div>\r\n");
|
||||
|
||||
|
||||
#line 625 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 629 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
if (canDelete || canShowJobs)
|
||||
{
|
||||
|
||||
@@ -1811,7 +1816,7 @@ WriteLiteral(">\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 628 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 632 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
Write(Html.ActionLinkButton("Delete", MVC.API.JobQueue.Delete(Model.Token.JobQueue.Id, true), "Config_JobQueues_Actions_Delete_Button"));
|
||||
|
||||
|
||||
@@ -1866,7 +1871,7 @@ WriteLiteral(@">
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 665 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 669 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
Write(Html.ActionLinkButton(string.Format("Show {0} job{1}", Model.OpenJobCount, (Model.OpenJobCount == 1 ? null : "s")), MVC.Job.Queue(Model.Token.JobQueue.Id), "Config_JobQueues_Actions_ShowJobs_Button"));
|
||||
|
||||
|
||||
@@ -1875,7 +1880,7 @@ WriteLiteral(" ");
|
||||
WriteLiteral("\r\n </div>\r\n");
|
||||
|
||||
|
||||
#line 667 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
#line 671 "..\..\Areas\Config\Views\JobQueue\Show.cshtml"
|
||||
}
|
||||
|
||||
#line default
|
||||
|
||||
@@ -148,22 +148,23 @@
|
||||
<th style="width: 135px">Primary Domain:
|
||||
</th>
|
||||
<td>
|
||||
<code><strong>@Model.ADPrimaryDomain.DnsName</strong> <span>[@Model.ADPrimaryDomain.NetBiosName]</span></code>
|
||||
<code><strong>@Model.ADPrimaryDomain.Name</strong> <span>[@Model.ADPrimaryDomain.NetBiosName]</span></code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="width: 135px">Additional Domains:
|
||||
</th>
|
||||
<td>
|
||||
@if (Model.ADAdditionalDomains.Count > 0)
|
||||
@if (Model.ADDomains.Count > 1)
|
||||
{
|
||||
var adDomainFirst = Model.ADAdditionalDomains.First();
|
||||
<code>@adDomainFirst.DnsName <span>[@adDomainFirst.NetBiosName]</span></code>
|
||||
foreach (var adDomain in Model.ADAdditionalDomains.Skip(1))
|
||||
var adAdditionalDomains = Model.ADDomains.Where(d => d != Model.ADPrimaryDomain).OrderBy(d => d.Name).ToList();
|
||||
var adDomainFirst = adAdditionalDomains.First();
|
||||
<code>@adDomainFirst.Name <span>[@adDomainFirst.NetBiosName]</span></code>
|
||||
foreach (var adDomain in adAdditionalDomains.Skip(1))
|
||||
{
|
||||
<hr />
|
||||
<div>
|
||||
<code>@adDomain.DnsName <span>[@adDomain.NetBiosName]</span></code>
|
||||
<code>@adDomain.Name <span>[@adDomain.NetBiosName]</span></code>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@@ -178,18 +179,42 @@
|
||||
</th>
|
||||
<td>
|
||||
<code><strong>@Model.ADSite.Name</strong></code>
|
||||
<hr />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="width: 135px">Servers:
|
||||
</th>
|
||||
<td>
|
||||
<div>
|
||||
@if (Model.ADSiteServers.Count > 0)
|
||||
@if (Model.ADServers.Count > 0)
|
||||
{
|
||||
<span>Servers:</span>
|
||||
<ul class="none">
|
||||
@foreach (var siteServer in Model.ADSiteServers)
|
||||
@foreach (var server in Model.ADServers)
|
||||
{
|
||||
var server = siteServer.Item1;
|
||||
var reachable = siteServer.Item2;
|
||||
var serverDescription = string.Format("{0} [{1}]", server.Name.EndsWith(server.Domain.Name, StringComparison.OrdinalIgnoreCase) ? server.Name.Substring(0, server.Name.Length - server.Domain.Name.Length - 1) : server.Name, server.Domain.NetBiosName);
|
||||
var reachable = server.IsAvailable;
|
||||
<li>
|
||||
<i class="fa @(reachable ? "fa-check success" : "fa-exclamation warning") fa-fw fa-lg" title="@(reachable ? "Reachable" : "Unavailable")"></i> <code>@(server.Name)</code>
|
||||
@if (server.IsAvailable)
|
||||
{
|
||||
<i class="fa fa-check success fa-fw fa-lg" title="Available"></i>
|
||||
}
|
||||
else
|
||||
{
|
||||
<i class="fa fa-exclamation warning fa-fw fa-lg" title="Unavailable, will retry at @(server.AvailableWhen.Value.ToLongTimeString())"></i>
|
||||
}
|
||||
<code>@(serverDescription)</code>
|
||||
@if (server.IsSiteServer)
|
||||
{
|
||||
<i class="fa fa-building-o information fa-fw" title="Site Server"></i>
|
||||
}
|
||||
else
|
||||
{
|
||||
<i class="fa fa-globe warning fa-fw" title="Not a Site Server"></i>
|
||||
}
|
||||
@if (server.IsWritable)
|
||||
{
|
||||
<i class="fa fa-pencil information fa-fw" title="Writable Domain Controller"></i>
|
||||
}
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
@@ -210,11 +235,12 @@
|
||||
@if (Model.ADForestServers == null)
|
||||
{
|
||||
<div>
|
||||
@Html.CheckBoxFor(m => m.ADSearchEntireForest, new { disabled = "disabled" }) @Html.LabelFor(m => m.ADSearchEntireForest)
|
||||
@Html.CheckBoxFor(m => m.ADSearchAllForestServers, new { disabled = "disabled" }) @Html.LabelFor(m => m.ADSearchAllForestServers)
|
||||
</div>
|
||||
<div style="padding: 0.7em 0.7em;" class="ui-state-highlight ui-corner-all">
|
||||
<i class="fa fa-info-circle information"></i> Forest servers are currently being retrieved.
|
||||
<br />Try refreshing this page in a moment.
|
||||
<br />
|
||||
Try refreshing this page in a moment.
|
||||
</div>
|
||||
}
|
||||
else
|
||||
@@ -225,20 +251,20 @@
|
||||
<div>
|
||||
@if (!canSearchEntireForest)
|
||||
{
|
||||
@Html.CheckBoxFor(m => m.ADSearchEntireForest, new { disabled = "disabled" }) @Html.LabelFor(m => m.ADSearchEntireForest)
|
||||
@Html.CheckBoxFor(m => m.ADSearchAllForestServers, new { disabled = "disabled" }) @Html.LabelFor(m => m.ADSearchAllForestServers)
|
||||
<div style="padding: 0.7em 0.7em;" class="ui-state-highlight ui-corner-all">
|
||||
<i class="fa fa-exclamation-circle warning"></i> Disco will not search entire forests which consist of more than @(Disco.Services.Interop.ActiveDirectory.ActiveDirectory.MaxForestServerSearch) servers. Only servers within this site will be searched.
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
@Html.CheckBoxFor(m => m.ADSearchEntireForest) @Html.LabelFor(m => m.ADSearchEntireForest) @AjaxHelpers.AjaxLoader()
|
||||
@Html.CheckBoxFor(m => m.ADSearchAllForestServers) @Html.LabelFor(m => m.ADSearchAllForestServers) @AjaxHelpers.AjaxLoader()
|
||||
<div class="smallMessage">
|
||||
If this setting is enabled, Disco will search all servers within the forest rather than only servers within this site.
|
||||
If this setting is enabled, Disco will query all servers within the forest rather than only servers within this site.
|
||||
</div>
|
||||
<script>
|
||||
$(function () {
|
||||
document.DiscoFunctions.PropertyChangeHelper($('#ADSearchEntireForest'), null, '@(Url.Action(MVC.API.System.UpdateActiveDirectorySearchEntireForest()))', 'SearchEntireForest');
|
||||
document.DiscoFunctions.PropertyChangeHelper($('#ADSearchAllForestServers'), null, '@(Url.Action(MVC.API.System.UpdateActiveDirectorySearchAllForestServers()))', 'SearchAllForestServers');
|
||||
});
|
||||
</script>
|
||||
}
|
||||
@@ -247,7 +273,7 @@
|
||||
else
|
||||
{
|
||||
<div>
|
||||
@Html.CheckBoxFor(m => m.ADSearchEntireForest, new { disabled = "disabled" }) @Html.LabelFor(m => m.ADSearchEntireForest)
|
||||
@Html.CheckBoxFor(m => m.ADSearchAllForestServers, new { disabled = "disabled" }) @Html.LabelFor(m => m.ADSearchAllForestServers)
|
||||
<div class="smallMessage">
|
||||
If this setting is enabled, Disco will search all servers within the forest rather than only servers within this site.
|
||||
</div>
|
||||
@@ -255,11 +281,25 @@
|
||||
}
|
||||
<div>
|
||||
<hr />
|
||||
<span>Servers:</span>
|
||||
<ul id="Config_System_AD_ForestServers">
|
||||
@foreach (var server in Model.ADForestServers.OrderBy(s => s))
|
||||
<span>All Servers:</span>
|
||||
<ul id="Config_System_AD_ForestServers" class="none">
|
||||
@{
|
||||
var domainIndex = Model.ADDomains.ToDictionary(d => d.Name, StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var server in Model.ADForestServers.OrderBy(s => s))
|
||||
{
|
||||
var isSiteServer = Model.ADServers.Any(s => s.IsSiteServer && s.Name.Equals(server, StringComparison.OrdinalIgnoreCase));
|
||||
var serverDescription = server;
|
||||
if (server.Contains('.'))
|
||||
{
|
||||
Disco.Services.Interop.ActiveDirectory.ADDomain serverDomain;
|
||||
if (domainIndex.TryGetValue(server.Substring(server.IndexOf('.') + 1), out serverDomain))
|
||||
{
|
||||
<li><code>@server</code> @(Model.ADSiteServers.Count(ss => ss.Item1.Name.Equals(server, StringComparison.InvariantCultureIgnoreCase)) > 0 ? "[Site Server]" : null)</li>
|
||||
serverDescription = string.Format("{0} [{1}]", server.Substring(0, server.IndexOf('.')), serverDomain.NetBiosName);
|
||||
}
|
||||
}
|
||||
<li><code>@serverDescription</code>@if (isSiteServer)
|
||||
{ <i class="fa fa-building-o information fa-fw" title="Site Server"></i> }</li>
|
||||
}
|
||||
}
|
||||
</ul>
|
||||
<script>
|
||||
|
||||
@@ -502,7 +502,7 @@ WriteLiteral(">Primary Domain:\r\n </th>\r\n <td>\r\n
|
||||
|
||||
|
||||
#line 151 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Model.ADPrimaryDomain.DnsName);
|
||||
Write(Model.ADPrimaryDomain.Name);
|
||||
|
||||
|
||||
#line default
|
||||
@@ -511,7 +511,7 @@ WriteLiteral("</strong> <span>[");
|
||||
|
||||
|
||||
#line 151 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Model.ADPrimaryDomain.NetBiosName);
|
||||
Write(Model.ADPrimaryDomain.NetBiosName);
|
||||
|
||||
|
||||
#line default
|
||||
@@ -530,9 +530,10 @@ WriteLiteral(">Additional Domains:\r\n </th>\r\n <td>\r\n"
|
||||
#line hidden
|
||||
|
||||
#line 158 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
if (Model.ADAdditionalDomains.Count > 0)
|
||||
if (Model.ADDomains.Count > 1)
|
||||
{
|
||||
var adDomainFirst = Model.ADAdditionalDomains.First();
|
||||
var adAdditionalDomains = Model.ADDomains.Where(d => d != Model.ADPrimaryDomain).OrderBy(d => d.Name).ToList();
|
||||
var adDomainFirst = adAdditionalDomains.First();
|
||||
|
||||
|
||||
#line default
|
||||
@@ -540,8 +541,8 @@ WriteLiteral(">Additional Domains:\r\n </th>\r\n <td>\r\n"
|
||||
WriteLiteral(" <code>");
|
||||
|
||||
|
||||
#line 161 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(adDomainFirst.DnsName);
|
||||
#line 162 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(adDomainFirst.Name);
|
||||
|
||||
|
||||
#line default
|
||||
@@ -549,8 +550,8 @@ WriteLiteral(" <code>");
|
||||
WriteLiteral(" <span>[");
|
||||
|
||||
|
||||
#line 161 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(adDomainFirst.NetBiosName);
|
||||
#line 162 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(adDomainFirst.NetBiosName);
|
||||
|
||||
|
||||
#line default
|
||||
@@ -558,8 +559,8 @@ WriteLiteral(" <span>[");
|
||||
WriteLiteral("]</span></code>\r\n");
|
||||
|
||||
|
||||
#line 162 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
foreach (var adDomain in Model.ADAdditionalDomains.Skip(1))
|
||||
#line 163 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
foreach (var adDomain in adAdditionalDomains.Skip(1))
|
||||
{
|
||||
|
||||
|
||||
@@ -570,8 +571,8 @@ WriteLiteral(" <hr />\r\n");
|
||||
WriteLiteral(" <div>\r\n <code>");
|
||||
|
||||
|
||||
#line 166 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(adDomain.DnsName);
|
||||
#line 167 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(adDomain.Name);
|
||||
|
||||
|
||||
#line default
|
||||
@@ -579,8 +580,8 @@ WriteLiteral(" <div>\r\n <code>");
|
||||
WriteLiteral(" <span>[");
|
||||
|
||||
|
||||
#line 166 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(adDomain.NetBiosName);
|
||||
#line 167 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(adDomain.NetBiosName);
|
||||
|
||||
|
||||
#line default
|
||||
@@ -588,7 +589,7 @@ WriteLiteral(" <span>[");
|
||||
WriteLiteral("]</span></code>\r\n </div>\r\n");
|
||||
|
||||
|
||||
#line 168 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 169 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -604,7 +605,7 @@ WriteLiteral(" class=\"smallMessage\"");
|
||||
WriteLiteral("><None></span>\r\n");
|
||||
|
||||
|
||||
#line 173 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 174 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -617,30 +618,33 @@ WriteLiteral(" style=\"width: 135px\"");
|
||||
WriteLiteral(">Site:\r\n </th>\r\n <td>\r\n <code><strong>");
|
||||
|
||||
|
||||
#line 180 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 181 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Model.ADSite.Name);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</strong></code>\r\n <hr />\r\n <div>\r\n");
|
||||
WriteLiteral("</strong></code>\r\n </td>\r\n </tr>\r\n <tr>\r\n <th" +
|
||||
"");
|
||||
|
||||
WriteLiteral(" style=\"width: 135px\"");
|
||||
|
||||
WriteLiteral(">Servers:\r\n </th>\r\n <td>\r\n <div>\r\n");
|
||||
|
||||
|
||||
#line 183 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 189 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 183 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
if (Model.ADSiteServers.Count > 0)
|
||||
#line 189 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
if (Model.ADServers.Count > 0)
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <span>Servers:</span>\r\n");
|
||||
|
||||
WriteLiteral(" <ul");
|
||||
|
||||
WriteLiteral(" class=\"none\"");
|
||||
@@ -648,59 +652,167 @@ WriteLiteral(" class=\"none\"");
|
||||
WriteLiteral(">\r\n");
|
||||
|
||||
|
||||
#line 187 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 192 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 187 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
foreach (var siteServer in Model.ADSiteServers)
|
||||
#line 192 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
foreach (var server in Model.ADServers)
|
||||
{
|
||||
var server = siteServer.Item1;
|
||||
var reachable = siteServer.Item2;
|
||||
var serverDescription = string.Format("{0} [{1}]", server.Name.EndsWith(server.Domain.Name, StringComparison.OrdinalIgnoreCase) ? server.Name.Substring(0, server.Name.Length - server.Domain.Name.Length - 1) : server.Name, server.Domain.NetBiosName);
|
||||
var reachable = server.IsAvailable;
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <li>\r\n <i");
|
||||
WriteLiteral(" <li>\r\n");
|
||||
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 7471), Tuple.Create("\"", 7554)
|
||||
, Tuple.Create(Tuple.Create("", 7479), Tuple.Create("fa", 7479), true)
|
||||
|
||||
#line 192 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create(" ", 7481), Tuple.Create<System.Object, System.Int32>(reachable ? "fa-check success" : "fa-exclamation warning"
|
||||
#line 197 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 7482), false)
|
||||
, Tuple.Create(Tuple.Create(" ", 7542), Tuple.Create("fa-fw", 7543), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 7548), Tuple.Create("fa-lg", 7549), true)
|
||||
|
||||
#line 197 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
if (server.IsAvailable)
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <i");
|
||||
|
||||
WriteLiteral(" class=\"fa fa-check success fa-fw fa-lg\"");
|
||||
|
||||
WriteLiteral(" title=\"Available\"");
|
||||
|
||||
WriteLiteral("></i>\r\n");
|
||||
|
||||
|
||||
#line 200 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <i");
|
||||
|
||||
WriteLiteral(" class=\"fa fa-exclamation warning fa-fw fa-lg\"");
|
||||
|
||||
WriteAttribute("title", Tuple.Create(" title=\"", 8221), Tuple.Create("\"", 8304)
|
||||
, Tuple.Create(Tuple.Create("", 8229), Tuple.Create("Unavailable,", 8229), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 8241), Tuple.Create("will", 8242), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 8246), Tuple.Create("retry", 8247), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 8252), Tuple.Create("at", 8253), true)
|
||||
|
||||
#line 203 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create(" ", 8255), Tuple.Create<System.Object, System.Int32>(server.AvailableWhen.Value.ToLongTimeString()
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 8256), false)
|
||||
);
|
||||
|
||||
WriteAttribute("title", Tuple.Create(" title=\"", 7555), Tuple.Create("\"", 7605)
|
||||
|
||||
#line 192 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 7563), Tuple.Create<System.Object, System.Int32>(reachable ? "Reachable" : "Unavailable"
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 7563), false)
|
||||
);
|
||||
|
||||
WriteLiteral("></i> <code>");
|
||||
WriteLiteral("></i>\r\n");
|
||||
|
||||
|
||||
#line 192 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(server.Name);
|
||||
#line 204 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</code>\r\n </li>\r\n");
|
||||
WriteLiteral(" <code>");
|
||||
|
||||
|
||||
#line 194 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 205 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(serverDescription);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</code>\r\n");
|
||||
|
||||
|
||||
#line 206 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 206 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
if (server.IsSiteServer)
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <i");
|
||||
|
||||
WriteLiteral(" class=\"fa fa-building-o information fa-fw\"");
|
||||
|
||||
WriteLiteral(" title=\"Site Server\"");
|
||||
|
||||
WriteLiteral("></i>\r\n");
|
||||
|
||||
|
||||
#line 209 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <i");
|
||||
|
||||
WriteLiteral(" class=\"fa fa-globe warning fa-fw\"");
|
||||
|
||||
WriteLiteral(" title=\"Not a Site Server\"");
|
||||
|
||||
WriteLiteral("></i>\r\n");
|
||||
|
||||
|
||||
#line 213 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 214 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
if (server.IsWritable)
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <i");
|
||||
|
||||
WriteLiteral(" class=\"fa fa-pencil information fa-fw\"");
|
||||
|
||||
WriteLiteral(" title=\"Writable Domain Controller\"");
|
||||
|
||||
WriteLiteral("></i>\r\n");
|
||||
|
||||
|
||||
#line 217 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" </li>\r\n");
|
||||
|
||||
|
||||
#line 219 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -709,7 +821,7 @@ WriteLiteral("</code>\r\n </li>\r\n");
|
||||
WriteLiteral(" </ul>\r\n");
|
||||
|
||||
|
||||
#line 196 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 221 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -728,7 +840,7 @@ WriteLiteral(" class=\"fa fa-exclamation-circle fa-lg\"");
|
||||
WriteLiteral("></i> <span>None Found</span>\r\n </div>\r\n");
|
||||
|
||||
|
||||
#line 202 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 227 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -742,13 +854,13 @@ WriteLiteral(" style=\"width: 135px\"");
|
||||
WriteLiteral(">Forest:\r\n </th>\r\n <td>\r\n");
|
||||
|
||||
|
||||
#line 210 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 235 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 210 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 235 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
if (Model.ADForestServers == null)
|
||||
{
|
||||
|
||||
@@ -760,8 +872,8 @@ WriteLiteral(" <div>\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 213 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.CheckBoxFor(m => m.ADSearchEntireForest, new { disabled = "disabled" }));
|
||||
#line 238 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.CheckBoxFor(m => m.ADSearchAllForestServers, new { disabled = "disabled" }));
|
||||
|
||||
|
||||
#line default
|
||||
@@ -769,8 +881,8 @@ WriteLiteral(" ");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 213 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.LabelFor(m => m.ADSearchEntireForest));
|
||||
#line 238 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.LabelFor(m => m.ADSearchAllForestServers));
|
||||
|
||||
|
||||
#line default
|
||||
@@ -788,10 +900,11 @@ WriteLiteral(">\r\n <i");
|
||||
WriteLiteral(" class=\"fa fa-info-circle information\"");
|
||||
|
||||
WriteLiteral("></i> Forest servers are currently being retrieved.\r\n " +
|
||||
" <br />Try refreshing this page in a moment.\r\n </div>\r\n");
|
||||
" <br />\r\n Try refreshing this page in a moment.\r\n " +
|
||||
" </div>\r\n");
|
||||
|
||||
|
||||
#line 219 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 245 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -805,13 +918,13 @@ WriteLiteral("></i> Forest servers are currently being retrieved.\r\n
|
||||
WriteLiteral(" <div>\r\n");
|
||||
|
||||
|
||||
#line 226 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 252 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 226 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 252 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
if (!canSearchEntireForest)
|
||||
{
|
||||
|
||||
@@ -819,28 +932,28 @@ WriteLiteral(" <div>\r\n");
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 228 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.CheckBoxFor(m => m.ADSearchEntireForest, new { disabled = "disabled" }));
|
||||
#line 254 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.CheckBoxFor(m => m.ADSearchAllForestServers, new { disabled = "disabled" }));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 228 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
#line 254 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 228 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.LabelFor(m => m.ADSearchEntireForest));
|
||||
#line 254 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.LabelFor(m => m.ADSearchAllForestServers));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 228 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
#line 254 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
|
||||
|
||||
#line default
|
||||
@@ -858,7 +971,7 @@ WriteLiteral(" class=\"fa fa-exclamation-circle warning\"");
|
||||
WriteLiteral("></i> Disco will not search entire forests which consist of more than ");
|
||||
|
||||
|
||||
#line 230 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 256 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Disco.Services.Interop.ActiveDirectory.ActiveDirectory.MaxForestServerSearch);
|
||||
|
||||
|
||||
@@ -868,7 +981,7 @@ WriteLiteral(" servers. Only servers within this site will be searched.\r\n
|
||||
" </div>\r\n");
|
||||
|
||||
|
||||
#line 232 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 258 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -877,41 +990,41 @@ WriteLiteral(" servers. Only servers within this site will be searched.\r\n
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 235 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.CheckBoxFor(m => m.ADSearchEntireForest));
|
||||
#line 261 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.CheckBoxFor(m => m.ADSearchAllForestServers));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 235 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
#line 261 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 235 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.LabelFor(m => m.ADSearchEntireForest));
|
||||
#line 261 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.LabelFor(m => m.ADSearchAllForestServers));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 235 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
#line 261 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 235 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(AjaxHelpers.AjaxLoader());
|
||||
#line 261 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(AjaxHelpers.AjaxLoader());
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 235 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
#line 261 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
|
||||
|
||||
#line default
|
||||
@@ -920,26 +1033,26 @@ WriteLiteral(" <div");
|
||||
|
||||
WriteLiteral(" class=\"smallMessage\"");
|
||||
|
||||
WriteLiteral(">\r\n If this setting is enabled, Disco will search " +
|
||||
"all servers within the forest rather than only servers within this site.\r\n " +
|
||||
" </div>\r\n");
|
||||
WriteLiteral(">\r\n If this setting is enabled, Disco will query a" +
|
||||
"ll servers within the forest rather than only servers within this site.\r\n " +
|
||||
" </div>\r\n");
|
||||
|
||||
WriteLiteral(" <script>\r\n $(function " +
|
||||
"() {\r\n document.DiscoFunctions.PropertyChange" +
|
||||
"Helper($(\'#ADSearchEntireForest\'), null, \'");
|
||||
"Helper($(\'#ADSearchAllForestServers\'), null, \'");
|
||||
|
||||
|
||||
#line 241 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Url.Action(MVC.API.System.UpdateActiveDirectorySearchEntireForest()));
|
||||
#line 267 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Url.Action(MVC.API.System.UpdateActiveDirectorySearchAllForestServers()));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\', \'SearchEntireForest\');\r\n });\r\n " +
|
||||
" </script>\r\n");
|
||||
WriteLiteral("\', \'SearchAllForestServers\');\r\n });\r\n " +
|
||||
" </script>\r\n");
|
||||
|
||||
|
||||
#line 244 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 270 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -948,7 +1061,7 @@ WriteLiteral("\', \'SearchEntireForest\');\r\n })
|
||||
WriteLiteral(" </div>\r\n");
|
||||
|
||||
|
||||
#line 246 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 272 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -961,8 +1074,8 @@ WriteLiteral(" <div>\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 250 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.CheckBoxFor(m => m.ADSearchEntireForest, new { disabled = "disabled" }));
|
||||
#line 276 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.CheckBoxFor(m => m.ADSearchAllForestServers, new { disabled = "disabled" }));
|
||||
|
||||
|
||||
#line default
|
||||
@@ -970,8 +1083,8 @@ WriteLiteral(" ");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 250 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.LabelFor(m => m.ADSearchEntireForest));
|
||||
#line 276 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.LabelFor(m => m.ADSearchAllForestServers));
|
||||
|
||||
|
||||
#line default
|
||||
@@ -985,29 +1098,43 @@ WriteLiteral(">\r\n If this setting is enabled, Disco
|
||||
" </div>\r\n </div>\r\n");
|
||||
|
||||
|
||||
#line 255 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 281 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <div>\r\n <hr />\r\n " +
|
||||
" <span>Servers:</span>\r\n <ul");
|
||||
" <span>All Servers:</span>\r\n <ul");
|
||||
|
||||
WriteLiteral(" id=\"Config_System_AD_ForestServers\"");
|
||||
|
||||
WriteLiteral(" class=\"none\"");
|
||||
|
||||
WriteLiteral(">\r\n");
|
||||
|
||||
|
||||
#line 260 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 286 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 260 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
foreach (var server in Model.ADForestServers.OrderBy(s => s))
|
||||
#line 286 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
var domainIndex = Model.ADDomains.ToDictionary(d => d.Name, StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var server in Model.ADForestServers.OrderBy(s => s))
|
||||
{
|
||||
var isSiteServer = Model.ADServers.Any(s => s.IsSiteServer && s.Name.Equals(server, StringComparison.OrdinalIgnoreCase));
|
||||
var serverDescription = server;
|
||||
if (server.Contains('.'))
|
||||
{
|
||||
Disco.Services.Interop.ActiveDirectory.ADDomain serverDomain;
|
||||
if (domainIndex.TryGetValue(server.Substring(server.IndexOf('.') + 1), out serverDomain))
|
||||
{
|
||||
serverDescription = string.Format("{0} [{1}]", server.Substring(0, server.IndexOf('.')), serverDomain.NetBiosName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#line default
|
||||
@@ -1015,31 +1142,46 @@ WriteLiteral(">\r\n");
|
||||
WriteLiteral(" <li><code>");
|
||||
|
||||
|
||||
#line 262 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(server);
|
||||
#line 300 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(serverDescription);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</code> ");
|
||||
WriteLiteral("</code>");
|
||||
|
||||
|
||||
#line 262 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Model.ADSiteServers.Count(ss => ss.Item1.Name.Equals(server, StringComparison.InvariantCultureIgnoreCase)) > 0 ? "[Site Server]" : null);
|
||||
#line 300 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
if (isSiteServer)
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <i");
|
||||
|
||||
WriteLiteral(" class=\"fa fa-building-o information fa-fw\"");
|
||||
|
||||
WriteLiteral(" title=\"Site Server\"");
|
||||
|
||||
WriteLiteral("></i> ");
|
||||
|
||||
|
||||
#line 301 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</li>\r\n");
|
||||
|
||||
|
||||
#line 263 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
|
||||
#line 302 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(@" </ul>
|
||||
WriteLiteral(@"
|
||||
</ul>
|
||||
<script>
|
||||
$(function () {
|
||||
var toManyServers = 5;
|
||||
@@ -1066,7 +1208,7 @@ WriteLiteral(@" </ul>
|
||||
");
|
||||
|
||||
|
||||
#line 288 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 328 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -1079,13 +1221,13 @@ WriteLiteral(" style=\"width: 135px\"");
|
||||
WriteLiteral(">Search Scope:\r\n </th>\r\n <td>\r\n");
|
||||
|
||||
|
||||
#line 295 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 335 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 295 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 335 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
if (Model.ADSearchContainers != null && Model.ADSearchContainers.Count > 0)
|
||||
{
|
||||
|
||||
@@ -1102,13 +1244,13 @@ WriteLiteral(" id=\"Config_System_AD_SearchScope_DistinguishedNames\"");
|
||||
WriteLiteral(">\r\n");
|
||||
|
||||
|
||||
#line 299 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 339 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 299 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 339 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
foreach (var adContainer in Model.ADSearchContainers)
|
||||
{
|
||||
|
||||
@@ -1120,7 +1262,7 @@ WriteLiteral(" <li");
|
||||
WriteLiteral(" data-distinguishedname=\"");
|
||||
|
||||
|
||||
#line 301 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 341 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(adContainer.Item1);
|
||||
|
||||
|
||||
@@ -1131,7 +1273,7 @@ WriteLiteral("\"");
|
||||
WriteLiteral("><code>");
|
||||
|
||||
|
||||
#line 301 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 341 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(adContainer.Item3);
|
||||
|
||||
|
||||
@@ -1140,7 +1282,7 @@ WriteLiteral("><code>");
|
||||
WriteLiteral("</code></li>\r\n");
|
||||
|
||||
|
||||
#line 302 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 342 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -1149,7 +1291,7 @@ WriteLiteral("</code></li>\r\n");
|
||||
WriteLiteral(" </ul>\r\n");
|
||||
|
||||
|
||||
#line 304 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 344 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1167,7 +1309,7 @@ WriteLiteral(">When searching, the entire domain will be queried. This is suitab
|
||||
"gle-domain deployments.</div>\r\n");
|
||||
|
||||
|
||||
#line 309 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 349 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -1176,7 +1318,7 @@ WriteLiteral(">When searching, the entire domain will be queried. This is suitab
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 310 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 350 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
if (canConfigAD)
|
||||
{
|
||||
|
||||
@@ -1211,7 +1353,7 @@ WriteLiteral(">\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 318 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 358 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(AjaxHelpers.AjaxLoader());
|
||||
|
||||
|
||||
@@ -1227,13 +1369,13 @@ WriteLiteral(" class=\"organisationalUnitTree\"");
|
||||
WriteLiteral(">\r\n </div>\r\n");
|
||||
|
||||
|
||||
#line 322 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 362 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 322 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 362 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
using (Html.BeginForm(MVC.API.System.UpdateActiveDirectorySearchScope(null, redirect: true)))
|
||||
{
|
||||
}
|
||||
@@ -1280,7 +1422,7 @@ WriteLiteral(" <script>\r\n $(function
|
||||
"\');\r\n\r\n $.getJSON(\'");
|
||||
|
||||
|
||||
#line 376 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 416 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Url.Action(MVC.API.System.DomainOrganisationalUnits()));
|
||||
|
||||
|
||||
@@ -1326,7 +1468,7 @@ WriteLiteral("\', null, function (data) {\r\n
|
||||
"\r\n </script>\r\n");
|
||||
|
||||
|
||||
#line 433 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 473 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -1335,7 +1477,7 @@ WriteLiteral("\', null, function (data) {\r\n
|
||||
WriteLiteral(" </td>\r\n </tr>\r\n </table>\r\n</div>\r\n");
|
||||
|
||||
|
||||
#line 438 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 478 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
if (canConfigProxy)
|
||||
{
|
||||
using (Html.BeginForm(MVC.API.System.UpdateProxySettings()))
|
||||
@@ -1360,7 +1502,7 @@ WriteLiteral(">Address:\r\n </th>\r\n <td>\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 449 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 489 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.EditorFor(m => m.ProxyAddress));
|
||||
|
||||
|
||||
@@ -1371,7 +1513,7 @@ WriteLiteral("<br />\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 450 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 490 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.ValidationMessageFor(m => m.ProxyAddress));
|
||||
|
||||
|
||||
@@ -1387,7 +1529,7 @@ WriteLiteral(">Port:\r\n </th>\r\n <td>\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 457 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 497 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.EditorFor(m => m.ProxyPort));
|
||||
|
||||
|
||||
@@ -1398,7 +1540,7 @@ WriteLiteral("<br />\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 458 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 498 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.ValidationMessageFor(m => m.ProxyPort));
|
||||
|
||||
|
||||
@@ -1414,7 +1556,7 @@ WriteLiteral(">Username:\r\n </th>\r\n <td>\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 465 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 505 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.EditorFor(m => m.ProxyUsername));
|
||||
|
||||
|
||||
@@ -1425,7 +1567,7 @@ WriteLiteral("<br />\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 466 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 506 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.ValidationMessageFor(m => m.ProxyUsername));
|
||||
|
||||
|
||||
@@ -1441,7 +1583,7 @@ WriteLiteral(">Password:\r\n </th>\r\n <td>\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 473 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 513 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.EditorFor(m => m.ProxyPassword));
|
||||
|
||||
|
||||
@@ -1452,7 +1594,7 @@ WriteLiteral("<br />\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 474 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 514 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.ValidationMessageFor(m => m.ProxyPassword));
|
||||
|
||||
|
||||
@@ -1474,7 +1616,7 @@ WriteLiteral(" value=\"Save Proxy Settings\"");
|
||||
WriteLiteral(" />\r\n </td>\r\n </tr>\r\n </table>\r\n </div>\r\n");
|
||||
|
||||
|
||||
#line 486 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 526 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1499,7 +1641,7 @@ WriteLiteral(">Address:\r\n </th>\r\n <td>\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 497 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 537 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.DisplayFor(m => m.ProxyAddress));
|
||||
|
||||
|
||||
@@ -1515,7 +1657,7 @@ WriteLiteral(">Port:\r\n </th>\r\n <td>\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 504 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 544 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.DisplayFor(m => m.ProxyPort));
|
||||
|
||||
|
||||
@@ -1531,7 +1673,7 @@ WriteLiteral(">Username:\r\n </th>\r\n <td>\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 511 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 551 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.DisplayFor(m => m.ProxyUsername));
|
||||
|
||||
|
||||
@@ -1546,7 +1688,7 @@ WriteLiteral(">Password:\r\n </th>\r\n <td>*******
|
||||
"</td>\r\n </tr>\r\n </table>\r\n </div>\r\n");
|
||||
|
||||
|
||||
#line 522 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 562 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -1561,7 +1703,7 @@ WriteLiteral(">\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 524 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
#line 564 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml"
|
||||
Write(Html.ActionLinkButton("Update Device Last Network Logons", MVC.API.System.UpdateLastNetworkLogonDates()));
|
||||
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Disco.Web.ClientSource.Style.Images.AttachmentTypes
|
||||
}
|
||||
|
||||
// Generic 'image' icon
|
||||
if (MimeType.StartsWith("image/", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
|
||||
return Links.ClientSource.Style.Images.AttachmentTypes.image_png;
|
||||
|
||||
// All other Attachments
|
||||
|
||||
@@ -12,8 +12,8 @@ using System.Management;
|
||||
using System.Web;
|
||||
using Disco.Services.Users;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Web.Areas.API.Models.Shared;
|
||||
|
||||
namespace Disco.Web.Controllers
|
||||
{
|
||||
@@ -255,9 +255,9 @@ namespace Disco.Web.Controllers
|
||||
public virtual ActionResult Administrators()
|
||||
{
|
||||
var administratorSubjects = UserService.AdministratorSubjectIds
|
||||
.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId, Quick: true))
|
||||
.Select(subjectId => ActiveDirectory.RetrieveADObject(subjectId, Quick: true))
|
||||
.Where(item => item != null)
|
||||
.Select(item => Disco.Web.Areas.Config.Models.AuthorizationRole.SubjectDescriptorModel.FromActiveDirectoryObject(item))
|
||||
.Select(item => SubjectDescriptorModel.FromActiveDirectoryObject(item))
|
||||
.OrderBy(item => item.Name).ToList();
|
||||
|
||||
var m = new AdministratorsModel()
|
||||
@@ -269,11 +269,11 @@ namespace Disco.Web.Controllers
|
||||
}
|
||||
public virtual ActionResult AdministratorsSearch(string term)
|
||||
{
|
||||
var groupResults = ActiveDirectory.SearchGroups(term).Cast<IActiveDirectoryObject>();
|
||||
var userResults = ActiveDirectory.SearchUserAccounts(term).Cast<IActiveDirectoryObject>();
|
||||
var groupResults = ActiveDirectory.SearchADGroups(term).Cast<IADObject>();
|
||||
var userResults = ActiveDirectory.SearchADUserAccounts(term, Quick: true).Cast<IADObject>();
|
||||
|
||||
var results = groupResults.Concat(userResults).OrderBy(r => r.SamAccountName)
|
||||
.Select(r => Disco.Web.Areas.API.Models.AuthorizationRole.SubjectItem.FromActiveDirectoryObject(r)).ToList();
|
||||
.Select(r => SubjectDescriptorModel.FromActiveDirectoryObject(r)).ToList();
|
||||
|
||||
return Json(results, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
@@ -282,14 +282,14 @@ namespace Disco.Web.Controllers
|
||||
if (string.IsNullOrWhiteSpace(Id))
|
||||
return Json(null, JsonRequestBehavior.AllowGet);
|
||||
else if (!Id.Contains(@"\"))
|
||||
Id = string.Format(@"{0}\{1}", ActiveDirectory.PrimaryDomain.NetBiosName, Id);
|
||||
Id = string.Format(@"{0}\{1}", ActiveDirectory.Context.PrimaryDomain.NetBiosName, Id);
|
||||
|
||||
var subject = ActiveDirectory.RetrieveObject(Id, Quick: true);
|
||||
var subject = ActiveDirectory.RetrieveADObject(Id, Quick: true);
|
||||
|
||||
if (subject == null || !(subject is ActiveDirectoryUserAccount || subject is ActiveDirectoryGroup))
|
||||
if (subject == null || !(subject is ADUserAccount || subject is ADGroup))
|
||||
return Json(null, JsonRequestBehavior.AllowGet);
|
||||
else
|
||||
return Json(Disco.Web.Areas.API.Models.AuthorizationRole.SubjectItem.FromActiveDirectoryObject(subject), JsonRequestBehavior.AllowGet);
|
||||
return Json(SubjectDescriptorModel.FromActiveDirectoryObject(subject), JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
[HttpPost]
|
||||
public virtual ActionResult Administrators(string[] Subjects)
|
||||
@@ -305,14 +305,14 @@ namespace Disco.Web.Controllers
|
||||
var subjects = Subjects
|
||||
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||
.Select(s => s.Trim())
|
||||
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveObject(s, Quick: true)))
|
||||
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveADObject(s, Quick: true)))
|
||||
.ToList();
|
||||
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
|
||||
|
||||
if (invalidSubjects.Count > 0)
|
||||
throw new ArgumentException(string.Format("Subjects not found: {0}", string.Join(", ", invalidSubjects)), "Subjects");
|
||||
|
||||
proposedSubjects = subjects.Select(s => s.Item2.NetBiosId).OrderBy(s => s).ToArray();
|
||||
proposedSubjects = subjects.Select(s => s.Item2.Id).OrderBy(s => s).ToArray();
|
||||
var currentSubjects = UserService.AdministratorSubjectIds;
|
||||
removedSubjects = currentSubjects.Except(proposedSubjects).ToArray();
|
||||
addedSubjects = proposedSubjects.Except(currentSubjects).ToArray();
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Disco.Web.Controllers
|
||||
throw new ArgumentNullException("id", "The User Id must be provided");
|
||||
|
||||
if (string.IsNullOrEmpty(Domain))
|
||||
id = ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + id;
|
||||
id = ActiveDirectory.Context.PrimaryDomain.NetBiosName + @"\" + id;
|
||||
else
|
||||
id = Domain + @"\" + id;
|
||||
|
||||
|
||||
@@ -193,9 +193,8 @@
|
||||
<Compile Include="Areas\API\Controllers\JobQueueJobController.cs" />
|
||||
<Compile Include="Areas\API\Controllers\PluginController.cs" />
|
||||
<Compile Include="Areas\API\Controllers\SearchController.cs" />
|
||||
<Compile Include="Areas\API\Models\AuthorizationRole\SubjectItem.cs" />
|
||||
<Compile Include="Areas\API\Models\JobQueue\SubjectItem.cs" />
|
||||
<Compile Include="Areas\API\Models\Job\DeviceHeldLocationModel.cs" />
|
||||
<Compile Include="Areas\API\Models\Shared\SubjectDescriptorModel.cs" />
|
||||
<Compile Include="Areas\API\Models\System\DomainOrganisationalUnitsModel.cs" />
|
||||
<Compile Include="Areas\Config\Controllers\AuthorizationRoleController.cs" />
|
||||
<Compile Include="Areas\Config\Controllers\JobPreferencesController.cs" />
|
||||
@@ -203,7 +202,6 @@
|
||||
<Compile Include="Areas\Config\Models\AuthorizationRole\CreateModel.cs" />
|
||||
<Compile Include="Areas\Config\Models\AuthorizationRole\IndexModel.cs" />
|
||||
<Compile Include="Areas\Config\Models\AuthorizationRole\ShowModel.cs" />
|
||||
<Compile Include="Areas\Config\Models\AuthorizationRole\SubjectDescriptorModel.cs" />
|
||||
<Compile Include="Areas\Config\Models\Config\IndexModel.cs" />
|
||||
<Compile Include="Areas\Config\Models\DeviceBatch\CreateModel.cs" />
|
||||
<Compile Include="Areas\Config\Models\DeviceBatch\TimelineModel.cs" />
|
||||
@@ -1998,6 +1996,8 @@
|
||||
<None Include="_bin_deployableAssemblies\x86\Microsoft.VC90.CRT\Microsoft.VC90.CRT.manifest" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Areas\API\Models\AuthorizationRole\" />
|
||||
<Folder Include="Areas\API\Models\JobQueue\" />
|
||||
<Folder Include="Areas\API\Models\Search\" />
|
||||
<Folder Include="Areas\API\Models\WirelessCertificate\" />
|
||||
<Folder Include="Areas\Services\Models\" />
|
||||
@@ -2053,7 +2053,7 @@
|
||||
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
<UserProperties BuildVersion_StartDate="2011/7/1" BuildVersion_BuildAction="Both" BuildVersion_UseGlobalSettings="False" BuildVersion_DetectChanges="False" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" />
|
||||
<UserProperties BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_DetectChanges="False" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildAction="Both" BuildVersion_StartDate="2011/7/1" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Disco.Web.Controllers
|
||||
throw new ArgumentException("The User Id is not in the correct format ({Domain}\\{Id})", "id");
|
||||
|
||||
string userDomain;
|
||||
if (splitId.Item1.Equals(ActiveDirectory.PrimaryDomain.NetBiosName, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (splitId.Item1.Equals(ActiveDirectory.Context.PrimaryDomain.NetBiosName, StringComparison.OrdinalIgnoreCase))
|
||||
userDomain = null; // Url doesn't contain Domain if it is the default.
|
||||
else
|
||||
userDomain = splitId.Item1;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Disco.Web.Areas.Config.Models.AuthorizationRole;
|
||||
using Disco.Web.Areas.API.Models.Shared;
|
||||
using Disco.Web.Areas.Config.Models.AuthorizationRole;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Disco.Web.Models.InitialConfig
|
||||
|
||||
@@ -55,9 +55,9 @@ namespace Disco.Web.Models.InitialConfig
|
||||
{
|
||||
DataSource = this.Server,
|
||||
InitialCatalog = this.DatabaseName,
|
||||
IntegratedSecurity = (this.AuthMethod.Equals("SSPI", StringComparison.InvariantCultureIgnoreCase)),
|
||||
UserID = (this.AuthMethod.Equals("SQL", StringComparison.InvariantCultureIgnoreCase)) ? this.Auth_SQL_Username : string.Empty,
|
||||
Password = (this.AuthMethod.Equals("SQL", StringComparison.InvariantCultureIgnoreCase)) ? this.Auth_SQL_Password : string.Empty,
|
||||
IntegratedSecurity = (this.AuthMethod.Equals("SSPI", StringComparison.OrdinalIgnoreCase)),
|
||||
UserID = (this.AuthMethod.Equals("SQL", StringComparison.OrdinalIgnoreCase)) ? this.Auth_SQL_Username : string.Empty,
|
||||
Password = (this.AuthMethod.Equals("SQL", StringComparison.OrdinalIgnoreCase)) ? this.Auth_SQL_Password : string.Empty,
|
||||
ApplicationName = "Disco WebApp",
|
||||
MultipleActiveResultSets = true,
|
||||
Pooling = true
|
||||
@@ -97,7 +97,7 @@ namespace Disco.Web.Models.InitialConfig
|
||||
{
|
||||
var instance = validationContext.ObjectInstance as DatabaseModel;
|
||||
|
||||
if (instance != null && instance.AuthMethod != null && instance.AuthMethod.Equals("SQL", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (instance != null && instance.AuthMethod != null && instance.AuthMethod.Equals("SQL", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var stringValue = value as string;
|
||||
if (string.IsNullOrWhiteSpace(stringValue))
|
||||
|
||||
+65
-117
@@ -2386,18 +2386,6 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
{
|
||||
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.UpdateAdministratorSubjects);
|
||||
}
|
||||
[NonAction]
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public virtual System.Web.Mvc.ActionResult SearchSubjects()
|
||||
{
|
||||
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.SearchSubjects);
|
||||
}
|
||||
[NonAction]
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public virtual System.Web.Mvc.ActionResult Subject()
|
||||
{
|
||||
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Subject);
|
||||
}
|
||||
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public AuthorizationRoleController Actions { get { return MVC.API.AuthorizationRole; } }
|
||||
@@ -2420,8 +2408,6 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
public readonly string UpdateSubjects = "UpdateSubjects";
|
||||
public readonly string Delete = "Delete";
|
||||
public readonly string UpdateAdministratorSubjects = "UpdateAdministratorSubjects";
|
||||
public readonly string SearchSubjects = "SearchSubjects";
|
||||
public readonly string Subject = "Subject";
|
||||
}
|
||||
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
@@ -2433,8 +2419,6 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
public const string UpdateSubjects = "UpdateSubjects";
|
||||
public const string Delete = "Delete";
|
||||
public const string UpdateAdministratorSubjects = "UpdateAdministratorSubjects";
|
||||
public const string SearchSubjects = "SearchSubjects";
|
||||
public const string Subject = "Subject";
|
||||
}
|
||||
|
||||
|
||||
@@ -2497,22 +2481,6 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
public readonly string Subjects = "Subjects";
|
||||
public readonly string redirect = "redirect";
|
||||
}
|
||||
static readonly ActionParamsClass_SearchSubjects s_params_SearchSubjects = new ActionParamsClass_SearchSubjects();
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public ActionParamsClass_SearchSubjects SearchSubjectsParams { get { return s_params_SearchSubjects; } }
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public class ActionParamsClass_SearchSubjects
|
||||
{
|
||||
public readonly string term = "term";
|
||||
}
|
||||
static readonly ActionParamsClass_Subject s_params_Subject = new ActionParamsClass_Subject();
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public ActionParamsClass_Subject SubjectParams { get { return s_params_Subject; } }
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public class ActionParamsClass_Subject
|
||||
{
|
||||
public readonly string Id = "Id";
|
||||
}
|
||||
static readonly ViewsClass s_views = new ViewsClass();
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public ViewsClass Views { get { return s_views; } }
|
||||
@@ -2603,26 +2571,6 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
return callInfo;
|
||||
}
|
||||
|
||||
partial void SearchSubjectsOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string term);
|
||||
|
||||
public override System.Web.Mvc.ActionResult SearchSubjects(string term)
|
||||
{
|
||||
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.SearchSubjects);
|
||||
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "term", term);
|
||||
SearchSubjectsOverride(callInfo, term);
|
||||
return callInfo;
|
||||
}
|
||||
|
||||
partial void SubjectOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string Id);
|
||||
|
||||
public override System.Web.Mvc.ActionResult Subject(string Id)
|
||||
{
|
||||
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Subject);
|
||||
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Id", Id);
|
||||
SubjectOverride(callInfo, Id);
|
||||
return callInfo;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8079,18 +8027,6 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
{
|
||||
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Delete);
|
||||
}
|
||||
[NonAction]
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public virtual System.Web.Mvc.ActionResult SearchSubjects()
|
||||
{
|
||||
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.SearchSubjects);
|
||||
}
|
||||
[NonAction]
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public virtual System.Web.Mvc.ActionResult Subject()
|
||||
{
|
||||
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Subject);
|
||||
}
|
||||
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public JobQueueController Actions { get { return MVC.API.JobQueue; } }
|
||||
@@ -8118,8 +8054,6 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
public readonly string UpdateSubjects = "UpdateSubjects";
|
||||
public readonly string UpdateJobSubTypes = "UpdateJobSubTypes";
|
||||
public readonly string Delete = "Delete";
|
||||
public readonly string SearchSubjects = "SearchSubjects";
|
||||
public readonly string Subject = "Subject";
|
||||
}
|
||||
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
@@ -8136,8 +8070,6 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
public const string UpdateSubjects = "UpdateSubjects";
|
||||
public const string UpdateJobSubTypes = "UpdateJobSubTypes";
|
||||
public const string Delete = "Delete";
|
||||
public const string SearchSubjects = "SearchSubjects";
|
||||
public const string Subject = "Subject";
|
||||
}
|
||||
|
||||
|
||||
@@ -8252,22 +8184,6 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
public readonly string id = "id";
|
||||
public readonly string redirect = "redirect";
|
||||
}
|
||||
static readonly ActionParamsClass_SearchSubjects s_params_SearchSubjects = new ActionParamsClass_SearchSubjects();
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public ActionParamsClass_SearchSubjects SearchSubjectsParams { get { return s_params_SearchSubjects; } }
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public class ActionParamsClass_SearchSubjects
|
||||
{
|
||||
public readonly string term = "term";
|
||||
}
|
||||
static readonly ActionParamsClass_Subject s_params_Subject = new ActionParamsClass_Subject();
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public ActionParamsClass_Subject SubjectParams { get { return s_params_Subject; } }
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public class ActionParamsClass_Subject
|
||||
{
|
||||
public readonly string Id = "Id";
|
||||
}
|
||||
static readonly ViewsClass s_views = new ViewsClass();
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public ViewsClass Views { get { return s_views; } }
|
||||
@@ -8420,26 +8336,6 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
return callInfo;
|
||||
}
|
||||
|
||||
partial void SearchSubjectsOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string term);
|
||||
|
||||
public override System.Web.Mvc.ActionResult SearchSubjects(string term)
|
||||
{
|
||||
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.SearchSubjects);
|
||||
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "term", term);
|
||||
SearchSubjectsOverride(callInfo, term);
|
||||
return callInfo;
|
||||
}
|
||||
|
||||
partial void SubjectOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string Id);
|
||||
|
||||
public override System.Web.Mvc.ActionResult Subject(string Id)
|
||||
{
|
||||
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Subject);
|
||||
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Id", Id);
|
||||
SubjectOverride(callInfo, Id);
|
||||
return callInfo;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9293,9 +9189,21 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
}
|
||||
[NonAction]
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public virtual System.Web.Mvc.ActionResult UpdateActiveDirectorySearchEntireForest()
|
||||
public virtual System.Web.Mvc.ActionResult UpdateActiveDirectorySearchAllForestServers()
|
||||
{
|
||||
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.UpdateActiveDirectorySearchEntireForest);
|
||||
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.UpdateActiveDirectorySearchAllForestServers);
|
||||
}
|
||||
[NonAction]
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public virtual System.Web.Mvc.ActionResult SearchSubjects()
|
||||
{
|
||||
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.SearchSubjects);
|
||||
}
|
||||
[NonAction]
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public virtual System.Web.Mvc.ActionResult Subject()
|
||||
{
|
||||
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Subject);
|
||||
}
|
||||
[NonAction]
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
@@ -9328,8 +9236,10 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
public readonly string DeleteOrganisationAddress = "DeleteOrganisationAddress";
|
||||
public readonly string UpdateMultiSiteMode = "UpdateMultiSiteMode";
|
||||
public readonly string UpdateActiveDirectorySearchScope = "UpdateActiveDirectorySearchScope";
|
||||
public readonly string UpdateActiveDirectorySearchEntireForest = "UpdateActiveDirectorySearchEntireForest";
|
||||
public readonly string UpdateActiveDirectorySearchAllForestServers = "UpdateActiveDirectorySearchAllForestServers";
|
||||
public readonly string DomainOrganisationalUnits = "DomainOrganisationalUnits";
|
||||
public readonly string SearchSubjects = "SearchSubjects";
|
||||
public readonly string Subject = "Subject";
|
||||
public readonly string UpdateProxySettings = "UpdateProxySettings";
|
||||
}
|
||||
|
||||
@@ -9345,8 +9255,10 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
public const string DeleteOrganisationAddress = "DeleteOrganisationAddress";
|
||||
public const string UpdateMultiSiteMode = "UpdateMultiSiteMode";
|
||||
public const string UpdateActiveDirectorySearchScope = "UpdateActiveDirectorySearchScope";
|
||||
public const string UpdateActiveDirectorySearchEntireForest = "UpdateActiveDirectorySearchEntireForest";
|
||||
public const string UpdateActiveDirectorySearchAllForestServers = "UpdateActiveDirectorySearchAllForestServers";
|
||||
public const string DomainOrganisationalUnits = "DomainOrganisationalUnits";
|
||||
public const string SearchSubjects = "SearchSubjects";
|
||||
public const string Subject = "Subject";
|
||||
public const string UpdateProxySettings = "UpdateProxySettings";
|
||||
}
|
||||
|
||||
@@ -9409,15 +9321,31 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
public readonly string Containers = "Containers";
|
||||
public readonly string redirect = "redirect";
|
||||
}
|
||||
static readonly ActionParamsClass_UpdateActiveDirectorySearchEntireForest s_params_UpdateActiveDirectorySearchEntireForest = new ActionParamsClass_UpdateActiveDirectorySearchEntireForest();
|
||||
static readonly ActionParamsClass_UpdateActiveDirectorySearchAllForestServers s_params_UpdateActiveDirectorySearchAllForestServers = new ActionParamsClass_UpdateActiveDirectorySearchAllForestServers();
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public ActionParamsClass_UpdateActiveDirectorySearchEntireForest UpdateActiveDirectorySearchEntireForestParams { get { return s_params_UpdateActiveDirectorySearchEntireForest; } }
|
||||
public ActionParamsClass_UpdateActiveDirectorySearchAllForestServers UpdateActiveDirectorySearchAllForestServersParams { get { return s_params_UpdateActiveDirectorySearchAllForestServers; } }
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public class ActionParamsClass_UpdateActiveDirectorySearchEntireForest
|
||||
public class ActionParamsClass_UpdateActiveDirectorySearchAllForestServers
|
||||
{
|
||||
public readonly string SearchEntireForest = "SearchEntireForest";
|
||||
public readonly string SearchAllForestServers = "SearchAllForestServers";
|
||||
public readonly string redirect = "redirect";
|
||||
}
|
||||
static readonly ActionParamsClass_SearchSubjects s_params_SearchSubjects = new ActionParamsClass_SearchSubjects();
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public ActionParamsClass_SearchSubjects SearchSubjectsParams { get { return s_params_SearchSubjects; } }
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public class ActionParamsClass_SearchSubjects
|
||||
{
|
||||
public readonly string term = "term";
|
||||
}
|
||||
static readonly ActionParamsClass_Subject s_params_Subject = new ActionParamsClass_Subject();
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public ActionParamsClass_Subject SubjectParams { get { return s_params_Subject; } }
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public class ActionParamsClass_Subject
|
||||
{
|
||||
public readonly string Id = "Id";
|
||||
}
|
||||
static readonly ActionParamsClass_UpdateProxySettings s_params_UpdateProxySettings = new ActionParamsClass_UpdateProxySettings();
|
||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||
public ActionParamsClass_UpdateProxySettings UpdateProxySettingsParams { get { return s_params_UpdateProxySettings; } }
|
||||
@@ -9555,14 +9483,14 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
return callInfo;
|
||||
}
|
||||
|
||||
partial void UpdateActiveDirectorySearchEntireForestOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, bool SearchEntireForest, bool redirect);
|
||||
partial void UpdateActiveDirectorySearchAllForestServersOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, bool SearchAllForestServers, bool redirect);
|
||||
|
||||
public override System.Web.Mvc.ActionResult UpdateActiveDirectorySearchEntireForest(bool SearchEntireForest, bool redirect)
|
||||
public override System.Web.Mvc.ActionResult UpdateActiveDirectorySearchAllForestServers(bool SearchAllForestServers, bool redirect)
|
||||
{
|
||||
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.UpdateActiveDirectorySearchEntireForest);
|
||||
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "SearchEntireForest", SearchEntireForest);
|
||||
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.UpdateActiveDirectorySearchAllForestServers);
|
||||
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "SearchAllForestServers", SearchAllForestServers);
|
||||
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "redirect", redirect);
|
||||
UpdateActiveDirectorySearchEntireForestOverride(callInfo, SearchEntireForest, redirect);
|
||||
UpdateActiveDirectorySearchAllForestServersOverride(callInfo, SearchAllForestServers, redirect);
|
||||
return callInfo;
|
||||
}
|
||||
|
||||
@@ -9575,6 +9503,26 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
return callInfo;
|
||||
}
|
||||
|
||||
partial void SearchSubjectsOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string term);
|
||||
|
||||
public override System.Web.Mvc.ActionResult SearchSubjects(string term)
|
||||
{
|
||||
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.SearchSubjects);
|
||||
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "term", term);
|
||||
SearchSubjectsOverride(callInfo, term);
|
||||
return callInfo;
|
||||
}
|
||||
|
||||
partial void SubjectOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string Id);
|
||||
|
||||
public override System.Web.Mvc.ActionResult Subject(string Id)
|
||||
{
|
||||
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Subject);
|
||||
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Id", Id);
|
||||
SubjectOverride(callInfo, Id);
|
||||
return callInfo;
|
||||
}
|
||||
|
||||
partial void UpdateProxySettingsOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string ProxyAddress, int? ProxyPort, string ProxyUsername, string ProxyPassword, bool redirect);
|
||||
|
||||
public override System.Web.Mvc.ActionResult UpdateProxySettings(string ProxyAddress, int? ProxyPort, string ProxyUsername, string ProxyPassword, bool redirect)
|
||||
|
||||
Reference in New Issue
Block a user