diff --git a/BLAZAM/BLAZAM.csproj b/BLAZAM/BLAZAM.csproj index 0488cf00..0cb3097e 100644 --- a/BLAZAM/BLAZAM.csproj +++ b/BLAZAM/BLAZAM.csproj @@ -6,7 +6,7 @@ enable false 0.8.9 - 2024.02.27.2343 + 2024.03.15.1259 false BLAZAM False @@ -28,6 +28,8 @@ + + diff --git a/BLAZAM/Pages/Benchmark.razor b/BLAZAM/Pages/Benchmark.razor index 9528fb3f..65e1b697 100644 --- a/BLAZAM/Pages/Benchmark.razor +++ b/BLAZAM/Pages/Benchmark.razor @@ -1,7 +1,8 @@ @inject IAppDatabaseFactory factory +@inject IActiveDirectoryContextFactory directoryFactory +@inherits AppComponentBase @page "/benchmark" -@inject IActiveDirectoryContext Dir

Benchmark

Number of cycles

@@ -16,17 +17,17 @@

User Bench

email: @userBench?.SamAccountName

@code { -#nullable disable warnings + #nullable disable warnings ActiveDirectoryContext ad; bool Running = false; - int runCount; + int runCount = 1; int cycle; double elapsed; double elapsed2; IADUser userBench; protected override void OnInitialized() { - // ad = new ActiveDirectory(factory, true); + // ad = new ActiveDirectory(factory, true); } async Task Benchmark1() { @@ -39,8 +40,9 @@ for (cycle = 0; cycle < runCount; cycle++) { DateTime start = DateTime.Now; + var dir = Directory as ActiveDirectoryContext; - + var user = dir.Authenticate(new() { Username = "johnsoncontrols", Password = "bburg123" }); runs[cycle] = (DateTime.Now - start).TotalSeconds; InvokeAsync(StateHasChanged); @@ -79,7 +81,9 @@ DateTime start = DateTime.Now; - Dir.Users.FindUsersByString("cja"); + var dir = Directory as ActiveDirectoryContext; + var user = dir.Authenticate_Alt(new() { Username = "johnsoncontrols", Password = "bburg123" }); + runs[cycle] = (DateTime.Now - start).TotalSeconds; InvokeAsync(StateHasChanged); diff --git a/BLAZAM/Pages/Configure/Audit.razor b/BLAZAM/Pages/Configure/Audit.razor index 4a9742bd..0be093b3 100644 --- a/BLAZAM/Pages/Configure/Audit.razor +++ b/BLAZAM/Pages/Configure/Audit.razor @@ -85,27 +85,35 @@ - - - - - - - - - - - - - + @if(ApplicationInfo.InDemoMode && CurrentUser.Username == "Demo") + { + Disabled in demo + } + else + { + + + + + + + + + + + + + + } + diff --git a/BLAZAM/Pages/Groups/ConfirmNewGroup.razor b/BLAZAM/Pages/Groups/ConfirmNewGroup.razor index bf6e5688..c4f30cdd 100644 --- a/BLAZAM/Pages/Groups/ConfirmNewGroup.razor +++ b/BLAZAM/Pages/Groups/ConfirmNewGroup.razor @@ -7,13 +7,13 @@ @Group.ADSPath - Create... + Create... } @code { -#nullable disable warnings + #nullable disable warnings - + private bool disableCreateGroupButton = false; [Parameter] public EventCallback Confirmed { get; set; } @@ -23,12 +23,26 @@ async Task CommitChanges() { - if (await MessageService.Confirm("Are you sure you want to create this OU?", "Create OU")) + if (await MessageService.Confirm("Are you sure you want to create this group?", "Create group")) { - await Group.CommitChangesAsync(); - SnackBarService.Success("Group created"); + disableCreateGroupButton = true; + await InvokeAsync(StateHasChanged); + IJob createGroupJob = new Job(AppLocalization["Create User"]); + createGroupJob.StopOnFailedStep = true; + createGroupJob.ShowJobDetailsDialog(MessageService); + var result = await Group.CommitChangesAsync(createGroupJob); + + disableCreateGroupButton = false; + InvokeAsync(StateHasChanged); + if (result.FailedSteps.Count == 0) + { + + SnackBarService.Success("Group created"); + + } + await AuditLogger.Group.Created(Group); + var commitJob = Group.CommitChanges(); await Confirmed.InvokeAsync(Group); - Nav.NavigateTo("/groups/create",true); } } } \ No newline at end of file diff --git a/BLAZAM/Pages/Home.razor b/BLAZAM/Pages/Home.razor index 51cd109a..8a83afe4 100644 --- a/BLAZAM/Pages/Home.razor +++ b/BLAZAM/Pages/Home.razor @@ -26,6 +26,14 @@ @if (ApplicationInfo.InDebugMode) { + + + + Test Item + Test Item + Test Item + +
Run Test Job } diff --git a/BLAZAM/Pages/Users/ConfirmNewUser.razor b/BLAZAM/Pages/Users/ConfirmNewUser.razor index c68e8f20..9338eeab 100644 --- a/BLAZAM/Pages/Users/ConfirmNewUser.razor +++ b/BLAZAM/Pages/Users/ConfirmNewUser.razor @@ -153,8 +153,15 @@ InDirectoryTemplate(ActiveDirectoryFields.PhysicalDeliveryOffice) +@if (!confirmed) +{ + Create User + +}else{ + Go To User + Create Another -Create User +} Print @code { @@ -173,7 +180,7 @@ InDirectoryTemplate(ActiveDirectoryFields.PhysicalDeliveryOffice) if (DirectoryTemplate == null) return true; return DirectoryTemplate?.FieldValues.Any(f => f.Field.FieldName == field.FieldName) == true; } - + bool confirmed = false; bool disableCreateUserButton=false; /// /// Triggered when the user confirms the creation of this @@ -196,8 +203,14 @@ InDirectoryTemplate(ActiveDirectoryFields.PhysicalDeliveryOffice) InvokeAsync(StateHasChanged); if (result.FailedSteps.Count == 0) { - + var newUser = Directory.Users.FindUsersByContainerName(User.CanonicalName, false, true); + if (newUser != null) + { + User = newUser; + } SnackBarService.Success("User has been created"); + confirmed = true; + Confirmed.InvokeAsync(); //Nav.NavigateTo("/search/" + User.SamAccountName); } diff --git a/BLAZAM/Pages/Users/CreateUser.razor b/BLAZAM/Pages/Users/CreateUser.razor index 8590e012..e2f420bd 100644 --- a/BLAZAM/Pages/Users/CreateUser.razor +++ b/BLAZAM/Pages/Users/CreateUser.razor @@ -30,11 +30,11 @@ { @AppLocalization["There are no templates available"] - - Create One + + Create One - - + + } Custom @@ -51,7 +51,7 @@ - + @@ -110,7 +110,7 @@ @*TODO: The following binding cause the next button to not update when validation is reached, updates are controlled from - this element + this element *@ Back @@ -204,8 +204,12 @@ newUser.StagePasswordChange(customConfirmPassword.ToSecureString()); { if (newUser == null) { - newUser = selectedOU.CreateUser(customUserDisplayName.Trim()); - newUser.DisplayName = customUserDisplayName; + if (customUserDisplayName == null) SnackBarService.Error(AppLocalization["No display name was set"]); + else + { + newUser = selectedOU.CreateUser(customUserDisplayName.Trim()); + newUser.DisplayName = customUserDisplayName; + } } else { @@ -240,22 +244,22 @@ newUser.StagePasswordChange(customConfirmPassword.ToSecureString()); { try { - if (fieldValue.Field != null) + if (fieldValue.Field != null && fieldValue.Value != null) if (fieldValue.Field.FieldName.ToLower() == "homedirectory") newUser.HomeDirectory = SelectedTemplate.ReplaceVariables(fieldValue.Value, newUserName); else newUser.NewEntryProperties[fieldValue.Field.FieldName] = SelectedTemplate.ReplaceVariables(fieldValue.Value, newUserName); - else if (fieldValue.CustomField != null) + else if (fieldValue.CustomField != null && fieldValue.Value != null) newUser.NewEntryProperties[fieldValue.CustomField.FieldName] = SelectedTemplate.ReplaceVariables(fieldValue.Value, newUserName); } catch (Exception ex) { - Loggers.ActiveDirectryLogger.Error("Could not set value for " + fieldValue.Field?.FieldName + ": " + fieldValue.Value.ToString() + " {@Error}", ex); + Loggers.ActiveDirectryLogger.Error("Could not set value for " + fieldValue.Field?.FieldName + ": " + fieldValue.Value?.ToString() + " {@Error}", ex); } } - var conflictingEntry = Directory.Users.FindUserByUsername(newUser.SamAccountName,false); - if (conflictingEntry != null) + var conflictingEntry = Directory.Users.FindUserByUsername(newUser.SamAccountName, false); + if (conflictingEntry != null && conflictingEntry.SamAccountName?.Equals(newUser.SamAccountName, StringComparison.InvariantCultureIgnoreCase) == true) { newUser = null; SnackBarService.Warning("An account with that name already exists! " + conflictingEntry.SamAccountName); @@ -278,7 +282,8 @@ newUser.StagePasswordChange(customConfirmPassword.ToSecureString()); SelectedStep = 6; } - }catch(Exception ex) + } + catch (Exception ex) { Loggers.ActiveDirectryLogger.Error("Error while creating template user {@Error}", ex); diff --git a/BLAZAMActiveDirectory/ActiveDirectoryContext.cs b/BLAZAMActiveDirectory/ActiveDirectoryContext.cs index 1ea308fe..d95a470f 100644 --- a/BLAZAMActiveDirectory/ActiveDirectoryContext.cs +++ b/BLAZAMActiveDirectory/ActiveDirectoryContext.cs @@ -17,6 +17,7 @@ using BLAZAM.Helpers; using System.DirectoryServices.ActiveDirectory; using System.Security.Cryptography; +using System.Diagnostics.Eventing.Reader; namespace BLAZAM.ActiveDirectory { @@ -39,7 +40,38 @@ public IApplicationUserState? CurrentUser public int FailedConnectionAttempts { get; set; } = 0; - private AuthenticationTypes _authType; + private AuthenticationTypes AuthType + { + get + { + AuthenticationTypes _authType = AuthenticationTypes.Secure; + var context = Factory.CreateDbContext(); + ADSettings? ad = context?.ActiveDirectorySettings.FirstOrDefault(); + ConnectionSettings = ad; + + if (ad != null) + { + Loggers.ActiveDirectryLogger.Information("Active Directory settings found in database. {@DirectorySettings}", ad); + //We need to determine what security options to use when authenticating + //based on the settings in the DB + + if (ad.UseTLS) + { + _authType = AuthenticationTypes.Encryption; + //_authType = AuthenticationTypes.Secure | AuthenticationTypes.Signing; + + //_authType = (AuthenticationTypes.SecureSocketsLayer|AuthenticationTypes.Secure); + } + if (ad.ServerPort == 636) + { + _authType = AuthenticationTypes.SecureSocketsLayer | AuthenticationTypes.Secure; + + } + } + return _authType; + + } + } /// @@ -60,16 +92,12 @@ public DirectoryEntry GetDirectoryEntry(string? baseDN = null) { if (baseDN == null || baseDN == "") baseDN = ConnectionSettings?.ApplicationBaseDN; - _authType = AuthenticationTypes.Secure; - if (ConnectionSettings != null && ConnectionSettings.UseTLS) - { - _authType = AuthenticationTypes.SecureSocketsLayer; - } + return new DirectoryEntry( "LDAP://" + ConnectionSettings?.ServerAddress + ":" + ConnectionSettings?.ServerPort + "/" + baseDN, ConnectionSettings?.Username, _encryption.DecryptObject(ConnectionSettings?.Password), - _authType + AuthType ); } /// @@ -100,7 +128,7 @@ public List GetDeletedObjects() { var model = new DirectoryEntryAdapter(); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - model.Parse(directory: this, searchResult: result ); + model.Parse(directory: this, searchResult: result); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed found.Add(model); } @@ -161,7 +189,7 @@ public DirectoryConnectionStatus Status } } public AppEvent? OnStatusChanged { get; set; } - + /// /// Called when a new user login matches an Active Directory user /// @@ -308,19 +336,7 @@ public void Connect() Loggers.ActiveDirectryLogger.Information("Active Directory settings found in database. {@DirectorySettings}", ad); //We need to determine what security options to use when authenticating //based on the settings in the DB - _authType = AuthenticationTypes.Secure; - if (ad.UseTLS) - { - _authType = AuthenticationTypes.Encryption; - //_authType = AuthenticationTypes.Secure | AuthenticationTypes.Signing; - - //_authType = (AuthenticationTypes.SecureSocketsLayer|AuthenticationTypes.Secure); - } - if (ad.ServerPort == 636) - { - _authType = AuthenticationTypes.SecureSocketsLayer | AuthenticationTypes.Secure; - - } + if (ad != null && ad.FQDN != null && ad.Username != null) { @@ -334,10 +350,10 @@ public void Connect() { Loggers.ActiveDirectryLogger.Information("Connecting Active Directory context"); var pass = _encryption.DecryptObject(ad.Password); - AppRootDirectoryEntry = new DirectoryEntry("LDAP://" + ad.ServerAddress + ":" + ad.ServerPort + "/" + ad.ApplicationBaseDN, ad.Username, pass, _authType); + AppRootDirectoryEntry = new DirectoryEntry("LDAP://" + ad.ServerAddress + ":" + ad.ServerPort + "/" + ad.ApplicationBaseDN, ad.Username, pass, AuthType); Loggers.ActiveDirectryLogger.Information("App Active Directory context connected"); - RootDirectoryEntry = new DirectoryEntry("LDAP://" + ad.ServerAddress + ":" + ad.ServerPort + "/" + ad.FQDN.FqdnToDN(), ad.Username, pass, _authType); + RootDirectoryEntry = new DirectoryEntry("LDAP://" + ad.ServerAddress + ":" + ad.ServerPort + "/" + ad.FQDN.FqdnToDN(), ad.Username, pass, AuthType); Loggers.ActiveDirectryLogger.Information("Root Active Directory context connected"); pass = null; @@ -376,12 +392,12 @@ public void Connect() catch (Exception) { //if (RootDirectoryEntry != null) - //_notificationPublisher.PublishNotification(new NotificationMessage() - //{ - // Level = NotificationLevel.Error, - // Message = "The configured BaseDN is not valid. Please correct your settings.", - // Title = "Active Directory Error" - //}); + //_notificationPublisher.PublishNotification(new NotificationMessage() + //{ + // Level = NotificationLevel.Error, + // Message = "The configured BaseDN is not valid. Please correct your settings.", + // Title = "Active Directory Error" + //}); Status = DirectoryConnectionStatus.BadConfiguration; if (FailedConnectionAttempts < 10) FailedConnectionAttempts++; @@ -506,24 +522,19 @@ private void TryGetDomainControllers() DomainControllers.Add(dc); } } - catch (Exception ex) + catch (Exception ex) { Loggers.ActiveDirectryLogger.Warning("Could not get domain controllers directly {@Error}", ex); } - + } public void Dispose() { _timer.Dispose(); } - /// - /// Authenticates a to verify - /// the provided credentials - /// - /// - /// The matched user if the credentials are valid, otherwise null. - public IADUser? Authenticate(LoginRequest loginReq) + + public IADUser? Authenticate_Alt(LoginRequest loginReq) { var startOfLogon = DateTime.Now; if (loginReq.Username != null && loginReq.Username.Contains("\\")) @@ -559,14 +570,14 @@ public void Dispose() NetworkCredential cred = new NetworkCredential() { - + UserName = loginReq.Username, SecurePassword = loginReq.Password?.ToSecureString() }; LdapConnection connection = new LdapConnection( new LdapDirectoryIdentifier(ConnectionSettings.ServerAddress, ConnectionSettings.ServerPort), cred, - AuthType.Negotiate); + System.DirectoryServices.Protocols.AuthType.Negotiate); using (connection) { @@ -596,7 +607,105 @@ public void Dispose() } catch (DirectoryServicesCOMException ex) { - Loggers.ActiveDirectryLogger.Error("Error authenticating user: " + ex.Message+" {@Error}",ex); + Loggers.ActiveDirectryLogger.Error("Error authenticating user: " + ex.Message + " {@Error}", ex); + switch (ex.Message) + { + case "The user name or password is incorrect.": + Loggers.ActiveDirectryLogger.Debug("Authentication failure: " + (DateTime.Now - startOfLogon).TotalMilliseconds + "ms"); + return null; + } + } + catch (Exception ex) + { + Loggers.ActiveDirectryLogger.Debug("Authentication failure: " + (DateTime.Now - startOfLogon).TotalMilliseconds + "ms"); + + Loggers.ActiveDirectryLogger.Error("Error while authenticating credentials. {@Error}", ex); + } + + + + } + } + } + catch (LdapException ex) + { + Loggers.ActiveDirectryLogger.Error("Error authenticating user: " + ex.Message + " {@Error}", ex); + switch (ex.Message) + { + case "The user name or password is incorrect.": + return null; + } + } + } + return null; + } + public IADUser? Authenticate(LoginRequest loginReq) + { + var startOfLogon = DateTime.Now; + if (loginReq.Username != null && loginReq.Username.Contains("\\")) + { + loginReq.Username = loginReq.Username.Substring(loginReq.Username.IndexOf("\\") + 1); + } + if (loginReq.Username != null && loginReq.Valid) + { + try + { + + var findUser = Users.FindUserByUsername(loginReq.Username.ToLower(), false); + if (findUser != null) + { + var user = new ADUser(); + if (ConnectionSettings != null) + { + if (!loginReq.Username.Contains("@")) + { + loginReq.Username += "@" + ConnectionSettings.FQDN; + } + + + + + + + try + { + Loggers.ActiveDirectryLogger.Information("Authenticating Active Directory credentials"); + + + + NetworkCredential cred = new NetworkCredential() + { + + UserName = loginReq.Username, + SecurePassword = loginReq.Password?.ToSecureString() + }; + var _authenticatedContext = new DirectoryEntry("LDAP://" + ConnectionSettings.ServerAddress + ":" + ConnectionSettings.ServerPort + "/" + ConnectionSettings.ApplicationBaseDN, loginReq.Username, loginReq.Password, AuthType); + var test = _authenticatedContext.AuthenticationType; + var test2 = _authenticatedContext.Children.GetEnumerator(); + test2.MoveNext(); + var test3 = test2.Current as DirectoryEntry; + var test4 = test3.Parent; + + _authenticatedContext.Dispose(); + return findUser; + + + + + + + + + //var _authenticatedContext = new DirectoryEntry("LDAP://" + ConnectionSettings.ServerAddress + ":" + ConnectionSettings.ServerPort + "/" + ConnectionSettings.ApplicationBaseDN, loginReq.Username, loginReq.Password, AuthenticationTypes.FastBind); + ////_authenticatedContext.RefreshCache(); + //var _name = _authenticatedContext.Name; + //Loggers.ActiveDirectryLogger.Debug("Authentication successful: " + (DateTime.Now - startOfLogon).TotalMilliseconds + "ms"); + //return findUser; + + } + catch (DirectoryServicesCOMException ex) + { + Loggers.ActiveDirectryLogger.Error("Error authenticating user: " + ex.Message + " {@Error}", ex); switch (ex.Message) { case "The user name or password is incorrect.": @@ -618,7 +727,7 @@ public void Dispose() } catch (LdapException ex) { - Loggers.ActiveDirectryLogger.Error("Error authenticating user: " + ex.Message+" {@Error}",ex); + Loggers.ActiveDirectryLogger.Error("Error authenticating user: " + ex.Message + " {@Error}", ex); switch (ex.Message) { case "The user name or password is incorrect.": @@ -649,7 +758,7 @@ public bool RestoreTombstone(IDirectoryEntryAdapter model, IADOrganizationalUnit UserName = ConnectionSettings.Username, SecurePassword = _encryption.DecryptObject(ConnectionSettings.Password)?.ToSecureString() }, - AuthType.Negotiate); + System.DirectoryServices.Protocols.AuthType.Negotiate); using (connection) { diff --git a/BLAZAMActiveDirectory/Adapters/GroupableDirectoryAdapter.cs b/BLAZAMActiveDirectory/Adapters/GroupableDirectoryAdapter.cs index b57a9bad..cb7d7d60 100644 --- a/BLAZAMActiveDirectory/Adapters/GroupableDirectoryAdapter.cs +++ b/BLAZAMActiveDirectory/Adapters/GroupableDirectoryAdapter.cs @@ -127,7 +127,6 @@ public override List Changes public override IJob CommitChanges(IJob? commitJob=null) { - //dcr ??= new DirectoryChangeResult(); if (ToAssignTo.Count > 0) { PostCommitSteps.Add(new Jobs.JobStep("Assign to groups", (step) => @@ -135,7 +134,6 @@ public override IJob CommitChanges(IJob? commitJob=null) ToAssignTo.ForEach(g => { g.Group.Invoke("Add", new object[] { g.Member.ADSPath }); - //dcr.AssignedGroups.Add(g.Group); }); return true; @@ -148,7 +146,6 @@ public override IJob CommitChanges(IJob? commitJob=null) ToUnassignFrom.ForEach(g => { g.Group.Invoke("Remove", new object[] { g.Member.ADSPath }); - // dcr.UnassignedGroups.Add(g.Group); }); return true; })); diff --git a/BLAZAMActiveDirectory/Searchers/ADGroupSearcher.cs b/BLAZAMActiveDirectory/Searchers/ADGroupSearcher.cs index dad10c24..6c72142a 100644 --- a/BLAZAMActiveDirectory/Searchers/ADGroupSearcher.cs +++ b/BLAZAMActiveDirectory/Searchers/ADGroupSearcher.cs @@ -130,7 +130,6 @@ public List FindGroupsByDN(List? list) List foundGroups = new List(); if (list != null) { - string query = ""; foreach (string groupDN in list) { diff --git a/BLAZAMDatabase/Models/ActiveDirectoryField.cs b/BLAZAMDatabase/Models/ActiveDirectoryField.cs index 3a1bd2c6..4afc5600 100644 --- a/BLAZAMDatabase/Models/ActiveDirectoryField.cs +++ b/BLAZAMDatabase/Models/ActiveDirectoryField.cs @@ -78,7 +78,7 @@ public bool IsActionAppropriateForObject(ActiveDirectoryObjectType objectType) case "description": case "displayName": case "distinguishedName": - case "employeedId": + case "employeeId": case "givenname": case "homeDirectory": case "homeDrive": diff --git a/BLAZAMGui/Layouts/DefualtPageHeader.razor b/BLAZAMGui/Layouts/DefualtPageHeader.razor deleted file mode 100644 index 32cfafe5..00000000 --- a/BLAZAMGui/Layouts/DefualtPageHeader.razor +++ /dev/null @@ -1,14 +0,0 @@ - - - - - -   - - - - - - \ No newline at end of file diff --git a/BLAZAMGui/Navs/ErrorMenu.razor b/BLAZAMGui/Navs/ErrorMenu.razor index 76f3c414..4e8b528d 100644 --- a/BLAZAMGui/Navs/ErrorMenu.razor +++ b/BLAZAMGui/Navs/ErrorMenu.razor @@ -1,19 +1,7 @@ @inject IStringLocalizer AppLocalization; @inject NavigationManager Nav - - - {Nav.NavigateTo("/",true);})> - - - - - - + @code { } diff --git a/BLAZAMGui/UI/Computers/ComputerSessions.razor b/BLAZAMGui/UI/Computers/ComputerSessions.razor index a3e754cd..70a3025f 100644 --- a/BLAZAMGui/UI/Computers/ComputerSessions.razor +++ b/BLAZAMGui/UI/Computers/ComputerSessions.razor @@ -165,5 +165,8 @@ else { base.Dispose(); t?.Dispose(); + Sessions.ForEach(s => { + s.Dispose(); + }); } } \ No newline at end of file diff --git a/BLAZAMGui/UI/Dashboard/Widgets/LockedOutUsers.razor b/BLAZAMGui/UI/Dashboard/Widgets/LockedOutUsers.razor index 832a21ca..4dec02d6 100644 --- a/BLAZAMGui/UI/Dashboard/Widgets/LockedOutUsers.razor +++ b/BLAZAMGui/UI/Dashboard/Widgets/LockedOutUsers.razor @@ -17,9 +17,27 @@ + + + + - @context.Item?.CanonicalName - + @context.Item?.CanonicalName + + + + + + @if (@context.Item.CanUnlock) + { + + @AppLocalization["Unlock User"] + + + } + + + @@ -49,13 +67,41 @@ await base.OnInitializedAsync(); Title = "Locked Out Users"; + await RefreshUsers(); + } + + async Task RefreshUsers() + { + LoadingData = true; + await InvokeAsync(StateHasChanged); LockedUsers = (await Directory.Users.FindLockedOutUsersAsync()).OrderByDescending(u => u.LockoutTime).Where(u => u.CanRead).ToList(); LoadingData = false; await InvokeAsync(StateHasChanged); } + void GoTo(DataGridRowClickEventArgs args) { Nav.NavigateTo(args.Item.SearchUri); } + async void UnlockAccount(IADUser userToUnlock) + { + if (userToUnlock.LockedOut){ + userToUnlock.LockedOut=false; + var changes = userToUnlock.Changes; + + var unlockJob = await userToUnlock.CommitChangesAsync(); + await AuditLogger.User.Changed(userToUnlock, changes); + if(unlockJob.Result== JobResult.Passed) + { + await RefreshUsers(); + + SnackBarService.Success(userToUnlock.CanonicalName + AppLocalization[" unlocked"]); + } + else + { + SnackBarService.Error("Could not unlock: "+unlockJob.Exception?.Message); + } + } + } } diff --git a/BLAZAMGui/UI/Groups/GroupMembersDataGrid.razor b/BLAZAMGui/UI/Groups/GroupMembersDataGrid.razor index c3695873..2db6f8b9 100644 --- a/BLAZAMGui/UI/Groups/GroupMembersDataGrid.razor +++ b/BLAZAMGui/UI/Groups/GroupMembersDataGrid.razor @@ -83,7 +83,9 @@ @if (Group.CanAssign) { - + } {InvokeAsync(OnInitializedAsync);}) Group="Group" /> diff --git a/BLAZAMGui/UI/Inputs/MudContextMenu.razor b/BLAZAMGui/UI/Inputs/MudContextMenu.razor new file mode 100644 index 00000000..f7b947dc --- /dev/null +++ b/BLAZAMGui/UI/Inputs/MudContextMenu.razor @@ -0,0 +1,54 @@ +
+ @if (Text != null) + { + @Text + } + @ChildContent +
+ + @MenuContents + +@code { + private MudMenu? contextMenu; + [Parameter] + public bool IsMenuShown + { + get { return contextMenu?.IsOpen ?? false; } + set + { + if (value) + { + if (!IsMenuShown) + { + contextMenu?.OpenMenu(null); + } + } + else + { + if (IsMenuShown) + { + contextMenu?.CloseMenu(); + } + } + } + } + [Parameter] + public EventCallback IsMenuShownChanged { get => contextMenu.IsOpenChanged; set => contextMenu.IsOpenChanged = value; } + [Parameter] + public RenderFragment ChildContent { get; set; } + [Parameter] + public string? Text { get; set; } = null; + [Parameter] + public RenderFragment MenuContents { get; set; } + + + private async void ShowContextMenu(MouseEventArgs? args = null) + { + // contextMenu?.Activate(activator, args); + contextMenu?.OpenMenu(args); + await InvokeAsync(StateHasChanged); + } +} + diff --git a/BLAZAMGui/UI/Inputs/MudSelectList.razor b/BLAZAMGui/UI/Inputs/MudSelectList.razor index 05548e35..2d32f73a 100644 --- a/BLAZAMGui/UI/Inputs/MudSelectList.razor +++ b/BLAZAMGui/UI/Inputs/MudSelectList.razor @@ -2,6 +2,7 @@ @typeparam T + ListClass=@(ListClass) + Style="@(Style+" min-width:100px;")" + AnchorOrigin="AnchorOrigin" + TransformOrigin="TransformOrigin"> @if (Values != null && Values.Count() > 0) { @foreach (var val in Values) diff --git a/BLAZAMGui/UI/Modals/AppUserProfileModalContent.razor b/BLAZAMGui/UI/Modals/AppUserProfileModalContent.razor index e2bd21fb..0274d131 100644 --- a/BLAZAMGui/UI/Modals/AppUserProfileModalContent.razor +++ b/BLAZAMGui/UI/Modals/AppUserProfileModalContent.razor @@ -24,6 +24,21 @@ Change Profile Icon } + @if (CurrentUser.State.Preferences.ProfilePicture != null) + { + + Remove + + + } + diff --git a/BLAZAMGui/UI/Settings/Templates/EditDirectoryTemplate.razor b/BLAZAMGui/UI/Settings/Templates/EditDirectoryTemplate.razor index 0a39a046..cfcf0d56 100644 --- a/BLAZAMGui/UI/Settings/Templates/EditDirectoryTemplate.razor +++ b/BLAZAMGui/UI/Settings/Templates/EditDirectoryTemplate.razor @@ -11,6 +11,9 @@ @AppLocalization["Current Template:"] @originalTemplate.Name @@ -28,19 +31,13 @@ await ParentTemplateChanged(null); - @* - *@ g.GroupSid == group.SID.ToSidString()).FirstOrDefaultAsync(); - if (existing == null) - existing = new DirectoryTemplateGroup() - { - GroupSid = group.SID.ToSidString() - }; - DirectoryTemplate.AssignedGroupSids.Add(existing); - SelectedGroup = null; + var existing = await Context.DirectoryTemplateGroups.Where(g => g.GroupSid == group.SID.ToSidString()).FirstOrDefaultAsync(); + if (existing == null) + existing = new DirectoryTemplateGroup() + { + GroupSid = group.SID.ToSidString() + }; + DirectoryTemplate.AssignedGroupSids.Add(existing); + SelectedGroup = null; } - + } catch (Exception ex) { @@ -465,7 +462,7 @@ await ParentTemplateChanged(null); } - if (DirectoryTemplate != null &&Context!=null && !Context.EntityIsTracked(DirectoryTemplate)==true) + if (DirectoryTemplate != null && Context != null && !Context.EntityIsTracked(DirectoryTemplate) == true) { var matching = await Context.DirectoryTemplates.Include(dt => dt.ParentTemplate).Where(dt => dt.Id == DirectoryTemplate.Id).FirstOrDefaultAsync(); if (matching != null) _template = matching; @@ -590,7 +587,12 @@ await ParentTemplateChanged(null); { if (Context == null) throw new ApplicationException("Database not available"); - DirectoryTemplate.ParentOU = SelectedOU.DN; + DirectoryTemplate.ParentOU = SelectedOU?.DN; + if (DirectoryTemplate.ParentTemplate != null) + { + DirectoryTemplate.ParentTemplate = await Context.DirectoryTemplates.FirstOrDefaultAsync(x => x.Id == DirectoryTemplate.ParentTemplate.Id); + } + if (DirectoryTemplate.Id == 0) { try @@ -607,7 +609,6 @@ await ParentTemplateChanged(null); field.Field = Context.ActiveDirectoryFields.FirstOrDefault(f => f.Id == field.Field.Id); } DirectoryTemplate.AssignedGroupSids = trackedGroups; - DirectoryTemplate.ParentTemplate = null; await Context.DirectoryTemplates.AddAsync(DirectoryTemplate); var result = await Context.SaveChangesAsync(); diff --git a/BLAZAMGui/UI/Users/NewTemplateUser.razor b/BLAZAMGui/UI/Users/NewTemplateUser.razor index 6401606f..108d0c2e 100644 --- a/BLAZAMGui/UI/Users/NewTemplateUser.razor +++ b/BLAZAMGui/UI/Users/NewTemplateUser.razor @@ -8,10 +8,8 @@ @{ - string adminEnabledHelperText = ""; if (IsAdmin) { - adminEnabledHelperText = "Field unlocked because you are admin."; All fields are editable because you are an admin. diff --git a/BLAZAMGui/UI/Users/UserListItem.razor b/BLAZAMGui/UI/Users/UserListItem.razor deleted file mode 100644 index 234d0b67..00000000 --- a/BLAZAMGui/UI/Users/UserListItem.razor +++ /dev/null @@ -1,20 +0,0 @@ - - - - - @User.SamAccountName - - - @User.DisplayName - - - @User.OU.ToPrettyOu() - - - - -@code { -#nullable disable warnings - [Parameter] - public IADUser User{ get; set; } -} diff --git a/BLAZAMServices/Chat/ChatService.cs b/BLAZAMServices/Chat/ChatService.cs index a2b41e99..25049c0e 100644 --- a/BLAZAMServices/Chat/ChatService.cs +++ b/BLAZAMServices/Chat/ChatService.cs @@ -200,7 +200,7 @@ public void DeleteAllChatRooms() public async Task GetChatRoom(ChatRoom? chatRoom) { - chatRoom = ChatRooms.Where(cr => cr.Equals(chatRoom)).FirstOrDefault(); + chatRoom = await ChatRooms.Where(cr => cr.Equals(chatRoom)).FirstOrDefaultAsync(); //var context = Context; // return null; //chatRoom = await context.ChatRooms.Where(cr => cr.Equals(chatRoom)).FirstOrDefaultAsync(); diff --git a/BLAZAMSession/ApplicationUserState.cs b/BLAZAMSession/ApplicationUserState.cs index 4fc8f244..51bed454 100644 --- a/BLAZAMSession/ApplicationUserState.cs +++ b/BLAZAMSession/ApplicationUserState.cs @@ -199,9 +199,10 @@ public async Task SaveUserSettings() dbUserSettings.Email = this.Preferences?.Email; dbUserSettings.ReadNewsItems = this.Preferences?.ReadNewsItems??new(); SaveDashboardWidgets(dbUserSettings); - OnSettingsChanged?.Invoke(dbUserSettings); await context.SaveChangesAsync(); GetUserSettingFromDB(); + OnSettingsChanged?.Invoke(dbUserSettings); + return true; } diff --git a/BLAZAMUpdate/Services/UpdateService.cs b/BLAZAMUpdate/Services/UpdateService.cs index 54968d4b..2cacfa47 100644 --- a/BLAZAMUpdate/Services/UpdateService.cs +++ b/BLAZAMUpdate/Services/UpdateService.cs @@ -248,6 +248,7 @@ private bool TestCustomCredentials() private bool TestDirectoryCredentials() { + if(_dbFactory == null)return false; using var context = _dbFactory.CreateDbContext(); //Prepare impersonation WindowsImpersonation? impersonation = null;