From 19fe76324bcf70aebed033bc32ca453fe4785ab2 Mon Sep 17 00:00:00 2001 From: Seji64 Date: Fri, 9 Aug 2024 15:02:14 +0200 Subject: [PATCH] NuGet Update + code refactor --- src/Components/LapsInformationDetail.razor | 4 +- src/Components/LapsInformationDetail.razor.cs | 6 +- src/Dialogs/Confirmation.razor | 6 +- src/Interfaces/ILDAPService.cs | 4 +- src/LAPS-WebUI.csproj | 14 +- src/Models/ADComputer.cs | 32 +- src/Pages/Index.razor | 2 +- src/Pages/Index.razor.cs | 2 +- src/Pages/LAPS.razor | 101 +++---- src/Pages/LAPS.razor.cs | 122 ++++---- src/Pages/Login.razor | 4 +- src/Pages/Login.razor.cs | 6 +- src/Pages/Logout.razor | 2 +- src/Pages/Logout.razor.cs | 4 +- src/Services/CryptService.cs | 8 +- src/Services/LDAPService.cs | 284 ++++++++---------- src/Services/SessionManagerService.cs | 40 +-- src/Shared/MainLayout.razor | 4 +- src/Shared/MainLayout.razor.cs | 6 +- 19 files changed, 299 insertions(+), 352 deletions(-) diff --git a/src/Components/LapsInformationDetail.razor b/src/Components/LapsInformationDetail.razor index e307019..c811862 100644 --- a/src/Components/LapsInformationDetail.razor +++ b/src/Components/LapsInformationDetail.razor @@ -1,6 +1,6 @@ @inherits MudComponentBase @inject ISnackbar Snackbar -@inject ClipboardService clipboard +@inject ClipboardService Clipboard @using CurrieTechnologies.Razor.Clipboard @if (LapsInfo != null) @@ -13,7 +13,7 @@ - + diff --git a/src/Components/LapsInformationDetail.razor.cs b/src/Components/LapsInformationDetail.razor.cs index a641fad..08a9190 100644 --- a/src/Components/LapsInformationDetail.razor.cs +++ b/src/Components/LapsInformationDetail.razor.cs @@ -14,7 +14,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { - IsCopyToClipboardSupported = await clipboard.IsSupportedAsync(); + IsCopyToClipboardSupported = await Clipboard.IsSupportedAsync(); } } @@ -22,11 +22,11 @@ private bool IsCopyButtonDisabled() { return !IsCopyToClipboardSupported || LapsInfo is null || string.IsNullOrEmpty(LapsInfo.Password); } - private async Task CopyLAPSPasswordToClipboardAsync() + private async Task CopyLapsPasswordToClipboardAsync() { if (LapsInfo != null && !string.IsNullOrEmpty(LapsInfo.Password)) { - await clipboard.WriteTextAsync(LapsInfo.Password); + await Clipboard.WriteTextAsync(LapsInfo.Password); Snackbar.Add("Copied password to clipboard!", Severity.Success); } else diff --git a/src/Dialogs/Confirmation.razor b/src/Dialogs/Confirmation.razor index 876085a..467d529 100644 --- a/src/Dialogs/Confirmation.razor +++ b/src/Dialogs/Confirmation.razor @@ -1,4 +1,4 @@ - + @@ -6,9 +6,9 @@ @if (ContentListItems != null && ContentListItems.Any()) { - foreach (var item in ContentListItems) + foreach (string? item in ContentListItems) { - + } diff --git a/src/Interfaces/ILDAPService.cs b/src/Interfaces/ILDAPService.cs index 54e8b45..0a31dc5 100644 --- a/src/Interfaces/ILDAPService.cs +++ b/src/Interfaces/ILDAPService.cs @@ -10,8 +10,8 @@ public interface ILdapService Task TestCredentialsAsync(string domainName, string username, string password); Task TestCredentialsAsync(string domainName, LdapCredential ldapCredential); Task> GetDomainsAsync(); - public Task GetADComputerAsync(string domainName, LdapCredential ldapCredential, string distinguishedName); - public Task> SearchADComputersAsync(string domainName, LdapCredential ldapCredential, string query); + public Task GetAdComputerAsync(string domainName, LdapCredential ldapCredential, string distinguishedName); + public Task> SearchAdComputersAsync(string domainName, LdapCredential ldapCredential, string query); public Task ClearLapsPassword(string domainName, LdapCredential ldapCredential, string distinguishedName, LAPSVersion version); } } diff --git a/src/LAPS-WebUI.csproj b/src/LAPS-WebUI.csproj index 358f455..a762de6 100644 --- a/src/LAPS-WebUI.csproj +++ b/src/LAPS-WebUI.csproj @@ -21,17 +21,17 @@ - + - - + + - - - - + + + + diff --git a/src/Models/ADComputer.cs b/src/Models/ADComputer.cs index 6e2a016..a2e30fc 100644 --- a/src/Models/ADComputer.cs +++ b/src/Models/ADComputer.cs @@ -1,31 +1,11 @@ namespace LAPS_WebUI.Models { - public class ADComputer + public class AdComputer(string distinguishedName, string name) { - public ADComputer(string DistinguishedName, string name) - { - this.DistinguishedName = DistinguishedName; - this.Name = name; - } - - public string Name { get; set; } - - public string DistinguishedName { get; set; } - public List? LAPSInformations { get; set; } - public bool FailedToRetrieveLAPSDetails { get; set; } - public bool Loading - { - get - { - if (LAPSInformations is null) - { - return true; - } - else - { - return false; - } - } - } + public string Name { get; set; } = name; + public string DistinguishedName { get; set; } = distinguishedName; + public List? LapsInformations { get; set; } + public bool FailedToRetrieveLapsDetails { get; set; } + public bool Loading => LapsInformations is null; } } diff --git a/src/Pages/Index.razor b/src/Pages/Index.razor index f6eb065..d3d155d 100644 --- a/src/Pages/Index.razor +++ b/src/Pages/Index.razor @@ -1,3 +1,3 @@ @page "/" -@inject ISessionManagerService sessionManager +@inject ISessionManagerService SessionManager @inject NavigationManager NavigationManager \ No newline at end of file diff --git a/src/Pages/Index.razor.cs b/src/Pages/Index.razor.cs index 7c8dad4..f75a9b0 100644 --- a/src/Pages/Index.razor.cs +++ b/src/Pages/Index.razor.cs @@ -5,7 +5,7 @@ public partial class Index protected override async Task OnAfterRenderAsync(bool firstRender) { // redirect to home if already logged in - if (await sessionManager.IsUserLoggedInAsync()) + if (await SessionManager.IsUserLoggedInAsync()) { NavigationManager.NavigateTo("/laps"); } diff --git a/src/Pages/LAPS.razor b/src/Pages/LAPS.razor index aff9c2b..7cbdca7 100644 --- a/src/Pages/LAPS.razor +++ b/src/Pages/LAPS.razor @@ -1,7 +1,7 @@ @page "/laps" -@inject ISessionManagerService sessionManager +@inject ISessionManagerService SessionManager @inject NavigationManager NavigationManager -@inject ILdapService LDAPService +@inject ILdapService LdapService @inject ISnackbar Snackbar @inject IDialogService Dialog @@ -13,9 +13,9 @@ } else { - + @($"{e.Name}") @@ -36,7 +36,7 @@ - @foreach(var computer in SelectedComputers) + @foreach(AdComputer computer in SelectedComputers) { @@ -57,59 +57,52 @@ - @if(!computer.Loading) - { - @if(!computer.FailedToRetrieveLAPSDetails) + + @if (!computer.FailedToRetrieveLapsDetails) { - - x.Version == Enums.LAPSVersion.v1 && x.IsCurrent))> - - - x.Version == Enums.LAPSVersion.v2 && x.IsCurrent))> - - - x.Version == Enums.LAPSVersion.v2 && !x.IsCurrent))> - - - - Account - Password - Date set - - - - @foreach (var entry in computer.LAPSInformations!.Where(x => x.IsCurrent == false && x.Version == Enums.LAPSVersion.v2)) - { - - - @entry.Account - - - @entry.Password - - - @entry.PasswordSetDate - - - } - - - - + + x is { Version: Enums.LAPSVersion.v1, IsCurrent: true }))> + + + x is { Version: Enums.LAPSVersion.v2, IsCurrent: true }))> + + + x is { Version: Enums.LAPSVersion.v2, IsCurrent: false }))> + + + + Account + Password + Date set + + + + @foreach (LapsInformation entry in computer.LapsInformations!.Where(x => x is { IsCurrent: false, Version: Enums.LAPSVersion.v2 })) + { + + + @entry.Account + + + @entry.Password + + + @entry.PasswordSetDate + + + } + + + + } else { - - No permission to retrieve LAPS Password or no LAPS Password set! - + + No permission to retrieve LAPS Password or no LAPS Password set! + } - } - else - { -
- -
- } +
diff --git a/src/Pages/LAPS.razor.cs b/src/Pages/LAPS.razor.cs index 2336abe..7f639dc 100644 --- a/src/Pages/LAPS.razor.cs +++ b/src/Pages/LAPS.razor.cs @@ -6,17 +6,18 @@ namespace LAPS_WebUI.Pages { - public partial class LAPS + public partial class LAPS : IDisposable { - private readonly Dictionary MudTabsDict = []; - private MudAutocomplete? AutoCompleteSearchBox; + private readonly Dictionary _mudTabsDict = []; + private MudAutocomplete? _autoCompleteSearchBox; + private bool _disposedValue; private bool Authenticated { get; set; } = true; private LdapForNet.LdapCredential? LdapCredential { get; set; } - private List SelectedComputers { get; set; } = []; + private List SelectedComputers { get; set; } = []; private string? DomainName { get; set; } protected override async Task OnAfterRenderAsync(bool firstRender) { - Authenticated = await sessionManager.IsUserLoggedInAsync(); + Authenticated = await SessionManager.IsUserLoggedInAsync(); if (!Authenticated) { @@ -25,52 +26,48 @@ protected override async Task OnAfterRenderAsync(bool firstRender) if (firstRender && Authenticated) { - LdapCredential = await sessionManager.GetLdapCredentialsAsync(); - DomainName = await sessionManager.GetDomainAsync(); + LdapCredential = await SessionManager.GetLdapCredentialsAsync(); + DomainName = await SessionManager.GetDomainAsync(); } await InvokeAsync(StateHasChanged); } - private async Task OnSelectedItemChangedAsync(ADComputer value) + private async Task OnSelectedItemChangedAsync(AdComputer value) { - if (value != null && !string.IsNullOrEmpty(value.Name) && !SelectedComputers.Exists(x => x.Name == value.Name)) + if (value != null && _autoCompleteSearchBox != null && !string.IsNullOrEmpty(value.Name) && !SelectedComputers.Exists(x => x.Name == value.Name)) { - AutoCompleteSearchBox?.Clear(); - MudTabsDict.Add(value.Name, null); + await _autoCompleteSearchBox.ClearAsync(); + _mudTabsDict.Add(value.Name, null); await FetchComputerDetailsAsync(value.DistinguishedName, value.Name); } } - private async Task ClearLapsPassword(ADComputer computer) + private async Task ClearLapsPassword(AdComputer computer) { try { - MudTabsDict.TryGetValue(computer.Name, out MudTabs? _tab); + _mudTabsDict.TryGetValue(computer.Name, out MudTabs? tab); - if (_tab != null && computer.LAPSInformations != null) + if (tab != null && computer.LapsInformations != null) { - LAPSVersion version = LAPSVersion.v1; - - if (_tab.ActivePanel.ID.ToString() == "v1") + LAPSVersion version = tab.ActivePanel.ID.ToString() switch { - version = LAPSVersion.v1; - } + "v1" => LAPSVersion.v1, + "v2" => LAPSVersion.v2, + _ => LAPSVersion.v1 + }; - if (_tab.ActivePanel.ID.ToString() == "v2") - { - version = LAPSVersion.v2; - } - var parameters = new DialogParameters { ["ContentText"] = $"Clear LAPS {version} Password on Computer '{computer.Name}' ?{Environment.NewLine}You have to invoke gpupdate /force on computer '{computer.Name}' in order so set a new LAPS password", ["CancelButtonText"] = "Cancel", ["ConfirmButtonText"] = "Clear", ["ConfirmButtonColor"] = Color.Error }; - IDialogReference dialog = Dialog.Show("Clear LAPS Password", parameters,new DialogOptions() { NoHeader = true }); - DialogResult result = await dialog.Result; + DialogParameters parameters = new DialogParameters { ["ContentText"] = $"Clear LAPS {version} Password on Computer '{computer.Name}' ?{Environment.NewLine}You have to invoke gpupdate /force on computer '{computer.Name}' in order so set a new LAPS password", ["CancelButtonText"] = "Cancel", ["ConfirmButtonText"] = "Clear", ["ConfirmButtonColor"] = Color.Error }; + IDialogReference dialog = await Dialog.ShowAsync("Clear LAPS Password", parameters,new DialogOptions() { NoHeader = true }); + DialogResult? result = await dialog.Result; - if(!result.Canceled) + if(result is { Canceled: false }) { - computer.LAPSInformations.Clear(); + computer.LapsInformations.Clear(); await InvokeAsync(StateHasChanged); - await LDAPService.ClearLapsPassword(DomainName ?? await sessionManager.GetDomainAsync(), LdapCredential ?? await sessionManager.GetLdapCredentialsAsync(), computer.DistinguishedName, version); + await LdapService.ClearLapsPassword(DomainName ?? await SessionManager.GetDomainAsync(), LdapCredential ?? await SessionManager.GetLdapCredentialsAsync(), computer.DistinguishedName, version); Snackbar.Add($"LAPS {version} Password for computer '{computer.Name}' successfully cleared! - Please invoke gpupdate on {computer.Name} to set a new LAPS Password", Severity.Success); } } @@ -86,29 +83,29 @@ private async Task ClearLapsPassword(ADComputer computer) } } - private async Task RefreshComputerDetailsAsync(ADComputer computer, bool supressNotify = false) + private async Task RefreshComputerDetailsAsync(AdComputer computer, bool supressNotify = false) { - ADComputer? placeHolder = null; + AdComputer? placeHolder = null; List backup = []; try { placeHolder = SelectedComputers.Single(x => x.Name == computer.Name); - if (placeHolder.LAPSInformations != null) + if (placeHolder.LapsInformations != null) { - backup.AddRange(placeHolder.LAPSInformations); + backup.AddRange(placeHolder.LapsInformations); } - placeHolder.LAPSInformations = null; + placeHolder.LapsInformations = null; await InvokeAsync(StateHasChanged); - var tmp = await LDAPService.GetADComputerAsync(DomainName ?? await sessionManager.GetDomainAsync(), LdapCredential ?? await sessionManager.GetLdapCredentialsAsync(), computer.DistinguishedName); + AdComputer? tmp = await LdapService.GetAdComputerAsync(DomainName ?? await SessionManager.GetDomainAsync(), LdapCredential ?? await SessionManager.GetLdapCredentialsAsync(), computer.DistinguishedName); if (tmp != null) { - placeHolder.LAPSInformations = tmp.LAPSInformations; + placeHolder.LapsInformations = tmp.LapsInformations; if (!supressNotify) { @@ -123,7 +120,7 @@ private async Task RefreshComputerDetailsAsync(ADComputer computer, bool supress if (placeHolder != null) { - placeHolder.LAPSInformations = backup; + placeHolder.LapsInformations = backup; } if (!supressNotify) @@ -140,29 +137,27 @@ private async Task RefreshComputerDetailsAsync(ADComputer computer, bool supress private async Task FetchComputerDetailsAsync(string distinguishedName, string computerName) { - ADComputer? placeHolder = null; - try { - placeHolder = new ADComputer(distinguishedName, computerName); + AdComputer placeHolder = new AdComputer(distinguishedName, computerName); SelectedComputers.Add(placeHolder); await InvokeAsync(StateHasChanged); - var AdComputerObject = await LDAPService.GetADComputerAsync(DomainName ?? await sessionManager.GetDomainAsync(), LdapCredential ?? await sessionManager.GetLdapCredentialsAsync(), distinguishedName); - var selectedComputer = SelectedComputers.SingleOrDefault(x => x.Name == computerName); + AdComputer? adComputerObject = await LdapService.GetAdComputerAsync(DomainName ?? await SessionManager.GetDomainAsync(), LdapCredential ?? await SessionManager.GetLdapCredentialsAsync(), distinguishedName); + AdComputer? selectedComputer = SelectedComputers.SingleOrDefault(x => x.Name == computerName); - if (AdComputerObject != null && selectedComputer != null) + if (adComputerObject != null && selectedComputer != null) { - selectedComputer.LAPSInformations = AdComputerObject.LAPSInformations; - selectedComputer.FailedToRetrieveLAPSDetails = AdComputerObject.FailedToRetrieveLAPSDetails; + selectedComputer.LapsInformations = adComputerObject.LapsInformations; + selectedComputer.FailedToRetrieveLapsDetails = adComputerObject.FailedToRetrieveLapsDetails; await InvokeAsync(StateHasChanged); - MudTabsDict.TryGetValue(computerName, out MudTabs? _tab); + _mudTabsDict.TryGetValue(computerName, out MudTabs? tab); - if (!selectedComputer.FailedToRetrieveLAPSDetails && _tab != null) + if (!selectedComputer.FailedToRetrieveLapsDetails && tab != null) { await InvokeAsync(StateHasChanged); - _tab.ActivatePanel(_tab.Panels.First(x => !x.Disabled)); + tab.ActivatePanel(tab.Panels.First(x => !x.Disabled)); } } @@ -177,28 +172,41 @@ private async Task FetchComputerDetailsAsync(string distinguishedName, string co private void RemoveComputerCard(string computerName) { - MudTabsDict.Remove(computerName); + _mudTabsDict.Remove(computerName); SelectedComputers.RemoveAll(x => x.Name == computerName); } - private async Task> SearchAsync(string value) + private async Task> SearchAsync(string value,CancellationToken token) { - List searchResult = []; - + List searchResult = []; if (string.IsNullOrEmpty(value)) { return []; } + List tmp = await LdapService.SearchAdComputersAsync(DomainName ?? await SessionManager.GetDomainAsync(), LdapCredential ?? await SessionManager.GetLdapCredentialsAsync(), value); + searchResult.AddRange(tmp); + return searchResult; - var tmp = await LDAPService.SearchADComputersAsync(DomainName ?? await sessionManager.GetDomainAsync(), LdapCredential ?? await sessionManager.GetLdapCredentialsAsync(), value); + } - if (tmp != null) + protected virtual void Dispose(bool disposing) + { + // check if already disposed + if (_disposedValue) return; + if (disposing) { - searchResult.AddRange(tmp); + // free managed objects here + SelectedComputers.Clear(); } + + // set the bool value to true + _disposedValue = true; + } - return searchResult; - + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); } } } diff --git a/src/Pages/Login.razor b/src/Pages/Login.razor index de2ed6b..e8a5e68 100644 --- a/src/Pages/Login.razor +++ b/src/Pages/Login.razor @@ -1,6 +1,6 @@ @page "/login" @inject NavigationManager NavigationManager -@inject ISessionManagerService sessionManager +@inject ISessionManagerService SessionManager @@ -12,7 +12,7 @@ - @foreach(var domain in _domains) + @foreach(string domain in _domains) { } diff --git a/src/Pages/Login.razor.cs b/src/Pages/Login.razor.cs index c96b371..ee49ab9 100644 --- a/src/Pages/Login.razor.cs +++ b/src/Pages/Login.razor.cs @@ -10,9 +10,9 @@ public partial class Login private string _errorMessage = string.Empty; private List _domains = []; - protected async override Task OnInitializedAsync() + protected override async Task OnInitializedAsync() { - _domains = await sessionManager.GetDomainsAsync(); + _domains = await SessionManager.GetDomainsAsync(); if (_domains.Count > 0 ) { @@ -26,7 +26,7 @@ private async Task OnValidSubmitAsync(EditContext context) _processing = true; try { - if (await sessionManager.LoginAsync(_loginRequest.DomainName ?? string.Empty, _loginRequest.Username ?? string.Empty, _loginRequest.Password ?? string.Empty)) + if (await SessionManager.LoginAsync(_loginRequest.DomainName ?? string.Empty, _loginRequest.Username ?? string.Empty, _loginRequest.Password ?? string.Empty)) { NavigationManager.NavigateTo("/laps"); } diff --git a/src/Pages/Logout.razor b/src/Pages/Logout.razor index dbeca02..357eab6 100644 --- a/src/Pages/Logout.razor +++ b/src/Pages/Logout.razor @@ -1,5 +1,5 @@ @page "/logout" -@inject ISessionManagerService sessionManager +@inject ISessionManagerService SessionManager @inject NavigationManager NavigationManager diff --git a/src/Pages/Logout.razor.cs b/src/Pages/Logout.razor.cs index eb6386a..c3c8faa 100644 --- a/src/Pages/Logout.razor.cs +++ b/src/Pages/Logout.razor.cs @@ -4,9 +4,9 @@ public partial class Logout { protected override async Task OnAfterRenderAsync(bool firstRender) { - if (await sessionManager.IsUserLoggedInAsync()) + if (await SessionManager.IsUserLoggedInAsync()) { - await sessionManager.LogoutAsync(); + await SessionManager.LogoutAsync(); } await Task.Delay(500); diff --git a/src/Services/CryptService.cs b/src/Services/CryptService.cs index 07b7a07..7e939f4 100644 --- a/src/Services/CryptService.cs +++ b/src/Services/CryptService.cs @@ -6,21 +6,21 @@ namespace LAPS_WebUI.Services public class CryptService : ICryptService { private readonly IDataProtectionProvider _dataProtectionProvider; - private readonly string keyString; + private readonly string _keyString; public CryptService(IDataProtectionProvider dataProtectionProvider) { _dataProtectionProvider = dataProtectionProvider; - keyString = Guid.NewGuid().ToString().Replace("-", ""); + _keyString = Guid.NewGuid().ToString().Replace("-", ""); } public string DecryptString(string cipherText) { - var protector = _dataProtectionProvider.CreateProtector(keyString); + IDataProtector protector = _dataProtectionProvider.CreateProtector(_keyString); return protector.Unprotect(cipherText); } public string EncryptString(string text) { - var protector = _dataProtectionProvider.CreateProtector(keyString); + IDataProtector protector = _dataProtectionProvider.CreateProtector(_keyString); return protector.Protect(text); } } diff --git a/src/Services/LDAPService.cs b/src/Services/LDAPService.cs index 4f21330..4ff6fe9 100644 --- a/src/Services/LDAPService.cs +++ b/src/Services/LDAPService.cs @@ -14,12 +14,12 @@ namespace LAPS_WebUI.Services { public class LdapService : ILdapService { - private readonly IOptions> _Domains; + private readonly IOptions> _domains; public LdapService(IOptions> domains) { - _Domains = domains; + _domains = domains; - if (_Domains.Value is null || _Domains.Value.Count == 0) + if (_domains.Value.Count == 0) { Log.Error("No Domains configured! Please check your configuration!"); } @@ -27,19 +27,18 @@ public LdapService(IOptions> domains) public async Task> GetDomainsAsync() { - return await Task.FromResult(_Domains.Value); + return await Task.FromResult(_domains.Value); } public async Task CreateBindAsync(string domainName, string username, string password) { - LdapConnection ldapConnection; - ldapConnection = new LdapConnection(); + LdapConnection ldapConnection = new(); try { - Domain domain = _Domains.Value.Single(x => x.Name == domainName); + Domain domain = _domains.Value.Single(x => x.Name == domainName); - ldapConnection.Connect(domain.Ldap.Server, domain.Ldap.Port, domain.Ldap.UseSSL ? LdapSchema.LDAPS : LdapSchema.LDAP); + ldapConnection.Connect(domain.Ldap.Server, domain.Ldap.Port, domain.Ldap.UseSsl ? LdapSchema.LDAPS : LdapSchema.LDAP); if (domain.Ldap.TrustAllCertificates) { @@ -62,28 +61,14 @@ public async Task> GetDomainsAsync() public async Task TestCredentialsAsync(string domainName, string username, string password) { - using var connection = await CreateBindAsync(domainName, username, password); - if (connection != null) - { - return true; - } - else - { - return false; - } + using LdapConnection? connection = await CreateBindAsync(domainName, username, password); + return connection != null; } public async Task TestCredentialsAsync(string domainName, LdapCredential ldapCredential) { - using var connection = await CreateBindAsync(domainName, ldapCredential.UserName, ldapCredential.Password); - if (connection != null) - { - return true; - } - else - { - return false; - } + using LdapConnection? connection = await CreateBindAsync(domainName, ldapCredential.UserName, ldapCredential.Password); + return connection != null; } public async Task ClearLapsPassword(string domainName, LdapCredential ldapCredential, string distinguishedName, LAPSVersion version) @@ -95,19 +80,14 @@ public async Task ClearLapsPassword(string domainName, LdapCredential ldap } using LdapConnection? ldapConnection = await CreateBindAsync(domainName, ldapCredential.UserName, ldapCredential.Password) ?? throw new Exception("LDAP bind failed!"); - string attribute = string.Empty; - - if (version == LAPSVersion.v1) - { - attribute = "ms-Mcs-AdmPwdExpirationTime"; - } - - if (version == LAPSVersion.v2) + string attribute = version switch { - attribute = "msLAPS-PasswordExpirationTime"; - } + LAPSVersion.v1 => "ms-Mcs-AdmPwdExpirationTime", + LAPSVersion.v2 => "msLAPS-PasswordExpirationTime", + _ => string.Empty + }; - var resetRequest = new DirectoryModificationAttribute + DirectoryModificationAttribute resetRequest = new DirectoryModificationAttribute { LdapModOperation = LdapModOperation.LDAP_MOD_REPLACE, Name = attribute @@ -115,148 +95,146 @@ public async Task ClearLapsPassword(string domainName, LdapCredential ldap resetRequest.Add(DateTime.Now.ToFileTimeUtc().ToString()); - var response = (ModifyResponse)await ldapConnection.SendRequestAsync(new ModifyRequest(distinguishedName, resetRequest)); + ModifyResponse? response = (ModifyResponse)await ldapConnection.SendRequestAsync(new ModifyRequest(distinguishedName, resetRequest)); return response.ResultCode == ResultCode.Success; } - public async Task GetADComputerAsync(string domainName, LdapCredential ldapCredential, string distinguishedName) + public async Task GetAdComputerAsync(string domainName, LdapCredential ldapCredential, string distinguishedName) { - ADComputer? ADComputer = null; - Domain? domain = _Domains.Value.SingleOrDefault(x => x.Name == domainName) ?? throw new Exception($"No configured domain found with name {domainName}"); + AdComputer? adComputer = null; + Domain? domain = _domains.Value.SingleOrDefault(x => x.Name == domainName) ?? throw new Exception($"No configured domain found with name {domainName}"); if (ldapCredential is null) { throw new Exception("Failed to get LDAP Credentials"); } - using (LdapConnection? ldapConnection = await CreateBindAsync(domainName, ldapCredential.UserName, ldapCredential.Password)) + using LdapConnection? ldapConnection = await CreateBindAsync(domainName, ldapCredential.UserName, ldapCredential.Password); + if (ldapConnection is null) { - if (ldapConnection is null) - { - throw new Exception("LDAP bind failed!"); - } + throw new Exception("LDAP bind failed!"); + } - string? defaultNamingContext = domain.Ldap.SearchBase; + string? defaultNamingContext = domain.Ldap.SearchBase; - var ldapSearchResult = (await ldapConnection.SearchAsync(defaultNamingContext, $"(&(objectCategory=computer)(distinguishedName={distinguishedName}))",null, LdapSearchScope.LDAP_SCOPE_SUB)).SingleOrDefault(); + LdapEntry? ldapSearchResult = (await ldapConnection.SearchAsync(defaultNamingContext, $"(&(objectCategory=computer)(distinguishedName={distinguishedName}))",null, LdapSearchScope.LDAP_SCOPE_SUB)).SingleOrDefault(); - if (ldapSearchResult != null) + if (ldapSearchResult != null) + { + adComputer = new AdComputer(ldapSearchResult.Dn, ldapSearchResult.DirectoryAttributes["cn"].GetValues().First()) { - ADComputer = new ADComputer(ldapSearchResult.Dn, ldapSearchResult.DirectoryAttributes["cn"].GetValues().First()) + LapsInformations = [] + }; + + #region "Try LAPS v1" + + if (ldapSearchResult.DirectoryAttributes.Any(x => x.Name == "ms-Mcs-AdmPwd") && (domain.Laps.ForceVersion == LAPSVersion.All || domain.Laps.ForceVersion == LAPSVersion.v1)) + { + LapsInformation lapsInformationEntry = new() { - LAPSInformations = [] + ComputerName = adComputer.Name, + Version = LAPSVersion.v1, + Account = null, + Password = ldapSearchResult.DirectoryAttributes["ms-Mcs-AdmPwd"].GetValues().First().ToString(), + PasswordExpireDate = DateTime.FromFileTimeUtc(Convert.ToInt64(ldapSearchResult.DirectoryAttributes["ms-Mcs-AdmPwdExpirationTime"].GetValues().First().ToString())).ToLocalTime(), + IsCurrent = true, + PasswordSetDate = null }; - #region "Try LAPS v1" + adComputer.LapsInformations.Add(lapsInformationEntry); + } - if (ldapSearchResult.DirectoryAttributes.Any(x => x.Name == "ms-Mcs-AdmPwd") && (domain.Laps.ForceVersion == LAPSVersion.All || domain.Laps.ForceVersion == LAPSVersion.v1)) - { - LapsInformation lapsInformationEntry = new() - { - ComputerName = ADComputer.Name, - Version = LAPSVersion.v1, - Account = null, - Password = ldapSearchResult.DirectoryAttributes["ms-Mcs-AdmPwd"].GetValues().First().ToString(), - PasswordExpireDate = DateTime.FromFileTimeUtc(Convert.ToInt64(ldapSearchResult.DirectoryAttributes["ms-Mcs-AdmPwdExpirationTime"].GetValues().First().ToString())).ToLocalTime(), - IsCurrent = true, - PasswordSetDate = null - }; - - ADComputer.LAPSInformations.Add(lapsInformationEntry); - } + #endregion - #endregion + #region "Try LAPS v2" - #region "Try LAPS v2" + string fieldName = (domain.Laps.EncryptionDisabled ? "msLAPS-Password" : "msLAPS-EncryptedPassword"); - string fieldName = (domain.Laps.EncryptionDisabled ? "msLAPS-Password" : "msLAPS-EncryptedPassword"); + if (ldapSearchResult.DirectoryAttributes.Any(x => x.Name == fieldName) && (domain.Laps.ForceVersion == LAPSVersion.All || domain.Laps.ForceVersion == LAPSVersion.v2)) + { + MsLapsPayload? msLapsPayload = null; + string ldapValue; - if (ldapSearchResult.DirectoryAttributes.Any(x => x.Name == fieldName) && (domain.Laps.ForceVersion == LAPSVersion.All || domain.Laps.ForceVersion == LAPSVersion.v2)) + if (domain.Laps.EncryptionDisabled) + { + ldapValue = ldapSearchResult.DirectoryAttributes["msLAPS-Password"].GetValues().First().ToString(); + } + else { - MsLapsPayload? msLAPS_Payload = null; - string ldapValue = string.Empty; + byte[] encryptedPass = ldapSearchResult.DirectoryAttributes["msLAPS-EncryptedPassword"].GetValues().First().Skip(16).ToArray(); + ldapValue = await DecryptLapsPayload(encryptedPass, ldapCredential); + } - if (domain.Laps.EncryptionDisabled) - { - ldapValue = ldapSearchResult.DirectoryAttributes["msLAPS-Password"].GetValues().First().ToString(); - } - else - { - byte[] encryptedPass = ldapSearchResult.DirectoryAttributes["msLAPS-EncryptedPassword"].GetValues().First().Skip(16).ToArray(); - ldapValue = await DecryptLAPSPayload(encryptedPass, ldapCredential); - } + msLapsPayload = JsonSerializer.Deserialize(ldapValue) ?? throw new Exception("Failed to parse LAPS Password"); - msLAPS_Payload = JsonSerializer.Deserialize(ldapValue) ?? throw new Exception("Failed to parse LAPS Password"); + LapsInformation lapsInformationEntry = new() + { + ComputerName = adComputer.Name, + Version = LAPSVersion.v2, + Account = msLapsPayload.ManagedAccountName, + Password = msLapsPayload.Password, + WasEncrypted = !domain.Laps.EncryptionDisabled, + PasswordExpireDate = DateTime.FromFileTimeUtc(Convert.ToInt64(ldapSearchResult.DirectoryAttributes["msLAPS-PasswordExpirationTime"].GetValues().First().ToString())).ToLocalTime(), + IsCurrent = true, + PasswordSetDate = DateTime.FromFileTimeUtc(Int64.Parse(msLapsPayload.PasswordUpdateTime!, System.Globalization.NumberStyles.HexNumber)).ToLocalTime() - LapsInformation lapsInformationEntry = new() - { - ComputerName = ADComputer.Name, - Version = LAPSVersion.v2, - Account = msLAPS_Payload.ManagedAccountName, - Password = msLAPS_Payload.Password, - WasEncrypted = !domain.Laps.EncryptionDisabled, - PasswordExpireDate = DateTime.FromFileTimeUtc(Convert.ToInt64(ldapSearchResult.DirectoryAttributes["msLAPS-PasswordExpirationTime"].GetValues().First().ToString())).ToLocalTime(), - IsCurrent = true, - PasswordSetDate = DateTime.FromFileTimeUtc(Int64.Parse(msLAPS_Payload.PasswordUpdateTime!, System.Globalization.NumberStyles.HexNumber)).ToLocalTime() + }; - }; + adComputer.LapsInformations.Add(lapsInformationEntry); - ADComputer.LAPSInformations.Add(lapsInformationEntry); + if (ldapSearchResult.DirectoryAttributes.Any(x => x.Name == "msLAPS-EncryptedPasswordHistory")) + { - if (ldapSearchResult.DirectoryAttributes.Any(x => x.Name == "msLAPS-EncryptedPasswordHistory")) + foreach (byte[]? historyEntry in ldapSearchResult.DirectoryAttributes["msLAPS-EncryptedPasswordHistory"].GetValues()) { + byte[] historicEncryptedPass = historyEntry.Skip(16).ToArray(); + string historicLdapValue = await DecryptLapsPayload(historicEncryptedPass, ldapCredential); + MsLapsPayload? historicMsLapsPayload = JsonSerializer.Deserialize(historicLdapValue); - foreach (var historyEntry in ldapSearchResult.DirectoryAttributes["msLAPS-EncryptedPasswordHistory"].GetValues()) + if (historicMsLapsPayload != null) { - byte[] historicEncryptedPass = historyEntry.Skip(16).ToArray(); - string historicLdapValue = await DecryptLAPSPayload(historicEncryptedPass, ldapCredential); - var historic_msLAPS_Payload = JsonSerializer.Deserialize(historicLdapValue); - - if (historic_msLAPS_Payload != null) - { - LapsInformation historicLapsInformationEntry = new() - { - ComputerName = ADComputer.Name, - Version = LAPSVersion.v2, - Account = historic_msLAPS_Payload.ManagedAccountName, - Password = historic_msLAPS_Payload.Password, - PasswordExpireDate = null, - PasswordSetDate = DateTime.FromFileTimeUtc(Int64.Parse(historic_msLAPS_Payload.PasswordUpdateTime!, System.Globalization.NumberStyles.HexNumber)).ToLocalTime() - }; - - ADComputer.LAPSInformations.Add(historicLapsInformationEntry); - } - else + LapsInformation historicLapsInformationEntry = new() { - Log.Warning("Failed to decrypt LAPS History entry"); - } + ComputerName = adComputer.Name, + Version = LAPSVersion.v2, + Account = historicMsLapsPayload.ManagedAccountName, + Password = historicMsLapsPayload.Password, + PasswordExpireDate = null, + PasswordSetDate = DateTime.FromFileTimeUtc(Int64.Parse(historicMsLapsPayload.PasswordUpdateTime!, System.Globalization.NumberStyles.HexNumber)).ToLocalTime() + }; + + adComputer.LapsInformations.Add(historicLapsInformationEntry); + } + else + { + Log.Warning("Failed to decrypt LAPS History entry"); } } } + } - #endregion + #endregion - if (ADComputer.LAPSInformations is null || ADComputer.LAPSInformations.Count == 0) - { - ADComputer.FailedToRetrieveLAPSDetails = true; - } - else - { - ADComputer.LAPSInformations = [.. ADComputer.LAPSInformations.OrderBy(x => x.PasswordExpireDate)]; - } - + if (adComputer.LapsInformations is null || adComputer.LapsInformations.Count == 0) + { + adComputer.FailedToRetrieveLapsDetails = true; } else { - throw new Exception($"AD Computer with DN '{distinguishedName}' could not be found"); + adComputer.LapsInformations = [.. adComputer.LapsInformations.OrderBy(x => x.PasswordExpireDate)]; } + + } + else + { + throw new Exception($"AD Computer with DN '{distinguishedName}' could not be found"); } - return ADComputer; + return adComputer; } - private static async Task DecryptLAPSPayload(byte[] value, LdapCredential ldapCredential) + private static async Task DecryptLapsPayload(byte[] value, LdapCredential ldapCredential) { StringBuilder pythonScriptResult = new(); @@ -267,7 +245,7 @@ private static async Task DecryptLAPSPayload(byte[] value, LdapCredentia try { - var pythonCmd = Cli.Wrap(pythonBin) + Command pythonCmd = Cli.Wrap(pythonBin) .WithArguments($"\"{pythonDecryptScriptPath}\" --user \"{ldapCredential.UserName}\" --password \"{ldapCredential.Password}\" --data \"{Convert.ToBase64String(value)}\"") .WithStandardOutputPipe(PipeTarget.ToStringBuilder(pythonScriptResult)); @@ -291,41 +269,37 @@ private static async Task DecryptLAPSPayload(byte[] value, LdapCredentia } - public async Task> SearchADComputersAsync(string domainName, LdapCredential ldapCredential, string query) + public async Task> SearchAdComputersAsync(string domainName, LdapCredential ldapCredential, string query) { - List result = []; - Domain? domain = _Domains.Value.SingleOrDefault(x => x.Name == domainName) ?? throw new Exception($"No configured domain found with name {domainName}"); + List result = []; + Domain? domain = _domains.Value.SingleOrDefault(x => x.Name == domainName) ?? throw new Exception($"No configured domain found with name {domainName}"); if (ldapCredential is null) { throw new Exception("Failed to get LDAP Credentials"); } - using (LdapConnection? ldapConnection = await CreateBindAsync(domainName, ldapCredential.UserName, ldapCredential.Password)) - { - string filter = $"(&(objectCategory=computer)(name={query}{(query.EndsWith('*') ? string.Empty : '*')}))"; - var PropertiesToLoad = new string[] { "cn", "distinguishedName" }; - string? defaultNamingContext = domain.Ldap.SearchBase; + using LdapConnection? ldapConnection = await CreateBindAsync(domainName, ldapCredential.UserName, ldapCredential.Password); + string filter = $"(&(objectCategory=computer)(name={query}{(query.EndsWith('*') ? string.Empty : '*')}))"; + string[] propertiesToLoad = new string[] { "cn", "distinguishedName" }; + string? defaultNamingContext = domain.Ldap.SearchBase; - try + try + { + if (ldapConnection is null) { - if (ldapConnection is null) - { - throw new Exception("LDAP Bind failed!"); - } + throw new Exception("LDAP Bind failed!"); + } - var ldapSearchResults = await ldapConnection.SearchAsync(defaultNamingContext, filter, PropertiesToLoad, LdapSearchScope.LDAP_SCOPE_SUB); + IList? ldapSearchResults = await ldapConnection.SearchAsync(defaultNamingContext, filter, propertiesToLoad, LdapSearchScope.LDAP_SCOPE_SUB); - result.AddRange(ldapSearchResults.Select(o => - { - return new ADComputer(o.Dn, o.DirectoryAttributes["cn"].GetValues().First()); - }).ToList()); - } - catch (Exception ex) - { - Log.Error("{ErrorMessage}", ex.Message); - } + result.AddRange(ldapSearchResults.Select(o => new AdComputer(o.Dn, o.DirectoryAttributes["cn"].GetValues().First())).ToList()); } + catch (Exception ex) + { + Log.Error("{ErrorMessage}", ex.Message); + } + return result; } } diff --git a/src/Services/SessionManagerService.cs b/src/Services/SessionManagerService.cs index 017ae12..1e4d73d 100644 --- a/src/Services/SessionManagerService.cs +++ b/src/Services/SessionManagerService.cs @@ -4,48 +4,40 @@ namespace LAPS_WebUI.Services { - public class SessionManagerService : ISessionManagerService + public class SessionManagerService( + ISessionStorageService sessionStorageService, + ILdapService ldapService, + ICryptService cryptService) + : ISessionManagerService { - - private readonly ISessionStorageService _sessionStorageService; - private readonly ILdapService _ldapService; - private readonly ICryptService _cryptService; - - public SessionManagerService(ISessionStorageService sessionStorageService, ILdapService ldapService, ICryptService cryptService) - { - _sessionStorageService = sessionStorageService; - _ldapService = ldapService; - _cryptService = cryptService; - } - public async Task> GetDomainsAsync() { - return (await _ldapService.GetDomainsAsync()).Select(x => x.Name).ToList(); + return (await ldapService.GetDomainsAsync()).Select(x => x.Name).ToList(); } public async Task GetDomainAsync() { - return await _sessionStorageService.GetItemAsync("domainName"); + return await sessionStorageService.GetItemAsync("domainName"); } public async Task GetLdapCredentialsAsync() { - var encryptedCreds = await _sessionStorageService.GetItemAsync("ldapCredentials"); + LdapCredential? encryptedCreds = await sessionStorageService.GetItemAsync("ldapCredentials"); - encryptedCreds.UserName = _cryptService.DecryptString(encryptedCreds.UserName); - encryptedCreds.Password = _cryptService.DecryptString(encryptedCreds.Password); + encryptedCreds.UserName = cryptService.DecryptString(encryptedCreds.UserName); + encryptedCreds.Password = cryptService.DecryptString(encryptedCreds.Password); return encryptedCreds; } public async Task IsUserLoggedInAsync() { - return await _sessionStorageService.GetItemAsync("loggedIn"); + return await sessionStorageService.GetItemAsync("loggedIn"); } public async Task LoginAsync(string domainName, string username, string password) { - var bindResult = await _ldapService.TestCredentialsAsync(domainName,username, password); + bool bindResult = await ldapService.TestCredentialsAsync(domainName,username, password); if (!bindResult) { @@ -53,16 +45,16 @@ public async Task LoginAsync(string domainName, string username, string pa } else { - await _sessionStorageService.SetItemAsync("loggedIn", bindResult); - await _sessionStorageService.SetItemAsync("domainName", domainName); - await _sessionStorageService.SetItemAsync("ldapCredentials", new LdapCredential() { UserName = _cryptService.EncryptString(username), Password = _cryptService.EncryptString(password) }); + await sessionStorageService.SetItemAsync("loggedIn", bindResult); + await sessionStorageService.SetItemAsync("domainName", domainName); + await sessionStorageService.SetItemAsync("ldapCredentials", new LdapCredential() { UserName = cryptService.EncryptString(username), Password = cryptService.EncryptString(password) }); return true; } } public async Task LogoutAsync() { - await _sessionStorageService.ClearAsync(); + await sessionStorageService.ClearAsync(); return true; } } diff --git a/src/Shared/MainLayout.razor b/src/Shared/MainLayout.razor index 00b24c4..6169ddd 100644 --- a/src/Shared/MainLayout.razor +++ b/src/Shared/MainLayout.razor @@ -1,9 +1,9 @@ @inherits LayoutComponentBase -@using MudBlazor.Utilities; @inject NavigationManager NavigationManager @inject ISessionManagerService sessionManager - + + diff --git a/src/Shared/MainLayout.razor.cs b/src/Shared/MainLayout.razor.cs index 73d0431..ea4631c 100644 --- a/src/Shared/MainLayout.razor.cs +++ b/src/Shared/MainLayout.razor.cs @@ -9,9 +9,9 @@ public partial class MainLayout private bool _isDarkMode; private MudThemeProvider _mudThemeProvider = new(); private bool IsUserLoggedIn { get; set; } = false; - private readonly MudTheme MyCustomTheme = new() + private readonly MudTheme _myCustomTheme = new() { - Palette = new PaletteLight() + PaletteLight = new PaletteLight() { Primary = new MudColor("#455FAC"), Secondary = new MudColor("#CE3C3C"), @@ -22,7 +22,7 @@ public partial class MainLayout } }; - void ToggleDarkMode() + private void ToggleDarkMode() { _isDarkMode = !_isDarkMode; }