Certificate/wireless plugins; major refactoring
Migrate much of BI to Services. Added Wireless Profile Provider plugin feature. Added Certificate Authority Provider plugin feature. Modified Certificate Provider plugin feature. Database migration v17, for Device Profiles. Enrolment Client Updated to support CA Certificates, Wireless Profiles and Hardware Info. New Client Enrolment Protocol to support new features. Plugin Manifest Generator added to main solution. Improved AD search performance.
This commit is contained in:
@@ -0,0 +1,647 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.ClientServices;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Users;
|
||||
using Exceptionless;
|
||||
using PList;
|
||||
using Renci.SshNet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace Disco.Services.Devices.Enrolment
|
||||
{
|
||||
public static class DeviceEnrolment
|
||||
{
|
||||
|
||||
public static MacSecureEnrolResponse MacSecureEnrol(DiscoDataContext Database, string Host)
|
||||
{
|
||||
MacEnrol trustedRequest = new MacEnrol();
|
||||
string sessionId = System.Guid.NewGuid().ToString("B");
|
||||
MacSecureEnrolResponse MacSecureEnrol;
|
||||
try
|
||||
{
|
||||
EnrolmentLog.LogSessionStarting(sessionId, Host, EnrolmentTypes.MacSecure);
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 0, $"Connecting to '{Host}' as '{Database.DiscoConfiguration.Bootstrapper.MacSshUsername}'");
|
||||
|
||||
var sshConnectionInfo = new KeyboardInteractiveConnectionInfo(Host, Database.DiscoConfiguration.Bootstrapper.MacSshUsername);
|
||||
sshConnectionInfo.AuthenticationPrompt += (sender, e) =>
|
||||
{
|
||||
foreach (var prompt in e.Prompts)
|
||||
{
|
||||
if (prompt.Request.StartsWith("Password", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 10, $"Authenticating at '{Host}' as '{Database.DiscoConfiguration.Bootstrapper.MacSshUsername}'");
|
||||
prompt.Response = Database.DiscoConfiguration.Bootstrapper.MacSshPassword;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using (var sshClient = new SshClient(sshConnectionInfo))
|
||||
{
|
||||
sshClient.Connect();
|
||||
|
||||
try
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 30, "Retrieving System Profile Information");
|
||||
var sshResult = sshClient.RunCommand("system_profiler -xml SPHardwareDataType SPNetworkDataType SPSoftwareDataType");
|
||||
PListRoot profilerData;
|
||||
using (var reader = new StringReader(sshResult.Result))
|
||||
{
|
||||
using (var xmlReader = XmlReader.Create(reader, new XmlReaderSettings() { DtdProcessing = DtdProcessing.Ignore }))
|
||||
{
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(PListRoot));
|
||||
profilerData = (PListRoot)serializer.Deserialize(xmlReader);
|
||||
}
|
||||
}
|
||||
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 90, "Processing System Profile Information");
|
||||
|
||||
PListDict profilerDataHardware = null;
|
||||
PListArray profilerDataNetwork = null;
|
||||
PListDict profilerDataSoftware = null;
|
||||
|
||||
foreach (PListDict node in (profilerData.Root as PListArray))
|
||||
{
|
||||
var nodeItems = ((PListArray)node["_items"]);
|
||||
|
||||
switch (((PListString)node["_dataType"]).Value)
|
||||
{
|
||||
case "SPHardwareDataType":
|
||||
profilerDataHardware = (PListDict)nodeItems[0];
|
||||
break;
|
||||
case "SPNetworkDataType":
|
||||
profilerDataNetwork = nodeItems;
|
||||
break;
|
||||
case "SPSoftwareDataType":
|
||||
profilerDataSoftware = (PListDict)nodeItems[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (profilerDataHardware == null || profilerDataNetwork == null || profilerDataSoftware == null)
|
||||
throw new InvalidOperationException("System Profiler didn't return information for a requested data type");
|
||||
|
||||
trustedRequest.DeviceSerialNumber = (profilerDataHardware["serial_number"] as PListString).Value;
|
||||
trustedRequest.DeviceUUID = (profilerDataHardware["platform_UUID"] as PListString).Value;
|
||||
trustedRequest.DeviceComputerName = (profilerDataSoftware["local_host_name"] as PListString).Value;
|
||||
|
||||
var profilerDataNetworkEthernet = profilerDataNetwork.Cast<PListDict>().FirstOrDefault(e => ((PListString)e["_name"]).Value == "Ethernet");
|
||||
if (profilerDataNetworkEthernet != null)
|
||||
{
|
||||
trustedRequest.DeviceLanMacAddress = ((PListString)(profilerDataNetworkEthernet["Ethernet"] as PListDict)["MAC Address"]).Value;
|
||||
}
|
||||
|
||||
var profilerDataNetworkWiFi = profilerDataNetwork.Cast<PListDict>().FirstOrDefault(e => ((PListString)e["_name"]).Value == "Wi-Fi");
|
||||
if (profilerDataNetworkWiFi != null)
|
||||
{
|
||||
trustedRequest.DeviceWlanMacAddress = ((PListString)(profilerDataNetworkWiFi["Ethernet"] as PListDict)["MAC Address"]).Value;
|
||||
}
|
||||
|
||||
trustedRequest.DeviceManufacturer = "Apple Inc.";
|
||||
trustedRequest.DeviceModel = (profilerDataHardware["machine_model"] as PListString).Value;
|
||||
|
||||
trustedRequest.DeviceModelType = ParseMacModelType((profilerDataHardware["machine_name"] as PListString).Value);
|
||||
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 99, "Disconnecting");
|
||||
|
||||
sshClient.Disconnect();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (sshClient != null)
|
||||
{
|
||||
bool connected = sshClient.IsConnected;
|
||||
if (connected)
|
||||
{
|
||||
sshClient.Disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 100, "Disconnected, Starting Disco Enrolment");
|
||||
MacSecureEnrolResponse response = MacSecureEnrolResponse.FromMacEnrolResponse(MacEnrol(Database, trustedRequest, true, sessionId));
|
||||
EnrolmentLog.LogSessionFinished(sessionId);
|
||||
MacSecureEnrol = response;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
ex.ToExceptionless().Submit();
|
||||
EnrolmentLog.LogSessionError(sessionId, ex);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return MacSecureEnrol;
|
||||
}
|
||||
|
||||
#region "Mac Enrol Helpers"
|
||||
|
||||
private static string ParseMacModelType(string ModelName)
|
||||
{
|
||||
string ParseMacModelType;
|
||||
if (!string.IsNullOrWhiteSpace(ModelName))
|
||||
{
|
||||
string mn = ModelName.ToLower();
|
||||
if (mn.Contains("imac") || mn.Contains("mini"))
|
||||
{
|
||||
ParseMacModelType = "Desktop";
|
||||
return ParseMacModelType;
|
||||
}
|
||||
if (mn.Contains("macbook"))
|
||||
{
|
||||
ParseMacModelType = "Mobile";
|
||||
return ParseMacModelType;
|
||||
}
|
||||
if (mn.Contains("xserve"))
|
||||
{
|
||||
ParseMacModelType = "Server";
|
||||
return ParseMacModelType;
|
||||
}
|
||||
}
|
||||
ParseMacModelType = "Unknown";
|
||||
return ParseMacModelType;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public static MacEnrolResponse MacEnrol(DiscoDataContext Database, MacEnrol Request, bool Trusted, string OpenSessionId = null)
|
||||
{
|
||||
string sessionId;
|
||||
if (OpenSessionId == null)
|
||||
{
|
||||
sessionId = System.Guid.NewGuid().ToString("B");
|
||||
EnrolmentLog.LogSessionStarting(sessionId, Request.DeviceSerialNumber, EnrolmentTypes.Mac);
|
||||
}
|
||||
else
|
||||
{
|
||||
sessionId = OpenSessionId;
|
||||
}
|
||||
EnrolmentLog.LogSessionDeviceInfo(sessionId, Request);
|
||||
MacEnrolResponse response = new MacEnrolResponse();
|
||||
try
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 10, "Querying Database");
|
||||
Device RepoDevice = Database.Devices.Include("AssignedUser").Include("DeviceProfile").Include("DeviceProfile").Where(d => d.SerialNumber == Request.DeviceSerialNumber).FirstOrDefault();
|
||||
if (!Trusted)
|
||||
{
|
||||
if (RepoDevice == null)
|
||||
throw new EnrolmentSafeException(string.Format("Unknown Device Serial Number (SN: '{0}')", Request.DeviceSerialNumber));
|
||||
if (!RepoDevice.AllowUnauthenticatedEnrol)
|
||||
throw new EnrolmentSafeException(string.Format("Device isn't allowed an Unauthenticated Enrolment (SN: '{0}')", Request.DeviceSerialNumber));
|
||||
}
|
||||
if (RepoDevice == null)
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 50, "New Device, Building Disco Instance");
|
||||
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.DeviceModelType.Trim());
|
||||
DeviceModel deviceModel = deviceModelResult.Item1;
|
||||
if (deviceModelResult.Item2)
|
||||
EnrolmentLog.LogSessionTaskCreatedDeviceModel(sessionId, Request.DeviceSerialNumber, deviceModelResult.Item1.Manufacturer, deviceModelResult.Item1.Model);
|
||||
else
|
||||
EnrolmentLog.LogSessionDevice(sessionId, Request.DeviceSerialNumber, deviceModel.Id);
|
||||
|
||||
RepoDevice = new Device
|
||||
{
|
||||
SerialNumber = Request.DeviceSerialNumber,
|
||||
DeviceDomainId = Request.DeviceComputerName,
|
||||
DeviceProfile = deviceProfile,
|
||||
DeviceModel = deviceModel,
|
||||
AllowUnauthenticatedEnrol = false,
|
||||
CreatedDate = DateTime.Now,
|
||||
EnrolledDate = DateTime.Now
|
||||
};
|
||||
Database.Devices.Add(RepoDevice);
|
||||
}
|
||||
else
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 50, "Existing Device, Updating Disco Instance");
|
||||
EnrolmentLog.LogSessionTaskUpdatingDevice(sessionId, Request.DeviceSerialNumber);
|
||||
|
||||
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);
|
||||
else
|
||||
EnrolmentLog.LogSessionDevice(sessionId, Request.DeviceSerialNumber, deviceModel.Id);
|
||||
|
||||
RepoDevice.DeviceModel = deviceModel;
|
||||
|
||||
RepoDevice.DeviceDomainId = Request.DeviceComputerName;
|
||||
if (!RepoDevice.EnrolledDate.HasValue)
|
||||
{
|
||||
RepoDevice.EnrolledDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
RepoDevice.LastEnrolDate = DateTime.Now;
|
||||
RepoDevice.AllowUnauthenticatedEnrol = false;
|
||||
// Removed 2012-06-14 G# - Properties moved to DeviceProfile model & DB Migrated in DBv3.
|
||||
//DeviceProfileConfiguration RepoDeviceProfileContext = RepoDevice.DeviceProfile.Configuration(Context);
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 90, "Building Response");
|
||||
//if (RepoDeviceProfileContext.DistributionType == DeviceProfileConfiguration.DeviceProfileDistributionTypes.OneToOne && RepoDevice.AssignedUser != null)
|
||||
if (RepoDevice.DeviceProfile.DistributionType == DeviceProfile.DistributionTypes.OneToOne && RepoDevice.AssignedUser != null)
|
||||
{
|
||||
ADUserAccount AssignedUserInfo = ActiveDirectory.RetrieveADUserAccount(RepoDevice.AssignedUser.UserId);
|
||||
EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.SamAccountName, AssignedUserInfo.Domain.NetBiosName, AssignedUserInfo.SecurityIdentifier.ToString());
|
||||
response.DeviceAssignedUserUsername = AssignedUserInfo.SamAccountName;
|
||||
response.DeviceAssignedUserDomain = AssignedUserInfo.Domain.NetBiosName;
|
||||
response.DeviceAssignedUserName = AssignedUserInfo.DisplayName;
|
||||
response.DeviceAssignedUserSID = AssignedUserInfo.SecurityIdentifier.ToString();
|
||||
}
|
||||
response.DeviceComputerName = RepoDevice.DeviceDomainId;
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 100, "Completed Successfully");
|
||||
}
|
||||
catch (EnrolmentSafeException ex)
|
||||
{
|
||||
EnrolmentLog.LogSessionError(sessionId, ex);
|
||||
return new MacEnrolResponse { ErrorMessage = ex.Message };
|
||||
}
|
||||
catch (System.Exception ex2)
|
||||
{
|
||||
ex2.ToExceptionless().Submit();
|
||||
EnrolmentLog.LogSessionError(sessionId, ex2);
|
||||
throw ex2;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (OpenSessionId == null)
|
||||
EnrolmentLog.LogSessionFinished(sessionId);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
public static EnrolResponse Enrol(DiscoDataContext Database, string Username, Enrol Request)
|
||||
{
|
||||
ADMachineAccount adMachineAccount = null;
|
||||
|
||||
EnrolResponse response = new EnrolResponse();
|
||||
|
||||
AuthorizationToken authenticatedToken = null;
|
||||
bool isAuthenticated = false;
|
||||
|
||||
ADDomain domain = null;
|
||||
Lazy<ADDomainController> domainController = new Lazy<ADDomainController>(() =>
|
||||
{
|
||||
if (domain == null)
|
||||
throw new InvalidOperationException("The [domain] variable must be initialized first");
|
||||
return domain.GetAvailableDomainController(RequireWritable: true);
|
||||
});
|
||||
|
||||
string sessionId = System.Guid.NewGuid().ToString("B");
|
||||
response.SessionId = sessionId;
|
||||
|
||||
EnrolmentLog.LogSessionStarting(sessionId, Request.SerialNumber, EnrolmentTypes.Normal);
|
||||
EnrolmentLog.LogSessionDeviceInfo(sessionId, Request);
|
||||
|
||||
try
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 10, "Loading User Data");
|
||||
if (!string.IsNullOrWhiteSpace(Username))
|
||||
{
|
||||
authenticatedToken = UserService.GetAuthorization(Username, Database);
|
||||
isAuthenticated = (authenticatedToken != null);
|
||||
}
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 13, "Loading Device Data");
|
||||
|
||||
Device RepoDevice = Database.Devices.Include("AssignedUser").Include("DeviceModel").Include("DeviceProfile").Where(d => d.SerialNumber == Request.SerialNumber).FirstOrDefault();
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 15, "Discovering User/Device Disco Permissions");
|
||||
if (isAuthenticated)
|
||||
{
|
||||
if (!authenticatedToken.Has(Claims.Device.Actions.EnrolDevices))
|
||||
{
|
||||
if (!authenticatedToken.Has(Claims.ComputerAccount))
|
||||
throw new EnrolmentSafeException(string.Format("Connection not correctly authenticated (SN: {0}; Auth User: {1})", Request.SerialNumber, authenticatedToken.User.UserId));
|
||||
|
||||
if (domain == null)
|
||||
domain = ActiveDirectory.Context.GetDomainByName(Request.DNSDomainName);
|
||||
|
||||
if (!authenticatedToken.User.UserId.Equals(string.Format(@"{0}\{1}$", domain.NetBiosName, Request.ComputerName), System.StringComparison.OrdinalIgnoreCase))
|
||||
throw new EnrolmentSafeException(string.Format("Connection not correctly authenticated (SN: {0}; Auth User: {1})", Request.SerialNumber, authenticatedToken.User.UserId));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RepoDevice == null)
|
||||
{
|
||||
throw new EnrolmentSafeException(string.Format("Unknown Device Serial Number (SN: '{0}')", Request.SerialNumber));
|
||||
}
|
||||
if (!RepoDevice.AllowUnauthenticatedEnrol)
|
||||
{
|
||||
if (RepoDevice.DeviceProfile.AllowUntrustedReimageJobEnrolment)
|
||||
{
|
||||
if (Database.Jobs.Count(j => j.DeviceSerialNumber == RepoDevice.SerialNumber && j.JobTypeId == JobType.JobTypeIds.SImg && !j.ClosedDate.HasValue) == 0)
|
||||
{
|
||||
throw new EnrolmentSafeException(string.Format("Device has no open 'Software - Reimage' job (SN: '{0}')", Request.SerialNumber));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new EnrolmentSafeException(string.Format("Device isn't allowed an Unauthenticated Enrolment (SN: '{0}')", Request.SerialNumber));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Request.IsPartOfDomain && !string.IsNullOrWhiteSpace(Request.ComputerName))
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 20, "Loading Active Directory Computer Account");
|
||||
System.Guid? uuidGuid = null;
|
||||
System.Guid? macAddressGuid = null;
|
||||
if (!string.IsNullOrEmpty(Request.Hardware.UUID))
|
||||
uuidGuid = ADMachineAccount.NetbootGUIDFromUUID(Request.Hardware.UUID);
|
||||
|
||||
// Use non-Wlan Adapter with fastest speed
|
||||
var macAddress = Request.Hardware?.NetworkAdapters?.Where(na => !na.IsWlanAdapter).OrderByDescending(na => na.Speed).Select(na => na.MACAddress).FirstOrDefault();
|
||||
if (!string.IsNullOrEmpty(macAddress))
|
||||
macAddressGuid = ADMachineAccount.NetbootGUIDFromMACAddress(macAddress);
|
||||
|
||||
if (domain == null)
|
||||
domain = ActiveDirectory.Context.GetDomainByName(Request.DNSDomainName);
|
||||
|
||||
var requestDeviceId = string.Format(@"{0}\{1}", domain.NetBiosName, Request.ComputerName);
|
||||
|
||||
adMachineAccount = domainController.Value.RetrieveADMachineAccount(requestDeviceId, uuidGuid, macAddressGuid);
|
||||
}
|
||||
if (RepoDevice == null)
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 30, "New Device, Creating Disco Instance");
|
||||
EnrolmentLog.LogSessionTaskAddedDevice(sessionId, Request.SerialNumber);
|
||||
DeviceProfile deviceProfile = Database.DeviceProfiles.Find(Database.DiscoConfiguration.DeviceProfiles.DefaultDeviceProfileId);
|
||||
|
||||
|
||||
var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.Hardware.Manufacturer.Trim(), Request.Hardware.Model.Trim(), Request.Hardware.ModelType.Trim());
|
||||
DeviceModel deviceModel = deviceModelResult.Item1;
|
||||
if (deviceModelResult.Item2)
|
||||
EnrolmentLog.LogSessionTaskCreatedDeviceModel(sessionId, Request.SerialNumber, deviceModelResult.Item1.Manufacturer, deviceModelResult.Item1.Model);
|
||||
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),
|
||||
DeviceProfile = deviceProfile,
|
||||
DeviceModel = deviceModel,
|
||||
AllowUnauthenticatedEnrol = false,
|
||||
CreatedDate = DateTime.Now,
|
||||
EnrolledDate = DateTime.Now,
|
||||
LastEnrolDate = DateTime.Now,
|
||||
DeviceDetails = new List<DeviceDetail>()
|
||||
};
|
||||
Database.Devices.Add(RepoDevice);
|
||||
|
||||
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))
|
||||
RepoDevice.DeviceDetails.LanMacAddress(RepoDevice, lanMacAddresses);
|
||||
if (!string.IsNullOrEmpty(wlanMacAddresses))
|
||||
RepoDevice.DeviceDetails.WLanMacAddress(RepoDevice, wlanMacAddresses);
|
||||
}
|
||||
else
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 30, "Existing Device, Updating Disco Instance");
|
||||
EnrolmentLog.LogSessionTaskUpdatingDevice(sessionId, Request.SerialNumber);
|
||||
|
||||
var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.Hardware.Manufacturer.Trim(), Request.Hardware.Model.Trim(), Request.Hardware.ModelType.Trim());
|
||||
DeviceModel deviceModel = deviceModelResult.Item1;
|
||||
if (deviceModelResult.Item2)
|
||||
EnrolmentLog.LogSessionTaskCreatedDeviceModel(sessionId, Request.SerialNumber, deviceModelResult.Item1.Manufacturer, deviceModelResult.Item1.Model);
|
||||
else
|
||||
EnrolmentLog.LogSessionDevice(sessionId, Request.SerialNumber, deviceModel.Id);
|
||||
|
||||
RepoDevice.DeviceModel = deviceModel;
|
||||
|
||||
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))
|
||||
RepoDevice.DeviceDetails.LanMacAddress(RepoDevice, lanMacAddresses);
|
||||
if (!string.IsNullOrEmpty(wlanMacAddresses))
|
||||
RepoDevice.DeviceDetails.WLanMacAddress(RepoDevice, wlanMacAddresses);
|
||||
|
||||
if (!RepoDevice.EnrolledDate.HasValue)
|
||||
RepoDevice.EnrolledDate = DateTime.Now;
|
||||
RepoDevice.LastEnrolDate = DateTime.Now;
|
||||
}
|
||||
|
||||
if (adMachineAccount == null)
|
||||
{
|
||||
if (RepoDevice.DeviceProfile.ProvisionADAccount)
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 50, "Provisioning an Active Directory Computer Account");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(RepoDevice.DeviceProfile.OrganisationalUnit))
|
||||
throw new InvalidOperationException("No Organisational Unit has been set in the device profile");
|
||||
if (domain == null)
|
||||
domain = ActiveDirectory.Context.GetDomainFromDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
|
||||
if (string.IsNullOrEmpty(RepoDevice.DeviceDomainId) || RepoDevice.DeviceProfile.EnforceComputerNameConvention)
|
||||
RepoDevice.DeviceDomainId = RepoDevice.ComputerNameRender(Database, domain);
|
||||
|
||||
string offlineProvisionDiagnosicInfo;
|
||||
EnrolmentLog.LogSessionTaskProvisioningADAccount(sessionId, RepoDevice.SerialNumber, RepoDevice.DeviceDomainId);
|
||||
adMachineAccount = domainController.Value.RetrieveADMachineAccount(RepoDevice.DeviceDomainId);
|
||||
|
||||
response.OfflineDomainJoinManifest = domainController.Value.OfflineDomainJoinProvision(RepoDevice.DeviceDomainId, RepoDevice.DeviceProfile.OrganisationalUnit, ref adMachineAccount, out offlineProvisionDiagnosicInfo);
|
||||
|
||||
EnrolmentLog.LogSessionDiagnosticInformation(sessionId, offlineProvisionDiagnosicInfo);
|
||||
|
||||
response.RequireReboot = true;
|
||||
}
|
||||
if (adMachineAccount != null)
|
||||
{
|
||||
response.ComputerName = adMachineAccount.Name;
|
||||
response.DomainName = adMachineAccount.Domain.NetBiosName;
|
||||
}
|
||||
else if (ActiveDirectory.IsValidDomainAccountId(RepoDevice.DeviceDomainId))
|
||||
{
|
||||
string accountUsername;
|
||||
ADDomain accountDomain;
|
||||
ActiveDirectory.ParseDomainAccountId(RepoDevice.DeviceDomainId, out accountUsername, out accountDomain);
|
||||
|
||||
response.DomainName = accountDomain == null ? null : accountDomain.NetBiosName;
|
||||
response.ComputerName = accountUsername;
|
||||
}
|
||||
else
|
||||
{
|
||||
response.DomainName = Request.DNSDomainName;
|
||||
response.ComputerName = Request.ComputerName;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RepoDevice.DeviceDomainId = adMachineAccount.Id.Trim('$');
|
||||
response.ComputerName = adMachineAccount.Name;
|
||||
response.DomainName = adMachineAccount.Domain.NetBiosName;
|
||||
|
||||
// Enforce Computer Name Convention
|
||||
if (!adMachineAccount.IsCriticalSystemObject && RepoDevice.DeviceProfile.EnforceComputerNameConvention)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(RepoDevice.DeviceProfile.OrganisationalUnit))
|
||||
throw new InvalidOperationException("No Organisational Unit has been set in the device profile");
|
||||
if (domain == null)
|
||||
domain = ActiveDirectory.Context.GetDomainFromDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
|
||||
var calculatedComputerName = RepoDevice.ComputerNameRender(Database, domain);
|
||||
string calculatedAccountUsername;
|
||||
ActiveDirectory.ParseDomainAccountId(calculatedComputerName, out calculatedAccountUsername);
|
||||
|
||||
if (!Request.ComputerName.Equals(calculatedAccountUsername, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 50, string.Format("Renaming Device: {0} -> {1}", Request.ComputerName, calculatedComputerName));
|
||||
EnrolmentLog.LogSessionTaskRenamingDevice(sessionId, Request.ComputerName, calculatedComputerName);
|
||||
|
||||
RepoDevice.DeviceDomainId = calculatedComputerName;
|
||||
response.DomainName = domain.NetBiosName;
|
||||
response.ComputerName = calculatedAccountUsername;
|
||||
|
||||
// Create New Account
|
||||
string offlineProvisionDiagnosicInfo;
|
||||
|
||||
response.OfflineDomainJoinManifest = domainController.Value.OfflineDomainJoinProvision(RepoDevice.DeviceDomainId, RepoDevice.DeviceProfile.OrganisationalUnit, ref adMachineAccount, out offlineProvisionDiagnosicInfo);
|
||||
|
||||
EnrolmentLog.LogSessionDiagnosticInformation(sessionId, offlineProvisionDiagnosicInfo);
|
||||
|
||||
response.RequireReboot = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce Organisational Unit
|
||||
if (!adMachineAccount.IsCriticalSystemObject && response.OfflineDomainJoinManifest == null && RepoDevice.DeviceProfile.EnforceOrganisationalUnit)
|
||||
{
|
||||
var parentDistinguishedName = adMachineAccount.ParentDistinguishedName;
|
||||
if (string.IsNullOrWhiteSpace(RepoDevice.DeviceProfile.OrganisationalUnit))
|
||||
throw new InvalidOperationException(string.Format("The Organisational Unit for the Device Profile '{0}' [{1}] is not set.", RepoDevice.DeviceProfile.Name, RepoDevice.DeviceProfile.Id));
|
||||
|
||||
if (!parentDistinguishedName.Equals(RepoDevice.DeviceProfile.OrganisationalUnit, StringComparison.OrdinalIgnoreCase)) // Custom OU
|
||||
{
|
||||
var proposedDomain = ActiveDirectory.Context.GetDomainFromDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
var currentDomain = ActiveDirectory.Context.GetDomainFromDistinguishedName(parentDistinguishedName);
|
||||
if (currentDomain != proposedDomain)
|
||||
throw new NotSupportedException("Unable to move the devices organisational unit when the source and destination domains are different.");
|
||||
if (domain == null)
|
||||
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 Organisational Unit: {0} -> {1}", parentDistinguishedName, RepoDevice.DeviceProfile.OrganisationalUnit));
|
||||
EnrolmentLog.LogSessionTaskMovingDeviceOrganisationUnit(sessionId, parentDistinguishedName, RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
adMachineAccount.MoveOrganisationalUnit(domainController.Value, RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
response.RequireReboot = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (adMachineAccount != null && !adMachineAccount.IsCriticalSystemObject)
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 75, "Updating Active Directory Computer Account Properties");
|
||||
// Use non-Wlan Adapter with fastest speed
|
||||
var macAddress = Request.Hardware?.NetworkAdapters?.Where(na => !na.IsWlanAdapter).OrderByDescending(na => na.Speed).Select(na => na.MACAddress).FirstOrDefault();
|
||||
adMachineAccount.UpdateNetbootGUID(Request.Hardware.UUID, macAddress);
|
||||
if (RepoDevice.AssignedUser != null)
|
||||
adMachineAccount.SetDescription(RepoDevice);
|
||||
}
|
||||
if (RepoDevice.DeviceProfile.DistributionType == DeviceProfile.DistributionTypes.OneToOne)
|
||||
{
|
||||
if (RepoDevice.AssignedUser == null)
|
||||
{
|
||||
response.AllowBootstrapperUninstall = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 80, "Retrieving Active Directory Assigned User Account");
|
||||
ADUserAccount AssignedUserInfo = ActiveDirectory.RetrieveADUserAccount(RepoDevice.AssignedUser.UserId);
|
||||
EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.SamAccountName, AssignedUserInfo.Domain.NetBiosName, AssignedUserInfo.SecurityIdentifier.ToString());
|
||||
response.AllowBootstrapperUninstall = true;
|
||||
response.AssignedUserIsLocalAdmin = RepoDevice.DeviceProfile.AssignedUserLocalAdmin;
|
||||
response.AssignedUserUsername = AssignedUserInfo.SamAccountName;
|
||||
response.AssignedUserDomain = AssignedUserInfo.Domain.NetBiosName;
|
||||
response.AssignedUserDescription = AssignedUserInfo.DisplayName;
|
||||
response.AssignedUserSID = AssignedUserInfo.SecurityIdentifier.ToString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
response.AllowBootstrapperUninstall = true;
|
||||
}
|
||||
|
||||
// Provision Certificates
|
||||
if (!string.IsNullOrEmpty(RepoDevice.DeviceProfile.CertificateProviders) ||
|
||||
!string.IsNullOrEmpty(RepoDevice.DeviceProfile.CertificateAuthorityProviders))
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 90, "Provisioning Certificates");
|
||||
|
||||
List<DeviceCertificate> provisionedCertificates;
|
||||
var provisionResult = RepoDevice.ProvisionCertificates(Database, Request, out provisionedCertificates);
|
||||
|
||||
if (provisionedCertificates != null && provisionedCertificates.Count > 0)
|
||||
{
|
||||
foreach (var deviceCertificate in provisionedCertificates)
|
||||
{
|
||||
EnrolmentLog.LogSessionTaskProvisioningCertificate(sessionId, RepoDevice.SerialNumber, deviceCertificate.Name);
|
||||
}
|
||||
}
|
||||
|
||||
response.Certificates = provisionResult;
|
||||
}
|
||||
|
||||
// Provision Wireless Profiles
|
||||
if (!string.IsNullOrEmpty(RepoDevice.DeviceProfile.WirelessProfileProviders))
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 95, "Provisioning Wireless Profiles");
|
||||
|
||||
var provisionResult = RepoDevice.ProvisionWirelessProfiles(Database, Request);
|
||||
|
||||
if (provisionResult != null && provisionResult.Profiles != null)
|
||||
{
|
||||
foreach (var wirelessProfiles in provisionResult.Profiles)
|
||||
{
|
||||
EnrolmentLog.LogSessionTaskProvisioningCertificate(sessionId, RepoDevice.SerialNumber, wirelessProfiles.Name);
|
||||
}
|
||||
}
|
||||
|
||||
response.WirelessProfiles = provisionResult;
|
||||
}
|
||||
|
||||
// Reset 'AllowUnauthenticatedEnrol'
|
||||
if (RepoDevice.AllowUnauthenticatedEnrol)
|
||||
RepoDevice.AllowUnauthenticatedEnrol = false;
|
||||
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 100, "Completed Successfully");
|
||||
}
|
||||
catch (EnrolmentSafeException ex)
|
||||
{
|
||||
EnrolmentLog.LogSessionError(sessionId, ex);
|
||||
return new EnrolResponse
|
||||
{
|
||||
SessionId = sessionId,
|
||||
ErrorMessage = ex.Message
|
||||
};
|
||||
}
|
||||
catch (System.Exception ex2)
|
||||
{
|
||||
ex2.ToExceptionless().Submit();
|
||||
EnrolmentLog.LogSessionError(sessionId, ex2);
|
||||
throw ex2;
|
||||
}
|
||||
finally
|
||||
{
|
||||
EnrolmentLog.LogSessionFinished(sessionId);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,503 @@
|
||||
using Disco.Models.ClientServices;
|
||||
using Disco.Services.Logging;
|
||||
using Disco.Services.Logging.Models;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Disco.Services.Devices.Enrolment
|
||||
{
|
||||
public class EnrolmentLog : LogBase
|
||||
{
|
||||
public enum EventTypeIds
|
||||
{
|
||||
SessionStarting = 10,
|
||||
SessionProgress,
|
||||
SessionDevice,
|
||||
SessionDeviceInfo,
|
||||
SessionFinished = 20,
|
||||
SessionDiagnosticInformation,
|
||||
SessionWarning,
|
||||
SessionError,
|
||||
SessionErrorWithInner,
|
||||
SessionClientError,
|
||||
SessionTaskAddedDevice = 50,
|
||||
SessionTaskUpdatingDevice,
|
||||
SessionTaskCreatedDeviceModel = 56,
|
||||
SessionTaskProvisioningADAccount = 58,
|
||||
SessionTaskAssigningUser = 60,
|
||||
SessionTaskProvisioningCertificate = 62,
|
||||
SessionTaskProvisioningWirelessProfile = 63,
|
||||
SessionTaskRenamingDevice = 64,
|
||||
SessionTaskMovingDeviceOrganisationUnit = 66,
|
||||
ClientError = 400
|
||||
}
|
||||
private const int _ModuleId = 50;
|
||||
public static EnrolmentLog Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return (EnrolmentLog)LogContext.LogModules[50];
|
||||
}
|
||||
}
|
||||
public override string ModuleDescription
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Device Enrolment";
|
||||
}
|
||||
}
|
||||
public override int ModuleId
|
||||
{
|
||||
get
|
||||
{
|
||||
return 50;
|
||||
}
|
||||
}
|
||||
public override string ModuleName
|
||||
{
|
||||
get
|
||||
{
|
||||
return "DeviceEnrolment";
|
||||
}
|
||||
}
|
||||
[System.Diagnostics.DebuggerNonUserCode]
|
||||
public EnrolmentLog()
|
||||
{
|
||||
}
|
||||
private static void Log(EnrolmentLog.EventTypeIds EventTypeId, params object[] Args)
|
||||
{
|
||||
EnrolmentLog.Current.Log((int)EventTypeId, Args);
|
||||
}
|
||||
public static void LogSessionStarting(string SessionId, string HostId, EnrolmentTypes EnrolmentType)
|
||||
{
|
||||
Log(EventTypeIds.SessionStarting, new object[]
|
||||
{
|
||||
SessionId,
|
||||
HostId,
|
||||
System.Enum.GetName(EnrolmentType.GetType(), EnrolmentType)
|
||||
});
|
||||
}
|
||||
public static void LogSessionDevice(string SessionId, string DeviceSerialNumber, int? DeviceModelId)
|
||||
{
|
||||
Log(EventTypeIds.SessionDevice, new object[]
|
||||
{
|
||||
SessionId,
|
||||
DeviceSerialNumber,
|
||||
DeviceModelId
|
||||
});
|
||||
}
|
||||
public static void LogSessionDeviceInfo(string SessionId, string SerialNumber, string UUID, string ComputerName, string LanMacAddress, string WlanMacAddress, string Manufacturer, string Model, string ModelType)
|
||||
{
|
||||
Log(EventTypeIds.SessionDeviceInfo, new object[]
|
||||
{
|
||||
SessionId,
|
||||
SerialNumber,
|
||||
UUID,
|
||||
ComputerName,
|
||||
LanMacAddress,
|
||||
WlanMacAddress,
|
||||
Manufacturer,
|
||||
Model,
|
||||
ModelType
|
||||
});
|
||||
}
|
||||
public static void LogSessionDeviceInfo(string SessionId, MacEnrol Request)
|
||||
{
|
||||
EnrolmentLog.LogSessionDeviceInfo(SessionId, Request.DeviceSerialNumber, Request.DeviceUUID, Request.DeviceComputerName, Request.DeviceLanMacAddress, Request.DeviceWlanMacAddress, Request.DeviceManufacturer, Request.DeviceModel, Request.DeviceModelType);
|
||||
}
|
||||
public static void LogSessionDeviceInfo(string SessionId, Enrol Request)
|
||||
{
|
||||
EnrolmentLog.LogSessionDeviceInfo(SessionId, Request.SerialNumber, Request.Hardware.UUID, Request.ComputerName, null, null, Request.Hardware.Manufacturer, Request.Hardware.Model, Request.Hardware.ModelType);
|
||||
}
|
||||
|
||||
public static void LogSessionProgress(string SessionId, int Progress, string Status)
|
||||
{
|
||||
Log(EventTypeIds.SessionProgress, new object[]
|
||||
{
|
||||
SessionId,
|
||||
Progress,
|
||||
Status
|
||||
});
|
||||
}
|
||||
public static void LogSessionFinished(string SessionId)
|
||||
{
|
||||
Log(EventTypeIds.SessionFinished, new object[]
|
||||
{
|
||||
SessionId
|
||||
});
|
||||
}
|
||||
public static void LogSessionDiagnosticInformation(string SessionId, string Message)
|
||||
{
|
||||
Log(EventTypeIds.SessionDiagnosticInformation, new object[]
|
||||
{
|
||||
SessionId,
|
||||
Message
|
||||
});
|
||||
}
|
||||
public static void LogSessionWarning(string SessionId, string Message)
|
||||
{
|
||||
Log(EventTypeIds.SessionWarning, new object[]
|
||||
{
|
||||
SessionId,
|
||||
Message
|
||||
});
|
||||
}
|
||||
public static void LogSessionError(string SessionId, System.Exception Ex)
|
||||
{
|
||||
if (Ex.InnerException == null)
|
||||
{
|
||||
Log(EventTypeIds.SessionError, new object[]
|
||||
{
|
||||
SessionId,
|
||||
Ex.GetType().Name,
|
||||
Ex.Message,
|
||||
Ex.StackTrace
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(EventTypeIds.SessionErrorWithInner, new object[]
|
||||
{
|
||||
SessionId,
|
||||
Ex.GetType().Name,
|
||||
Ex.Message,
|
||||
Ex.InnerException.GetType().Name,
|
||||
Ex.InnerException.Message,
|
||||
Ex.StackTrace,
|
||||
Ex.InnerException.StackTrace
|
||||
});
|
||||
}
|
||||
}
|
||||
public static void LogSessionClientError(string SessionId, string ClientIP, string ClientIdentifier, string ClientVersion, string Error, string RawError)
|
||||
{
|
||||
Log(EventTypeIds.SessionClientError, new object[]
|
||||
{
|
||||
SessionId,
|
||||
ClientIP,
|
||||
ClientIdentifier,
|
||||
ClientVersion,
|
||||
Error,
|
||||
RawError
|
||||
});
|
||||
}
|
||||
public static void LogSessionTaskAddedDevice(string SessionId, string DeviceSerialNumber)
|
||||
{
|
||||
Log(EventTypeIds.SessionTaskAddedDevice, new object[]
|
||||
{
|
||||
SessionId,
|
||||
DeviceSerialNumber
|
||||
});
|
||||
}
|
||||
public static void LogSessionTaskUpdatingDevice(string SessionId, string DeviceSerialNumber)
|
||||
{
|
||||
Log(EventTypeIds.SessionTaskUpdatingDevice, new object[]
|
||||
{
|
||||
SessionId,
|
||||
DeviceSerialNumber
|
||||
});
|
||||
}
|
||||
public static void LogSessionTaskCreatedDeviceModel(string SessionId, string DeviceSerialNumber, string Manufacturer, string Model)
|
||||
{
|
||||
Log(EventTypeIds.SessionTaskCreatedDeviceModel, new object[]
|
||||
{
|
||||
SessionId,
|
||||
DeviceSerialNumber,
|
||||
Manufacturer,
|
||||
Model
|
||||
});
|
||||
}
|
||||
public static void LogSessionTaskProvisioningADAccount(string SessionId, string DeviceSerialNumber, string ADAccountName)
|
||||
{
|
||||
Log(EventTypeIds.SessionTaskProvisioningADAccount, new object[]
|
||||
{
|
||||
SessionId,
|
||||
DeviceSerialNumber,
|
||||
ADAccountName
|
||||
});
|
||||
}
|
||||
public static void LogSessionTaskAssigningUser(string SessionId, string DeviceSerialNumber, string UserDisplayName, string UserUsername, string UserDomain, string UserSID)
|
||||
{
|
||||
Log(EventTypeIds.SessionTaskAssigningUser, new object[]
|
||||
{
|
||||
SessionId,
|
||||
DeviceSerialNumber,
|
||||
UserDisplayName,
|
||||
UserUsername,
|
||||
UserDomain,
|
||||
UserSID
|
||||
});
|
||||
}
|
||||
public static void LogSessionTaskProvisioningCertificate(string SessionId, string DeviceSerialNumber, string CertificateName)
|
||||
{
|
||||
Log(EventTypeIds.SessionTaskProvisioningCertificate, new object[]
|
||||
{
|
||||
SessionId,
|
||||
DeviceSerialNumber,
|
||||
CertificateName
|
||||
});
|
||||
}
|
||||
public static void LogSessionTaskProvisioningWirelessProfile(string SessionId, string DeviceSerialNumber, string WirelessProfileName)
|
||||
{
|
||||
Log(EventTypeIds.SessionTaskProvisioningWirelessProfile, new object[]
|
||||
{
|
||||
SessionId,
|
||||
DeviceSerialNumber,
|
||||
WirelessProfileName
|
||||
});
|
||||
}
|
||||
public static void LogSessionTaskRenamingDevice(string SessionId, string OldComputerName, string NewComputerName)
|
||||
{
|
||||
Log(EventTypeIds.SessionTaskRenamingDevice, new object[]
|
||||
{
|
||||
SessionId,
|
||||
OldComputerName,
|
||||
NewComputerName
|
||||
});
|
||||
}
|
||||
public static void LogSessionTaskMovingDeviceOrganisationUnit(string SessionId, string OldOrganisationUnit, string NewOrganisationUnit)
|
||||
{
|
||||
Log(EventTypeIds.SessionTaskMovingDeviceOrganisationUnit, new object[]
|
||||
{
|
||||
SessionId,
|
||||
OldOrganisationUnit,
|
||||
NewOrganisationUnit
|
||||
});
|
||||
}
|
||||
public static void LogClientError(string ClientIP, string ClientIdentifier, string ClientVersion, string Error, string RawError)
|
||||
{
|
||||
Log(EventTypeIds.ClientError, new object[]
|
||||
{
|
||||
ClientIP,
|
||||
ClientIdentifier,
|
||||
ClientVersion,
|
||||
Error,
|
||||
RawError
|
||||
});
|
||||
}
|
||||
protected override List<LogEventType> LoadEventTypes()
|
||||
{
|
||||
return new List<LogEventType>
|
||||
{
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.SessionStarting,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Session Starting",
|
||||
Format = "Starting '{2}' Enrolment for {1} (Session# {0})",
|
||||
Severity = 0,
|
||||
UseLive = true,
|
||||
UsePersist = true,
|
||||
UseDisplay = true
|
||||
},
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.SessionProgress,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Session Progress",
|
||||
Format = "Processing Session# {0}; {1}% Complete; Status: {2}",
|
||||
Severity = 0,
|
||||
UseLive = true,
|
||||
UsePersist = false,
|
||||
UseDisplay = false
|
||||
},
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.SessionDevice,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Session Device",
|
||||
Format = null,
|
||||
Severity = 0,
|
||||
UseLive = true,
|
||||
UsePersist = true,
|
||||
UseDisplay = false
|
||||
},
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.SessionDeviceInfo,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Session Device Info",
|
||||
Format = null,
|
||||
Severity = 0,
|
||||
UseLive = true,
|
||||
UsePersist = true,
|
||||
UseDisplay = true
|
||||
},
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.SessionFinished,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Session Finished",
|
||||
Format = "Finished Session# {0}",
|
||||
Severity = 0,
|
||||
UseLive = true,
|
||||
UsePersist = true,
|
||||
UseDisplay = true
|
||||
},
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.SessionDiagnosticInformation,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Session Diagnostic Information",
|
||||
Format = null,
|
||||
Severity = 0,
|
||||
UseLive = true,
|
||||
UsePersist = false,
|
||||
UseDisplay = false
|
||||
},
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.SessionWarning,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Session Warning",
|
||||
Format = null,
|
||||
Severity = 1,
|
||||
UseLive = true,
|
||||
UsePersist = true,
|
||||
UseDisplay = true
|
||||
},
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.SessionError,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Session Error",
|
||||
Format = "An Error Occurred: [{1}] {2}",
|
||||
Severity = 2,
|
||||
UseLive = true,
|
||||
UsePersist = true,
|
||||
UseDisplay = true
|
||||
},
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.SessionErrorWithInner,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Session Error with Internal",
|
||||
Format = "An Error Occurred: [{1}] {2}; Internal Error: [{3}] {4}",
|
||||
Severity = 2,
|
||||
UseLive = true,
|
||||
UsePersist = true,
|
||||
UseDisplay = true
|
||||
},
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.SessionClientError,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Client Error",
|
||||
Format = "IP: {1}; Device ID: {2}; Version: {3} Error: {4}; Session# {0}",
|
||||
Severity = (int)LogEventType.Severities.Error,
|
||||
UseLive = true,
|
||||
UsePersist = true,
|
||||
UseDisplay = true
|
||||
},
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.SessionTaskAddedDevice,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Task - Added Device",
|
||||
Format = "Creating Disco Device {1}",
|
||||
Severity = 0,
|
||||
UseLive = true,
|
||||
UsePersist = true,
|
||||
UseDisplay = true
|
||||
},
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.SessionTaskUpdatingDevice,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Task - Updating Device",
|
||||
Format = "Updating Disco Device {1}",
|
||||
Severity = 0,
|
||||
UseLive = true,
|
||||
UsePersist = true,
|
||||
UseDisplay = true
|
||||
},
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.SessionTaskCreatedDeviceModel,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Task - Creating Device Model",
|
||||
Format = "Creating Device Model '{2} {3}' for Device {1}",
|
||||
Severity = 0,
|
||||
UseLive = true,
|
||||
UsePersist = true,
|
||||
UseDisplay = true
|
||||
},
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.SessionTaskProvisioningADAccount,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Task - Provisioning Active Directory Account",
|
||||
Format = "Provisioning Active Directory Account '{2}' for Device {1}",
|
||||
Severity = 0,
|
||||
UseLive = true,
|
||||
UsePersist = true,
|
||||
UseDisplay = true
|
||||
},
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.SessionTaskAssigningUser,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Task - Assigning User",
|
||||
Format = "Assigning User '{2}' ({4}\\{3} {{{5}}}) for Device {1}",
|
||||
Severity = 0,
|
||||
UseLive = true,
|
||||
UsePersist = true,
|
||||
UseDisplay = true
|
||||
},
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.SessionTaskProvisioningCertificate,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Task - Provisioning Certificate",
|
||||
Format = "Provisioning Certificate '{2}' for Device {1}",
|
||||
Severity = 0,
|
||||
UseLive = true,
|
||||
UsePersist = true,
|
||||
UseDisplay = true
|
||||
},
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.SessionTaskProvisioningWirelessProfile,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Task - Provisioning Wireless Profile",
|
||||
Format = "Provisioning Wireless Profile '{2}' for Device {1}",
|
||||
Severity = 0,
|
||||
UseLive = true,
|
||||
UsePersist = true,
|
||||
UseDisplay = true
|
||||
},
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.SessionTaskRenamingDevice,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Task - Renaming Device",
|
||||
Format = "Renaming Device '{1}' to '{2}'",
|
||||
Severity = 0,
|
||||
UseLive = true,
|
||||
UsePersist = true,
|
||||
UseDisplay = true
|
||||
},
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.SessionTaskMovingDeviceOrganisationUnit,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Task - Moving Device Organisation Unit",
|
||||
Format = "Moving Device Organisation Unit '{1}' to '{2}'",
|
||||
Severity = 0,
|
||||
UseLive = true,
|
||||
UsePersist = true,
|
||||
UseDisplay = true
|
||||
},
|
||||
new LogEventType
|
||||
{
|
||||
Id = (int)EventTypeIds.ClientError,
|
||||
ModuleId = _ModuleId,
|
||||
Name = "Client Error",
|
||||
Format = "IP: {0}; Device ID: {1}; Version: {2} Error: {3}",
|
||||
Severity = (int)LogEventType.Severities.Error,
|
||||
UseLive = true,
|
||||
UsePersist = true,
|
||||
UseDisplay = true
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace Disco.Services.Devices.Enrolment
|
||||
{
|
||||
public class EnrolmentSafeException : Exception
|
||||
{
|
||||
public EnrolmentSafeException(string Message) : base(Message)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Services.Devices.Enrolment
|
||||
{
|
||||
public enum EnrolmentTypes
|
||||
{
|
||||
Normal,
|
||||
Mac = 5,
|
||||
MacSecure,
|
||||
Register = 30
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Services.Logging;
|
||||
using Disco.Services.Tasks;
|
||||
using Quartz;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.Services.Devices.Enrolment
|
||||
{
|
||||
public class LogMacAddressImportingTask : ScheduledTask
|
||||
{
|
||||
public override string TaskName { get { return "Migration: Logs to Device Mac Address Details"; } }
|
||||
|
||||
public override bool SingleInstanceTask { get { return true; } }
|
||||
public override bool CancelInitiallySupported { get { return false; } }
|
||||
|
||||
#region Required Helpers
|
||||
private static string RequiredFilePath(DiscoDataContext Database)
|
||||
{
|
||||
if (Database.DiscoConfiguration.DataStoreLocation != null)
|
||||
return System.IO.Path.Combine(Database.DiscoConfiguration.DataStoreLocation, "_LogMacAddressImportingRequired.txt");
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool IsRequired(DiscoDataContext Database)
|
||||
{
|
||||
var requiredFilePath = RequiredFilePath(Database);
|
||||
|
||||
if (requiredFilePath == null)
|
||||
return false;
|
||||
else
|
||||
return System.IO.File.Exists(requiredFilePath);
|
||||
}
|
||||
public static void SetRequired(DiscoDataContext Database)
|
||||
{
|
||||
var requiredFilePath = RequiredFilePath(Database);
|
||||
|
||||
if (requiredFilePath != null)
|
||||
{
|
||||
System.IO.File.WriteAllText(requiredFilePath, "This file exists to indicate an Importing of Mac Address from the Disco Logs is required. It will automatically be deleted when the import completes.");
|
||||
System.IO.File.SetAttributes(requiredFilePath, System.IO.FileAttributes.Hidden);
|
||||
}
|
||||
// ELSE: Could never be required if no DataStoreLocation is set (no logs to process)
|
||||
}
|
||||
#endregion
|
||||
|
||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
||||
{
|
||||
if (IsRequired(Database))
|
||||
{
|
||||
// Schedule in 15mins
|
||||
var trigger = TriggerBuilder.Create()
|
||||
.StartAt(DateTimeOffset.Now.AddMinutes(5));
|
||||
|
||||
this.ScheduleTask(trigger);
|
||||
}
|
||||
}
|
||||
|
||||
public static ScheduledTaskStatus ScheduleImmediately()
|
||||
{
|
||||
var existingTask = ScheduledTasks.GetTaskStatuses(typeof(LogMacAddressImportingTask)).Where(s => s.IsRunning).FirstOrDefault();
|
||||
if (existingTask != null)
|
||||
return existingTask;
|
||||
|
||||
var instance = new LogMacAddressImportingTask();
|
||||
return instance.ScheduleTask();
|
||||
}
|
||||
|
||||
protected override void ExecuteTask()
|
||||
{
|
||||
using (DiscoDataContext database = new DiscoDataContext())
|
||||
{
|
||||
Status.UpdateStatus(0, "Importing MAC Addresses", "Querying Logs for Details");
|
||||
// Load Logs
|
||||
var logRetriever = new ReadLogContext()
|
||||
{
|
||||
Module = EnrolmentLog.Current.ModuleId,
|
||||
EventTypes = new List<int>() { (int)EnrolmentLog.EventTypeIds.SessionDeviceInfo }
|
||||
};
|
||||
var results = logRetriever.Query(database);
|
||||
|
||||
Status.UpdateStatus(50, string.Format("Passing {0} logs", results.Count));
|
||||
|
||||
Dictionary<string, Tuple<string, string>> addresses = new Dictionary<string, Tuple<string, string>>();
|
||||
|
||||
foreach (var result in results.OrderBy(r => r.Timestamp))
|
||||
addresses[((string)result.Arguments[1]).ToLower()] = new Tuple<string, string>((string)result.Arguments[4], (string)result.Arguments[5]);
|
||||
|
||||
Status.UpdateStatus(75, string.Format("Importing {0} details", addresses.Count));
|
||||
|
||||
var devices = database.Devices.Include("DeviceDetails").ToList();
|
||||
|
||||
Tuple<string, string> addressResult;
|
||||
foreach (var device in devices)
|
||||
{
|
||||
if (addresses.TryGetValue(device.SerialNumber.ToLower(), out addressResult))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(addressResult.Item1))
|
||||
device.DeviceDetails.LanMacAddress(device, addressResult.Item1);
|
||||
if (!string.IsNullOrEmpty(addressResult.Item2))
|
||||
device.DeviceDetails.WLanMacAddress(device, addressResult.Item2);
|
||||
}
|
||||
}
|
||||
|
||||
Status.UpdateStatus(90, "Saving to Database");
|
||||
|
||||
database.SaveChanges();
|
||||
|
||||
// Finished - Remove Placeholder File
|
||||
var requiredFilePath = RequiredFilePath(database);
|
||||
if (System.IO.File.Exists(requiredFilePath))
|
||||
System.IO.File.Delete(requiredFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user