From 85d51c0e4536e2889ff9f8315de7195f8223f2c5 Mon Sep 17 00:00:00 2001 From: Gary Sharp Date: Thu, 11 Jan 2024 16:27:40 +1100 Subject: [PATCH] Fix #141 preserve computer names for non-domain joined devices --- Disco.Data/Repository/DiscoDataSeeder.cs | 26 +++++++++---------- Disco.Services/Devices/DeviceExtensions.cs | 14 +++++----- .../Devices/Enrolment/DeviceEnrolment.cs | 21 ++++++++------- .../Fields/DeviceComputerNameImportField.cs | 5 +++- .../ActiveDirectory/ADMachineAccount.cs | 2 +- Disco.Web/Controllers/DeviceController.cs | 9 ++++++- 6 files changed, 44 insertions(+), 33 deletions(-) diff --git a/Disco.Data/Repository/DiscoDataSeeder.cs b/Disco.Data/Repository/DiscoDataSeeder.cs index 0a1139de..20780b99 100644 --- a/Disco.Data/Repository/DiscoDataSeeder.cs +++ b/Disco.Data/Repository/DiscoDataSeeder.cs @@ -1,11 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Disco.Models.Repository; +using Disco.Models.Repository; +using System; using System.Data.SqlClient; -using System.DirectoryServices.ActiveDirectory; using System.DirectoryServices; +using System.DirectoryServices.ActiveDirectory; +using System.Linq; namespace Disco.Data.Repository { @@ -370,7 +368,7 @@ DELETE [Users] WHERE [Id]=@IdExisting;"; string defaultNamingContext; using (Domain d = Domain.GetComputerDomain()) { - string ldapPath = string.Format("LDAP://{0}/", d.Name); + string ldapPath = $"LDAP://{d.Name}/"; string configurationNamingContext; using (var adRootDSE = new DirectoryEntry(ldapPath + "RootDSE")) @@ -381,7 +379,7 @@ DELETE [Users] WHERE [Id]=@IdExisting;"; using (var configSearchRoot = new DirectoryEntry(ldapPath + "CN=Partitions," + configurationNamingContext)) { - var configSearchFilter = string.Format("(&(objectcategory=Crossref)(dnsRoot={0})(netBIOSName=*))", d.Name); + var configSearchFilter = $"(&(objectcategory=Crossref)(dnsRoot={d.Name})(netBIOSName=*))"; var configSearchLoadProperites = new string[] { "NetBIOSName" }; using (var configSearcher = new DirectorySearcher(configSearchRoot, configSearchFilter, configSearchLoadProperites, SearchScope.OneLevel)) @@ -403,14 +401,14 @@ DELETE [Users] WHERE [Id]=@IdExisting;"; // 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))); + var ids = string.Join(",", authRole.SubjectIds.Split(',').Select(id => id.Contains('\\') ? id : $@"{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))); + var ids = string.Join(",", jobQueue.SubjectIds.Split(',').Select(id => id.Contains('\\') ? id : $@"{netBiosName}\{id}")); if (ids != jobQueue.SubjectIds) jobQueue.SubjectIds = ids; } @@ -418,9 +416,9 @@ DELETE [Users] WHERE [Id]=@IdExisting;"; 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); + deviceProfile.OrganisationalUnit = $"CN=Computers,{defaultNamingContext}"; else - deviceProfile.OrganisationalUnit = string.Format("{0},{1}", deviceProfile.OrganisationalUnit, defaultNamingContext); + deviceProfile.OrganisationalUnit = $"{deviceProfile.OrganisationalUnit},{defaultNamingContext}"; } Database.SaveChanges(); @@ -451,7 +449,7 @@ DELETE [Users] WHERE [Id]=@IdExisting;"; // 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); + device.DeviceDomainId = $@"{netBiosName}\{device.DeviceDomainId}"; } Database.SaveChanges(); @@ -462,7 +460,7 @@ DELETE [Users] WHERE [Id]=@IdExisting;"; idExisting.Value = user.UserId; SqlParameter idNew = new SqlParameter("@IdNew", System.Data.SqlDbType.NVarChar, 50); - idNew.Value = string.Format("{0}\\{1}", netBiosName, user.UserId); + idNew.Value = $@"{netBiosName}\{user.UserId}"; Database.Database.ExecuteSqlCommand(MigratePreDomainUsers_Sql, idExisting, idNew); } diff --git a/Disco.Services/Devices/DeviceExtensions.cs b/Disco.Services/Devices/DeviceExtensions.cs index 6740381f..edf784fb 100644 --- a/Disco.Services/Devices/DeviceExtensions.cs +++ b/Disco.Services/Devices/DeviceExtensions.cs @@ -189,14 +189,16 @@ namespace Disco.Services if (ActiveDirectory.IsValidDomainAccountId(d.DeviceDomainId)) { var adMachineAccount = ActiveDirectory.RetrieveADMachineAccount(d.DeviceDomainId); - try + if (adMachineAccount != null) { - if (adMachineAccount != null) + try + { adMachineAccount.SetDescription(d); - } - catch (Exception ex) - { - SystemLog.LogWarning($"Unable to update AD Machine Account Description for {d.DeviceDomainId}: {ex.Message}"); + } + catch (Exception ex) + { + SystemLog.LogWarning($"Unable to update AD Machine Account Description for {d.DeviceDomainId}: {ex.Message}"); + } } } diff --git a/Disco.Services/Devices/Enrolment/DeviceEnrolment.cs b/Disco.Services/Devices/Enrolment/DeviceEnrolment.cs index 5aa75f8c..4da17ba7 100644 --- a/Disco.Services/Devices/Enrolment/DeviceEnrolment.cs +++ b/Disco.Services/Devices/Enrolment/DeviceEnrolment.cs @@ -392,7 +392,6 @@ namespace Disco.Services.Devices.Enrolment EnrolmentLog.LogSessionTaskAddedDevice(sessionId, Request.SerialNumber); DeviceProfile deviceProfile = Database.DeviceProfiles.Find(Database.DiscoConfiguration.DeviceProfiles.DefaultDeviceProfileId); - var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.Hardware.Manufacturer, Request.Hardware.Model, Request.Hardware.ModelType); DeviceModel deviceModel = deviceModelResult.Item1; if (deviceModelResult.Item2) @@ -400,13 +399,10 @@ namespace Disco.Services.Devices.Enrolment else EnrolmentLog.LogSessionDevice(sessionId, Request.SerialNumber, deviceModel.Id); - if (domain == null) - domain = ActiveDirectory.Context.GetDomainByName(Request.DNSDomainName); - RepoDevice = new Device { SerialNumber = Request.SerialNumber, - DeviceDomainId = string.Format(@"{0}\{1}", domain.NetBiosName, Request.ComputerName), + DeviceDomainId = domain == null ? Request.ComputerName : $@"{domain.NetBiosName}\{Request.ComputerName}", DeviceProfile = deviceProfile, DeviceModel = deviceModel, AllowUnauthenticatedEnrol = false, @@ -438,6 +434,10 @@ namespace Disco.Services.Devices.Enrolment RepoDevice.DeviceModel = deviceModel; + var deviceDomainId = domain == null ? Request.ComputerName : $@"{domain.NetBiosName}\{Request.ComputerName}"; + if (!string.Equals(RepoDevice.DeviceDomainId, deviceDomainId, StringComparison.Ordinal)) + RepoDevice.DeviceDomainId = deviceDomainId; + var lanMacAddresses = string.Join("; ", Request.Hardware.NetworkAdapters?.Where(na => !na.IsWlanAdapter).Select(na => na.MACAddress)); var wlanMacAddresses = string.Join("; ", Request.Hardware.NetworkAdapters?.Where(na => na.IsWlanAdapter).Select(na => na.MACAddress)); if (!string.IsNullOrEmpty(lanMacAddresses)) @@ -481,6 +481,11 @@ namespace Disco.Services.Devices.Enrolment if (string.IsNullOrEmpty(RepoDevice.DeviceDomainId) || RepoDevice.DeviceProfile.EnforceComputerNameConvention) RepoDevice.DeviceDomainId = RepoDevice.ComputerNameRender(Database, domain); + else if (!ActiveDirectory.IsValidDomainAccountId(RepoDevice.DeviceDomainId)) + if (RepoDevice.DeviceProfile.EnforceComputerNameConvention) + RepoDevice.DeviceDomainId = RepoDevice.ComputerNameRender(Database, domain); + else + RepoDevice.DeviceDomainId = $@"{domain.NetBiosName}\{Request.ComputerName}"; string offlineProvisionDiagnosicInfo; EnrolmentLog.LogSessionTaskProvisioningADAccount(sessionId, RepoDevice.SerialNumber, RepoDevice.DeviceDomainId); @@ -497,12 +502,8 @@ namespace Disco.Services.Devices.Enrolment response.ComputerName = adMachineAccount.Name; response.DomainName = adMachineAccount.Domain.NetBiosName; } - else if (ActiveDirectory.IsValidDomainAccountId(RepoDevice.DeviceDomainId)) + else if (ActiveDirectory.IsValidDomainAccountId(RepoDevice.DeviceDomainId, out var accountUsername, out var accountDomain)) { - string accountUsername; - ADDomain accountDomain; - ActiveDirectory.ParseDomainAccountId(RepoDevice.DeviceDomainId, out accountUsername, out accountDomain); - response.DomainName = accountDomain == null ? null : accountDomain.NetBiosName; response.ComputerName = accountUsername; } diff --git a/Disco.Services/Devices/Importing/Fields/DeviceComputerNameImportField.cs b/Disco.Services/Devices/Importing/Fields/DeviceComputerNameImportField.cs index 1e5ef9a9..722024d0 100644 --- a/Disco.Services/Devices/Importing/Fields/DeviceComputerNameImportField.cs +++ b/Disco.Services/Devices/Importing/Fields/DeviceComputerNameImportField.cs @@ -35,7 +35,10 @@ namespace Disco.Services.Devices.Importing.Fields try { - parsedValue = ActiveDirectory.ParseDomainAccountId(parsedValue); + if (ActiveDirectory.IsValidDomainAccountId(parsedValue, out var accountUsername, out var accountDomain)) + parsedValue = $@"{accountDomain.NetBiosName}\{accountUsername}"; + else + return Error(@"The expected format is 'DOMAIN\ComputerName'"); } catch (ArgumentException ex) when (ex.ParamName == "NetBiosName") { diff --git a/Disco.Services/Interop/ActiveDirectory/ADMachineAccount.cs b/Disco.Services/Interop/ActiveDirectory/ADMachineAccount.cs index 9bbf0908..940494f0 100644 --- a/Disco.Services/Interop/ActiveDirectory/ADMachineAccount.cs +++ b/Disco.Services/Interop/ActiveDirectory/ADMachineAccount.cs @@ -19,7 +19,7 @@ namespace Disco.Services.Interop.ActiveDirectory public string DistinguishedName { get; private set; } public SecurityIdentifier SecurityIdentifier { get; private set; } - public string Id { get { return string.Format(@"{0}\{1}", Domain.NetBiosName, SamAccountName); } } + public string Id { get { return $@"{Domain.NetBiosName}\{SamAccountName}"; } } public string SamAccountName { get; private set; } diff --git a/Disco.Web/Controllers/DeviceController.cs b/Disco.Web/Controllers/DeviceController.cs index 4727ebf9..4e402820 100644 --- a/Disco.Web/Controllers/DeviceController.cs +++ b/Disco.Web/Controllers/DeviceController.cs @@ -84,7 +84,14 @@ namespace Disco.Web.Controllers { try { - m.Device.DeviceDomainId = ActiveDirectory.ParseDomainAccountId(m.Device.DeviceDomainId); + if (ActiveDirectory.IsValidDomainAccountId(m.Device.DeviceDomainId, out var accountUsername, out var accountDomain)) + { + m.Device.DeviceDomainId = $@"{accountDomain.NetBiosName}\{accountUsername}"; + } + else + { + ModelState.AddModelError("Device.DeviceDomainId", @"The computer name must be in the format 'DOMAIN\Username'"); + } } catch (ArgumentException ex) {