Feature #42: Active Directory Interop Upgrade

AD Interop moved to Disco.Services; Supports multi-domain environments,
sites, and searching restricted with OUs.
This commit is contained in:
Gary Sharp committed 2014-04-10 17:58:04 +10:00
1 parent b841c6b2c0
commit db73cc1a12
218 files changed
+6420 -2572

No files matched your search

+105 -54
View File
@@ -1,13 +1,14 @@
using Disco.BI.Extensions;
using Disco.BI.Interop.ActiveDirectory;
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;
using Disco.Services.Users;
using System;
using System.Collections.Generic;
using System.DirectoryServices.ActiveDirectory;
using System.Linq;
using System.Text.RegularExpressions;
using Tamir.SharpSsh;
@@ -242,7 +243,7 @@ namespace Disco.BI.DeviceBI
EnrolmentLog.LogSessionTaskAddedDevice(sessionId, Request.DeviceSerialNumber);
DeviceProfile deviceProfile = Database.DeviceProfiles.Find(Database.DiscoConfiguration.DeviceProfiles.DefaultDeviceProfileId);
var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModel.Trim());
var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModelType.Trim());
DeviceModel deviceModel = deviceModelResult.Item1;
if (deviceModelResult.Item2)
EnrolmentLog.LogSessionTaskCreatedDeviceModel(sessionId, Request.DeviceSerialNumber, deviceModelResult.Item1.Manufacturer, deviceModelResult.Item1.Model);
@@ -252,7 +253,7 @@ namespace Disco.BI.DeviceBI
RepoDevice = new Device
{
SerialNumber = Request.DeviceSerialNumber,
ComputerName = Request.DeviceComputerName,
DeviceDomainId = Request.DeviceComputerName,
DeviceProfile = deviceProfile,
DeviceModel = deviceModel,
AllowUnauthenticatedEnrol = false,
@@ -267,7 +268,7 @@ namespace Disco.BI.DeviceBI
EnrolmentLog.LogSessionTaskUpdatingDevice(sessionId, Request.DeviceSerialNumber);
if (!RepoDevice.DeviceModelId.HasValue || RepoDevice.DeviceModelId.Value == 1)
{
var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModel.Trim());
var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModelType.Trim());
DeviceModel deviceModel = deviceModelResult.Item1;
if (deviceModelResult.Item2)
EnrolmentLog.LogSessionTaskCreatedDeviceModel(sessionId, Request.DeviceSerialNumber, deviceModelResult.Item1.Manufacturer, deviceModelResult.Item1.Model);
@@ -280,7 +281,7 @@ namespace Disco.BI.DeviceBI
{
EnrolmentLog.LogSessionDevice(sessionId, Request.DeviceSerialNumber, RepoDevice.DeviceModelId);
}
RepoDevice.ComputerName = Request.DeviceComputerName;
RepoDevice.DeviceDomainId = Request.DeviceComputerName;
if (!RepoDevice.EnrolledDate.HasValue)
{
RepoDevice.EnrolledDate = DateTime.Now;
@@ -294,14 +295,14 @@ 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 = ActiveDirectory.GetUserAccount(RepoDevice.AssignedUser.Id);
ActiveDirectoryUserAccount AssignedUserInfo = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.RetrieveUserAccount(RepoDevice.AssignedUser.UserId);
EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.SamAccountName, AssignedUserInfo.Domain, AssignedUserInfo.SecurityIdentifier);
response.DeviceAssignedUserUsername = AssignedUserInfo.SamAccountName;
response.DeviceAssignedUserDomain = AssignedUserInfo.Domain;
response.DeviceAssignedUserName = AssignedUserInfo.DisplayName;
response.DeviceAssignedUserSID = AssignedUserInfo.SecurityIdentifier;
}
response.DeviceComputerName = RepoDevice.ComputerName;
response.DeviceComputerName = RepoDevice.DeviceDomainId;
EnrolmentLog.LogSessionProgress(sessionId, 100, "Completed Successfully");
}
catch (EnrolSafeException ex)
@@ -323,14 +324,26 @@ namespace Disco.BI.DeviceBI
}
public static EnrolResponse Enrol(DiscoDataContext Database, string Username, Models.ClientServices.Enrol Request)
{
ActiveDirectoryMachineAccount MachineInfo = null;
ActiveDirectoryMachineAccount adMachineAccount = null;
EnrolResponse response = new EnrolResponse();
AuthorizationToken authenticatedToken = null;
bool isAuthenticated = false;
ActiveDirectoryDomain domain = null;
Lazy<DomainController> domainController = new Lazy<DomainController>(() => {
if (domain == null)
throw new InvalidOperationException("The [domain] variable must be initialized first");
return domain.RetrieveWritableDomainController();
});
string sessionId = System.Guid.NewGuid().ToString("B");
response.SessionId = sessionId;
EnrolmentLog.LogSessionStarting(sessionId, Request.DeviceSerialNumber, EnrolmentTypes.Normal);
EnrolmentLog.LogSessionDeviceInfo(sessionId, Request);
try
{
EnrolmentLog.LogSessionProgress(sessionId, 10, "Loading User Data");
@@ -348,9 +361,9 @@ namespace Disco.BI.DeviceBI
if (!authenticatedToken.Has(Claims.Device.Actions.EnrolDevices))
{
if (!authenticatedToken.Has(Claims.ComputerAccount))
throw new EnrolSafeException(string.Format("Connection not correctly authenticated (SN: {0}; Auth User: {1})", Request.DeviceSerialNumber, authenticatedToken.User.Id));
if (!authenticatedToken.User.Id.Equals(string.Format("{0}$", Request.DeviceComputerName), System.StringComparison.InvariantCultureIgnoreCase))
throw new EnrolSafeException(string.Format("Connection not correctly authenticated (SN: {0}; Auth User: {1})", Request.DeviceSerialNumber, authenticatedToken.User.Id));
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))
throw new EnrolSafeException(string.Format("Connection not correctly authenticated (SN: {0}; Auth User: {1})", Request.DeviceSerialNumber, authenticatedToken.User.UserId));
}
}
else
@@ -380,10 +393,16 @@ namespace Disco.BI.DeviceBI
System.Guid? uuidGuid = null;
System.Guid? macAddressGuid = null;
if (!string.IsNullOrEmpty(Request.DeviceUUID))
uuidGuid = ActiveDirectoryMachineAccountExtensions.NetbootGUIDFromUUID(Request.DeviceUUID);
uuidGuid = ActiveDirectoryExtensions.NetbootGUIDFromUUID(Request.DeviceUUID);
if (!string.IsNullOrEmpty(Request.DeviceLanMacAddress))
macAddressGuid = ActiveDirectoryMachineAccountExtensions.NetbootGUIDFromMACAddress(Request.DeviceLanMacAddress);
MachineInfo = ActiveDirectory.GetMachineAccount(Request.DeviceComputerName, uuidGuid, macAddressGuid);
macAddressGuid = ActiveDirectoryExtensions.NetbootGUIDFromMACAddress(Request.DeviceLanMacAddress);
if (domain == null)
domain = ActiveDirectory.GetDomainByDnsName(Request.DeviceDNSDomainName);
var requestDeviceId = string.Format(@"{0}\{1}", domain.NetBiosName, Request.DeviceComputerName);
adMachineAccount = ActiveDirectory.RetrieveMachineAccount(domainController.Value, requestDeviceId, uuidGuid, macAddressGuid);
}
if (RepoDevice == null)
{
@@ -392,7 +411,7 @@ namespace Disco.BI.DeviceBI
DeviceProfile deviceProfile = Database.DeviceProfiles.Find(Database.DiscoConfiguration.DeviceProfiles.DefaultDeviceProfileId);
var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModel.Trim());
var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModelType.Trim());
DeviceModel deviceModel = deviceModelResult.Item1;
if (deviceModelResult.Item2)
EnrolmentLog.LogSessionTaskCreatedDeviceModel(sessionId, Request.DeviceSerialNumber, deviceModelResult.Item1.Manufacturer, deviceModelResult.Item1.Model);
@@ -402,7 +421,7 @@ namespace Disco.BI.DeviceBI
RepoDevice = new Device
{
SerialNumber = Request.DeviceSerialNumber,
ComputerName = Request.DeviceComputerName,
DeviceDomainId = Request.DeviceComputerName,
DeviceProfile = deviceProfile,
DeviceModel = deviceModel,
AllowUnauthenticatedEnrol = false,
@@ -423,7 +442,7 @@ namespace Disco.BI.DeviceBI
EnrolmentLog.LogSessionProgress(sessionId, 30, "Existing Device, Updating Disco Instance");
EnrolmentLog.LogSessionTaskUpdatingDevice(sessionId, Request.DeviceSerialNumber);
var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModel.Trim());
var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModelType.Trim());
DeviceModel deviceModel = deviceModelResult.Item1;
if (deviceModelResult.Item2)
EnrolmentLog.LogSessionTaskCreatedDeviceModel(sessionId, Request.DeviceSerialNumber, deviceModelResult.Item1.Manufacturer, deviceModelResult.Item1.Model);
@@ -442,88 +461,120 @@ namespace Disco.BI.DeviceBI
RepoDevice.LastEnrolDate = DateTime.Now;
}
if (MachineInfo == null)
if (adMachineAccount == null)
{
if (isAuthenticated || RepoDevice.AllowUnauthenticatedEnrol)
{
if (RepoDevice.DeviceProfile.ProvisionADAccount)
{
EnrolmentLog.LogSessionProgress(sessionId, 50, "Provisioning an Active Directory Computer Account");
if (string.IsNullOrEmpty(RepoDevice.ComputerName) || RepoDevice.DeviceProfile.EnforceComputerNameConvention)
RepoDevice.ComputerName = RepoDevice.ComputerNameRender(Database);
EnrolmentLog.LogSessionTaskProvisioningADAccount(sessionId, RepoDevice.SerialNumber, RepoDevice.ComputerName);
MachineInfo = ActiveDirectory.GetMachineAccount(RepoDevice.ComputerName);
response.OfflineDomainJoin = ActiveDirectory.OfflineDomainJoinProvision(ref MachineInfo, RepoDevice.ComputerName, RepoDevice.DeviceProfile.OrganisationalUnit, sessionId);
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);
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);
EnrolmentLog.LogSessionDiagnosticInformation(sessionId, offlineProvisionDiagnosicInfo);
response.RequireReboot = true;
}
if (MachineInfo != null)
if (adMachineAccount != null)
{
response.DeviceComputerName = MachineInfo.Name;
response.DeviceDomainName = MachineInfo.Domain;
response.DeviceComputerName = adMachineAccount.Name;
response.DeviceDomainName = adMachineAccount.Domain;
}
else
{
response.DeviceComputerName = RepoDevice.ComputerName;
response.DeviceDomainName = RepoDevice.ComputerName;
var computerId = Disco.Services.UserExtensions.SplitUserId(RepoDevice.DeviceDomainId);
response.DeviceDomainName = computerId.Item1;
response.DeviceComputerName = computerId.Item2;
}
}
else
{
RepoDevice.ComputerName = Request.DeviceComputerName;
response.DeviceComputerName = Request.DeviceComputerName;
response.DeviceDomainName = RepoDevice.ComputerName;
response.DeviceDomainName = Request.DeviceDNSDomainName;
}
}
else
{
RepoDevice.ComputerName = MachineInfo.Name;
response.DeviceComputerName = MachineInfo.Name;
response.DeviceDomainName = MachineInfo.Domain;
RepoDevice.DeviceDomainId = adMachineAccount.Name;
response.DeviceComputerName = adMachineAccount.Name;
response.DeviceDomainName = adMachineAccount.Domain;
// Enforce Computer Name Convention
if (!MachineInfo.IsCriticalSystemObject && RepoDevice.DeviceProfile.EnforceComputerNameConvention)
if (!adMachineAccount.IsCriticalSystemObject && RepoDevice.DeviceProfile.EnforceComputerNameConvention)
{
var calculatedComputerName = RepoDevice.ComputerNameRender(Database);
if (!Request.DeviceComputerName.Equals(calculatedComputerName, StringComparison.InvariantCultureIgnoreCase))
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);
var calculatedComputerName = RepoDevice.ComputerNameRender(Database, domain);
var computerNameSplit = Disco.Services.UserExtensions.SplitUserId(calculatedComputerName);
if (!Request.DeviceComputerName.Equals(computerNameSplit.Item2, StringComparison.InvariantCultureIgnoreCase))
{
EnrolmentLog.LogSessionProgress(sessionId, 50, string.Format("Renaming Device: {0} -> {1}", Request.DeviceComputerName, calculatedComputerName));
EnrolmentLog.LogSessionTaskRenamingDevice(sessionId, Request.DeviceComputerName, calculatedComputerName);
RepoDevice.ComputerName = calculatedComputerName;
response.DeviceComputerName = calculatedComputerName;
RepoDevice.DeviceDomainId = calculatedComputerName;
response.DeviceDomainName = computerNameSplit.Item1;
response.DeviceComputerName = computerNameSplit.Item2;
// Create New Account
response.OfflineDomainJoin = ActiveDirectory.OfflineDomainJoinProvision(ref MachineInfo, RepoDevice.ComputerName, RepoDevice.DeviceProfile.OrganisationalUnit, sessionId);
string offlineProvisionDiagnosicInfo;
response.OfflineDomainJoin = ActiveDirectory.OfflineDomainJoinProvision(domain, domainController.Value, RepoDevice.DeviceDomainId, RepoDevice.DeviceProfile.OrganisationalUnit, ref adMachineAccount, out offlineProvisionDiagnosicInfo);
EnrolmentLog.LogSessionDiagnosticInformation(sessionId, offlineProvisionDiagnosicInfo);
response.RequireReboot = true;
}
}
// Enforce Organisation Unit
if (!MachineInfo.IsCriticalSystemObject && response.OfflineDomainJoin == null && RepoDevice.DeviceProfile.EnforceOrganisationalUnit)
// Enforce Organisational Unit
if (!adMachineAccount.IsCriticalSystemObject && response.OfflineDomainJoin == null && RepoDevice.DeviceProfile.EnforceOrganisationalUnit)
{
var parentDistinguishedName = MachineInfo.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 ((RepoDevice.DeviceProfile.OrganisationalUnit == null && parentDistinguishedName != null
&& parentDistinguishedName.Equals("CN=Computers", StringComparison.InvariantCultureIgnoreCase)) // Null (Default) OU
|| !parentDistinguishedName.Equals(RepoDevice.DeviceProfile.OrganisationalUnit, StringComparison.InvariantCultureIgnoreCase)) // Custom OU
if (!parentDistinguishedName.Equals(RepoDevice.DeviceProfile.OrganisationalUnit, StringComparison.InvariantCultureIgnoreCase)) // Custom OU
{
string newOU = RepoDevice.DeviceProfile.OrganisationalUnit ?? "CN=Computers";
var proposedDomain = ActiveDirectory.GetDomainByDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
var currentDomain = ActiveDirectory.GetDomainByDistinguishedName(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)
domain = proposedDomain;
else if (domain != proposedDomain)
throw new NotSupportedException("To many domains involved in this enrolment, contact support regarding your scenario.");
EnrolmentLog.LogSessionProgress(sessionId, 65, string.Format("Moving Device Organisation Unit: {0} -> {1}", parentDistinguishedName, newOU));
EnrolmentLog.LogSessionTaskMovingDeviceOrganisationUnit(sessionId, parentDistinguishedName, newOU);
MachineInfo.MoveOrganisationUnit(RepoDevice.DeviceProfile.OrganisationalUnit);
MachineInfo = ActiveDirectory.GetMachineAccount(MachineInfo.SamAccountName);
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;
}
}
}
if (MachineInfo != null && !MachineInfo.IsCriticalSystemObject)
if (adMachineAccount != null && !adMachineAccount.IsCriticalSystemObject)
{
EnrolmentLog.LogSessionProgress(sessionId, 75, "Updating Active Directory Computer Account Properties");
MachineInfo.UpdateNetbootGUID(Request.DeviceUUID, Request.DeviceLanMacAddress);
adMachineAccount.UpdateNetbootGUID(Request.DeviceUUID, Request.DeviceLanMacAddress);
if (RepoDevice.AssignedUser != null)
MachineInfo.SetDescription(RepoDevice);
adMachineAccount.SetDescription(RepoDevice);
}
if (RepoDevice.DeviceProfile.DistributionType == DeviceProfile.DistributionTypes.OneToOne)
{
@@ -534,7 +585,7 @@ namespace Disco.BI.DeviceBI
else
{
EnrolmentLog.LogSessionProgress(sessionId, 80, "Retrieving Active Directory Assigned User Account");
ActiveDirectoryUserAccount AssignedUserInfo = ActiveDirectory.GetUserAccount(RepoDevice.AssignedUser.Id);
ActiveDirectoryUserAccount AssignedUserInfo = Services.Interop.ActiveDirectory.ActiveDirectory.RetrieveUserAccount(RepoDevice.AssignedUser.UserId);
EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.SamAccountName, AssignedUserInfo.Domain, AssignedUserInfo.SecurityIdentifier);
response.AllowBootstrapperUninstall = true;
response.DeviceAssignedUserIsLocalAdmin = RepoDevice.DeviceProfile.AssignedUserLocalAdmin;
@@ -1,10 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.BI.Extensions;
using Disco.Models.Repository;
using Disco.BI.Extensions;
using Disco.BI.Interop.ActiveDirectory;
using Disco.Services.Interop.ActiveDirectory;
using System;
namespace Disco.BI.Expressions.Extensions
{
@@ -1,10 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.BI.Extensions;
using Disco.Models.Repository;
using Disco.BI.Extensions;
using Disco.BI.Interop.ActiveDirectory;
using Disco.Services.Interop.ActiveDirectory;
using System;
namespace Disco.BI.Expressions.Extensions
{
@@ -48,7 +48,7 @@ namespace Disco.BI.Extensions
WhoAmIResponse response = new WhoAmIResponse()
{
Username = token.User.Id,
Username = token.User.UserId,
DisplayName = token.User.DisplayName,
Type = token.Has(Claims.ComputerAccount) ? "Computer Account" : "User Account"
};
@@ -1,12 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.Data.Repository;
using Disco.Models.Repository;
using Disco.Data.Repository;
using Disco.BI.Interop.ActiveDirectory;
using Disco.Services.Users;
using Disco.Services.Authorization;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Users;
using System;
using System.Linq;
namespace Disco.BI.Extensions
{
@@ -90,7 +88,7 @@ namespace Disco.BI.Extensions
d.DecommissionReason = Reason;
// Disable AD Account
if (d.ComputerName != null)
if (d.DeviceDomainId != null)
{
var adAccount = d.ActiveDirectoryAccount();
if (adAccount != null && !adAccount.IsCriticalSystemObject)
@@ -117,7 +115,7 @@ namespace Disco.BI.Extensions
d.DecommissionReason = null;
// Enable AD Account
if (d.ComputerName != null)
if (d.DeviceDomainId != null)
{
var adAccount = d.ActiveDirectoryAccount();
if (adAccount != null && !adAccount.IsCriticalSystemObject)
@@ -157,10 +155,10 @@ namespace Disco.BI.Extensions
JobLog jobLog = new JobLog()
{
JobId = j.Id,
TechUserId = UserService.CurrentUser.Id,
TechUserId = UserService.CurrentUser.UserId,
Timestamp = DateTime.Now,
Comments = string.Format("Device Deleted{0}{0}Serial Number: {1}{0}Computer Name: {2}{0}Model: {3}{0}Profile: {4}",
Environment.NewLine, d.SerialNumber, d.ComputerName, d.DeviceModel, d.DeviceProfile)
Environment.NewLine, d.SerialNumber, d.DeviceDomainId, d.DeviceModel, d.DeviceProfile)
};
Database.JobLogs.Add(jobLog);
}
+15 -11
View File
@@ -1,5 +1,4 @@
using System.Linq;
using Disco.BI.Interop.ActiveDirectory;
using Disco.Data.Configuration;
using Disco.Data.Repository;
using Disco.Models.BI.DocumentTemplates;
@@ -10,14 +9,18 @@ using System.IO;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Services.Users;
using Disco.Services.Authorization;
using Disco.Services.Interop.ActiveDirectory;
namespace Disco.BI.Extensions
{
public static class DeviceExtensions
{
public static string ComputerNameRender(this Device device, DiscoDataContext Database)
public static string ComputerNameRender(this Device device, DiscoDataContext Database, ActiveDirectoryDomain Domain)
{
if (Domain == null)
throw new ArgumentNullException("Domain");
DeviceProfile deviceProfile = device.DeviceProfile;
Expressions.Expression computerNameTemplateExpression = null;
computerNameTemplateExpression = Expressions.ExpressionCache.GetValue(DeviceProfileExtensions.ComputerNameExpressionCacheModule, deviceProfile.Id.ToString(), () =>
@@ -40,7 +43,8 @@ namespace Disco.BI.Extensions
{
throw new System.InvalidOperationException("The rendered computer name would be invalid or longer than 24 characters");
}
return rendered.ToString();
return string.Format(@"{0}\{1}", Domain.NetBiosName, rendered);
}
public static System.Collections.Generic.List<DocumentTemplate> AvailableDocumentTemplates(this Device d, DiscoDataContext Database, User User, System.DateTime TimeStamp)
{
@@ -52,7 +56,7 @@ namespace Disco.BI.Extensions
public static bool UpdateLastNetworkLogonDate(this Device Device)
{
return ActiveDirectoryUpdateLastNetworkLogonDateJob.UpdateLastNetworkLogonDate(Device);
return Disco.Services.Interop.ActiveDirectory.Internal.ADUpdateLastNetworkLogonDateJob.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)
@@ -63,7 +67,7 @@ namespace Disco.BI.Extensions
DeviceAttachment da = new DeviceAttachment()
{
DeviceSerialNumber = Device.SerialNumber,
TechUserId = CreatorUser.Id,
TechUserId = CreatorUser.UserId,
Filename = Filename,
MimeType = MimeType,
Timestamp = DateTime.Now,
@@ -160,12 +164,12 @@ namespace Disco.BI.Extensions
newDua = new DeviceUserAssignment()
{
DeviceSerialNumber = d.SerialNumber,
AssignedUserId = u.Id,
AssignedUserId = u.UserId,
AssignedDate = DateTime.Now
};
Database.DeviceUserAssignments.Add(newDua);
d.AssignedUserId = u.Id;
d.AssignedUserId = u.UserId;
d.AssignedUser = u;
}
else
@@ -174,9 +178,9 @@ namespace Disco.BI.Extensions
}
// Update AD Account
if (!string.IsNullOrEmpty(d.ComputerName) && d.ComputerName.Length <= 24)
if (!string.IsNullOrEmpty(d.DeviceDomainId))
{
var adMachineAccount = Interop.ActiveDirectory.ActiveDirectory.GetMachineAccount(d.ComputerName);
var adMachineAccount = ActiveDirectory.RetrieveMachineAccount(d.DeviceDomainId);
if (adMachineAccount != null)
{
adMachineAccount.SetDescription(d);
@@ -188,8 +192,8 @@ namespace Disco.BI.Extensions
public static ActiveDirectoryMachineAccount ActiveDirectoryAccount(this Device Device, params string[] AdditionalProperties)
{
if (!string.IsNullOrEmpty(Device.ComputerName))
return Interop.ActiveDirectory.ActiveDirectory.GetMachineAccount(Device.ComputerName, AdditionalProperties: AdditionalProperties);
if (!string.IsNullOrEmpty(Device.DeviceDomainId))
return ActiveDirectory.RetrieveMachineAccount(Device.DeviceDomainId, AdditionalProperties: AdditionalProperties);
else
return null;
}
@@ -136,7 +136,7 @@ namespace Disco.BI.Extensions
if (!(Data is User))
throw new ArgumentException("This Document Template is configured for Users only", "Data");
User d3 = (User)Data;
return d3.Id;
return d3.UserId;
default:
throw new InvalidOperationException("Invalid Document Template Scope");
}
+12 -12
View File
@@ -41,7 +41,7 @@ namespace Disco.BI.Extensions
throw new InvalidOperationException("Holding Device was Denied");
j.DeviceHeld = DateTime.Now;
j.DeviceHeldTechUserId = Technician.Id;
j.DeviceHeldTechUserId = Technician.UserId;
j.DeviceReadyForReturn = null;
j.DeviceReadyForReturnTechUserId = null;
j.DeviceReturnedDate = null;
@@ -64,7 +64,7 @@ namespace Disco.BI.Extensions
throw new InvalidOperationException("Device Ready for Return was Denied");
j.DeviceReadyForReturn = DateTime.Now;
j.DeviceReadyForReturnTechUserId = Technician.Id;
j.DeviceReadyForReturnTechUserId = Technician.UserId;
}
#endregion
@@ -83,7 +83,7 @@ namespace Disco.BI.Extensions
throw new InvalidOperationException("Device Return was Denied");
j.DeviceReturnedDate = DateTime.Now;
j.DeviceReturnedTechUserId = Technician.Id;
j.DeviceReturnedTechUserId = Technician.UserId;
}
#endregion
@@ -106,7 +106,7 @@ namespace Disco.BI.Extensions
JobLog jobLog = new JobLog()
{
JobId = j.Id,
TechUserId = Technician.Id,
TechUserId = Technician.UserId,
Timestamp = DateTime.Now,
Comments = string.Format("Waiting on User Action{0}Reason: {1}", Environment.NewLine, Reason)
};
@@ -133,7 +133,7 @@ namespace Disco.BI.Extensions
JobLog jobLog = new JobLog()
{
JobId = j.Id,
TechUserId = Technician.Id,
TechUserId = Technician.UserId,
Timestamp = DateTime.Now,
Comments = string.Format("User Action Resolved{0}Resolution: {1}", Environment.NewLine, Resolution)
};
@@ -178,7 +178,7 @@ namespace Disco.BI.Extensions
JobLog jobLog = new JobLog()
{
JobId = j.Id,
TechUserId = TechUser.Id,
TechUserId = TechUser.UserId,
Timestamp = DateTime.Now,
Comments = string.Format("Warranty Claim Submitted{0}{0}Provider: {1}{0}Repair Address: {2}{0}Provider Reference: {3}{0}{0}{4}", Environment.NewLine, WarrantyProvider.Manifest.Name, Address.Name, providerRef, FaultDescription)
};
@@ -248,7 +248,7 @@ namespace Disco.BI.Extensions
Database.JobComponents.Add(new JobComponent()
{
Job = j,
TechUserId = techUser.Id,
TechUserId = techUser.UserId,
Cost = component.Cost,
Description = component.Description
});
@@ -258,7 +258,7 @@ namespace Disco.BI.Extensions
JobLog jobLog = new JobLog()
{
JobId = j.Id,
TechUserId = techUser.Id,
TechUserId = techUser.UserId,
Timestamp = DateTime.Now,
Comments = string.Format("Job Type Converted{0}From: {1}{0}To: {2}", Environment.NewLine, Database.JobTypes.Find(JobType.JobTypeIds.HWar), Database.JobTypes.Find(JobType.JobTypeIds.HNWar))
};
@@ -302,7 +302,7 @@ namespace Disco.BI.Extensions
var techUser = UserService.CurrentUser;
j.JobMetaInsurance.ClaimFormSentDate = DateTime.Now;
j.JobMetaInsurance.ClaimFormSentUserId = techUser.Id;
j.JobMetaInsurance.ClaimFormSentUserId = techUser.UserId;
}
#endregion
@@ -356,7 +356,7 @@ namespace Disco.BI.Extensions
throw new InvalidOperationException("Close was Denied");
j.ClosedDate = DateTime.Now;
j.ClosedTechUserId = Technician.Id;
j.ClosedTechUserId = Technician.UserId;
}
private static bool CanCloseNever(this Job j, JobQueueJob IgnoreJobQueueJob = null)
@@ -475,14 +475,14 @@ namespace Disco.BI.Extensions
JobLog jobLog = new JobLog()
{
JobId = j.Id,
TechUserId = Technician.Id,
TechUserId = Technician.UserId,
Timestamp = DateTime.Now,
Comments = string.Format("Job Forcibly Closed{0}Reason: {1}", Environment.NewLine, Reason)
};
Database.JobLogs.Add(jobLog);
j.ClosedDate = DateTime.Now;
j.ClosedTechUserId = Technician.Id;
j.ClosedTechUserId = Technician.UserId;
}
#endregion
+3 -3
View File
@@ -22,7 +22,7 @@ namespace Disco.BI.Extensions
JobAttachment ja = new JobAttachment()
{
JobId = Job.Id,
TechUserId = CreatorUser.Id,
TechUserId = CreatorUser.UserId,
Filename = Filename,
MimeType = MimeType,
Timestamp = DateTime.Now,
@@ -148,7 +148,7 @@ namespace Disco.BI.Extensions
Database.JobLogs.Add(new JobLog()
{
JobId = j.Id,
TechUserId = TechUser.Id,
TechUserId = TechUser.UserId,
Timestamp = DateTime.Now,
Comments = logBuilder.ToString()
});
@@ -182,7 +182,7 @@ namespace Disco.BI.Extensions
Database.JobComponents.Add(new JobComponent()
{
Job = j,
TechUserId = TechUser.Id,
TechUserId = TechUser.UserId,
Cost = c.Cost,
Description = c.Description
});
@@ -149,7 +149,7 @@ namespace Disco.BI.Extensions
throw new InvalidOperationException("Removing job from queue is Denied");
jqj.RemovedDate = DateTime.Now;
jqj.RemovedUserId = Technician.Id;
jqj.RemovedUserId = Technician.UserId;
jqj.RemovedComment = string.IsNullOrWhiteSpace(Comment) ? null : Comment.Trim();
}
#endregion
@@ -201,7 +201,7 @@ namespace Disco.BI.Extensions
JobQueueId = jq.Id,
JobId = j.Id,
AddedDate = DateTime.Now,
AddedUserId = Technician.Id,
AddedUserId = Technician.UserId,
AddedComment = string.IsNullOrWhiteSpace(Comment) ? null : Comment.Trim(),
SLAExpiresDate = SLAExpires,
Priority = Priority
+3 -3
View File
@@ -19,8 +19,8 @@ namespace Disco.BI.Extensions
UserAttachment ua = new UserAttachment()
{
UserId = User.Id,
TechUserId = CreatorUser.Id,
UserId = User.UserId,
TechUserId = CreatorUser.UserId,
Filename = Filename,
MimeType = MimeType,
Timestamp = DateTime.Now,
@@ -59,7 +59,7 @@ namespace Disco.BI.Extensions
}
public static ActiveDirectoryUserAccount ActiveDirectoryAccount(this User User, params string[] AdditionalProperties)
{
return Interop.ActiveDirectory.ActiveDirectory.GetUserAccount(User.Id, AdditionalProperties);
return Disco.Services.Interop.ActiveDirectory.ActiveDirectory.RetrieveUserAccount(User.UserId, AdditionalProperties);
}
public static bool CanCreateJob(this User u)
File diff suppressed because it is too large. Load diff
@@ -1,19 +0,0 @@
using Disco.Models.Interop.ActiveDirectory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Disco.BI.Interop.ActiveDirectory
{
public static class ActiveDirectoryGroupExtensions
{
public static IEnumerable<Tuple<string, string>> GetMembers(ActiveDirectoryGroup group)
{
throw new NotImplementedException();
}
}
}
@@ -1,198 +1,198 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Text;
using System.Threading;
//using System;
//using System.Collections;
//using System.Collections.Generic;
//using System.DirectoryServices;
//using System.DirectoryServices.ActiveDirectory;
//using System.Runtime.CompilerServices;
//using System.Runtime.InteropServices;
//using System.Security.Principal;
//using System.Text;
//using System.Threading;
namespace Disco.BI.Interop.ActiveDirectory
{
internal static class ActiveDirectoryHelpers
{
#region Static Cached Properties
private static string _DefaultDomainName;
private static string _DefaultDomainPDCName;
private static System.Collections.Generic.List<string> _DefaultDomainDCNames;
private static string _DefaultDomainNetBiosName;
private static string _DefaultDomainQualifiedName;
private static string _DefaultLdapPath;
private static bool _DetermineDomainProperties_Loaded = false;
private static object _DetermineDomainProperties_Lock = new object();
internal static string DefaultDomainName
{
get
{
ActiveDirectoryHelpers.DetermineDomainProperties();
return ActiveDirectoryHelpers._DefaultDomainName;
}
}
internal static string DefaultDomainPDCName
{
get
{
ActiveDirectoryHelpers.DetermineDomainProperties();
return ActiveDirectoryHelpers._DefaultDomainPDCName;
}
}
internal static System.Collections.Generic.List<string> DefaultDomainDCNames
{
get
{
ActiveDirectoryHelpers.DetermineDomainProperties();
return ActiveDirectoryHelpers._DefaultDomainDCNames;
}
}
internal static string DefaultDomainNetBiosName
{
get
{
ActiveDirectoryHelpers.DetermineDomainProperties();
return ActiveDirectoryHelpers._DefaultDomainNetBiosName;
}
}
internal static string DefaultDomainQualifiedName
{
get
{
ActiveDirectoryHelpers.DetermineDomainProperties();
return ActiveDirectoryHelpers._DefaultDomainQualifiedName;
}
}
internal static string DefaultLdapPath
{
get
{
ActiveDirectoryHelpers.DetermineDomainProperties();
return ActiveDirectoryHelpers._DefaultLdapPath;
}
}
internal static string DefaultDCLdapPath(string DC)
{
return string.Format("LDAP://{0}/", DC);
}
internal static DirectoryEntry DefaultLdapRoot
{
get
{
return new DirectoryEntry(string.Concat(ActiveDirectoryHelpers.DefaultLdapPath, ActiveDirectoryHelpers.DefaultDomainQualifiedName));
}
}
internal static DirectoryEntry DefaultDCLdapRoot(string DC)
{
return new DirectoryEntry(string.Concat(ActiveDirectoryHelpers.DefaultDCLdapPath(DC), ActiveDirectoryHelpers.DefaultDomainQualifiedName));
}
//namespace Disco.BI.Interop.ActiveDirectory
//{
// internal static class ActiveDirectoryHelpers
// {
// #region Static Cached Properties
// private static string _DefaultDomainName;
// private static string _DefaultDomainPDCName;
// private static System.Collections.Generic.List<string> _DefaultDomainDCNames;
// private static string _DefaultDomainNetBiosName;
// private static string _DefaultDomainQualifiedName;
// private static string _DefaultLdapPath;
// private static bool _DetermineDomainProperties_Loaded = false;
// private static object _DetermineDomainProperties_Lock = new object();
// internal static string DefaultDomainName
// {
// get
// {
// ActiveDirectoryHelpers.DetermineDomainProperties();
// return ActiveDirectoryHelpers._DefaultDomainName;
// }
// }
// internal static string DefaultDomainPDCName
// {
// get
// {
// ActiveDirectoryHelpers.DetermineDomainProperties();
// return ActiveDirectoryHelpers._DefaultDomainPDCName;
// }
// }
// internal static System.Collections.Generic.List<string> DefaultDomainDCNames
// {
// get
// {
// ActiveDirectoryHelpers.DetermineDomainProperties();
// return ActiveDirectoryHelpers._DefaultDomainDCNames;
// }
// }
// internal static string DefaultDomainNetBiosName
// {
// get
// {
// ActiveDirectoryHelpers.DetermineDomainProperties();
// return ActiveDirectoryHelpers._DefaultDomainNetBiosName;
// }
// }
// internal static string DefaultDomainQualifiedName
// {
// get
// {
// ActiveDirectoryHelpers.DetermineDomainProperties();
// return ActiveDirectoryHelpers._DefaultDomainQualifiedName;
// }
// }
// internal static string DefaultLdapPath
// {
// get
// {
// ActiveDirectoryHelpers.DetermineDomainProperties();
// return ActiveDirectoryHelpers._DefaultLdapPath;
// }
// }
// internal static string DefaultDCLdapPath(string DC)
// {
// return string.Format("LDAP://{0}/", DC);
// }
// internal static DirectoryEntry DefaultLdapRoot
// {
// get
// {
// return new DirectoryEntry(string.Concat(ActiveDirectoryHelpers.DefaultLdapPath, ActiveDirectoryHelpers.DefaultDomainQualifiedName));
// }
// }
// internal static DirectoryEntry DefaultDCLdapRoot(string DC)
// {
// return new DirectoryEntry(string.Concat(ActiveDirectoryHelpers.DefaultDCLdapPath(DC), ActiveDirectoryHelpers.DefaultDomainQualifiedName));
// }
private static void DetermineDomainProperties()
{
if (!ActiveDirectoryHelpers._DetermineDomainProperties_Loaded)
{
lock (ActiveDirectoryHelpers._DetermineDomainProperties_Lock)
{
// private static void DetermineDomainProperties()
// {
// if (!ActiveDirectoryHelpers._DetermineDomainProperties_Loaded)
// {
// lock (ActiveDirectoryHelpers._DetermineDomainProperties_Lock)
// {
if (!ActiveDirectoryHelpers._DetermineDomainProperties_Loaded)
{
using (Domain domain = Domain.GetDomain(new DirectoryContext(DirectoryContextType.Domain)))
{
ActiveDirectoryHelpers._DefaultDomainName = domain.Name;
ActiveDirectoryHelpers._DefaultDomainPDCName = domain.PdcRoleOwner.Name;
ActiveDirectoryHelpers._DefaultDomainDCNames = new System.Collections.Generic.List<string>(domain.DomainControllers.Count);
foreach (DomainController dc in domain.DomainControllers)
{
ActiveDirectoryHelpers._DefaultDomainDCNames.Add(dc.Name);
}
}
ActiveDirectoryHelpers._DefaultDomainQualifiedName = string.Format("DC={0}", ActiveDirectoryHelpers._DefaultDomainName.Replace(".", ",DC="));
ActiveDirectoryHelpers._DefaultLdapPath = string.Format("LDAP://{0}/", ActiveDirectoryHelpers._DefaultDomainPDCName);
using (DirectoryEntry entry = new DirectoryEntry(string.Format("{0}CN=Partitions,CN=Configuration,{1}", ActiveDirectoryHelpers._DefaultLdapPath, ActiveDirectoryHelpers._DefaultDomainQualifiedName)))
{
using (DirectorySearcher searcher = new DirectorySearcher(entry, "(&(objectClass=crossRef)(nETBIOSName=*))", new string[] { "nETBIOSName" }))
{
SearchResult result = searcher.FindOne();
if (result != null)
{
ActiveDirectoryHelpers._DefaultDomainNetBiosName = result.Properties["nETBIOSName"][0].ToString();
}
else
{
ActiveDirectoryHelpers._DefaultDomainNetBiosName = ActiveDirectoryHelpers._DefaultDomainQualifiedName;
}
}
}
}
ActiveDirectoryHelpers._DetermineDomainProperties_Loaded = true;
}
}
}
#endregion
// if (!ActiveDirectoryHelpers._DetermineDomainProperties_Loaded)
// {
// using (Domain domain = Domain.GetDomain(new DirectoryContext(DirectoryContextType.Domain)))
// {
// ActiveDirectoryHelpers._DefaultDomainName = domain.Name;
// ActiveDirectoryHelpers._DefaultDomainPDCName = domain.PdcRoleOwner.Name;
// ActiveDirectoryHelpers._DefaultDomainDCNames = new System.Collections.Generic.List<string>(domain.DomainControllers.Count);
// foreach (DomainController dc in domain.DomainControllers)
// {
// ActiveDirectoryHelpers._DefaultDomainDCNames.Add(dc.Name);
// }
// }
// ActiveDirectoryHelpers._DefaultDomainQualifiedName = string.Format("DC={0}", ActiveDirectoryHelpers._DefaultDomainName.Replace(".", ",DC="));
// ActiveDirectoryHelpers._DefaultLdapPath = string.Format("LDAP://{0}/", ActiveDirectoryHelpers._DefaultDomainPDCName);
// using (DirectoryEntry entry = new DirectoryEntry(string.Format("{0}CN=Partitions,CN=Configuration,{1}", ActiveDirectoryHelpers._DefaultLdapPath, ActiveDirectoryHelpers._DefaultDomainQualifiedName)))
// {
// using (DirectorySearcher searcher = new DirectorySearcher(entry, "(&(objectClass=crossRef)(nETBIOSName=*))", new string[] { "nETBIOSName" }))
// {
// SearchResult result = searcher.FindOne();
// if (result != null)
// {
// ActiveDirectoryHelpers._DefaultDomainNetBiosName = result.Properties["nETBIOSName"][0].ToString();
// }
// else
// {
// ActiveDirectoryHelpers._DefaultDomainNetBiosName = ActiveDirectoryHelpers._DefaultDomainQualifiedName;
// }
// }
// }
// }
// ActiveDirectoryHelpers._DetermineDomainProperties_Loaded = true;
// }
// }
// }
// #endregion
internal static string ConvertBytesToSDDLString(byte[] SID)
{
SecurityIdentifier sID = new SecurityIdentifier(SID, 0);
// internal static string ConvertBytesToSDDLString(byte[] SID)
// {
// SecurityIdentifier sID = new SecurityIdentifier(SID, 0);
return sID.ToString();
}
// return sID.ToString();
// }
internal static byte[] ConvertSDDLStringToBytes(string SidSsdlString)
{
SecurityIdentifier sID = new SecurityIdentifier(SidSsdlString);
// internal static byte[] ConvertSDDLStringToBytes(string SidSsdlString)
// {
// SecurityIdentifier sID = new SecurityIdentifier(SidSsdlString);
var sidBytes = new byte[sID.BinaryLength];
// var sidBytes = new byte[sID.BinaryLength];
sID.GetBinaryForm(sidBytes, 0);
// sID.GetBinaryForm(sidBytes, 0);
return sidBytes;
}
// return sidBytes;
// }
internal static byte[] BuildPrimaryGroupSid(byte[] UserSID, int PrimaryGroupId)
{
var groupSid = (byte[])UserSID.Clone();
// 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;
}
// 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;
}
// return groupSid;
// }
internal static string ConvertBytesToBinarySidString(byte[] SID)
{
StringBuilder escapedSid = new StringBuilder();
// internal static string ConvertBytesToBinarySidString(byte[] SID)
// {
// StringBuilder escapedSid = new StringBuilder();
foreach (var sidByte in SID)
{
escapedSid.Append('\\');
escapedSid.Append(sidByte.ToString("x2"));
}
// foreach (var sidByte in SID)
// {
// escapedSid.Append('\\');
// escapedSid.Append(sidByte.ToString("x2"));
// }
return escapedSid.ToString();
}
// 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();
}
}
}
}
// 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();
// }
// }
// }
//}
@@ -1,301 +0,0 @@
using Disco.Models.Interop.ActiveDirectory;
using Disco.Models.Repository;
using System;
using System.Collections;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Text;
using System.Net.NetworkInformation;
using System.Management;
namespace Disco.BI.Interop.ActiveDirectory
{
public static class ActiveDirectoryMachineAccountExtensions
{
public static void DeleteAccount(this ActiveDirectoryMachineAccount account)
{
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 machineDE = new DirectoryEntry(account.Path))
{
DeleteAccountRecursive(machineDE);
using (var machineDEParent = machineDE.Parent)
{
machineDEParent.Children.Remove(machineDE);
}
}
}
private static void DeleteAccountRecursive(DirectoryEntry parent)
{
List<DirectoryEntry> children = new List<DirectoryEntry>();
foreach (DirectoryEntry child in parent.Children)
children.Add(child);
foreach (var child in children)
{
DeleteAccountRecursive(child);
parent.Children.Remove(child);
child.Dispose();
}
}
private static void SetNetbootGUID(this ActiveDirectoryMachineAccount account, System.Guid updatedNetbootGUID)
{
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 machineDE = new DirectoryEntry(account.Path))
{
PropertyValueCollection netbootGUIDProp = machineDE.Properties["netbootGUID"];
bool flag = netbootGUIDProp.Count > 0;
if (flag)
{
netbootGUIDProp.Clear();
}
netbootGUIDProp.Add(updatedNetbootGUID.ToByteArray());
machineDE.CommitChanges();
}
}
public static void SetDescription(this ActiveDirectoryMachineAccount account, string Description)
{
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
{
PropertyValueCollection descriptionProp = machineDE.Properties["description"];
if (descriptionProp.Count > 0)
{
descriptionProp.Clear();
}
if (!string.IsNullOrEmpty(Description))
{
descriptionProp.Add(Description);
}
machineDE.CommitChanges();
}
}
public static void SetDescription(this ActiveDirectoryMachineAccount account, Device Device)
{
System.Text.StringBuilder descriptionBuilder = new System.Text.StringBuilder();
if (Device.AssignedUserId != null)
{
descriptionBuilder.Append(Device.AssignedUser.Id).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(description);
}
public static void DisableAccount(this ActiveDirectoryMachineAccount account)
{
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 machineDE = new DirectoryEntry(account.Path))
{
int accountControl = (int)machineDE.Properties["userAccountControl"][0];
int updatedAccountControl = (accountControl | 2);
if (accountControl != updatedAccountControl)
{
machineDE.Properties["userAccountControl"][0] = updatedAccountControl;
machineDE.CommitChanges();
}
}
}
public static void EnableAccount(this ActiveDirectoryMachineAccount account)
{
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 machineDE = new DirectoryEntry(account.Path))
{
int accountControl = (int)machineDE.Properties["userAccountControl"][0];
if ((accountControl & 2) == 2)
{
int updatedAccountControl = (accountControl ^ 2);
machineDE.Properties["userAccountControl"][0] = updatedAccountControl;
machineDE.CommitChanges();
}
}
}
public static bool UpdateNetbootGUID(this ActiveDirectoryMachineAccount account, 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));
System.Guid netbootGUID = System.Guid.Empty;
bool flag = !string.IsNullOrWhiteSpace(UUID);
if (flag)
{
netbootGUID = ActiveDirectoryMachineAccountExtensions.NetbootGUIDFromUUID(UUID);
}
else
{
flag = !string.IsNullOrWhiteSpace(MACAddress);
if (flag)
{
netbootGUID = ActiveDirectoryMachineAccountExtensions.NetbootGUIDFromMACAddress(MACAddress);
}
}
flag = (netbootGUID != System.Guid.Empty && netbootGUID != account.NetbootGUID);
bool UpdateNetbootGUID;
if (flag)
{
account.SetNetbootGUID(netbootGUID);
UpdateNetbootGUID = true;
}
else
{
UpdateNetbootGUID = false;
}
return UpdateNetbootGUID;
}
internal 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;
}
internal 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;
}
}
// Didn't Work - WMI Limitation?
// G# - 2012-06-18
//public static void OnlineRenameComputer(this ActiveDirectoryMachineAccount account, string NewComputerName)
//{
// 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));
// try
// {
// IPStatus pingResult = account.PingComputer();
// if (pingResult != IPStatus.Success)
// throw new Exception(string.Format("Ping Error Result: {0}", pingResult.ToString()));
// }
// catch (Exception ex)
// {
// throw new Exception(string.Format("Error trying to Ping the Device: {0}; {1}", account.DnsName, ex.Message), ex);
// }
// ConnectionOptions wmiConnectionOptions = new ConnectionOptions()
// {
// Authentication = AuthenticationLevel.PacketPrivacy,
// Impersonation = ImpersonationLevel.Impersonate,
// EnablePrivileges = true,
// Timeout = new TimeSpan(0, 0, 6)
// };
// ManagementPath wmiPath = new ManagementPath()
// {
// Server = account.DnsName,
// NamespacePath = @"root\cimv2",
// ClassName = "Win32_ComputerSystem"
// };
// ManagementScope wmiScope = new ManagementScope(wmiPath, wmiConnectionOptions);
// ObjectGetOptions wmiGetOptions = new ObjectGetOptions() { Timeout = new TimeSpan(0, 1, 0) };
// using (ManagementClass wmiClass = new ManagementClass(wmiScope, wmiPath, wmiGetOptions))
// {
// foreach (ManagementObject wmiWin32ComputerSystem in wmiClass.GetInstances())
// {
// UInt32 result = (UInt32)wmiWin32ComputerSystem.InvokeMethod("Rename", new object[] { NewComputerName });
// if (result != 0)
// throw new Exception(string.Format("Error Renaming Computer; WMI Remote Method 'Rename' returned: {0}", result));
// }
// }
//}
public static void MoveOrganisationUnit(this ActiveDirectoryMachineAccount account, 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))
{
string ouPath;
if (string.IsNullOrWhiteSpace(NewOrganisationUnit))
ouPath = string.Format("{0}CN=Computers,{1}", ActiveDirectoryHelpers.DefaultLdapPath, ActiveDirectoryHelpers.DefaultDomainQualifiedName);
else
ouPath = string.Format("{0}{1},{2}", ActiveDirectoryHelpers.DefaultLdapPath, NewOrganisationUnit, ActiveDirectoryHelpers.DefaultDomainQualifiedName);
using (DirectoryEntry ou = new DirectoryEntry(ouPath))
{
using (DirectoryEntry i = new DirectoryEntry(account.Path) { UsePropertyCache = false })
{
i.MoveTo(ou);
}
}
}
}
public static string ParentDistinguishedName(this ActiveDirectoryMachineAccount account)
{
// Determine Parent
if (!string.IsNullOrWhiteSpace(account.DistinguishedName))
return account.DistinguishedName.Substring(0, account.DistinguishedName.IndexOf(",DC=")).Substring(account.DistinguishedName.IndexOf(",") + 1);
else
return null;
}
}
}
@@ -1,14 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;
namespace Disco.BI.Interop.ActiveDirectory
{
public class ActiveDirectoryOrganisationalUnit
{
public string Name { get; set; }
public string Path { get; set; }
public List<ActiveDirectoryOrganisationalUnit> Children { get; set; }
}
}
//namespace Disco.BI.Interop.ActiveDirectory
//{
// public class ActiveDirectoryOrganisationalUnit
// {
// public string Name { get; set; }
// public string Path { get; set; }
// public List<ActiveDirectoryOrganisationalUnit> Children { get; set; }
// }
//}
@@ -1,264 +1,264 @@
using Disco.Data.Repository;
using Disco.Services.Logging;
using Disco.Models.Repository;
using Quartz;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.DirectoryServices;
using System.Linq;
using System.Linq.Expressions;
using System.Net.NetworkInformation;
using System.Reflection;
using Disco.Services.Tasks;
namespace Disco.BI.Interop.ActiveDirectory
{
public class ActiveDirectoryUpdateLastNetworkLogonDateJob : ScheduledTask
{
//using Disco.Data.Repository;
//using Disco.Services.Logging;
//using Disco.Models.Repository;
//using Quartz;
//using System;
//using System.Collections;
//using System.Collections.Generic;
//using System.Diagnostics;
//using System.DirectoryServices;
//using System.Linq;
//using System.Linq.Expressions;
//using System.Net.NetworkInformation;
//using System.Reflection;
//using Disco.Services.Tasks;
//namespace Disco.BI.Interop.ActiveDirectory
//{
// public class ActiveDirectoryUpdateLastNetworkLogonDateJob : 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 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));
// public override void InitalizeScheduledTask(DiscoDataContext Database)
// {
// // ActiveDirectoryUpdateLastNetworkLogonDateJob @ 11:30pm
// TriggerBuilder triggerBuilder = TriggerBuilder.Create().
// WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(23, 30));
this.ScheduleTask(triggerBuilder);
}
// this.ScheduleTask(triggerBuilder);
// }
protected override void ExecuteTask()
{
int changeCount;
// 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");
}
// 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()
});
}
// SystemLog.LogInformation(new string[]
// {
// "Updated LastNetworkLogon Device Property for Device/s",
// changeCount.ToString()
// });
// }
public static ScheduledTaskStatus ScheduleImmediately()
{
var existingTask = ScheduledTasks.GetTaskStatuses(typeof(ActiveDirectoryUpdateLastNetworkLogonDateJob)).Where(s => s.IsRunning).FirstOrDefault();
if (existingTask != null)
return existingTask;
// public static ScheduledTaskStatus ScheduleImmediately()
// {
// var existingTask = ScheduledTasks.GetTaskStatuses(typeof(ActiveDirectoryUpdateLastNetworkLogonDateJob)).Where(s => s.IsRunning).FirstOrDefault();
// if (existingTask != null)
// return existingTask;
var instance = new ActiveDirectoryUpdateLastNetworkLogonDateJob();
return instance.ScheduleTask();
}
// var instance = new ActiveDirectoryUpdateLastNetworkLogonDateJob();
// return instance.ScheduleTask();
// }
public static bool UpdateLastNetworkLogonDate(Device Device)
{
System.DateTime? computerLastLogonDate = Device.LastNetworkLogonDate;
if (!string.IsNullOrEmpty(Device.ComputerName))
{
foreach (var dcName in ActiveDirectoryHelpers.DefaultDomainDCNames)
{
try
{
Ping p = new Ping();
PingReply pr;
try
{
pr = p.Send(dcName, 500);
}
finally
{
if (p != null)
{
((System.IDisposable)p).Dispose();
}
}
if (pr.Status == IPStatus.Success)
{
using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultDCLdapRoot(dcName))
{
DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectCategory=Computer)(sAMAccountName={0}$))", ActiveDirectoryHelpers.EscapeLdapQuery(Device.ComputerName)), new string[]
{
"lastLogon"
}, SearchScope.Subtree);
SearchResult dResult = dSearcher.FindOne();
if (dResult != null)
{
ResultPropertyValueCollection dProp = dResult.Properties["lastLogon"];
if (dProp != null && dProp.Count > 0)
{
long lastLogonInt = (long)dProp[0];
if (lastLogonInt > 0L)
{
System.DateTime computerNameDate = System.DateTime.FromFileTime(lastLogonInt);
if (computerLastLogonDate.HasValue)
{
if (System.DateTime.Compare(computerLastLogonDate.Value, computerNameDate) < 0)
{
computerLastLogonDate = computerNameDate;
}
}
else
{
computerLastLogonDate = computerNameDate;
}
}
}
}
// public static bool UpdateLastNetworkLogonDate(Device Device)
// {
// System.DateTime? computerLastLogonDate = Device.LastNetworkLogonDate;
// if (!string.IsNullOrEmpty(Device.ComputerName))
// {
// foreach (var dcName in ActiveDirectoryHelpers.DefaultDomainDCNames)
// {
// try
// {
// Ping p = new Ping();
// PingReply pr;
// try
// {
// pr = p.Send(dcName, 500);
// }
// finally
// {
// if (p != null)
// {
// ((System.IDisposable)p).Dispose();
// }
// }
// if (pr.Status == IPStatus.Success)
// {
// using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultDCLdapRoot(dcName))
// {
// DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectCategory=Computer)(sAMAccountName={0}$))", ActiveDirectoryHelpers.EscapeLdapQuery(Device.ComputerName)), new string[]
// {
// "lastLogon"
// }, SearchScope.Subtree);
// SearchResult dResult = dSearcher.FindOne();
// if (dResult != null)
// {
// ResultPropertyValueCollection dProp = dResult.Properties["lastLogon"];
// if (dProp != null && dProp.Count > 0)
// {
// long lastLogonInt = (long)dProp[0];
// if (lastLogonInt > 0L)
// {
// System.DateTime computerNameDate = System.DateTime.FromFileTime(lastLogonInt);
// if (computerLastLogonDate.HasValue)
// {
// if (System.DateTime.Compare(computerLastLogonDate.Value, computerNameDate) < 0)
// {
// computerLastLogonDate = computerNameDate;
// }
// }
// else
// {
// computerLastLogonDate = computerNameDate;
// }
// }
// }
// }
}
}
else
{
SystemLog.LogError(new string[]
{
string.Format("Unable to ping Domain Controller: '{0}' (ref: Disco.BI.Interop.ActiveDirectory.ActiveDirectoryUpdateLastNetworkLogonDateJob.UpdateDeviceLastNetworkLogonDate)", dcName)
});
}
}
catch (System.Exception ex)
{
SystemLog.LogException("UpdateDeviceLastNetworkLogonDate", ex);
}
}
}
bool UpdateLastNetworkLogonDate;
if (computerLastLogonDate.HasValue)
{
if (!Device.LastNetworkLogonDate.HasValue)
{
Device.LastNetworkLogonDate = computerLastLogonDate;
UpdateLastNetworkLogonDate = true;
return UpdateLastNetworkLogonDate;
}
if (System.DateTime.Compare(computerLastLogonDate.Value, Device.LastNetworkLogonDate.Value) > 0)
{
Device.LastNetworkLogonDate = computerLastLogonDate;
UpdateLastNetworkLogonDate = true;
return UpdateLastNetworkLogonDate;
}
}
UpdateLastNetworkLogonDate = false;
return UpdateLastNetworkLogonDate;
}
private static void UpdateLastNetworkLogonDates(DiscoDataContext Database, ScheduledTaskStatus status)
{
System.Collections.Generic.Dictionary<string, System.DateTime> computerLastLogonDates = new System.Collections.Generic.Dictionary<string, System.DateTime>();
// }
// }
// else
// {
// SystemLog.LogError(new string[]
// {
// string.Format("Unable to ping Domain Controller: '{0}' (ref: Disco.BI.Interop.ActiveDirectory.ActiveDirectoryUpdateLastNetworkLogonDateJob.UpdateDeviceLastNetworkLogonDate)", dcName)
// });
// }
// }
// catch (System.Exception ex)
// {
// SystemLog.LogException("UpdateDeviceLastNetworkLogonDate", ex);
// }
// }
// }
// bool UpdateLastNetworkLogonDate;
// if (computerLastLogonDate.HasValue)
// {
// if (!Device.LastNetworkLogonDate.HasValue)
// {
// Device.LastNetworkLogonDate = computerLastLogonDate;
// UpdateLastNetworkLogonDate = true;
// return UpdateLastNetworkLogonDate;
// }
// if (System.DateTime.Compare(computerLastLogonDate.Value, Device.LastNetworkLogonDate.Value) > 0)
// {
// Device.LastNetworkLogonDate = computerLastLogonDate;
// UpdateLastNetworkLogonDate = true;
// return UpdateLastNetworkLogonDate;
// }
// }
// UpdateLastNetworkLogonDate = false;
// return UpdateLastNetworkLogonDate;
// }
// private static void UpdateLastNetworkLogonDates(DiscoDataContext Database, ScheduledTaskStatus status)
// {
// System.Collections.Generic.Dictionary<string, System.DateTime> computerLastLogonDates = new System.Collections.Generic.Dictionary<string, System.DateTime>();
int progressDCCountTotal = ActiveDirectoryHelpers.DefaultDomainDCNames.Count;
int progressDCCount = 0;
double progressDCProgress = 0;
if (progressDCCountTotal > 0)
progressDCProgress = 90 / progressDCCountTotal;
// int progressDCCountTotal = ActiveDirectoryHelpers.DefaultDomainDCNames.Count;
// int progressDCCount = 0;
// double progressDCProgress = 0;
// if (progressDCCountTotal > 0)
// progressDCProgress = 90 / progressDCCountTotal;
foreach (var dcName in ActiveDirectoryHelpers.DefaultDomainDCNames)
{
try
{
PingReply pr;
using (Ping p = new Ping())
{
pr = p.Send(dcName, 2000);
}
if (pr.Status == IPStatus.Success)
{
using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultDCLdapRoot(dcName))
{
double progressDCStart = 5 + (progressDCCount * progressDCProgress);
status.UpdateStatus(progressDCStart, string.Format("Querying Domain Controller: {0}", dcName), "Searching...");
// foreach (var dcName in ActiveDirectoryHelpers.DefaultDomainDCNames)
// {
// try
// {
// PingReply pr;
// using (Ping p = new Ping())
// {
// pr = p.Send(dcName, 2000);
// }
// if (pr.Status == IPStatus.Success)
// {
// using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultDCLdapRoot(dcName))
// {
// double progressDCStart = 5 + (progressDCCount * progressDCProgress);
// status.UpdateStatus(progressDCStart, string.Format("Querying Domain Controller: {0}", dcName), "Searching...");
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, "(objectCategory=Computer)", new string[] { "sAMAccountName", "lastLogon" }, SearchScope.Subtree))
{
using (SearchResultCollection dResults = dSearcher.FindAll())
{
// using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, "(objectCategory=Computer)", new string[] { "sAMAccountName", "lastLogon" }, SearchScope.Subtree))
// {
// using (SearchResultCollection dResults = dSearcher.FindAll())
// {
int progressItemCount = 0;
double progressItemProgress = dResults.Count == 0 ? 0 : (progressDCProgress / dResults.Count);
// int progressItemCount = 0;
// double progressItemProgress = dResults.Count == 0 ? 0 : (progressDCProgress / dResults.Count);
foreach (SearchResult dResult in dResults)
{
ResultPropertyValueCollection dProp = dResult.Properties["sAMAccountName"];
if (dProp != null && dProp.Count > 0)
{
string computerName = ((string)dProp[0]).TrimEnd(new char[] { '$' }).ToUpper();
// foreach (SearchResult dResult in dResults)
// {
// ResultPropertyValueCollection dProp = dResult.Properties["sAMAccountName"];
// if (dProp != null && dProp.Count > 0)
// {
// string computerName = ((string)dProp[0]).TrimEnd(new char[] { '$' }).ToUpper();
if (progressItemCount % 150 == 0) // Only Update Status every 150 devices
status.UpdateStatus(progressDCStart + (progressItemProgress * progressItemCount), string.Format("Analysing Device: {0}", computerName));
// if (progressItemCount % 150 == 0) // Only Update Status every 150 devices
// status.UpdateStatus(progressDCStart + (progressItemProgress * progressItemCount), string.Format("Analysing Device: {0}", computerName));
dProp = dResult.Properties["lastLogon"];
if (dProp != null && dProp.Count > 0)
{
long lastLogonInt = (long)dProp[0];
if (lastLogonInt > 0L)
{
System.DateTime computerNameDate = System.DateTime.FromFileTime(lastLogonInt);
System.DateTime existingDate;
if (computerLastLogonDates.TryGetValue(computerName, out existingDate))
{
if (System.DateTime.Compare(existingDate, computerNameDate) < 0)
{
computerLastLogonDates[computerName] = computerNameDate;
}
}
else
{
computerLastLogonDates[computerName] = computerNameDate;
}
}
}
}
progressItemCount++;
}
}
}
}
}
else
{
SystemLog.LogError(new string[]
{
string.Format("Unable to ping Domain Controller: '{0}' (ref: Disco.BI.Interop.ActiveDirectory.ActiveDirectoryUpdateLastNetworkLogonDateJob.UpdateLastNetworkLogonDates)", dcName)
});
}
}
catch (System.Exception ex)
{
SystemLog.LogException("UpdateLastNetworkLogonDates", ex);
}
progressDCCount++;
}
// dProp = dResult.Properties["lastLogon"];
// if (dProp != null && dProp.Count > 0)
// {
// long lastLogonInt = (long)dProp[0];
// if (lastLogonInt > 0L)
// {
// System.DateTime computerNameDate = System.DateTime.FromFileTime(lastLogonInt);
// System.DateTime existingDate;
// if (computerLastLogonDates.TryGetValue(computerName, out existingDate))
// {
// if (System.DateTime.Compare(existingDate, computerNameDate) < 0)
// {
// computerLastLogonDates[computerName] = computerNameDate;
// }
// }
// else
// {
// computerLastLogonDates[computerName] = computerNameDate;
// }
// }
// }
// }
// progressItemCount++;
// }
// }
// }
// }
// }
// else
// {
// SystemLog.LogError(new string[]
// {
// string.Format("Unable to ping Domain Controller: '{0}' (ref: Disco.BI.Interop.ActiveDirectory.ActiveDirectoryUpdateLastNetworkLogonDateJob.UpdateLastNetworkLogonDates)", dcName)
// });
// }
// }
// catch (System.Exception ex)
// {
// SystemLog.LogException("UpdateLastNetworkLogonDates", ex);
// }
// progressDCCount++;
// }
foreach (Device d in Database.Devices.Where(device => device.ComputerName != null))
{
DateTime computerLastLogonDate;
if (computerLastLogonDates.TryGetValue(d.ComputerName.ToUpper(), out computerLastLogonDate))
{
if (d.LastNetworkLogonDate.HasValue)
{
// Change accuracy to the second
computerLastLogonDate = new DateTime((computerLastLogonDate.Ticks / 10000000L) * 10000000L);
// foreach (Device d in Database.Devices.Where(device => device.ComputerName != null))
// {
// DateTime computerLastLogonDate;
// if (computerLastLogonDates.TryGetValue(d.ComputerName.ToUpper(), out computerLastLogonDate))
// {
// if (d.LastNetworkLogonDate.HasValue)
// {
// // Change accuracy to the second
// computerLastLogonDate = new DateTime((computerLastLogonDate.Ticks / 10000000L) * 10000000L);
if (System.DateTime.Compare(d.LastNetworkLogonDate.Value, computerLastLogonDate) < 0)
{
d.LastNetworkLogonDate = computerLastLogonDate;
}
}
else
{
d.LastNetworkLogonDate = computerLastLogonDate;
}
}
}
}
}
}
// if (System.DateTime.Compare(d.LastNetworkLogonDate.Value, computerLastLogonDate) < 0)
// {
// d.LastNetworkLogonDate = computerLastLogonDate;
// }
// }
// else
// {
// d.LastNetworkLogonDate = computerLastLogonDate;
// }
// }
// }
// }
// }
//}
@@ -1,37 +1,37 @@
using Disco.Models.Interop.ActiveDirectory;
using System;
using Disco.Models.Repository;
namespace Disco.BI.Interop.ActiveDirectory
{
internal static class ActiveDirectoryUserAccountExtensions
{
public static object GetPropertyValue(this ActiveDirectoryUserAccount 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 "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;
}
}
}
}
//using Disco.Models.Interop.ActiveDirectory;
//using System;
//using Disco.Models.Repository;
//namespace Disco.BI.Interop.ActiveDirectory
//{
// internal static class ActiveDirectoryUserAccountExtensions
// {
// public static object GetPropertyValue(this ActiveDirectoryUserAccount 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 "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;
// }
// }
// }
//}
+7 -3
View File
@@ -65,6 +65,10 @@ namespace Disco.BI.Interop.Pdf
DataObjects = new object[DataObjectsIds.Length];
for (int idIndex = 0; idIndex < DataObjectsIds.Length; idIndex++)
{
string dataObjectId = DataObjectsIds[idIndex];
if (!dataObjectId.Contains('\\'))
dataObjectId = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + dataObjectId;
DataObjects[idIndex] = UserService.GetUser(DataObjectsIds[idIndex], Database, true);
if (DataObjects[idIndex] == null)
throw new Exception(string.Format("Unknown Username specified: {0}", DataObjectsIds[idIndex]));
@@ -122,7 +126,7 @@ namespace Disco.BI.Interop.Pdf
if (pdfFieldKey.Equals("DiscoAttachmentId", StringComparison.InvariantCultureIgnoreCase))
{
AcroFields.Item fields = pdfStamper.AcroFields.Fields[pdfFieldKey];
string fieldValue = dt.UniqueIdentifier(Data, CreatorUser.Id, TimeStamp);
string fieldValue = dt.UniqueIdentifier(Data, CreatorUser.UserId, TimeStamp);
if (FlattenFields)
pdfStamper.AcroFields.SetField(pdfFieldKey, String.Empty);
else
@@ -132,7 +136,7 @@ namespace Disco.BI.Interop.Pdf
for (int pdfFieldOrdinal = 0; pdfFieldOrdinal < fields.Size; pdfFieldOrdinal++)
{
AcroFields.FieldPosition pdfFieldPosition = pdfFieldPositions[pdfFieldOrdinal];
string pdfBarcodeContent = dt.UniquePageIdentifier(Data, CreatorUser.Id, TimeStamp, pdfFieldPosition.page);
string pdfBarcodeContent = dt.UniquePageIdentifier(Data, CreatorUser.UserId, TimeStamp, pdfFieldPosition.page);
BarcodeQRCode pdfBarcode = new BarcodeQRCode(pdfBarcodeContent, (int)pdfFieldPosition.position.Width, (int)pdfFieldPosition.position.Height, null);
iTextSharp.text.Image pdfBarcodeImage = pdfBarcode.GetImage();
pdfBarcodeImage.SetAbsolutePosition(pdfFieldPosition.position.Left, pdfFieldPosition.position.Bottom);
@@ -237,7 +241,7 @@ namespace Disco.BI.Interop.Pdf
JobLog jl = new JobLog()
{
JobId = j.Id,
TechUserId = CreatorUser.Id,
TechUserId = CreatorUser.UserId,
Timestamp = DateTime.Now
};
jl.Comments = string.Format("Document Generated{0}{1} [{2}]", Environment.NewLine, dt.Description, dt.Id);
@@ -61,7 +61,7 @@ namespace Disco.BI.Interop.SignalRHandlers
{
User u = (User)e.Entity;
var userDevices = e.Database.Devices.Where(d => d.AssignedUserId == u.Id);
var userDevices = e.Database.Devices.Where(d => d.AssignedUserId == u.UserId);
foreach (var userDevice in userDevices)
{
@@ -76,7 +76,7 @@ namespace Disco.BI.Interop.SignalRHandlers
{
User u = (User)e.Entity;
notificationContext.Connection.Broadcast(u.Id);
notificationContext.Connection.Broadcast(u.UserId);
}
}
}
+4 -4
View File
@@ -15,7 +15,7 @@ namespace Disco.BI.JobBI
Job j = new Job()
{
JobType = type,
OpenedTechUserId = initialTech.Id,
OpenedTechUserId = initialTech.UserId,
OpenedTechUser = initialTech,
OpenedDate = DateTime.Now
};
@@ -31,7 +31,7 @@ namespace Disco.BI.JobBI
if (user != null)
{
j.User = user;
j.UserId = user.Id;
j.UserId = user.UserId;
}
// Sub Types
@@ -61,7 +61,7 @@ namespace Disco.BI.JobBI
JobQueueId = queue.queue.Id,
Job = j,
AddedDate = DateTime.Now,
AddedUserId = initialTech.Id,
AddedUserId = initialTech.UserId,
AddedComment = commentBuilder.ToString(),
SLAExpiresDate = queue.queue.DefaultSLAExpiry.HasValue ? (DateTime?)DateTime.Now.AddMinutes(queue.queue.DefaultSLAExpiry.Value) : null,
Priority = JobQueuePriority.Normal
@@ -110,7 +110,7 @@ namespace Disco.BI.JobBI
Database.JobComponents.Add(new JobComponent()
{
Job = j,
TechUserId = initialTech.Id,
TechUserId = initialTech.UserId,
Cost = c.Cost,
Description = c.Description
});
-3
View File
@@ -175,10 +175,7 @@
<Compile Include="BI\DocumentTemplateBI\Importer\DocumentImporterCleanCacheJob.cs" />
<Compile Include="BI\DocumentTemplateBI\Importer\DocumentImporterLog.cs" />
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectory.cs" />
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryCachedGroups.cs" />
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryGroupExtensions.cs" />
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryHelpers.cs" />
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryMachineAccountExtensions.cs" />
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryOrganisationalUnit.cs" />
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryUpdateLastNetworkLogonDateJob.cs" />
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryUserAccountExtensions.cs" />
@@ -26,6 +26,7 @@ namespace Disco.Client.Extensions
enrol.DeviceModelType = Interop.SystemAudit.DeviceType;
enrol.DeviceIsPartOfDomain = Interop.SystemAudit.DeviceIsPartOfDomain;
enrol.DeviceDNSDomainName = Interop.SystemAudit.DeviceDNSDomainName;
// LAN
enrol.DeviceLanMacAddress = Interop.Network.PrimaryLanMacAddress;
+4 -1
View File
@@ -17,6 +17,7 @@ namespace Disco.Client.Interop
public static string DeviceType { get; private set; }
public static string DeviceUUID { get; private set; }
public static bool DeviceIsPartOfDomain { get; private set; }
public static string DeviceDNSDomainName { get; private set; }
public static void Initialize()
{
@@ -56,7 +57,7 @@ namespace Disco.Client.Interop
// Get System Information
try
{
using (ManagementObjectSearcher mSearcher = new ManagementObjectSearcher("SELECT Manufacturer, Model, PartOfDomain, PCSystemType FROM Win32_ComputerSystem"))
using (ManagementObjectSearcher mSearcher = new ManagementObjectSearcher("SELECT Manufacturer, Model, PartOfDomain, PCSystemType, Domain FROM Win32_ComputerSystem"))
{
using (ManagementObjectCollection mResults = mSearcher.Get())
{
@@ -74,6 +75,8 @@ namespace Disco.Client.Interop
DeviceIsPartOfDomain = (bool)mItem.GetPropertyValue("PartOfDomain");
DeviceType = PCSystemTypeToString((UInt16)mItem.GetPropertyValue("PCSystemType"));
DeviceDNSDomainName = DeviceIsPartOfDomain ? mItem.GetPropertyValue("Domain") as string : null;
}
else
{
@@ -0,0 +1,37 @@
using Disco.Data.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Data.Configuration.Modules
{
public class ActiveDirectoryConfiguration : ConfigurationBase
{
public ActiveDirectoryConfiguration(DiscoDataContext Database) : base(Database) { }
public override string Scope
{
get { return "ActiveDirectory"; }
}
public List<string> SearchContainers
{
get
{
return GetFromJson<List<string>>(null);
}
set
{
SetAsJson(value);
}
}
public bool? SearchEntireForest
{
get { return GetFromJson<bool?>(null); }
set { SetAsJson(value); }
}
}
}
@@ -21,6 +21,7 @@ namespace Disco.Data.Configuration
this.moduleDeviceProfilesConfiguration = new Lazy<Modules.DeviceProfilesConfiguration>(() => new Modules.DeviceProfilesConfiguration(Database));
this.moduleOrganisationAddressesConfiguration = new Lazy<Modules.OrganisationAddressesConfiguration>(() => new Modules.OrganisationAddressesConfiguration(Database));
this.moduleJobPreferencesConfiguration = new Lazy<Modules.JobPreferencesConfiguration>(() => new Modules.JobPreferencesConfiguration(Database));
this.moduleActiveDirectoryConfiguration = new Lazy<Modules.ActiveDirectoryConfiguration>(() => new Modules.ActiveDirectoryConfiguration(Database));
}
#region Configuration Modules
@@ -29,6 +30,7 @@ namespace Disco.Data.Configuration
private Lazy<Modules.DeviceProfilesConfiguration> moduleDeviceProfilesConfiguration;
private Lazy<Modules.OrganisationAddressesConfiguration> moduleOrganisationAddressesConfiguration;
private Lazy<Modules.JobPreferencesConfiguration> moduleJobPreferencesConfiguration;
private Lazy<Modules.ActiveDirectoryConfiguration> moduleActiveDirectoryConfiguration;
public Modules.BootstrapperConfiguration Bootstrapper
{
@@ -58,6 +60,13 @@ namespace Disco.Data.Configuration
return moduleJobPreferencesConfiguration.Value;
}
}
public Modules.ActiveDirectoryConfiguration ActiveDirectory
{
get
{
return moduleActiveDirectoryConfiguration.Value;
}
}
#endregion
+9
View File
@@ -48,6 +48,7 @@
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Data.Entity" />
<Reference Include="System.DirectoryServices" />
<Reference Include="System.Drawing" />
<Reference Include="System.Reactive.Core">
<HintPath>..\packages\Rx-Core.2.1.30214.0\lib\Net45\System.Reactive.Core.dll</HintPath>
@@ -72,6 +73,7 @@
<Compile Include="Configuration\CommunityHelpers.cs" />
<Compile Include="Configuration\ConfigurationBase.cs" />
<Compile Include="Configuration\ConfigurationCache.cs" />
<Compile Include="Configuration\Modules\ActiveDirectoryConfiguration.cs" />
<Compile Include="Configuration\Modules\JobPreferencesConfiguration.cs" />
<Compile Include="Configuration\SystemConfiguration.cs" />
<Compile Include="Configuration\Modules\BootstrapperConfiguration.cs" />
@@ -130,6 +132,10 @@
<Compile Include="Migrations\201402032322432_DBv12.Designer.cs">
<DependentUpon>201402032322432_DBv12.cs</DependentUpon>
</Compile>
<Compile Include="Migrations\201404080227546_DBv13.cs" />
<Compile Include="Migrations\201404080227546_DBv13.Designer.cs">
<DependentUpon>201404080227546_DBv13.cs</DependentUpon>
</Compile>
<Compile Include="Migrations\Configuration.cs" />
<Compile Include="Migrations\DiscoDataMigrator.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
@@ -181,6 +187,9 @@
<EmbeddedResource Include="Migrations\201402032322432_DBv12.resx">
<DependentUpon>201402032322432_DBv12.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Migrations\201404080227546_DBv13.resx">
<DependentUpon>201404080227546_DBv13.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
+27
View File
@@ -0,0 +1,27 @@
// <auto-generated />
namespace Disco.Data.Migrations
{
using System.Data.Entity.Migrations;
using System.Data.Entity.Migrations.Infrastructure;
using System.Resources;
public sealed partial class DBv13 : IMigrationMetadata
{
private readonly ResourceManager Resources = new ResourceManager(typeof(DBv13));
string IMigrationMetadata.Id
{
get { return "201404080227546_DBv13"; }
}
string IMigrationMetadata.Source
{
get { return null; }
}
string IMigrationMetadata.Target
{
get { return Resources.GetString("Target"); }
}
}
}
@@ -0,0 +1,18 @@
namespace Disco.Data.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class DBv13 : DbMigration
{
public override void Up()
{
AlterColumn("dbo.Devices", "ComputerName", c => c.String(maxLength: 50));
}
public override void Down()
{
AlterColumn("dbo.Devices", "ComputerName", c => c.String(maxLength: 24));
}
}
}
@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Target" xml:space="preserve">
<value>H4sIAAAAAAAEAO19yXIcSZLlfUTmHyA4zbRIE9ySSZaA3YIkyCyiSAIFMLOOFGeEAfAuD/dodw8mUL82h/mk+YUx321Rtd2XQOKSSYSZq6mpPVPb9f2///N/j//zbpMc/CB5EWfp28NnT54eHpB0la3j9Obt4a68/vfXh//5H//zfxy/X2/uDn7v8r2o8tEv0+Lt4W1Zbv9ydFSsbskmKp5s4lWeFdl1+WSVbY6idXb0/OnTN0fPnh0RKuKQyjo4OL7cpWW8IfUf9M93Wboi23IXJZ+zNUmK9neaclVLPfgSbUixjVbk7eFpXKyyJ6dRGT25JNusiMssvz88OEniiCpzRZLrw4Pty7/8VpCrMs/Sm6ttVMZR8vV+S2j6dZQUpFX9L9uXpto/fV5pfxSlaVZScVnqVPvDvl60Zu+pBcr7Sq26dm8PqRGu45tdXsv/WBIuO/3gb+Se+4H+dJFnW5KX95fkuhVytaK/HB4c6XNScWK+4yOxjP47XnylNf2jzClKDg8+xHdk/YmkN+Vtb+DP0V33y2sKld/SmGKKflPmO5r6ZZck0feE9NmPlKXWqk5c5u9RsrOtKf2notjmb7bU46MBBEponGar3Yak5Vey2SZRSVyQ8XFt39zVN1YWeOFt91NSrPJ42/Qxq7Kf/+RduAu8X/kW+iFOSpK/v9vmpChCV1sGHaAAhVRJ0g9ZvunK/iXLEhKl+rp8iX7EN7XHEoSeZd+vdt9rr3t4cEmSOk9xG28bH/1EhPQ37oMPeba5zBIA+my+b1fZLl9VDZYZZP4a5TekdOyBg6AwfQ/MRgupSpikpz737iyMtlYl/zSfi3j21L7WKMJPyjJa3dZwGxflHXCNUN51CdNanJIf8Yq8yzbbLKUykWrwmdBa4NnkSijy2taBfvv3HdkhbdClYlpD6ZK6YCYHPWsPgmhZpSmUFJMhHaU8DiqiVlToptNLq5P5VIjHzfQzoY9p+eI54DbomuOKLkXIryQldA5P1hfVqJqn1bekroXer1VVq1dAiuJMRvSxPKRJ2e+youwKPSWreBMlhwcXOf1Xu8R8fXhwtYoqcZAZ7fxWbSyFy6rTv8k+TvRZcD7EaSGZHbqaeobk73Sl+ZGBg/bolU1rPKge6dqPfvLuR5+jdHcdrcpdTnLruZ134U2/mqPUZoS0Kvmlb8Gn5DraJeUF7S23UUFOqyV258Lov7/GGweRTVdzc4YWSv8jyvMoLe9p6o94bY0Ve9uFmEp6+mXYr2mcuF01VNp/4wYfUWc2FRlBuCwBpkNOO4Ukj6Pky27zvcKM9UYg97Xdhon3yvOkKEjpVLa3p/iUraLge1Pm/iTM5LCSRH+8jhOiH0VNhP0SlatbT7WqHrujw3P1l/Vg62lcCqj4JiXr3wqS2+9neGMqKsovpPwjy//5KbvJ0hDDz0mSZH/8lka78raa6qyq6c/7NM/6Qd14h09sppxUsnQ6GsmqFUr0wkyNWMsLM3ivss0mrrdjw6jHSrwkUcF4kGZcEZML33FYtzSyGMTg4RYc5+x0bJ2QQss2x7d+UBYVFTIgA66Yy22XrHZzCmXrdFxVLhlRlM9jqybrx1RNz+eT2p5Nxhqfy+PW+tWnjZiNZrrI52zNIysOZkMMDed1w8UpKaM4UVWgyYEqziUjCvN53BQdtqxVyg65UIWlLIjScr5gG5KtvCZdgnD1MwbdOi3AdkfnvR7QhofD5MvlTEVcTNxmeelU9HxHSf4bPO36/Ty/idK4qOF9sl5Xh8DB5tH9fYGQ9xjMDBsXtKzvu6pW3I5O3XWFxMJaPGu0KKGqlkGraGLn9+l1ljcbDZ2532Xpj6qfDWBynWW3wvFqugqud4mqWebJ6clqle1Sb4nsRKBaHScn603sbYB2/UIboqB+7JLEm+iGUMddT/Gr8cR7HUP/HV/XC6Nu58x65ffqZeC9M9VIZz0Thkc/bL7sMQ420+I/9yjoPxyYbj6bjai77TaJZzg46GvRTYkntmLlI8fcdK/k/30XtTDy2oWrR/9w23rdOcDvURKvqeeMExWKbCS6taX/CPsxLXZ5mO2XWlSUrshsHaOtTJCG6WszV8vQSU+7iBy7YMWAKfYfg40Z+RNsj0bMiYymaPbwh05Wm0tqbQOM/PXOkcOQ3+2w2w774XfmTZcxdAF17zAh8PcYV7s8naPcX2O6iJmlxhe3WUqczvX8ry2931BPKqy/TQu3PwFC/UCFc9V24pD+Tdy8FZKkHTkx3XYnrt4x1Wwg8nlAFYVkUE0xj9tup/P+snp7XJHZbK8Z3F733g+tpYm7of2P0ogwpHiPAw2owo0G8HWFcR82zTS+uDw4CbDhav+gKkChU7yo0vkvX58K9SLI5zr3pcHzPaQNlXnuVXwlq9uZ+vWHOCEOkzf1/odRyZ/petLhCmWAkquVbFFGm6337pXj8jJAHcSnNWEfQAb0V5aTLMhvYRMxU/267mWi45AX1bPLotO1z2e9xBYf0RroLX+D6i+9ytLUQ8ofYCeen2i6jCCNHNXdUPCzbkrb7NXZDkFQodNfKWUq4Om/5r1O+FsaGVbGzh8ZXi4KtpaC97BMVl92y8Sx7h0Z6S/cnnF9m/yQJoszvise0w0Zdd1ZHMb5lrbVesbZcqNAmCvFd1uyoqh7l2RFmKOjRtI41jEvP0RNPiTRzTCn7mY7n6M0uiGVM2rTXV4T/JUka1/1BknzGXvQwfGhh/9GdKPCJYnW9x+y/JKUuzwNY1pe5txGbrQIdbuelThfzf4RxSUtiNq4HuZXLID8J2Ca8AHf+nTpaX71szQfYdNsZ066t8sW0QIQtZTvkr0mdcorw8h7PW4LPcgCXrFVD52IuGnAj+xoS4nZ+MbiU8H2ErLYNhk/xKJqitl4NflUUE0hixuy2AEKVRXKyqsr5wBVBrK5qQ07f00FsI+gqsB5FZVCPnCtHu/7tRUTs8NV4nMpKyNkdfCousNVLkvlEASt+UQoDIuQw+HsUfO6m80BaMilQQryGRz0+5TdoJrRNECn9ldImy5pnHhE7UAHhSJqk9AoRF26g2KfSRn198cw/bhMgJJSOqSpnMlR3e4eokrbLg+iLJuM6crlcVT1S5aaaMtkQxQWcmA6i9m8Ygl088fJ95L2PXCc9TReN3eu5+QWkcCAcUnK47vF+DBPpmnFfEMgPB4zT1ry4zFz2GPmevzxn20CLgiZjwY5X+bFI9N4k9NlJNsoh8t8WaqzZXVOTSXCniyzs/JHz78Uzz/nw+WJIjwqHJP5GhPoKfAiNJRXGqQjTknOoFZS6ZJsejFdzT7236X039lnMS5v/F26qnrTBUC+uB8TqmNWcpEuySZhKgXrht0GzgPri3W1fDtkgD59sl6HusVVSZrJPdRltz178tedl2ST/QhzMNuKmuc0ti18LjNefTp5f7eNc1KEsORFHmc58+ic20oeEn1ceC1KHUK/c15wAP0+FQ+fP2Rx2GH13U4HXDu43W58I7LzEFrFmJywen0GpZJDLltVmY6oVZbLC6vLZFEqzOYLMnA+pFHzi/3OXYBnWHOuHD+uHCLn+la4KvRdllCUWhvb39Z1YIBuJPCLGBJoBJBemX//L7IqP67nDOZgcCRiT+GC+SWv20XMABhinER1lIdSV7fJH/g6uM92Um7rQQPM5T9lRXGen0ZV7K8Qc6j3VXQ21wjeAS52ujpe/7no19s4pwMU/eFdtCtI3y6u0dNEeQ5Dmb9BRSX+cWv7qvmVtw7/iMuUFAUpqj+LNn4EsY4g4W+MX3b5TRLl919vyXVJ+/xttj6/pv4gt7VJgDAe7Z9VSO4rQoLEM7/IknhFvmRVzD5/+PLSrsp5HAKvRXgrvcupiIojNy+/ZJa1e+ldu0uyolP//JKsdyvCX4U2JnH1ftlS3pKcjj2E9sp6hp6XsXXnDBDplTbn+XUXGs//QUoUbyqyzis6moV54cIInGirxmWZb38rDZhe4VfXzG8rC+Yy0xf4TKG9lFtfF/mTEFPH/jrbXs0c399VS/EoCb7ENppmtoV/ym5uwvj1TiI1LXVl9cXNmepUnUsmxIAAJGivt7ndifQT8DalT8dgr3ruVd/4WPQ+o3YZvpOpNo40xeG728qul+S/d3GguJ2Y7HkOFERtjM6anAUvo44XUTxKFSu589Swm4ed52s6PY3iQK9rAbFLqJ/jiKGkB7fWItRMVRI6j4U/pj+y+s3PisSBDkoFkXMdmG4j6l1dKNj8Zxhd4eFmTZ3E+WZNnQYjzZpUo6Pp8xO1DOW7FNWn2DTM+Hvrs1hsCHU1BHZka/ydiwncD3ix8dW1+sP3VrXvPnOpfP+tbd2Rode06ujnypojX5lUHPvUq94muxGoEoo9Ce031jVW7k+o6gsMkqa1BT9V1hX4wqSm0GcOb4HDvh400Nt7Wcyy1E0YeW7kuMALCE33GCN4SlYJTfAQKyJHOAIcTPbo0ece5svM+aOxPT7snLTk2Z9EPLCHnVpf5sTzCvs0nA82yPMNqRDoIQeaSa/zuM8+ZRMpXn5qMxu0QND3nye78jbL43/VtapKfEiDzDxXcKe8cwkdXhdnxeh30CznMAwd50PC18Uo1KJmd5y6otM1ufM7MXS53ffa+5FxWjKvdn6J06i6yqbrnK9evH5pfbadVnm9L5XVV7xrLxnkvCxJqouqIeNjTjqXdp+WMK4AnZfIeZBhEchoNxruNpyvWtGpZVxU79wvSUS9KPXgH4s6cG5vtt9oh8uTe2pWts/x1vlMqkbo8bc+v/4UX9Nv6/Xv28Onkjm5D66yKtpum/eZLnNJzZH22Z9rsn+qH/e3mV9oMjdXswddXuryZ2kF6T7/T0/lZmgMrmoEmT3cuwnOU/I1+xyl96ZNUH9A/zM0g0NNwPDLfV2abgVUhY4NCs0+ptdVl65Ffmu96K/V5WRMVRMBH5OE3FRhHjoU2Yv4Pa5wuBos9tJexkWWp9lNHm1vh4Z6bSHmr9Hqn7W76yzxLine truncated
</data>
</root>
+129
View File
@@ -3,6 +3,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.Models.Repository;
using System.Data.SqlClient;
using System.DirectoryServices.ActiveDirectory;
using System.DirectoryServices;
namespace Disco.Data.Repository
{
@@ -15,6 +18,9 @@ namespace Disco.Data.Repository
Database.SeedDeviceProfiles();
Database.SeedJobTypes();
Database.SeedJobSubTypes();
// Migration Maintenance
Database.MigratePreDomainObjects();
}
public static void SeedDeploymentId(this DiscoDataContext Database)
@@ -304,5 +310,128 @@ namespace Disco.Data.Repository
}
}
// End Added: 2013-02-07 G#
#region Migrate Users SQL
private const string MigratePreDomainUsers_Sql = @"INSERT INTO [Users] SELECT @IdNew, u.DisplayName, u.Surname, u.GivenName, u.PhoneNumber, u.EmailAddress FROM [Users] u WHERE [Id]=@IdExisting;
UPDATE [JobQueueJobs] SET [AddedUserId]=@IdNew WHERE [AddedUserId]=@IdExisting;
UPDATE [JobQueueJobs] SET [RemovedUserId]=@IdNew WHERE [RemovedUserId]=@IdExisting;
UPDATE [DeviceAttachments] SET [TechUserId]=@IdNew WHERE [TechUserId]=@IdExisting;
UPDATE [Devices] SET [AssignedUserId]=@IdNew WHERE [AssignedUserId]=@IdExisting;
UPDATE [DeviceUserAssignments] SET [AssignedUserId]=@IdNew WHERE [AssignedUserId]=@IdExisting;
UPDATE [JobAttachments] SET [TechUserId]=@IdNew WHERE [TechUserId]=@IdExisting;
UPDATE [JobComponents] SET [TechUserId]=@IdNew WHERE [TechUserId]=@IdExisting;
UPDATE [JobLogs] SET [TechUserId]=@IdNew WHERE [TechUserId]=@IdExisting;
UPDATE [JobMetaInsurances] SET [ClaimFormSentUserId]=@IdNew WHERE [ClaimFormSentUserId]=@IdExisting;
UPDATE [JobMetaNonWarranties] SET [AccountingChargeAddedUserId]=@IdNew WHERE [AccountingChargeAddedUserId]=@IdExisting;
UPDATE [JobMetaNonWarranties] SET [AccountingChargePaidUserId]=@IdNew WHERE [AccountingChargePaidUserId]=@IdExisting;
UPDATE [JobMetaNonWarranties] SET [AccountingChargeRequiredUserId]=@IdNew WHERE [AccountingChargeRequiredUserId]=@IdExisting;
UPDATE [JobMetaNonWarranties] SET [InvoiceReceivedUserId]=@IdNew WHERE [InvoiceReceivedUserId]=@IdExisting;
UPDATE [JobMetaNonWarranties] SET [PurchaseOrderRaisedUserId]=@IdNew WHERE [PurchaseOrderRaisedUserId]=@IdExisting;
UPDATE [JobMetaNonWarranties] SET [PurchaseOrderSentUserId]=@IdNew WHERE [PurchaseOrderSentUserId]=@IdExisting;
UPDATE [Jobs] SET [ClosedTechUserId]=@IdNew WHERE [ClosedTechUserId]=@IdExisting;
UPDATE [Jobs] SET [DeviceHeldTechUserId]=@IdNew WHERE [DeviceHeldTechUserId]=@IdExisting;
UPDATE [Jobs] SET [DeviceReadyForReturnTechUserId]=@IdNew WHERE [DeviceReadyForReturnTechUserId]=@IdExisting;
UPDATE [Jobs] SET [DeviceReturnedTechUserId]=@IdNew WHERE [DeviceReturnedTechUserId]=@IdExisting;
UPDATE [Jobs] SET [OpenedTechUserId]=@IdNew WHERE [OpenedTechUserId]=@IdExisting;
UPDATE [Jobs] SET [UserId]=@IdNew WHERE [UserId]=@IdExisting;
UPDATE [UserAttachments] SET [TechUserId]=@IdNew WHERE [TechUserId]=@IdExisting;
UPDATE [UserAttachments] SET [UserId]=@IdNew WHERE [UserId]=@IdExisting;
DELETE [Users] WHERE [Id]=@IdExisting;";
#endregion
public static void MigratePreDomainObjects(this DiscoDataContext Database)
{
if (Database.Users.Count(u => !u.UserId.Contains(@"\")) > 0)
{
// Determine Computer Domain
string netBiosName = null;
string defaultNamingContext;
using (Domain d = Domain.GetComputerDomain())
{
string ldapPath = string.Format("LDAP://{0}/", d.Name);
string configurationNamingContext;
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, SearchScope.OneLevel))
{
SearchResult configResult = configSearcher.FindOne();
if (configResult != null)
netBiosName = configResult.Properties["NetBIOSName"][0].ToString();
else
netBiosName = null;
}
}
}
if (string.IsNullOrWhiteSpace(netBiosName))
throw new InvalidOperationException("Unable to determine the Domains NetBIOS Name");
// MIGRATE SETTINGS
// Authorization Roles
foreach (var authRole in Database.AuthorizationRoles.Where(ar => ar.SubjectIds != null).ToList())
{
var ids = string.Join(",", authRole.SubjectIds.Split(',').Select(id => id.Contains('\\') ? id : string.Format("{0}\\{1}", netBiosName, id)));
if (ids != authRole.SubjectIds)
authRole.SubjectIds = ids;
}
// Job Queues
foreach (var jobQueue in Database.JobQueues.Where(jq => jq.SubjectIds != null).ToList())
{
var ids = string.Join(",", jobQueue.SubjectIds.Split(',').Select(id => id.Contains('\\') ? id : string.Format("{0}\\{1}", netBiosName, id)));
if (ids != jobQueue.SubjectIds)
jobQueue.SubjectIds = ids;
}
// Device Profiles - OU
foreach (var deviceProfile in Database.DeviceProfiles.Where(dp => dp.OrganisationalUnit == null || !dp.OrganisationalUnit.Contains(@"DC=")).ToList())
{
if (string.IsNullOrWhiteSpace(deviceProfile.OrganisationalUnit))
deviceProfile.OrganisationalUnit = string.Format("CN=Computers,{0}", defaultNamingContext);
else
deviceProfile.OrganisationalUnit = string.Format("{0},{1}", deviceProfile.OrganisationalUnit, defaultNamingContext);
}
Database.SaveChanges();
// MIGRATE DEVICES
foreach (var device in Database.Devices.Where(d => d.DeviceDomainId != null && !d.DeviceDomainId.Contains(@"\")).ToList())
{
device.DeviceDomainId = string.Format("{0}\\{1}", netBiosName, device.DeviceDomainId);
}
Database.SaveChanges();
// MIGRATE USERS
foreach (var user in Database.Users.Where(u => !u.UserId.Contains(@"\")).ToList())
{
SqlParameter idExisting = new SqlParameter("@IdExisting", System.Data.SqlDbType.NVarChar, 50);
idExisting.Value = user.UserId;
SqlParameter idNew = new SqlParameter("@IdNew", System.Data.SqlDbType.NVarChar, 50);
idNew.Value = string.Format("{0}\\{1}", netBiosName, user.UserId);
Database.Database.ExecuteSqlCommand(MigratePreDomainUsers_Sql, idExisting, idNew);
}
}
}
}
}
+1
View File
@@ -15,6 +15,7 @@ namespace Disco.Models.ClientServices
public string DeviceSerialNumber { get; set; }
public string DeviceUUID { get; set; }
public string DeviceDNSDomainName { get; set; }
public string DeviceComputerName { get; set; }
public bool DeviceIsPartOfDomain { get; set; }
+5 -1
View File
@@ -38,6 +38,7 @@
<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" />
@@ -46,6 +47,9 @@
</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" />
@@ -168,7 +172,7 @@
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
<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" />
<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" />
</VisualStudio>
</ProjectExtensions>
<PropertyGroup>
@@ -0,0 +1,30 @@
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,19 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace Disco.Models.Interop.ActiveDirectory
{
public class ActiveDirectoryGroup : IActiveDirectoryObject
{
public string Name { get; set; }
public string DistinguishedName { get; set; }
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 List<string> MemberOf { get; set; }
public string NetBiosId { get { return string.Format(@"{0}\{1}", Domain, SamAccountName); } }
}
}
@@ -1,21 +1,23 @@
using System;
using Disco.Models.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.Models.Repository;
namespace Disco.Models.Interop.ActiveDirectory
{
public class ActiveDirectoryMachineAccount : IActiveDirectoryObject
{
public string DistinguishedName { get; set; }
public string DnsName { get; set; }
public string Domain { get; set; }
public string Name { get; set; }
public Guid NetbootGUID { get; set; }
public string SecurityIdentifier { get; set; }
public string Path { 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 DnsName { get; set; }
public Guid NetbootGUID { get; set; }
public bool IsCriticalSystemObject { get; set; }
public Dictionary<string, object[]> LoadedProperties { get; set; }
@@ -23,10 +25,11 @@ namespace Disco.Models.Interop.ActiveDirectory
{
return new User
{
Id = this.SamAccountName,
UserId = this.Domain + "\\" + this.SamAccountName,
DisplayName = this.Name
};
}
public string NetBiosId { get { return string.Format(@"{0}\{1}", Domain, SamAccountName); } }
}
}
@@ -0,0 +1,16 @@
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; }
}
}
@@ -0,0 +1,16 @@
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; }
}
}
@@ -8,25 +8,29 @@ namespace Disco.Models.Interop.ActiveDirectory
{
public class ActiveDirectoryUserAccount : IActiveDirectoryObject
{
public string DisplayName { get; set; }
public string DistinguishedName { get; set; }
public string Domain { get; set; }
public string Email { get; set; }
public string GivenName { get; set; }
public List<string> Groups { get; set; }
public string Name { get; set; }
public string SamAccountName { get; set; }
public string DistinguishedName { get; set; }
public string SecurityIdentifier { get; set; }
public string Path { get; set; }
public string Phone { get; set; }
public string SamAccountName { 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
{
Id = this.SamAccountName,
UserId = this.Domain + "\\" + this.SamAccountName,
DisplayName = this.DisplayName,
Surname = this.Surname,
GivenName = this.GivenName,
@@ -35,5 +39,6 @@ namespace Disco.Models.Interop.ActiveDirectory
};
}
public string NetBiosId { get { return string.Format(@"{0}\{1}", Domain, SamAccountName); } }
}
}
@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Disco.Models.Interop.ActiveDirectory
{
public interface IActiveDirectoryObject
@@ -11,7 +6,9 @@ namespace Disco.Models.Interop.ActiveDirectory
string DistinguishedName { get; set; }
string SecurityIdentifier { get; set; }
string Domain { get; set; }
string SamAccountName { get; set; }
string NetBiosId { get; }
string Name { get; set; }
}
+22 -2
View File
@@ -22,8 +22,8 @@ namespace Disco.Models.Repository
public int DeviceProfileId { get; set; }
public int? DeviceBatchId { get; set; }
[StringLength(24)]
public string ComputerName { get; set; }
[StringLength(50), Column("ComputerName")]
public string DeviceDomainId { get; set; }
public string AssignedUserId { get; set; }
public DateTime? LastNetworkLogonDate { get; set; }
@@ -67,6 +67,26 @@ namespace Disco.Models.Repository
return this.SerialNumber;
}
[NotMapped]
public string ComputerName
{
get
{
var index = DeviceDomainId.IndexOf('\\');
return index < 0 ? DeviceDomainId : DeviceDomainId.Substring(index + 1);
}
}
[NotMapped]
public string ComputerDomainName
{
get
{
var index = DeviceDomainId.IndexOf('\\');
return index < 0 ? null : DeviceDomainId.Substring(0, index);
}
}
public enum DecommissionReasons
{
EndOfLife = 0,
+24 -4
View File
@@ -9,8 +9,8 @@ namespace Disco.Models.Repository
{
public class User
{
[StringLength(50), Key]
public string Id { get; set; }
[StringLength(50), Key, Column("Id")]
public string UserId { get; set; }
[StringLength(200)]
public string DisplayName { get; set; }
@@ -30,14 +30,34 @@ namespace Disco.Models.Repository
[InverseProperty("UserId")]
public virtual IList<Job> Jobs { get; set; }
[NotMapped, Obsolete("Should be using Combined Domain\\User format - UserId")]
public string Id
{
get
{
var index = UserId.IndexOf('\\');
return index < 0 ? UserId : UserId.Substring(index + 1);
}
}
[NotMapped]
public string Domain
{
get
{
var index = UserId.IndexOf('\\');
return index < 0 ? null : UserId.Substring(0, index);
}
}
public override string ToString()
{
return string.Format("{0} ({1})", this.DisplayName, this.Id);
return string.Format("{0} ({1})", this.DisplayName, this.UserId);
}
public void UpdateSelf(User u)
{
if (!this.Id.Equals(u.Id, StringComparison.InvariantCultureIgnoreCase))
if (!this.UserId.Equals(u.UserId, StringComparison.InvariantCultureIgnoreCase))
throw new ArgumentException("User Id's do not match", "u");
if (this.Surname != u.Surname)
@@ -7,6 +7,7 @@ namespace Disco.Models.Services.Jobs.JobLists
{
public int JobId { get; set; }
#pragma warning disable 809
[Obsolete("Use [int] JobId instead")]
public override string Id
{
@@ -20,6 +21,7 @@ namespace Disco.Models.Services.Jobs.JobLists
this.JobId = int.Parse(value);
}
}
#pragma warning restore 618
public DateTime OpenedDate { get; set; }
public DateTime? ClosedDate { get; set; }
public string JobTypeId { get; set; }
@@ -30,6 +32,7 @@ namespace Disco.Models.Services.Jobs.JobLists
public int? DeviceAddressId { get; set; }
public string DeviceAddress { get; set; }
public string OpenedTechUserId { get; set; }
public string OpenedTechUserFriendlyId { get; set; }
public string OpenedTechUserDisplayName { get; set; }
public string StatusDescription { get; set; }
public string StatusId { get; set; }
@@ -13,7 +13,7 @@ namespace Disco.Models.Services.Searching
public string Id { get; set; }
public string Type { get { return type; } }
public string Description { get { return string.Format("{0} ({1})", this.Id, this.ComputerName); } }
public string ScoreValue { get { return string.Format("{0} {1} {2} {3}", this.Id, this.AssignedUserId, this.AssignedUserDisplayName, this.AssetNumber); } }
public string ScoreValue { get { return string.Format("{0} {1} {2} {3} {4}", this.Id, this.AssignedUserId.Substring(0, this.AssignedUserId.IndexOf('\\')), this.AssignedUserId, this.AssignedUserDisplayName, this.AssetNumber); } }
public string AssetNumber { get; set; }
public string AssignedUserDescription
@@ -13,11 +13,12 @@ namespace Disco.Models.Services.Searching
public virtual string Id { get; set; }
public string Type { get { return type; } }
public string Description { get { return string.Format("{0} ({1}; {2})", this.Id, this.UserId, this.DeviceSerialNumber); } }
public string ScoreValue { get { return string.Format("{0} {1} {2} {3}", this.Id, this.UserId, this.DeviceSerialNumber, this.UserDisplayName); } }
public string ScoreValue { get { return string.Format("{0} {1} {2} {3} {4}", this.Id, this.UserId.Substring(0, this.UserId.IndexOf('\\')), this.UserId, this.DeviceSerialNumber, this.UserDisplayName); } }
public string DeviceSerialNumber { get; set; }
public string UserId { get; set; }
public string UserFriendlyId { get; set; }
public string UserDisplayName { get; set; }
}
}
@@ -13,7 +13,7 @@ namespace Disco.Models.Services.Searching
public string Id { get; set; }
public string Type { get { return type; } }
public string Description { get { return string.Format("{0} ({1})", this.DisplayName, this.Id); } }
public string ScoreValue { get { return string.Format("{0} {1}", this.Id, this.DisplayName); } }
public string ScoreValue { get { return string.Format("{0} {1} {2}", this.Id.Substring(0, this.Id.IndexOf('\\')), this.Id, this.DisplayName); } }
public int AssignedDevicesCount { get; set; }
public string DisplayName { get; set; }
+8
View File
@@ -59,6 +59,7 @@ namespace Disco.Services.Authorization
{ "Config.Plugin.Install", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Config.Plugin.Install, (c, v) => c.Config.Plugin.Install = v, "Install/Update Plugins", "Can install and update plugins", false) },
{ "Config.Plugin.Show", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Config.Plugin.Show, (c, v) => c.Config.Plugin.Show = v, "Show Plugins", "Can show plugins", false) },
{ "Config.Plugin.Uninstall", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Config.Plugin.Uninstall, (c, v) => c.Config.Plugin.Uninstall = v, "Uninstall Plugins", "Can uninstall plugins", false) },
{ "Config.System.ConfigureActiveDirectory", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Config.System.ConfigureActiveDirectory, (c, v) => c.Config.System.ConfigureActiveDirectory = v, "Configure Active Directory Settings", "Can configure the Active Directory interoperability settings", false) },
{ "Config.System.ConfigureProxy", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Config.System.ConfigureProxy, (c, v) => c.Config.System.ConfigureProxy = v, "Configure Proxy Settings", "Can configure the proxy settings", false) },
{ "Config.System.Show", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Config.System.Show, (c, v) => c.Config.System.Show = v, "Show System Configuration", "Can show the system configuration", false) },
{ "Config.Organisation.ConfigureAddresses", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Config.Organisation.ConfigureAddresses, (c, v) => c.Config.Organisation.ConfigureAddresses = v, "Configure Addresses", "Can configure organisation addresses", false) },
@@ -286,6 +287,7 @@ namespace Disco.Services.Authorization
new ClaimNavigatorItem("Config.Plugin.Uninstall", false)
}),
new ClaimNavigatorItem("Config.System", "System", "Permissions related to System Configuration", false, new List<IClaimNavigatorItem>() {
new ClaimNavigatorItem("Config.System.ConfigureActiveDirectory", false),
new ClaimNavigatorItem("Config.System.ConfigureProxy", false),
new ClaimNavigatorItem("Config.System.Show", false)
}),
@@ -551,6 +553,7 @@ namespace Disco.Services.Authorization
c.Config.Plugin.Install = true;
c.Config.Plugin.Show = true;
c.Config.Plugin.Uninstall = true;
c.Config.System.ConfigureActiveDirectory = true;
c.Config.System.ConfigureProxy = true;
c.Config.System.Show = true;
c.Config.Organisation.ConfigureAddresses = true;
@@ -956,6 +959,11 @@ namespace Disco.Services.Authorization
public static class System
{
/// <summary>Configure Active Directory Settings
/// <para>Can configure the Active Directory interoperability settings</para>
/// </summary>
public const string ConfigureActiveDirectory = "Config.System.ConfigureActiveDirectory";
/// <summary>Configure Proxy Settings
/// <para>Can configure the proxy settings</para>
/// </summary>
@@ -39,7 +39,7 @@ namespace Disco.Services.Authorization
// Log Access Denied
if (Token != null) // Don't log anonymous
AuthorizationLog.LogAccessDenied(Token.User.Id, resultResource, resultMessage);
AuthorizationLog.LogAccessDenied(Token.User.UserId, resultResource, resultMessage);
// Build Response View
var ex = new AccessDeniedException(resultMessage, resultResource);
@@ -14,5 +14,8 @@ namespace Disco.Services.Authorization.Roles.ClaimGroups.Configuration.System
[ClaimDetails("Configure Proxy Settings", "Can configure the proxy settings")]
public bool ConfigureProxy { get; set; }
[ClaimDetails("Configure Active Directory Settings", "Can configure the Active Directory interoperability settings")]
public bool ConfigureActiveDirectory { get; set; }
}
}
@@ -98,7 +98,7 @@ namespace Disco.Services.Authorization.Roles
}
internal static List<IRoleToken> GetRoleTokens(IEnumerable<string> SecurityGroup, User User)
{
var subjectIds = (new string[] { User.Id }).Concat(SecurityGroup).Select(sg => sg.ToLower());
var subjectIds = (new string[] { User.UserId }).Concat(SecurityGroup).Select(sg => sg.ToLower());
return _Cache.Where(t => subjectIds.Any(sg => t.SubjectIdHashes.Contains(sg))).Cast<IRoleToken>().ToList();
}
+7 -1
View File
@@ -174,6 +174,12 @@
<Compile Include="Authorization\Roles\RoleToken.cs" />
<Compile Include="Extensions\DateTimeExtensions.cs" />
<Compile Include="Extensions\StringExtensions.cs" />
<Compile Include="Interop\ActiveDirectory\ActiveDirectory.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="Jobs\JobExtensions.cs" />
<Compile Include="Jobs\JobLists\JobTableExtensions.cs" />
<Compile Include="Jobs\JobQueues\Cache.cs" />
@@ -240,7 +246,7 @@
<Compile Include="Plugins\Features\UIExtension\UIExtensions.cs" />
<Compile Include="Users\Cache.cs" />
<Compile Include="Users\CacheCleanTask.cs" />
<Compile Include="Users\Searching.cs" />
<Compile Include="Users\UserExtensions.cs" />
<Compile Include="Users\UserService.cs" />
<Compile Include="Web\AuthorizedController.cs" />
<Compile Include="Web\AuthorizedDatabaseController.cs" />
@@ -0,0 +1,531 @@
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.Linq;
using System.Threading.Tasks;
namespace Disco.Services.Interop.ActiveDirectory
{
public static class ActiveDirectory
{
private const int SingleSearchResult = 1;
public const int MaxForestServerSearch = 30;
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
{
return ADInterop.PrimaryDomain;
}
}
public static IEnumerable<ActiveDirectoryDomain> Domains
{
get
{
return ADInterop.Domains.ToList();
}
}
public static ActiveDirectorySite Site
{
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)
{
var ldapFilter = string.Format(ldapNetbootGuidFilterTemplate, ADInterop.FormatGuidForLdapQuery(UUIDNetbootGUID.Value));
adResult = ADInterop.SearchAll(domain, DomainController, ldapFilter, SingleSearchResult, loadProperites).FirstOrDefault();
}
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);
else
return null; // Not Found
}
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.SearchDomain(Domain, DomainController, Domain.DistinguishedName, ldapFilter, 1, loadProperites).FirstOrDefault();
if (ldapResult != null)
MachineAccount = ldapResult.AsMachineAccount(loadAdditionalProperties);
return offlineJoinResult;
}
#endregion
#region User Account
private static readonly string[] UserLoadProperties = { "name", "distinguishedName", "sAMAccountName", "objectSid", "displayName", "sn", "givenName", "memberOf", "primaryGroupID", "mail", "telephoneNumber" };
public static ActiveDirectoryUserAccount RetrieveUserAccount(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(AdditionalProperties)).FirstOrDefault();
}
public static IEnumerable<ActiveDirectoryUserAccount> SearchUserAccounts(string Term, params string[] AdditionalProperties)
{
const int resultLimit = 30; // Default Search Limit
if (string.IsNullOrWhiteSpace(Term))
throw new ArgumentNullException("Term");
string ldapFilter = string.Format("(&(objectCategory=Person)(objectClass=user)(|(sAMAccountName=*{0}*)(displayName=*{0}*)))", ADInterop.EscapeLdapQuery(Term));
string[] loadProperites = (AdditionalProperties != null && AdditionalProperties.Length > 0)
? UserLoadProperties.Concat(AdditionalProperties).ToArray()
: UserLoadProperties;
return ADInterop.SearchScope(ldapFilter, resultLimit, loadProperites).Select(result => result.AsUserAccount(AdditionalProperties));
}
private static ActiveDirectoryUserAccount AsUserAccount(this ActiveDirectorySearchResult item, 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);
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();
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));
List<string> groups = ADGroupCache.GetGroups(groupDistinguishedNames).ToList();
// 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 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
};
}
#endregion
#region Groups
private static readonly string[] GroupLoadProperties = { "name", "distinguishedName", "cn", "sAMAccountName", "objectSid", "memberOf" };
public static ActiveDirectoryGroup RetrieveGroup(string Id)
{
const string ldapFilter = "(&(objectCategory=Group)(objectSid={0}))";
return SearchBySamAccountName(Id, ldapFilter, GroupLoadProperties).Select(result => result.AsGroup()).FirstOrDefault();
}
public static ActiveDirectoryGroup RetrieveGroupWithDistinguishedName(string DistinguishedName)
{
ActiveDirectoryDomain domain;
using (var groupEntry = ADInterop.RetrieveDirectoryEntry(DistinguishedName, out domain))
{
if (groupEntry == null)
return null;
return groupEntry.AsGroup(domain);
}
}
public static ActiveDirectoryGroup RetrieveGroupWithSecurityIdentifier(string 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();
}
public static IEnumerable<ActiveDirectoryGroup> SearchGroups(string Term)
{
const int resultLimit = 30; // Default Search Limit
if (string.IsNullOrWhiteSpace(Term))
throw new ArgumentNullException("Term");
string ldapFilter = string.Format("(&(objectCategory=Group)(|(sAMAccountName=*{0}*)(name=*{0}*)(cn=*{0}*)))", ADInterop.EscapeLdapQuery(Term));
return ADInterop.SearchScope(ldapFilter, resultLimit, GroupLoadProperties).Select(result => result.AsGroup());
}
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();
return new ActiveDirectoryGroup()
{
Domain = item.Domain.DnsName,
Name = name,
DistinguishedName = distinguishedName,
CommonName = cn,
SamAccountName = sAMAccountName,
SecurityIdentifier = objectSid,
MemberOf = memberOf
};
}
private static ActiveDirectoryGroup AsGroup(this DirectoryEntry item, ActiveDirectoryDomain Domain)
{
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.DnsName,
Name = name,
DistinguishedName = distinguishedName,
CommonName = cn,
SamAccountName = sAMAccountName,
SecurityIdentifier = objectSid,
MemberOf = memberOf
};
}
#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)
{
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(null);
case "cn=computer":
return result.AsMachineAccount(null);
case "cn=group":
return result.AsGroup();
default:
throw new InvalidOperationException("Unexpected objectCategory");
}
}).FirstOrDefault();
}
#endregion
#region Organisation Units
public static List<ActiveDirectoryOrganisationalUnit> RetrieveOrganisationalUnitStructure(ActiveDirectoryDomain Domain)
{
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>>();
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;
}
}
#endregion
#region Helpers
private static IEnumerable<ActiveDirectorySearchResult> SearchBySamAccountName(string Id, string LdapFilterTemplate, string[] LoadProperties)
{
var splitId = UserExtensions.SplitUserId(Id);
var ldapFilter = string.Format(LdapFilterTemplate, splitId.Item2);
var domains = ADInterop.GetDomainFromId(Id);
return ADInterop.SearchAll(domains, ldapFilter, SingleSearchResult, LoadProperties);
}
#endregion
}
}
@@ -0,0 +1,391 @@
using Disco.Models.Interop.ActiveDirectory;
using Disco.Models.Repository;
using Disco.Services.Interop.ActiveDirectory.Internal;
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Services.Interop.ActiveDirectory
{
public static class ActiveDirectoryExtensions
{
#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)
{
using (Ping p = new Ping())
{
var pr = p.Send(ds.Name, 500);
return (pr.Status == IPStatus.Success);
}
}
public static string GetFriendlyOrganisationalUnitName(this ActiveDirectoryDomain domain, string DistinguishedName)
{
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();
}
public static string GetDefaultComputerContainer(this ActiveDirectoryDomain domain)
{
return string.Format("CN=Computers,{0}", domain.DistinguishedName);
}
#endregion
#region User Account Extensions
public static object GetPropertyValue(this ActiveDirectoryUserAccount 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 "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;
}
}
#endregion
#region Machine Account Extensions
public static void DeleteAccount(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))
{
deAccount.DeleteObjectRecursive();
}
}
public static void DeleteAccount(this ActiveDirectoryMachineAccount account)
{
var domain = account.GetDomain();
using (var domainController = domain.RetrieveWritableDomainController())
{
account.DeleteAccount(domainController);
}
}
private static void SetNetbootGUID(this ActiveDirectoryMachineAccount account, DomainController DomainController, System.Guid updatedNetbootGUID)
{
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();
}
}
public static void SetDescription(this ActiveDirectoryMachineAccount account, DomainController DomainController, string Description)
{
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);
}
}
public static void SetDescription(this ActiveDirectoryMachineAccount account, DomainController DomainController, 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);
account.SetDescription(DomainController, description);
}
public static void SetDescription(this ActiveDirectoryMachineAccount account, Device Device)
{
var domain = account.GetDomain();
using (var domainController = domain.RetrieveWritableDomainController())
{
account.SetDescription(domainController, Device);
}
}
public static void DisableAccount(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];
int updatedAccountControl = (accountControl | 2);
if (accountControl != updatedAccountControl)
{
deAccount.Properties["userAccountControl"][0] = updatedAccountControl;
deAccount.CommitChanges();
}
}
}
public static void DisableAccount(this ActiveDirectoryMachineAccount account)
{
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;
}
#endregion
}
}
@@ -0,0 +1,68 @@
using Disco.Data.Repository;
using Disco.Services.Tasks;
using System;
using System.Collections.Generic;
using System.DirectoryServices.ActiveDirectory;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Services.Interop.ActiveDirectory.Internal
{
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; } }
protected override void ExecuteTask()
{
var forestServers = DiscoverForestServers();
ADInterop._ForestServers = forestServers;
// Restrict Searching Entire Forest if to many servers
using (DiscoDataContext Database = new DiscoDataContext())
{
var searchEntireForest = Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest;
// Check explicitly configured: No
if (!searchEntireForest.HasValue || searchEntireForest.Value)
{
// Not Configured, or explicitly configured: Yes
if (forestServers.Count > ActiveDirectory.MaxForestServerSearch)
{
// Update Database
Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest = false;
}
else
{
// Default
Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest = true;
}
Database.SaveChanges();
}
}
}
internal static ScheduledTaskStatus ScheduleNow()
{
var 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()
{
using (var computerDomain = Domain.GetComputerDomain())
{
return computerDomain.Forest.Domains.Cast<Domain>().SelectMany(d => d.FindAllDomainControllers().Cast<DomainController>()).Select(dc => dc.Name).ToList();
}
}
}
}
@@ -1,18 +1,15 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Disco.Data.Repository;
using Disco.Data.Repository;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Services.Tasks;
using Quartz;
using Disco.Models.Interop.ActiveDirectory;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace Disco.BI.Interop.ActiveDirectory
namespace Disco.Services.Interop.ActiveDirectory.Internal
{
public class ActiveDirectoryCachedGroups : ScheduledTask
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>>();
@@ -72,7 +69,7 @@ namespace Disco.BI.Interop.ActiveDirectory
if (groupRecord == null)
{
// Load from AD
var group = ActiveDirectory.GetGroupFromDistinguishedName(DistinguishedName);
var group = ActiveDirectory.RetrieveGroupWithDistinguishedName(DistinguishedName);
SetValue(group);
return group;
@@ -91,7 +88,7 @@ namespace Disco.BI.Interop.ActiveDirectory
if (groupRecord == null)
{
// Load from AD
var group = ActiveDirectory.GetGroupFromSecurityIdentifier(SecurityIdentifier);
var group = ActiveDirectory.RetrieveGroupWithSecurityIdentifier(SecurityIdentifier);
SetValue(group);
return group;
@@ -0,0 +1,617 @@
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
List<string> searchContainersAll = Database.DiscoConfiguration.ActiveDirectory.SearchContainers;
List<string> searchContainers = null;
if (searchContainersAll != null && searchContainersAll.Count > 0)
searchContainers = Database.DiscoConfiguration.ActiveDirectory.SearchContainers.Where(c => c.EndsWith(defaultNamingContext, StringComparison.InvariantCultureIgnoreCase)).ToList();
else
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)
{
if (Containers != null)
{
var distinctContainers = Containers
.Where(c => !string.IsNullOrWhiteSpace(c))
.Distinct().ToList();
Containers = distinctContainers.Where(c => !distinctContainers.Any(s => (c != s) && (c.EndsWith(s))));
}
if (Containers == null || Containers.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 = Containers.ToList();
Domains.ForEach(d => { d.UpdateSearchContainers(Containers.Where(c => c.EndsWith(d.DistinguishedName, StringComparison.InvariantCultureIgnoreCase))); });
}
}
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<Tuple<ActiveDirectoryDomain, DomainController>> DomainsWithController, string LdapFilter, int? ResultLimit, string[] LoadProperties)
{
var query = DomainsWithController
.SelectMany(d => SearchAll(d.Item1, d.Item2, LdapFilter, ResultLimit, LoadProperties));
if (ResultLimit.HasValue)
query = query.Take(ResultLimit.Value);
return query.ToList();
}
public static IEnumerable<ActiveDirectorySearchResult> SearchAll(IEnumerable<ActiveDirectoryDomain> Domains, string LdapFilter, int? ResultLimit, string[] LoadProperties)
{
var query = Domains
.SelectMany(domain => SearchAll(domain, LdapFilter, ResultLimit, LoadProperties));
if (ResultLimit.HasValue)
query = query.Take(ResultLimit.Value);
return query.ToList();
}
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> SearchAll(ActiveDirectoryDomain Domain, string LdapFilter, int? ResultLimit, string[] LoadProperties)
{
return SearchDomain(Domain, 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<Tuple<ActiveDirectoryDomain, DomainController>> DomainsWithController, string LdapFilter, int? ResultLimit, string[] LoadProperties)
{
var query = DomainsWithController
.SelectMany(d => SearchScope(d.Item1, d.Item2, LdapFilter, ResultLimit, LoadProperties));
if (ResultLimit.HasValue)
query = query.Take(ResultLimit.Value);
return query.ToList();
}
public static IEnumerable<ActiveDirectorySearchResult> SearchScope(IEnumerable<ActiveDirectoryDomain> Domains, string LdapFilter, int? ResultLimit, string[] LoadProperties)
{
var query = Domains
.SelectMany(domain => SearchScope(domain, LdapFilter, ResultLimit, LoadProperties));
if (ResultLimit.HasValue)
query = query.Take(ResultLimit.Value);
return query.ToList();
}
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)
return Enumerable.Empty<ActiveDirectorySearchResult>();
var query = Domain.SearchContainers
.SelectMany(container => SearchDomain(Domain, DomainController, container, LdapFilter, ResultLimit, LoadProperties));
if (ResultLimit.HasValue)
query = query.Take(ResultLimit.Value);
return query.ToList();
}
public static IEnumerable<ActiveDirectorySearchResult> SearchDomain(ActiveDirectoryDomain Domain, string SearchRoot, string LdapFilter, int? ResultLimit, string[] LoadProperties)
{
return SearchDomain(Domain, null, SearchRoot, LdapFilter, ResultLimit, LoadProperties);
}
public static IEnumerable<ActiveDirectorySearchResult> SearchDomain(ActiveDirectoryDomain Domain, DomainController DomainController, string SearchRoot, string LdapFilter, int? ResultLimit, string[] LoadProperties)
{
string ldapServer = DomainController == null ? Domain.DnsName : DomainController.Name;
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);
Domain = domain;
return new DirectoryEntry(string.Format(@"LDAP://{0}/{1}", domain.DnsName, 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
}
}
@@ -0,0 +1,231 @@
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;
}
}
}
}
}
}
+4
View File
@@ -1,5 +1,6 @@
using Disco.Models.Repository;
using Disco.Models.Services.Jobs.JobLists;
using Disco.Services.Interop.ActiveDirectory;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -61,10 +62,13 @@ namespace Disco.Services
{
i.UserId = j.UserId;
i.UserDisplayName = j.User.DisplayName;
i.UserFriendlyId = UserExtensions.FriendlyUserId(j.UserId);
}
if (j.OpenedTechUser != null)
{
i.OpenedTechUserId = j.OpenedTechUserId;
i.OpenedTechUserFriendlyId = UserExtensions.FriendlyUserId(j.OpenedTechUserId);
i.OpenedTechUserDisplayName = j.OpenedTechUser.DisplayName;
}
@@ -232,8 +232,13 @@ namespace Disco.Services
model.ShowDeviceAddress = Database.DiscoConfiguration.MultiSiteMode;
foreach (var j in items)
{
j.UserFriendlyId =j.UserId == null ? null : UserExtensions.FriendlyUserId(j.UserId);
j.OpenedTechUserFriendlyId = UserExtensions.FriendlyUserId(j.OpenedTechUserId);
if (j.DeviceAddressId.HasValue)
j.DeviceAddress = Database.DiscoConfiguration.OrganisationAddresses.GetAddress(j.DeviceAddressId.Value).Name;
}
return items;
}
@@ -131,7 +131,7 @@ namespace Disco.Services.Jobs.JobQueues
public static ReadOnlyCollection<JobQueueToken> UsersQueues(User User)
{
return UsersQueues(User.Id);
return UsersQueues(User.UserId);
}
public static ReadOnlyCollection<JobQueueToken> UsersQueues(string UserId)
{
@@ -141,7 +141,7 @@ namespace Disco.Services.Jobs.JobQueues
}
public static ReadOnlyCollection<JobQueueToken> UsersQueues(AuthorizationToken UserAuthorization)
{
string cacheKey = string.Format(_cacheHttpRequestKey, UserAuthorization.User.Id);
string cacheKey = string.Format(_cacheHttpRequestKey, UserAuthorization.User.UserId);
ReadOnlyCollection<JobQueueToken> tokens = null;
// Check for ASP.NET
@@ -152,7 +152,7 @@ namespace Disco.Services.Jobs.JobQueues
if (tokens == null)
{
var subjectIds = (new string[] { UserAuthorization.User.Id }).Concat(UserAuthorization.GroupMembership);
var subjectIds = (new string[] { UserAuthorization.User.UserId }).Concat(UserAuthorization.GroupMembership);
tokens = _cache.GetQueuesForSubject(subjectIds);
HttpContext.Current.Items[_cacheHttpRequestKey] = tokens;
@@ -30,7 +30,7 @@ namespace Disco.Services.Plugins
var resource = string.Format("{0} [{1}]", attributeDenied.AuthorizeResource, HostController.Request.RawUrl);
if (CurrentUser != null)
AuthorizationLog.LogAccessDenied(CurrentUser.Id, resource, message);
AuthorizationLog.LogAccessDenied(CurrentUser.UserId, resource, message);
return new HttpUnauthorizedResult();
}
+13 -12
View File
@@ -3,6 +3,7 @@ using Disco.Models.Interop.ActiveDirectory;
using Disco.Models.Repository;
using Disco.Models.Services.Jobs.JobLists;
using Disco.Models.Services.Searching;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Users;
using System;
using System.Collections.Generic;
@@ -29,7 +30,7 @@ namespace Disco.Services.Searching
j.Id == termInt ||
j.Device.SerialNumber.Contains(Term) ||
j.Device.AssetNumber.Contains(Term) ||
j.User.Id == Term ||
j.User.UserId == Term ||
j.User.DisplayName.Contains(Term));
}
else
@@ -37,7 +38,7 @@ namespace Disco.Services.Searching
query = Database.Jobs.Where(j =>
j.Device.SerialNumber.Contains(Term) ||
j.Device.AssetNumber.Contains(Term) ||
j.User.Id == Term ||
j.User.UserId == Term ||
j.User.DisplayName.Contains(Term));
}
@@ -75,7 +76,7 @@ namespace Disco.Services.Searching
j.DeviceHeldLocation.Contains(Term) ||
j.Device.SerialNumber.Contains(Term) ||
j.Device.AssetNumber.Contains(Term) ||
j.User.Id == Term ||
j.User.UserId == Term ||
j.User.Surname.Contains(Term) ||
j.User.GivenName.Contains(Term) ||
j.User.DisplayName.Contains(Term) ||
@@ -89,7 +90,7 @@ namespace Disco.Services.Searching
j.DeviceHeldLocation.Contains(Term) ||
j.Device.SerialNumber.Contains(Term) ||
j.Device.AssetNumber.Contains(Term) ||
j.User.Id == Term ||
j.User.UserId == Term ||
j.User.Surname.Contains(Term) ||
j.User.GivenName.Contains(Term) ||
j.User.DisplayName.Contains(Term));
@@ -103,7 +104,7 @@ namespace Disco.Services.Searching
j.DeviceHeldLocation.Contains(Term) ||
j.Device.SerialNumber.Contains(Term) ||
j.Device.AssetNumber.Contains(Term) ||
j.User.Id == Term ||
j.User.UserId == Term ||
j.User.Surname.Contains(Term) ||
j.User.GivenName.Contains(Term) ||
j.User.DisplayName.Contains(Term) ||
@@ -116,7 +117,7 @@ namespace Disco.Services.Searching
j.DeviceHeldLocation.Contains(Term) ||
j.Device.SerialNumber.Contains(Term) ||
j.Device.AssetNumber.Contains(Term) ||
j.User.Id == Term ||
j.User.UserId == Term ||
j.User.Surname.Contains(Term) ||
j.User.GivenName.Contains(Term) ||
j.User.DisplayName.Contains(Term));
@@ -148,7 +149,7 @@ namespace Disco.Services.Searching
UserService.SearchUsers(Database, Term);
var matches = Database.Users.Where(u =>
u.Id.Contains(Term) ||
u.UserId.Contains(Term) ||
u.Surname.Contains(Term) ||
u.GivenName.Contains(Term) ||
u.DisplayName.Contains(Term)
@@ -159,7 +160,7 @@ namespace Disco.Services.Searching
return matches.Select(u => new UserSearchResultItem()
{
Id = u.Id,
Id = u.UserId,
Surname = u.Surname,
GivenName = u.GivenName,
DisplayName = u.DisplayName,
@@ -170,7 +171,7 @@ namespace Disco.Services.Searching
public static List<User> SearchUsersUpstream(string Term, int? LimitCount = null)
{
IEnumerable<ActiveDirectoryUserAccount> matches = UserService.SearchUsers(Term);
IEnumerable<ActiveDirectoryUserAccount> matches = ActiveDirectory.SearchUserAccounts(Term);
if (LimitCount.HasValue)
matches = matches.Take(LimitCount.Value);
@@ -190,7 +191,7 @@ namespace Disco.Services.Searching
{
query = Database.Devices.Where(d =>
d.AssetNumber.Contains(Term) ||
d.ComputerName.Contains(Term) ||
d.DeviceDomainId.Contains(Term) ||
d.SerialNumber.Contains(Term) ||
d.Location.Contains(Term) ||
Term.Contains(d.SerialNumber) ||
@@ -201,7 +202,7 @@ namespace Disco.Services.Searching
{
query = Database.Devices.Where(d =>
d.AssetNumber.Contains(Term) ||
d.ComputerName.Contains(Term) ||
d.DeviceDomainId.Contains(Term) ||
d.SerialNumber.Contains(Term) ||
d.Location.Contains(Term) ||
Term.Contains(d.SerialNumber));
@@ -232,7 +233,7 @@ namespace Disco.Services.Searching
{
Id = d.SerialNumber,
AssetNumber = d.AssetNumber,
ComputerName = d.ComputerName,
ComputerName = d.DeviceDomainId,
DeviceModelDescription = d.DeviceModel.Description,
DeviceProfileDescription = d.DeviceProfile.Description,
DecommissionedDate = d.DecommissionedDate,
+16 -5
View File
@@ -5,6 +5,7 @@ using System.Text;
using Quartz;
using System.Web.Script.Serialization;
using System.Threading;
using System.Threading.Tasks;
namespace Disco.Services.Tasks
{
@@ -16,7 +17,7 @@ namespace Disco.Services.Tasks
private string _triggerKey;
private string _taskName;
private Type _taskType;
private EventWaitHandle _waitHandle;
private TaskCompletionSource<ScheduledTaskStatus> _tcs;
private bool _isSilent;
private byte _progress;
@@ -72,6 +73,14 @@ namespace Disco.Services.Tasks
}
}
public Task CompletionTask
{
get
{
return _tcs.Task;
}
}
#endregion
#region Events
@@ -87,7 +96,7 @@ namespace Disco.Services.Tasks
{
this._taskName = Task.TaskName;
this._taskType = Task.GetType();
this._waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
this._tcs = new TaskCompletionSource<ScheduledTaskStatus>();
this._sessionId = SessionId;
this._triggerKey = TriggerKey;
@@ -294,11 +303,13 @@ namespace Disco.Services.Tasks
}
internal void Finally()
{
this._waitHandle.Set();
this._tcs.SetResult(this);
}
public void Reset(DateTime? NextScheduledTimestamp)
{
this._waitHandle.Reset();
if (this._tcs != null)
this._tcs.Task.Dispose();
this._tcs = new TaskCompletionSource<ScheduledTaskStatus>();
List<string> changedProperties = new List<string>();
@@ -352,7 +363,7 @@ namespace Disco.Services.Tasks
}
public bool WaitUntilFinished(TimeSpan Timeout)
{
return this._waitHandle.WaitOne(Timeout);
return this._tcs.Task.Wait(Timeout);
}
#endregion
-13
View File
@@ -1,13 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Services.Users
{
public static class Searching
{
}
}
+42
View File
@@ -0,0 +1,42 @@
using Disco.Models.Repository;
using Disco.Services.Interop.ActiveDirectory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Services
{
public static class UserExtensions
{
public static bool IsInPrimaryDomain(this User u)
{
return u.Domain.Equals(Disco.Services.Interop.ActiveDirectory.ActiveDirectory.PrimaryDomain.NetBiosName, StringComparison.InvariantCultureIgnoreCase);
}
public static string FriendlyId(this User u)
{
return FriendlyUserId(u.UserId);
}
public static string FriendlyUserId(string UserId)
{
var splitUserId = SplitUserId(UserId);
if (splitUserId.Item1 != null && splitUserId.Item1.Equals(ActiveDirectory.PrimaryDomain.NetBiosName, StringComparison.InvariantCultureIgnoreCase))
return splitUserId.Item2;
else
return UserId;
}
public static Tuple<string, string> SplitUserId(string UserId)
{
var slashIndex = UserId.IndexOf('\\');
if (slashIndex < 0)
return Tuple.Create<string, string>(null, UserId);
else
return Tuple.Create(UserId.Substring(0, slashIndex), UserId.Substring(slashIndex + 1));
}
}
}
+9 -28
View File
@@ -3,6 +3,7 @@ using Disco.Models.Interop.ActiveDirectory;
using Disco.Models.Repository;
using Disco.Services.Authorization;
using Disco.Services.Authorization.Roles;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Logging;
using Newtonsoft.Json;
using System;
@@ -20,19 +21,9 @@ namespace Disco.Services.Users
public static class UserService
{
private const string _cacheHttpRequestKey = "Disco_CurrentUserToken";
private static Func<string, string[], ActiveDirectoryUserAccount> _GetActiveDirectoryUserAccount;
private static Func<string, string[], ActiveDirectoryMachineAccount> _GetActiveDirectoryMachineAccount;
private static Func<string, List<ActiveDirectoryUserAccount>> _SearchActiveDirectoryUsers;
public static void Initialize(DiscoDataContext Database,
Func<string, string[], ActiveDirectoryUserAccount> GetActiveDirectoryUserAccount,
Func<string, string[], ActiveDirectoryMachineAccount> GetActiveDirectoryMachineAccount,
Func<string, List<ActiveDirectoryUserAccount>> SearchActiveDirectoryUsers)
public static void Initialize(DiscoDataContext Database)
{
_GetActiveDirectoryUserAccount = GetActiveDirectoryUserAccount;
_GetActiveDirectoryMachineAccount = GetActiveDirectoryMachineAccount;
_SearchActiveDirectoryUsers = SearchActiveDirectoryUsers;
Authorization.Roles.RoleCache.Initialize(Database);
}
@@ -56,9 +47,6 @@ namespace Disco.Services.Users
userId = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
}
if (userId.Contains("\\"))
return userId.Substring(checked(userId.IndexOf("\\") + 1));
else
return userId;
}
}
@@ -204,38 +192,31 @@ namespace Disco.Services.Users
Cache.FlushCache();
}
internal static List<ActiveDirectoryUserAccount> SearchUsers(string Term)
internal static IEnumerable<ActiveDirectoryUserAccount> SearchUsers(DiscoDataContext Database, string Term)
{
return _SearchActiveDirectoryUsers(Term);
}
internal static List<ActiveDirectoryUserAccount> SearchUsers(DiscoDataContext Database, string Term)
{
var adImportedUsers = SearchUsers(Term);
var adImportedUsers = ActiveDirectory.SearchUserAccounts(Term);
foreach (var adU in adImportedUsers.Select(adU => adU.ToRepositoryUser()))
{
var existingUser = Database.Users.Find(adU.Id);
var existingUser = Database.Users.Find(adU.UserId);
if (existingUser != null)
existingUser.UpdateSelf(adU);
else
Database.Users.Add(adU);
Database.SaveChanges();
UserService.InvalidateCachedUser(adU.Id);
UserService.InvalidateCachedUser(adU.UserId);
}
return adImportedUsers;
}
internal static Tuple<User, AuthorizationToken> ImportUser(DiscoDataContext Database, string UserId)
{
if (_GetActiveDirectoryUserAccount == null)
throw new InvalidOperationException("UserServer has not been Initialized");
if (string.IsNullOrEmpty(UserId))
throw new ArgumentNullException("UserId is required", "UserId");
if (UserId.EndsWith("$"))
{
// Machine Account
var adAccount = _GetActiveDirectoryMachineAccount(UserId, null);
var adAccount = ActiveDirectory.RetrieveMachineAccount(UserId);
if (adAccount == null)
return null;
@@ -252,7 +233,7 @@ namespace Disco.Services.Users
ActiveDirectoryUserAccount adAccount;
try
{
adAccount = _GetActiveDirectoryUserAccount(UserId, null);
adAccount = ActiveDirectory.RetrieveUserAccount(UserId);
if (adAccount == null)
throw new ArgumentException(string.Format("Invalid Username: '{0}'; User not found in Active Directory", UserId), "Username");
@@ -275,7 +256,7 @@ namespace Disco.Services.Users
var user = adAccount.ToRepositoryUser();
// Update Repository
User existingUser = Database.Users.Find(user.Id);
User existingUser = Database.Users.Find(user.UserId);
if (existingUser == null)
Database.Users.Add(user);
else
+1 -1
View File
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34003
// Runtime Version:4.0.30319.34011
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
+3 -3
View File
@@ -2,11 +2,11 @@
@using Disco;
@using Disco.BI.Extensions;
@using Disco.Models.Repository;
@using Disco.Services;
@using Disco.Services.Web;
@using Disco.Web;
@using System.Web.Mvc
@using System.Web.Mvc.Html;
@using Disco.Services.Web;
@helper FriendlyDate(DateTime d, string ElementId = null, bool WithoutSuffix = false)
{<span @(ElementId == null ? null : new HtmlString(string.Format("id=\"{0}\" ", ElementId)))title="@d.ToFullDateTime()" data-livestamp="@d.ToUnixEpoc()" data-isodate="@d.ToISO8601()" class="date nowrap@(WithoutSuffix ? " noMomentSuffix" : null)">@d.ToFullDateTime()</span>}
@@ -34,7 +34,7 @@
{
if (u != null)
{
@prepend <span title="@u">@u.Id</span>
@prepend <span title="@u">@u.FriendlyId()</span>
}
else
{
+12 -6
View File
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34003
// Runtime Version:4.0.30319.34011
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -20,13 +20,13 @@ namespace Disco.Web
using System.Web;
using System.Web.Helpers;
#line 6 "..\..\App_Code\CommonHelpers.cshtml"
#line 8 "..\..\App_Code\CommonHelpers.cshtml"
using System.Web.Mvc;
#line default
#line hidden
#line 7 "..\..\App_Code\CommonHelpers.cshtml"
#line 9 "..\..\App_Code\CommonHelpers.cshtml"
using System.Web.Mvc.Html;
#line default
@@ -54,13 +54,19 @@ namespace Disco.Web
#line default
#line hidden
#line 8 "..\..\App_Code\CommonHelpers.cshtml"
#line 5 "..\..\App_Code\CommonHelpers.cshtml"
using Disco.Services;
#line default
#line hidden
#line 6 "..\..\App_Code\CommonHelpers.cshtml"
using Disco.Services.Web;
#line default
#line hidden
#line 5 "..\..\App_Code\CommonHelpers.cshtml"
#line 7 "..\..\App_Code\CommonHelpers.cshtml"
using Disco.Web;
#line default
@@ -509,7 +515,7 @@ WriteLiteralTo(@__razor_helper_writer, "\">");
#line 37 "..\..\App_Code\CommonHelpers.cshtml"
WriteTo(@__razor_helper_writer, u.Id);
WriteTo(@__razor_helper_writer, u.FriendlyId());
#line default
#line hidden
+6 -10
View File
@@ -1,10 +1,7 @@
using System;
using System.Collections.Generic;
using Disco.Data.Repository;
using System;
using System.Linq;
using System.Web;
using Disco.Data.Repository;
using System.Threading;
using System.Reflection;
namespace Disco.Web
{
@@ -32,6 +29,9 @@ namespace Disco.Web
// Initialize Logging
Disco.Services.Logging.LogContext.Initalize(Database, DiscoApplication.SchedulerFactory);
// Initialize Active Directory Interop
Disco.Services.Interop.ActiveDirectory.ActiveDirectory.Initialize(Database);
// Load Organisation Name
DiscoApplication.OrganisationName = Database.DiscoConfiguration.OrganisationName;
DiscoApplication.MultiSiteMode = Database.DiscoConfiguration.MultiSiteMode;
@@ -43,11 +43,7 @@ namespace Disco.Web
Database.DiscoConfiguration.ProxyPassword);
// Initialize User Service Interop
Disco.Services.Users.UserService.Initialize(Database,
(UserId, AdditionalProperties) => Disco.BI.Interop.ActiveDirectory.ActiveDirectory.GetUserAccount(UserId, AdditionalProperties),
(UserId, AdditionalProperties) => Disco.BI.Interop.ActiveDirectory.ActiveDirectory.GetMachineAccount(UserId, null, null, AdditionalProperties),
(Term) => Disco.BI.Interop.ActiveDirectory.ActiveDirectory.SearchUsers(Term));
Disco.Services.Users.UserService.Initialize(Database);
}
public static void InitalizeNormalEnvironment(DiscoDataContext Database)
@@ -1,9 +1,9 @@
using Disco.BI.Extensions;
using Disco.BI.Interop.ActiveDirectory;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Models.Repository;
using Disco.Services.Authorization;
using Disco.Services.Authorization.Roles;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Users;
using Disco.Services.Web;
using System;
@@ -75,7 +75,7 @@ namespace Disco.Web.Areas.API.Controllers
var oldRoleName = AuthorizationRole.Name;
AuthorizationRole.Name = Name;
UserService.UpdateAuthorizationRole(Database, AuthorizationRole);
AuthorizationLog.LogRoleConfiguredRenamed(AuthorizationRole, CurrentUser.Id, oldRoleName);
AuthorizationLog.LogRoleConfiguredRenamed(AuthorizationRole, CurrentUser.UserId, oldRoleName);
}
}
}
@@ -93,9 +93,9 @@ namespace Disco.Web.Areas.API.Controllers
UserService.UpdateAuthorizationRole(Database, AuthorizationRole);
if (removedClaims.Length > 0)
AuthorizationLog.LogRoleConfiguredClaimsRemoved(AuthorizationRole, CurrentUser.Id, removedClaims);
AuthorizationLog.LogRoleConfiguredClaimsRemoved(AuthorizationRole, CurrentUser.UserId, removedClaims);
if (addedClaims.Length > 0)
AuthorizationLog.LogRoleConfiguredClaimsAdded(AuthorizationRole, CurrentUser.Id, addedClaims);
AuthorizationLog.LogRoleConfiguredClaimsAdded(AuthorizationRole, CurrentUser.UserId, addedClaims);
}
private void UpdateSubjects(AuthorizationRole AuthorizationRole, string[] Subjects)
@@ -107,7 +107,7 @@ namespace Disco.Web.Areas.API.Controllers
// Validate Subjects
if (Subjects != null && Subjects.Length > 0)
{
var subjects = Subjects.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Select(s => new Tuple<string, IActiveDirectoryObject>(s, ActiveDirectory.GetObject(s))).ToList();
var subjects = Subjects.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Select(s => new Tuple<string, IActiveDirectoryObject>(s, ActiveDirectory.RetrieveObject(s))).ToList();
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
if (invalidSubjects.Count > 0)
@@ -130,9 +130,9 @@ namespace Disco.Web.Areas.API.Controllers
UserService.UpdateAuthorizationRole(Database, AuthorizationRole);
if (removedSubjects != null && removedSubjects.Length > 0)
AuthorizationLog.LogRoleConfiguredSubjectsRemoved(AuthorizationRole, CurrentUser.Id, removedSubjects);
AuthorizationLog.LogRoleConfiguredSubjectsRemoved(AuthorizationRole, CurrentUser.UserId, removedSubjects);
if (addedSubjects != null && addedSubjects.Length > 0)
AuthorizationLog.LogRoleConfiguredSubjectsAdded(AuthorizationRole, CurrentUser.Id, addedSubjects);
AuthorizationLog.LogRoleConfiguredSubjectsAdded(AuthorizationRole, CurrentUser.UserId, addedSubjects);
}
}
@@ -234,8 +234,8 @@ namespace Disco.Web.Areas.API.Controllers
public virtual ActionResult SearchSubjects(string term)
{
var groupResults = BI.Interop.ActiveDirectory.ActiveDirectory.SearchGroups(term).Cast<IActiveDirectoryObject>();
var userResults = BI.Interop.ActiveDirectory.ActiveDirectory.SearchUsers(term).Cast<IActiveDirectoryObject>();
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();
@@ -245,7 +245,7 @@ namespace Disco.Web.Areas.API.Controllers
public virtual ActionResult Subject(string Id)
{
var subject = ActiveDirectory.GetObject(Id);
var subject = ActiveDirectory.RetrieveObject(Id);
if (subject == null || !(subject is ActiveDirectoryUserAccount || subject is ActiveDirectoryGroup))
return Json(null, JsonRequestBehavior.AllowGet);
@@ -1,6 +1,6 @@
using Disco.BI.Extensions;
using Disco.BI.Interop.ActiveDirectory;
using Disco.Services.Authorization;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Users;
using Disco.Services.Web;
using System;
@@ -148,9 +148,9 @@ namespace Disco.Web.Areas.API.Controllers
device.DeviceProfile = p;
// Update AD Account
if (!string.IsNullOrEmpty(device.ComputerName) && device.ComputerName.Length <= 24)
if (!string.IsNullOrEmpty(device.DeviceDomainId) && device.DeviceDomainId.Length <= 24)
{
var adMachineAccount = ActiveDirectory.GetMachineAccount(device.ComputerName);
var adMachineAccount = ActiveDirectory.RetrieveMachineAccount(device.DeviceDomainId);
if (adMachineAccount != null)
adMachineAccount.SetDescription(device);
}
@@ -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.Id, StringComparison.InvariantCultureIgnoreCase))
if (da.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase))
Authorization.RequireAny(Claims.Device.Actions.RemoveAnyAttachments, Claims.Device.Actions.RemoveOwnAttachments);
else
Authorization.Require(Claims.Device.Actions.RemoveAnyAttachments);
@@ -1,6 +1,7 @@
using Disco.BI.Extensions;
using Disco.Models.Repository;
using Disco.Services.Authorization;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Web;
using System;
using System.Linq;
@@ -90,7 +91,7 @@ namespace Disco.Web.Areas.API.Controllers
throw new Exception("Invalid Device Profile Number");
}
if (redirect.HasValue && redirect.Value)
return RedirectToAction(MVC.Config.DeviceModel.Index(deviceProfile.Id));
return RedirectToAction(MVC.Config.DeviceProfile.Index(deviceProfile.Id));
else
return Json("OK", JsonRequestBehavior.AllowGet);
}
@@ -245,12 +246,14 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateOrganisationalUnit(Disco.Models.Repository.DeviceProfile deviceProfile, string OrganisationalUnit)
{
if (string.IsNullOrWhiteSpace(OrganisationalUnit))
OrganisationalUnit = null;
OrganisationalUnit = ActiveDirectory.PrimaryDomain.GetDefaultComputerContainer();
if (OrganisationalUnit != deviceProfile.OrganisationalUnit)
{
deviceProfile.OrganisationalUnit = OrganisationalUnit;
Database.SaveChanges();
}
}
private void UpdateComputerNameTemplate(Disco.Models.Repository.DeviceProfile deviceProfile, string ComputerNameTemplate)
{
@@ -364,13 +367,6 @@ namespace Disco.Web.Areas.API.Controllers
}
#endregion
[DiscoAuthorize(Claims.Config.DeviceProfile.Configure)]
public virtual ActionResult OrganisationalUnits()
{
var OUs = BI.Interop.ActiveDirectory.ActiveDirectory.GetOrganisationalUnitStructure();
return Json(OUs, JsonRequestBehavior.AllowGet);
}
#region Actions
[DiscoAuthorize(Claims.Config.DeviceProfile.Delete)]
@@ -663,7 +663,7 @@ namespace Disco.Web.Areas.API.Controllers
throw new Exception("Invalid Date Format");
}
}
job.JobMetaNonWarranty.AccountingChargeRequiredUserId = CurrentUser.Id;
job.JobMetaNonWarranty.AccountingChargeRequiredUserId = CurrentUser.UserId;
Database.SaveChanges();
return new Models.Job._DateChangeModel()
{
@@ -697,7 +697,7 @@ namespace Disco.Web.Areas.API.Controllers
throw new Exception("Invalid Date Format");
}
}
job.JobMetaNonWarranty.AccountingChargeAddedUserId = CurrentUser.Id;
job.JobMetaNonWarranty.AccountingChargeAddedUserId = CurrentUser.UserId;
Database.SaveChanges();
return new Models.Job._DateChangeModel()
{
@@ -731,7 +731,7 @@ namespace Disco.Web.Areas.API.Controllers
throw new Exception("Invalid Date Format");
}
}
job.JobMetaNonWarranty.AccountingChargePaidUserId = CurrentUser.Id;
job.JobMetaNonWarranty.AccountingChargePaidUserId = CurrentUser.UserId;
Database.SaveChanges();
return new Models.Job._DateChangeModel()
{
@@ -765,7 +765,7 @@ namespace Disco.Web.Areas.API.Controllers
throw new Exception("Invalid Date Format");
}
}
job.JobMetaNonWarranty.PurchaseOrderRaisedUserId = CurrentUser.Id;
job.JobMetaNonWarranty.PurchaseOrderRaisedUserId = CurrentUser.UserId;
Database.SaveChanges();
return new Models.Job._DateChangeModel()
{
@@ -808,7 +808,7 @@ namespace Disco.Web.Areas.API.Controllers
throw new Exception("Invalid Date Format");
}
}
job.JobMetaNonWarranty.PurchaseOrderSentUserId = CurrentUser.Id;
job.JobMetaNonWarranty.PurchaseOrderSentUserId = CurrentUser.UserId;
Database.SaveChanges();
return new Models.Job._DateChangeModel()
{
@@ -842,7 +842,7 @@ namespace Disco.Web.Areas.API.Controllers
throw new Exception("Invalid Date Format");
}
}
job.JobMetaNonWarranty.InvoiceReceivedUserId = CurrentUser.Id;
job.JobMetaNonWarranty.InvoiceReceivedUserId = CurrentUser.UserId;
Database.SaveChanges();
return new Models.Job._DateChangeModel()
{
@@ -991,7 +991,7 @@ namespace Disco.Web.Areas.API.Controllers
}
}
}
job.JobMetaInsurance.ClaimFormSentUserId = CurrentUser.Id;
job.JobMetaInsurance.ClaimFormSentUserId = CurrentUser.UserId;
Database.SaveChanges();
return new Models.Job._DateChangeModel()
{
@@ -1508,7 +1508,7 @@ namespace Disco.Web.Areas.API.Controllers
JobLog jobLog = new JobLog()
{
JobId = job.Id,
TechUserId = CurrentUser.Id,
TechUserId = CurrentUser.UserId,
Timestamp = DateTime.Now,
Comments = string.Format("Added Flag: {0}{1}Reason: {2}", flagStatus.Item1, Environment.NewLine, Reason)
};
@@ -1857,7 +1857,7 @@ namespace Disco.Web.Areas.API.Controllers
var jl = new Disco.Models.Repository.JobLog()
{
JobId = j.Id,
TechUserId = CurrentUser.Id,
TechUserId = CurrentUser.UserId,
Timestamp = DateTime.Now,
Comments = comment
};
@@ -1876,7 +1876,7 @@ namespace Disco.Web.Areas.API.Controllers
var jl = Database.JobLogs.Find(id);
if (jl != null)
{
if (jl.TechUserId.Equals(CurrentUser.Id, StringComparison.InvariantCultureIgnoreCase))
if (jl.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase))
Authorization.RequireAny(Claims.Job.Actions.RemoveAnyLogs, Claims.Job.Actions.RemoveOwnLogs);
else
Authorization.Require(Claims.Job.Actions.RemoveAnyLogs);
@@ -1950,7 +1950,7 @@ namespace Disco.Web.Areas.API.Controllers
var ja = new Disco.Models.Repository.JobAttachment()
{
JobId = j.Id,
TechUserId = CurrentUser.Id,
TechUserId = CurrentUser.UserId,
Filename = file.FileName,
MimeType = contentType,
Timestamp = DateTime.Now,
@@ -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.Id, StringComparison.InvariantCultureIgnoreCase))
if (ja.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase))
Authorization.RequireAny(Claims.Job.Actions.RemoveAnyAttachments, Claims.Job.Actions.RemoveOwnAttachments);
else
Authorization.Require(Claims.Job.Actions.RemoveAnyAttachments);
@@ -2046,7 +2046,7 @@ namespace Disco.Web.Areas.API.Controllers
JobId = j.Id,
Description = Description,
Cost = cost,
TechUserId = CurrentUser.Id
TechUserId = CurrentUser.UserId
};
Database.JobComponents.Add(jc);
Database.SaveChanges();
@@ -1,5 +1,4 @@
using Disco.BI.Interop.ActiveDirectory;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Models.Repository;
using Disco.Services.Authorization;
using Disco.Services.Jobs.JobQueues;
@@ -9,6 +8,7 @@ using System;
using System.Linq;
using System.Web.Mvc;
using System.Collections.Generic;
using Disco.Services.Interop.ActiveDirectory;
namespace Disco.Web.Areas.API.Controllers
{
@@ -288,7 +288,7 @@ namespace Disco.Web.Areas.API.Controllers
// Validate Subjects
if (Subjects != null && Subjects.Length > 0)
{
var subjects = Subjects.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Select(s => new Tuple<string, IActiveDirectoryObject>(s, ActiveDirectory.GetObject(s))).ToList();
var subjects = Subjects.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Select(s => new Tuple<string, IActiveDirectoryObject>(s, ActiveDirectory.RetrieveObject(s))).ToList();
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
if (invalidSubjects.Count > 0)
@@ -370,8 +370,8 @@ namespace Disco.Web.Areas.API.Controllers
[DiscoAuthorize(Claims.Config.JobQueue.Configure)]
public virtual ActionResult SearchSubjects(string term)
{
var groupResults = BI.Interop.ActiveDirectory.ActiveDirectory.SearchGroups(term).Cast<IActiveDirectoryObject>();
var userResults = BI.Interop.ActiveDirectory.ActiveDirectory.SearchUsers(term).Cast<IActiveDirectoryObject>();
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();
@@ -382,7 +382,7 @@ namespace Disco.Web.Areas.API.Controllers
[DiscoAuthorize(Claims.Config.JobQueue.Configure)]
public virtual ActionResult Subject(string Id)
{
var subject = ActiveDirectory.GetObject(Id);
var subject = ActiveDirectory.RetrieveObject(Id);
if (subject == null || !(subject is ActiveDirectoryUserAccount || subject is ActiveDirectoryGroup))
return Json(null, JsonRequestBehavior.AllowGet);
@@ -1,8 +1,11 @@
using Disco.BI.Extensions;
using Disco.BI.Interop.ActiveDirectory;
using Disco.Data.Configuration;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Services.Authorization;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Web;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
@@ -17,7 +20,7 @@ namespace Disco.Web.Areas.API.Controllers
[DiscoAuthorize(Claims.Config.System.Show)]
public virtual ActionResult UpdateLastNetworkLogonDates()
{
var taskStatus = ActiveDirectoryUpdateLastNetworkLogonDateJob.ScheduleImmediately();
var taskStatus = Disco.Services.Interop.ActiveDirectory.Internal.ADUpdateLastNetworkLogonDateJob.ScheduleImmediately();
return RedirectToAction(MVC.Config.Logging.TaskStatus(taskStatus.SessionId));
}
@@ -219,5 +222,97 @@ namespace Disco.Web.Areas.API.Controllers
#endregion
#region Active Directory
[DiscoAuthorize(Claims.Config.System.ConfigureActiveDirectory)]
public virtual ActionResult UpdateActiveDirectorySearchScope(List<string> Containers, bool redirect = false)
{
ActiveDirectory.UpdateSearchContainers(Database, Containers);
Database.SaveChanges();
if (redirect)
return RedirectToAction(MVC.Config.SystemConfig.Index());
else
return Json("OK", JsonRequestBehavior.AllowGet);
}
[DiscoAuthorize(Claims.Config.System.ConfigureActiveDirectory)]
public virtual ActionResult UpdateActiveDirectorySearchEntireForest(bool SearchEntireForest, bool redirect = false)
{
try
{
var result = ActiveDirectory.UpdateSearchEntireForest(Database, SearchEntireForest);
Database.SaveChanges();
if (!result)
{
var forestServers = ActiveDirectory.LoadForestServers();
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
throw new InvalidOperationException("Unable to change the 'SearchEntireForest' property for an unknown reason, please report this bug");
}
if (redirect)
return RedirectToAction(MVC.Config.SystemConfig.Index());
else
return Json("OK", JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
if (redirect)
throw;
else
return Json(string.Format("Error: {0}", ex.Message), JsonRequestBehavior.AllowGet);
}
}
[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) })
.Select(ous => ous.ToFancyTreeNode()).ToList();
return Json(domainOUs, JsonRequestBehavior.AllowGet);
}
#endregion
#region Proxy Settings
[DiscoAuthorize(Claims.Config.System.ConfigureProxy)]
public virtual ActionResult UpdateProxySettings(string ProxyAddress, int? ProxyPort, string ProxyUsername, string ProxyPassword, bool redirect = false)
{
// Default Proxy Port
if (!ProxyPort.HasValue)
ProxyPort = 8080;
SystemConfiguration config = Database.DiscoConfiguration;
//config.DataStoreLocation = DataStoreLocation;
config.ProxyAddress = ProxyAddress;
config.ProxyPort = ProxyPort.Value;
config.ProxyUsername = ProxyUsername;
config.ProxyPassword = ProxyPassword;
DiscoApplication.SetGlobalProxy(ProxyAddress, ProxyPort.Value, ProxyUsername, ProxyPassword);
Database.SaveChanges();
// Try and check for updates if needed - After Proxy Changed
if (Database.DiscoConfiguration.UpdateLastCheck == null
|| Database.DiscoConfiguration.UpdateLastCheck.ResponseTimestamp < DateTime.Now.AddDays(-1))
{
Disco.BI.Interop.Community.UpdateCheckTask.ScheduleNow();
}
if (redirect)
return RedirectToAction(MVC.Config.SystemConfig.Index());
else
return Json("OK", JsonRequestBehavior.AllowGet);
}
#endregion
}
}
@@ -1,5 +1,6 @@
using Disco.BI.Extensions;
using Disco.Services.Authorization;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Users;
using Disco.Services.Web;
using System;
@@ -61,8 +62,13 @@ namespace Disco.Web.Areas.API.Controllers
}
[DiscoAuthorize(Claims.User.Actions.AddAttachments)]
public virtual ActionResult AttachmentUpload(string id, string Comments)
public virtual ActionResult AttachmentUpload(string id, string Domain, string Comments)
{
if (string.IsNullOrEmpty(Domain))
id = ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + id;
else
id = Domain + @"\" + id;
var u = Database.Users.Find(id);
if (u != null)
{
@@ -77,7 +83,7 @@ namespace Disco.Web.Areas.API.Controllers
var ua = new Disco.Models.Repository.UserAttachment()
{
UserId = u.Id,
UserId = u.UserId,
TechUserId = UserService.CurrentUserId,
Filename = file.FileName,
MimeType = contentType,
@@ -118,9 +124,14 @@ namespace Disco.Web.Areas.API.Controllers
}
[DiscoAuthorize(Claims.User.ShowAttachments)]
public virtual ActionResult Attachments(string id)
public virtual ActionResult Attachments(string id, string Domain)
{
var u = Database.Users.Include("UserAttachments.TechUser").Where(m => m.Id == id).FirstOrDefault();
if (string.IsNullOrEmpty(Domain))
id = ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + id;
else
id = Domain + @"\" + id;
var u = Database.Users.Include("UserAttachments.TechUser").Where(m => m.UserId == id).FirstOrDefault();
if (u != null)
{
var m = new Models.Attachment.AttachmentsModel()
@@ -140,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.Id, StringComparison.InvariantCultureIgnoreCase))
if (ua.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase))
Authorization.RequireAny(Claims.User.Actions.RemoveAnyAttachments, Claims.User.Actions.RemoveOwnAttachments);
else
Authorization.Require(Claims.User.Actions.RemoveAnyAttachments);
@@ -155,12 +166,18 @@ namespace Disco.Web.Areas.API.Controllers
#endregion
[DiscoAuthorize(Claims.User.Actions.GenerateDocuments)]
public virtual ActionResult GeneratePdf(string id, string DocumentTemplateId)
public virtual ActionResult GeneratePdf(string id, string Domain, string DocumentTemplateId)
{
if (string.IsNullOrEmpty(id))
throw new ArgumentNullException("id");
if (string.IsNullOrEmpty(DocumentTemplateId))
throw new ArgumentNullException("AttachmentTypeId");
if (string.IsNullOrEmpty(Domain))
id = ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + id;
else
id = Domain + @"\" + id;
var user = Database.Users.Find(id);
if (user != null)
{
@@ -174,7 +191,7 @@ namespace Disco.Web.Areas.API.Controllers
pdf = documentTemplate.GeneratePdf(Database, user, UserService.CurrentUser, timeStamp, generationState);
}
Database.SaveChanges();
return File(pdf, "application/pdf", string.Format("{0}_{1}_{2:yyyyMMdd-HHmmss}.pdf", documentTemplate.Id, user.Id, timeStamp));
return File(pdf, "application/pdf", string.Format("{0}_{1}_{2:yyyyMMdd-HHmmss}.pdf", documentTemplate.Id, user.UserId, timeStamp));
}
else
{
@@ -0,0 +1,47 @@
using Disco.Models.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 FancyTreeNode ToFancyTreeNode()
{
FancyTreeNode[] children = OrganisationalUnits.Select(ou => OrganisationalUnitToFancyTreeNode(ou)).ToArray();
return new FancyTreeNode()
{
key = Domain.DistinguishedName,
title = Domain.NetBiosName,
folder = true,
tooltip = Domain.DnsName,
children = children,
unselectable = false,
expanded = true
};
}
private FancyTreeNode OrganisationalUnitToFancyTreeNode(ActiveDirectoryOrganisationalUnit OrganisationalUnit)
{
FancyTreeNode[] children = OrganisationalUnit.Children == null
? null
: OrganisationalUnit.Children.Select(ou => OrganisationalUnitToFancyTreeNode(ou)).ToArray();
return new FancyTreeNode()
{
key = OrganisationalUnit.DistinguishedName,
title = OrganisationalUnit.Name,
folder = true,
tooltip = OrganisationalUnit.DistinguishedName,
children = children,
unselectable = false
};
}
}
}
@@ -2,6 +2,7 @@
using Disco.Models.UI.Config.AuthorizationRole;
using Disco.Services.Authorization;
using Disco.Services.Authorization.Roles;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Plugins.Features.UIExtension;
using Disco.Services.Users;
using Disco.Services.Web;
@@ -27,7 +28,7 @@ namespace Disco.Web.Areas.Config.Controllers
var token = RoleToken.FromAuthorizationRole(ar);
var subjects = token.SubjectIds == null ? new List<Models.AuthorizationRole.ShowModel.SubjectDescriptor>() :
token.SubjectIds.Select(subjectId => Disco.BI.Interop.ActiveDirectory.ActiveDirectory.GetObject(subjectId))
token.SubjectIds.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId))
.Where(item => item != null)
.Select(item => Models.AuthorizationRole.ShowModel.SubjectDescriptor.FromActiveDirectoryObject(item))
.OrderBy(item => item.Name).ToList();
@@ -2,6 +2,7 @@
using Disco.Models.Repository;
using Disco.Models.UI.Config.DeviceProfile;
using Disco.Services.Authorization;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Plugins;
using Disco.Services.Plugins.Features.CertificateProvider;
using Disco.Services.Plugins.Features.UIExtension;
@@ -75,7 +76,8 @@ namespace Disco.Web.Areas.Config.Controllers
{
ComputerNameTemplate = DeviceProfile.DefaultComputerNameTemplate,
ProvisionADAccount = true,
DistributionType = DeviceProfile.DistributionTypes.OneToMany
DistributionType = DeviceProfile.DistributionTypes.OneToMany,
OrganisationalUnit = ActiveDirectory.PrimaryDomain.GetDefaultComputerContainer()
}
};
@@ -2,6 +2,7 @@
using Disco.Models.Services.Jobs.JobQueues;
using Disco.Models.UI.Config.JobQueue;
using Disco.Services.Authorization;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Jobs.JobQueues;
using Disco.Services.Plugins.Features.UIExtension;
using Disco.Services.Web;
@@ -28,7 +29,7 @@ namespace Disco.Web.Areas.Config.Controllers
var token = JobQueueToken.FromJobQueue(jq);
var subjects = token.SubjectIds == null ? new List<Models.JobQueue.ShowModel.SubjectDescriptor>() :
token.SubjectIds.Select(subjectId => Disco.BI.Interop.ActiveDirectory.ActiveDirectory.GetObject(subjectId))
token.SubjectIds.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId))
.Where(item => item != null)
.Select(item => Models.JobQueue.ShowModel.SubjectDescriptor.FromActiveDirectoryObject(item))
.OrderBy(item => item.Name).ToList();
@@ -12,20 +12,5 @@ namespace Disco.Web.Areas.Config.Controllers
var m = Models.SystemConfig.IndexModel.FromConfiguration(Database.DiscoConfiguration);
return View(m);
}
[DiscoAuthorizeAll(Claims.Config.System.Show, Claims.Config.System.ConfigureProxy), HttpPost]
public virtual ActionResult Index(Models.SystemConfig.IndexModel config)
{
if (ModelState.IsValid)
{
config.ToConfiguration(Database);
return RedirectToAction(MVC.Config.Config.Index());
}
else
{
return View();
}
}
}
}
@@ -40,7 +40,7 @@ namespace Disco.Web.Areas.Config.Models.AuthorizationRole
{
var item = new SubjectDescriptor()
{
Id = ADObject.SamAccountName,
Id = ADObject.NetBiosId,
Name = ADObject.Name
};
@@ -8,6 +8,9 @@ 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;
namespace Disco.Web.Areas.Config.Models.SystemConfig
{
@@ -72,6 +75,20 @@ namespace Disco.Web.Areas.Config.Models.SystemConfig
}
#endregion
#region Active Directory
[Display(Name="Search Entire Forest")]
public bool ADSearchEntireForest { 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<string> ADForestServers { get; set; }
#endregion
#region Proxy
public string ProxyAddress { get; set; }
public int ProxyPort { get; set; }
@@ -87,7 +104,7 @@ namespace Disco.Web.Areas.Config.Models.SystemConfig
public static IndexModel FromConfiguration(SystemConfiguration config)
{
return new IndexModel()
var m = new IndexModel()
{
DiscoVersion = typeof(DiscoApplication).Assembly.GetName().Version,
DataStoreLocation = config.DataStoreLocation,
@@ -100,27 +117,33 @@ namespace Disco.Web.Areas.Config.Models.SystemConfig
UpdateNextScheduled = Disco.BI.Interop.Community.UpdateCheckTask.NextScheduled,
UpdateBetaDeployment = config.UpdateBetaDeployment
};
}
public void ToConfiguration(DiscoDataContext Database)
// 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();
var configSearchContainers = config.ActiveDirectory.SearchContainers;
m.ADSearchContainers = configSearchContainers == null ? null : configSearchContainers.Select(c =>
{
SystemConfiguration config = Database.DiscoConfiguration;
//config.DataStoreLocation = DataStoreLocation;
config.ProxyAddress = ProxyAddress;
config.ProxyPort = ProxyPort;
config.ProxyUsername = ProxyUsername;
config.ProxyPassword = ProxyPassword;
DiscoApplication.SetGlobalProxy(ProxyAddress, ProxyPort, ProxyUsername, ProxyPassword);
var d = ActiveDirectory.GetDomainByDistinguishedName(c);
return Tuple.Create(c, d, d.GetFriendlyOrganisationalUnitName(c));
}).ToList();
Database.SaveChanges();
// Try and check for updates if needed - After Proxy Changed
if (Database.DiscoConfiguration.UpdateLastCheck == null
|| Database.DiscoConfiguration.UpdateLastCheck.ResponseTimestamp < DateTime.Now.AddDays(-1))
var loadForestServersTask = ActiveDirectory.LoadForestServersAsync();
if (loadForestServersTask.Wait(TimeSpan.FromSeconds(3)))
{
Disco.BI.Interop.Community.UpdateCheckTask.ScheduleNow();
m.ADForestServers = loadForestServersTask.Result;
var configValue = config.ActiveDirectory.SearchEntireForest ?? true;
m.ADSearchEntireForest = configValue && m.ADForestServers.Count <= ActiveDirectory.MaxForestServerSearch;
}
else
{
m.ADForestServers = null;
m.ADSearchEntireForest = config.ActiveDirectory.SearchEntireForest ?? true;
}
return m;
}
}
}
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34003
// Runtime Version:4.0.30319.34011
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.AuthorizationRole
using Disco;
using Disco.BI.Extensions;
using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using Disco.Web;
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34003
// Runtime Version:4.0.30319.34011
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.AuthorizationRole
using Disco;
using Disco.BI.Extensions;
using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using Disco.Web;
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34003
// Runtime Version:4.0.30319.34011
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -35,6 +35,7 @@ namespace Disco.Web.Areas.Config.Views.AuthorizationRole
#line default
#line hidden
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using Disco.Web;
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34003
// Runtime Version:4.0.30319.34011
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.Config
using Disco;
using Disco.BI.Extensions;
using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using Disco.Web;
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34003
// Runtime Version:4.0.30319.34011
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceBatch
using Disco;
using Disco.BI.Extensions;
using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using Disco.Web;
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34003
// Runtime Version:4.0.30319.34011
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceBatch
using Disco;
using Disco.BI.Extensions;
using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using Disco.Web;
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34003
// Runtime Version:4.0.30319.34011
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceBatch
using Disco;
using Disco.BI.Extensions;
using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using Disco.Web;
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34003
// Runtime Version:4.0.30319.34011
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceBatch
using Disco;
using Disco.BI.Extensions;
using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using Disco.Web;
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34003
// Runtime Version:4.0.30319.34011
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceModel
using Disco;
using Disco.BI.Extensions;
using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using Disco.Web;
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34003
// Runtime Version:4.0.30319.34011
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceModel
using Disco;
using Disco.BI.Extensions;
using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using Disco.Web;
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34003
// Runtime Version:4.0.30319.34011
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceModel
using Disco;
using Disco.BI.Extensions;
using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using Disco.Web;
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34003
// Runtime Version:4.0.30319.34011
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceModel
using Disco;
using Disco.BI.Extensions;
using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using Disco.Web;
@@ -35,6 +35,7 @@
@Html.HiddenFor(model => model.DeviceProfile.ComputerNameTemplate)
@Html.HiddenFor(model => model.DeviceProfile.ProvisionADAccount)
@Html.HiddenFor(model => model.DeviceProfile.DistributionType)
@Html.HiddenFor(model => model.DeviceProfile.OrganisationalUnit)
<p class="actions">
<input type="submit" class="button" value="Create" />
</p>
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34003
// Runtime Version:4.0.30319.34011
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceProfile
using Disco;
using Disco.BI.Extensions;
using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using Disco.Web;
@@ -174,6 +175,17 @@ WriteLiteral(" ");
Write(Html.HiddenFor(model => model.DeviceProfile.DistributionType));
#line default
#line hidden
WriteLiteral("\r\n");
WriteLiteral(" ");
#line 38 "..\..\Areas\Config\Views\DeviceProfile\Create.cshtml"
Write(Html.HiddenFor(model => model.DeviceProfile.OrganisationalUnit));
#line default
#line hidden
WriteLiteral("\r\n <p");
@@ -198,7 +210,7 @@ WriteLiteral(">\r\n $(function () {\r\n $(\'#Name\').focus().s
"\r\n </script>\r\n");
#line 47 "..\..\Areas\Config\Views\DeviceProfile\Create.cshtml"
#line 48 "..\..\Areas\Config\Views\DeviceProfile\Create.cshtml"
}
@@ -2,7 +2,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34003
// Runtime Version:4.0.30319.34011
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceProfile
using Disco;
using Disco.BI.Extensions;
using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using Disco.Web;
Loaded 100 of 218 files, more files were not shown because too many files have changed in this diff. Show more