Skip to content

Commit

Permalink
Merge pull request #679 from Blazam-App/v1-Dev
Browse files Browse the repository at this point in the history
Nightly Update
  • Loading branch information
jacobsen9026 authored Dec 1, 2024
2 parents ba0fc32 + 05be8f7 commit 38938d5
Show file tree
Hide file tree
Showing 31 changed files with 268 additions and 197 deletions.
4 changes: 2 additions & 2 deletions BLAZAM/BLAZAM.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<ServerGarbageCollection>false</ServerGarbageCollection>
<AssemblyVersion>1.2.0</AssemblyVersion>
<Version>2024.11.29.1745</Version>
<AssemblyVersion>1.2.1</AssemblyVersion>
<Version>2024.11.30.2133</Version>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<RootNamespace>BLAZAM</RootNamespace>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
Expand Down
4 changes: 2 additions & 2 deletions BLAZAM/Pages/API/Data/NewUserDetails.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ public class NewUserDetails
/// The fields to set for this user. Template field with values will also
/// be applied.
/// </summary>
public List<NewUserField>? Fields { get; set; }
public List<NewUserField>? Fields { get; set; } = new();
/// <summary>
/// A list of group SID's to assign for this user. Template groups will also
/// be applied.
/// </summary>
public List<string>? Groups { get; set; }
public List<string>? Groups { get; set; } = new();

/// <summary>
/// If the template is set to send a welcome email, and requests a destination, will be sent
Expand Down
19 changes: 12 additions & 7 deletions BLAZAM/Pages/API/v1/ApiController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ namespace BLAZAM.Pages.API.v1
public class ApiController : Controller
{
private DateTime _startTime = DateTime.Now;

/// <summary>
/// A string dictionary that contains the base of the response.
/// </summary>
protected Dictionary<string, object?> ResponseData = new();
/// <summary>
/// A factory for <see cref="IDatabaseContext"/> connections
Expand All @@ -31,6 +35,9 @@ public class ApiController : Controller
/// The API audit logger
/// </summary>
protected readonly AuditLogger AuditLogger;
/// <summary>
///
/// </summary>
protected readonly IApplicationUserStateService UserStateService;

/// <summary>
Expand All @@ -56,11 +63,9 @@ public ApiController(IApplicationUserStateService applicationUserStateService, A
ResponseData.Add("IP Address", httpContextAccessor?.HttpContext?.Connection?.RemoteIpAddress?.ToString());

}
//[HttpGet("badrequest")] // Add a route attribute
//public IActionResult BadRequest()
//{
// return new BadRequestResult();
//}
/// <summary>
/// The current API users Active Directory connection
/// </summary>
protected IActiveDirectoryContext Directory { get; }
/// <summary>
/// A unique ID for the execution of this controller
Expand All @@ -72,8 +77,8 @@ public ApiController(IApplicationUserStateService applicationUserStateService, A
/// Returns a JSON response with the data and footer
/// fields appended
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
/// <param name="data">A JSON serializable object</param>
/// <returns>A new <see cref="JsonResult"/> containing the <see cref="ResponseData"/></returns>
protected IActionResult FormatData(dynamic data)
{
ResponseData.Add("Data", data);
Expand Down
52 changes: 25 additions & 27 deletions BLAZAM/Pages/API/v1/Templates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@

namespace BLAZAM.Pages.API.v1
{
/// <summary>
/// Template API endpoints provide listing of templates
/// and execution to create users.
/// </summary>
public class Templates : ApiController
{
private IAppDatabaseFactory _appDatabaseFactory;
Expand All @@ -39,9 +43,10 @@ public Templates(NotificationGenerationService ouNotificationService, EmailServi


/// <summary>
/// Executes a user creation template. Any required fields will need to be provided in form data.
/// Executes a user creation template. Any required fields will need to be
/// provided in post body data.
/// </summary>
/// /// <remarks>
/// <remarks>
/// Sample request:
///
/// POST /api/v1/templates/execute/2
Expand All @@ -51,7 +56,7 @@ public Templates(NotificationGenerationService ouNotificationService, EmailServi
/// "fields": [
/// {
/// "FieldName": "l",
/// "FieldValue": "Boston"
/// "FieldValue": "Boston"
/// }
/// ]
/// "groups": [
Expand All @@ -73,19 +78,19 @@ public Templates(NotificationGenerationService ouNotificationService, EmailServi

public async Task<IActionResult> Execute(int templateId, [FromBody] NewUserDetails newUserDetails)
{
//newUserDetails.Fields.Add(new() { FieldName = "test", FieldValue = "val" });
//var test = JsonConvert.SerializeObject(newUserDetails);

var context = await DbFactory.CreateDbContextAsync();
var template = await context.DirectoryTemplates.Include(t => t.ParentTemplate).FirstOrDefaultAsync(t => t.Id == templateId);

if (template != null)
{
//Check if the request has the required fields for this template
if (template.HasRequiredFields())
{
var requiredFields = template.EffectiveFieldValues.Where(fv => fv.Required).ToList();
foreach (var field in requiredFields)
{
//If any are missing return an error with explanation
if (!newUserDetails.Fields.Any(f => f.FieldName.Equals(field.FieldName, StringComparison.InvariantCultureIgnoreCase)))
{
return new BadRequestObjectResult(field.FieldName + " is a required field");
Expand All @@ -94,37 +99,30 @@ public async Task<IActionResult> Execute(int templateId, [FromBody] NewUserDetai
}
}

//Prepare new user name
var newUserName = new NewUserName()
{
GivenName = newUserDetails.FirstName,
MiddleName = newUserDetails.MiddleName,
Surname = newUserDetails.LastName
};

//Generate IADUser
var newUser = template.GenerateTemplateUser(newUserName, Directory);

//Override username if provided
if (!newUserDetails.Username.IsNullOrEmpty())
{
newUser.SamAccountName = newUserDetails.Username;
}

//Store password in memory for later
var password = newUser.NewPassword.ToPlainText().ToSecureString();
foreach (var fieldValue in template.EffectiveFieldValues)
{
try
{
if (fieldValue.Field != null && fieldValue.Value != null)
if (fieldValue.Field.FieldName.ToLower() == "homedirectory")
newUser.HomeDirectory = template.ReplaceVariables(fieldValue.Value, newUserName, newUser.SamAccountName);
else
newUser.NewEntryProperties[fieldValue.Field.FieldName] = template.ReplaceVariables(fieldValue.Value, newUserName, newUser.SamAccountName);
else if (fieldValue.CustomField != null && fieldValue.Value != null)
newUser.NewEntryProperties[fieldValue.CustomField.FieldName] = template.ReplaceVariables(fieldValue.Value, newUserName, newUser.SamAccountName);
}
catch (Exception ex)
{
Loggers.ActiveDirectoryLogger.Error("Could not set value for " + fieldValue.Field?.FieldName + ": " + fieldValue.Value?.ToString() + " {@Error}", ex);
}

}
//Set each field in template
template.PopulateFields(newUser, newUserName);

//Set API provided fields
if (newUserDetails.Fields != null)
{
foreach (var field in newUserDetails.Fields)
Expand All @@ -146,6 +144,8 @@ public async Task<IActionResult> Execute(int templateId, [FromBody] NewUserDetai
newUser.SetCustomProperty(field.FieldName,value) ;
}
}

//Set API provided groups
if (newUserDetails.Groups != null)
{
foreach (var groupSid in newUserDetails.Groups)
Expand All @@ -163,12 +163,11 @@ public async Task<IActionResult> Execute(int templateId, [FromBody] NewUserDetai
}
}


//Prepare commit job
IJob createUserJob = new Job(AppLocalization["Create User"]);
createUserJob.StopOnFailedStep = true;
//createUserJob.ShowJobDetailsDialog(MessageService);
//_username = User.SamAccountName;
//_userPassword = User.NewPassword;

//Commmit
var result = await newUser.CommitChangesAsync(createUserJob);
if (result.FailedSteps.Count == 0)
{
Expand Down Expand Up @@ -208,7 +207,6 @@ public async Task<IActionResult> Execute(int templateId, [FromBody] NewUserDetai
{
return new NotFoundObjectResult(templateId);
}
return new BadRequestResult();
}


Expand Down
2 changes: 1 addition & 1 deletion BLAZAM/Pages/Home.razor
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

@if (MOTD.HasValue && MOTD.Value.ToString() != "")
{
<MudAlert Class="mb-6 mud-theme-info" ShowCloseIcon=false Elevation="3">
<MudAlert Class="mb-6 mud-theme-info rounded-t-0" ShowCloseIcon=false Elevation="3">


@MOTD.Value
Expand Down
13 changes: 5 additions & 8 deletions BLAZAM/Pages/Users/CreateUser.razor
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@

@if (TemplateCategories != null && Templates != null && Templates.Count(t => t.DeletedAt == null && t.Visible) > 0)
{
@* <MudSelectList Values="TemplateCategories"
@bind-Value=SelectedCategory /> *@

<MudCarousel Style="height:50vh"
ShowArrows=false
Expand Down Expand Up @@ -180,7 +178,7 @@
<ChildContent>
<MemberOfList Target="_blank"
AssignToClicked="@(async()=>{await _assignToModal?.ShowAsync();})"
Disabled="@(SelectedTemplate.EffectiveAllowCustomGroups!=true && !CurrentUser.State.IsSuperAdmin)"
Disabled="@(SelectedTemplate?.EffectiveAllowCustomGroups!=true && !CurrentUser.State.IsSuperAdmin)"
Model="@newUser" />
<AppModal @ref=_assignToModal>
<AssignToModalContent ModelChanged=@(async()=>{
Expand All @@ -203,7 +201,6 @@
@AppLocalization["OU"]
</TabContent>
<ChildContent>
@* <ADTreeView ShowAllEntries=false SelectedEntryChanged="OUSelected"/> *@
<OUTreeView AdditionalVisibilityFilters=@(AdditionalShow)
StartRootExpanded=true
SelectedEntryChanged="OUSelected" />
Expand Down Expand Up @@ -242,10 +239,10 @@ selectedStep=6;
OnClick="@(()=>{SelectedStep=4;})">Back</MudButton>
<MudButton Color=Color.Success
OnClick="@(()=>{
SelectedStep=7;
if(newUser?.NewPassword==null || !newUser.NewPassword.Equals(customConfirmPassword))
newUser?.StagePasswordChange(customConfirmPassword.ToSecureString());
})"
SelectedStep=7;
if(newUser?.NewPassword==null || !newUser.NewPassword.Equals(customConfirmPassword))
newUser?.StagePasswordChange(customConfirmPassword.ToSecureString());
})"
Disabled=@(customConfirmPassword.IsNullOrEmpty()||customPassword.IsNullOrEmpty()||!customPassword.Equals(customConfirmPassword))>

@AppLocalization["Next"]
Expand Down
2 changes: 1 addition & 1 deletion BLAZAM/Pages/Users/ViewUser.razor
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@

<MudCard Elevation="2"
Style="width:fit-content;height:fit-content"
Class="relative mx-auto my-auto d-block p-1"
Class="relative mx-auto d-block p-1 mb-5"
@onmouseenter=@(()=>{showRemoveThumbnail=true;})
@onmouseleave=@(()=>{showRemoveThumbnail=false;})>

Expand Down
4 changes: 3 additions & 1 deletion BLAZAMActiveDirectory/Adapters/DirectoryEntryAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,9 @@ public virtual void MoveTo(IADOrganizationalUnit parentOUToMoveTo)
HasUnsavedChanges = true;
}

public virtual string? OU { get => DirectoryTools.DnToOu(DN) ?? DirectoryTools.DnToOu(ADSPath); }


public virtual string? OU { get => DN.DnToOu() ?? ADSPath.DnToOu(); }

public IDirectoryEntryAdapter? GetParent()
{
Expand Down
3 changes: 2 additions & 1 deletion BLAZAMActiveDirectory/Adapters/SharedPrinter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using BLAZAM.ActiveDirectory.Interfaces;
using BLAZAM.ActiveDirectory.Helpers;
using BLAZAM.ActiveDirectory.Interfaces;
using BLAZAM.Helpers;
using System;
using System.Collections.Generic;
Expand Down
3 changes: 2 additions & 1 deletion BLAZAMActiveDirectory/Adapters/WmiConnection.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using BLAZAM.ActiveDirectory.Interfaces;
using BLAZAM.ActiveDirectory.Helpers;
using BLAZAM.ActiveDirectory.Interfaces;
using BLAZAM.Helpers;
using BLAZAM.Logger;
using System.Management;
Expand Down
45 changes: 43 additions & 2 deletions BLAZAMActiveDirectory/Helpers/ActiveDirectoryHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using BLAZAM.ActiveDirectory.Adapters;
using BLAZAM.ActiveDirectory.Interfaces;
using BLAZAM.Common.Data;
using BLAZAM.Database.Models.Templates;
using BLAZAM.Logger;
using Microsoft.Extensions.DependencyInjection;
using System;
Expand Down Expand Up @@ -86,8 +87,35 @@ public static string FqdnToDn(string fqdn)
// Return the DN
return dnBuilder.ToString();
}
/// <summary>
/// Populates the fields of the provided <see cref="IADUser"/>
/// with the values set within this <see cref="DirectoryTemplate"/>
/// </summary>
/// <param name="template">This template</param>
/// <param name="user">The user to set the template fields for</param>
/// <param name="newUserName">The new user's name details</param>
public static void PopulateFields(this DirectoryTemplate template,IADUser user,NewUserName newUserName)
{
foreach (var fieldValue in template.EffectiveFieldValues)
{
try
{
if (fieldValue.Field != null && fieldValue.Value != null)
if (fieldValue.Field.FieldName.ToLower() == "homedirectory")
user.HomeDirectory = template.ReplaceVariables(fieldValue.Value, newUserName, user.SamAccountName);
else
user.NewEntryProperties[fieldValue.Field.FieldName] = template.ReplaceVariables(fieldValue.Value, newUserName, user.SamAccountName);
else if (fieldValue.CustomField != null && fieldValue.Value != null)
user.NewEntryProperties[fieldValue.CustomField.FieldName] = template.ReplaceVariables(fieldValue.Value, newUserName, user.SamAccountName);
}
catch (Exception ex)
{
Loggers.ActiveDirectoryLogger.Error("Could not set value for " + fieldValue.Field?.FieldName + ": " + fieldValue.Value?.ToString() + " {@Error}", ex);
}

public static string? DnToOu(string? dN)
}
}
public static string? DnToOu(this string? dN)
{
if (dN == null) return null;
var ouComponents = Regex.Matches(dN, @"OU=([^,]+)")
Expand All @@ -97,7 +125,15 @@ public static string FqdnToDn(string fqdn)
return string.Join(",", ouComponents);
}


public static string? ToPrettyOu(this IADOrganizationalUnit? ou)
{
if (ou == null) return null;
var ouComponents = Regex.Matches(ou.DN, @"OU=([^,]*)")
.Select(m => m.Groups[1].Value)
.ToList();
ouComponents.Reverse();
return "/" + string.Join("/", ouComponents);
}

public static string? ParentOU(string? dN)
{
Expand Down Expand Up @@ -252,5 +288,10 @@ public static List<IDirectoryEntryAdapter> Encapsulate(this DirectoryEntries r,
}
return objects;
}





}
}
27 changes: 27 additions & 0 deletions BLAZAMActiveDirectory/Helpers/WmiHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Text;
using System.Threading.Tasks;

namespace BLAZAM.ActiveDirectory.Helpers
{
public static class WmiHelpers
{
public static T? GetPropertyValue<T>(this ManagementObject? mo, string propertyName)
{
var value = mo.GetPropertyValue(propertyName);
if (value is T) { return (T)value; }
return default;
try
{
return (T)value;
}
catch
{
return default;
}
}
}
}
Loading

0 comments on commit 38938d5

Please sign in to comment.