Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Config/Settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
}
],
"UseADModule": false,
"UseLDAPS": false,
"DemoMode": true,
"LogPath": "Logs/error_log.txt",
"LoggingEnabled": true,
Expand Down
1 change: 1 addition & 0 deletions Config/Settings.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ $script:AppSettings = $null
$settingsTemplate = @{
DemoMode = $false
UseADModule = $true
UseLDAPS = $false
DefaultDomain = $env:USERDNSDOMAIN
AutoReplyTemplate = "I am currently unavailable..."
LoggingEnabled = $true
Expand Down
43 changes: 43 additions & 0 deletions Functions/Core/Dependencies/DotNetVersionCheck.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,46 @@ function Load-LdapLibrary {
throw "Unsupported environment: $Environment"
}
}

function Initialize-LDAPAssemblies {
try {
Write-Host "Checking LDAP assemblies..."

# Check .NET Framework version
$dotNetVersion = [System.Environment]::Version
Write-Host "Detected .NET version: $dotNetVersion"

if ($dotNetVersion.Major -lt 4) {
throw ".NET Framework 4.0 or higher is required for LDAP operations"
}

# Try to load the assembly if not already loaded
$ldapAssembly = [System.AppDomain]::CurrentDomain.GetAssemblies() |
Where-Object { $_.FullName -like "System.DirectoryServices.Protocols*" }

if (-not $ldapAssembly) {
Write-Host "Loading System.DirectoryServices.Protocols assembly..."
try {
Add-Type -AssemblyName System.DirectoryServices.Protocols
Write-Host "Successfully loaded LDAP assemblies"
}
catch {
throw "Failed to load System.DirectoryServices.Protocols assembly: $($_.Exception.Message)"
}
}
else {
Write-Host "LDAP assemblies already loaded"
}

# Verify we can access the types we need
$null = [System.DirectoryServices.Protocols.LdapConnection]
$null = [System.DirectoryServices.Protocols.SearchRequest]

return $true
}
catch {
Write-Host "Failed to initialize LDAP assemblies: $($_.Exception.Message)"
Write-Host "This might affect LDAPS functionality"
return $false
}
}
2 changes: 1 addition & 1 deletion Functions/Core/Environment.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@
}
}

Write-Host "Using LDAP for directory access"
Write-Host "Using LDAP(S) for directory access"
return $true
}
184 changes: 128 additions & 56 deletions Functions/Data/LDAP/LDAPConnection.ps1
Original file line number Diff line number Diff line change
@@ -1,76 +1,148 @@
function Get-LDAPConnection {
param (
[Parameter(Mandatory=$true)]
function Test-LDAPSConnection {
param(
[string]$DomainController,
[Parameter(Mandatory=$true)]
[System.Management.Automation.PSCredential]$Credential
[int]$Port = 636
)

try {
Write-Host "Connecting with DC: $($DomainController)"
$networkCred = $Credential.GetNetworkCredential()
Write-Host "Testing LDAPS prerequisites..."

# Try LDAPS first (SSL)
$ldapPath = "LDAPS://$DomainController"
$authType = [System.DirectoryServices.AuthenticationTypes]::SecureSocketsLayer

# Write-Host "Attempting secure LDAPS connection..."
# try {
# $directoryEntry = New-Object System.DirectoryServices.DirectoryEntry(
# $ldapPath,
# $Credential.UserName,
# $networkCred.Password,
# $authType
# )

# # Test connection
# $null = $directoryEntry.NativeObject
# Write-Host "LDAPS connection successful"
# Test if port 636 is open
$tcpClient = New-Object System.Net.Sockets.TcpClient
$connectionResult = $tcpClient.BeginConnect($DomainController, $Port, $null, $null)
$waited = $connectionResult.AsyncWaitHandle.WaitOne(1000, $false)

if (-not $waited) {
Write-Host "Port $Port is not accessible on $DomainController"
return $false
}

Write-Host "Port $Port is open on $DomainController"

# Test SSL certificate
$cert = $null
try {
$tcpClient = New-Object System.Net.Sockets.TcpClient($DomainController, $Port)
$sslStream = New-Object System.Net.Security.SslStream($tcpClient.GetStream())
$sslStream.AuthenticateAsClient($DomainController)
$cert = $sslStream.RemoteCertificate

# return $directoryEntry
# }
# catch {
# Write-Host "LDAPS connection failed, trying standard LDAP..."
Write-Host "LDAPS connection failed, currently unsupported..."
# If LDAPS fails, try regular LDAP
$ldapPath = "LDAP://$DomainController"
$authType = [System.DirectoryServices.AuthenticationTypes]::Secure -bor
[System.DirectoryServices.AuthenticationTypes]::Sealing -bor
[System.DirectoryServices.AuthenticationTypes]::Signing

$directoryEntry = New-Object System.DirectoryServices.DirectoryEntry(
$ldapPath,
"$($networkCred.Domain)\$($networkCred.Username)",
$networkCred.Password,
$authType
)
# Test connection using NativeObject
$null = $directoryEntry.NativeObject
$script:searchBase = Set-RootSearchBase -DomainController $DomainController
Write-Host "LDAP connection successful"
return $directoryEntry
# }
Write-Host "SSL Certificate Details:"
Write-Host "Subject: $($cert.Subject)"
Write-Host "Issuer: $($cert.Issuer)"
Write-Host "Valid From: $($cert.NotBefore)"
Write-Host "Valid To: $($cert.NotAfter)"
Write-Host "Thumbprint: $($cert.Thumbprint)"
}
catch {
Write-Host "SSL Certificate error: $($_.Exception.Message)"
return $false
}
finally {
if ($sslStream) { $sslStream.Dispose() }
if ($tcpClient) { $tcpClient.Dispose() }
}

return $true
}
catch {
Write-Host "LDAP connection error: $($_.Exception.Message)"
throw
Write-Host "LDAPS test error: $($_.Exception.Message)"
return $false
}
}

function Set-RootSearchBase {
function Get-LDAPConnection {
param (
[Parameter(Mandatory=$true)]
[string]$DomainController
[string]$DomainController,
[Parameter(Mandatory=$true)]
[System.Management.Automation.PSCredential]$Credential,
[Parameter(Mandatory=$false)]
[bool]$UseLDAPS = $false
)

try {
# Retrieve the default search base
$rootDSE = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$DomainController/RootDSE")
Write-Host "Default search base: $searchBase"
return $rootDSE.Properties["defaultNamingContext"][0]
Write-Host "Connecting with DC: $($DomainController)"
$networkCred = $Credential.GetNetworkCredential()

# Convert domain to DC format
$dcPath = "DC=" + ($networkCred.Domain.Split('.') -join ',DC=')

# If LDAPS is requested, try it first
if ($UseLDAPS) {
try {
Write-Host "LDAPS connection requested"

# Test LDAPS prerequisites
if (-not (Test-LDAPSConnection -DomainController $DomainController)) {
Write-Host "LDAPS prerequisites not met, falling back to LDAP"
throw "LDAPS prerequisites not met"
}

$ldapPath = "LDAPS://$DomainController/$dcPath"
Write-Host "Attempting LDAPS connection to: $ldapPath"

$authType = [System.DirectoryServices.AuthenticationTypes]::Secure -bor
[System.DirectoryServices.AuthenticationTypes]::Sealing -bor
[System.DirectoryServices.AuthenticationTypes]::Signing -bor
[System.DirectoryServices.AuthenticationTypes]::SecureSocketsLayer

# Create callback to ignore certificate validation
$callback = [System.Net.Security.RemoteCertificateValidationCallback]{
param($sender, $certificate, $chain, $sslPolicyErrors)
return $true
}
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = $callback

$directoryEntry = New-Object System.DirectoryServices.DirectoryEntry(
$ldapPath,
"$($networkCred.Domain)\$($networkCred.Username)",
$Credential.GetNetworkCredential().Password,
$authType
)

# Test the connection
$null = $directoryEntry.NativeObject
Write-Host "LDAPS connection successful"

return @{
Connection = $directoryEntry
IsLDAPS = $true
Credentials = $Credential
}
}
catch {
Write-Host "LDAPS connection failed: $($_.Exception.Message)"
Write-Host "Falling back to standard LDAP..."
}
}

# Standard LDAP connection (fallback or primary if LDAPS not requested)
Write-Host "Attempting standard LDAP connection..."
$ldapPath = "LDAP://$DomainController"
$authType = [System.DirectoryServices.AuthenticationTypes]::Secure -bor
[System.DirectoryServices.AuthenticationTypes]::Sealing -bor
[System.DirectoryServices.AuthenticationTypes]::Signing

$directoryEntry = New-Object System.DirectoryServices.DirectoryEntry(
$ldapPath,
"$($networkCred.Domain)\$($networkCred.Username)",
$Credential.GetNetworkCredential().Password,
$authType
)

# Test the connection
$null = $directoryEntry.NativeObject
Write-Host "LDAP connection successful"

return @{
Connection = $directoryEntry
IsLDAPS = $false
Credentials = $Credential
}
}
catch {
Write-Host "Retrieving seachbase failed: $($_.Exception.Message)"
Write-Host "All connection attempts failed: $($_.Exception.Message)"
throw
}

}
80 changes: 70 additions & 10 deletions Functions/Data/LDAP/LDAPUsers.ps1
Original file line number Diff line number Diff line change
@@ -1,16 +1,76 @@
function Get-LDAPUsers {
param (
[System.DirectoryServices.DirectoryEntry]$Directory,
[Parameter(Mandatory=$true)]
$Directory,
[string]$SearchFilter = "(objectClass=user)"
)

$searcher = New-Object System.DirectoryServices.DirectorySearcher($Directory)
$searcher.Filter = $SearchFilter
$searcher.PropertiesToLoad.AddRange(@(
"userPrincipalName", "displayName", "mail", "department",
"title", "manager", "telephoneNumber", "mobile",
"whenCreated", "whenChanged", "memberOf", "userAccountControl"
))

return $searcher.FindAll()
try {
if ($Directory.IsLDAPS) {
Write-Host "Using System.DirectoryServices.Protocols for LDAPS..."

# Extract server name from path
$serverName = $Directory.Connection.Path -replace 'LDAPS://', ''
Write-Host "Server name: $serverName"

# Get credentials from directory entry
$username = $Directory.Connection.Username
$password = $Directory.Connection.Password
Write-Host "Using credentials for: $username"

# Create LDAP identifier
$identifier = New-Object System.DirectoryServices.Protocols.LdapDirectoryIdentifier($serverName, 636)

# Create network credential
$networkCred = New-Object System.Net.NetworkCredential($username, $password)

# Create and configure LDAP connection
$ldapConnection = New-Object System.DirectoryServices.Protocols.LdapConnection($identifier)
$ldapConnection.Credential = $networkCred
$ldapConnection.AuthType = [System.DirectoryServices.Protocols.AuthType]::Negotiate
$ldapConnection.SessionOptions.ProtocolVersion = 3
$ldapConnection.SessionOptions.SecureSocketLayer = $true

Write-Host "Created LDAPS connection, attempting search..."

# Create the search request
$searchRequest = New-Object System.DirectoryServices.Protocols.SearchRequest
$searchRequest.DistinguishedName = "" # Root
$searchRequest.Filter = $SearchFilter
$searchRequest.Scope = [System.DirectoryServices.Protocols.SearchScope]::Subtree

# Add attributes to retrieve
@(
"userPrincipalName", "displayName", "mail", "department",
"title", "manager", "telephoneNumber", "mobile",
"whenCreated", "whenChanged", "memberOf", "userAccountControl"
) | ForEach-Object {
$searchRequest.Attributes.Add($_) | Out-Null
}

Write-Host "Executing LDAPS search..."
$timeSpan = New-Object System.TimeSpan(0, 0, 30) # 30 seconds timeout
$response = $ldapConnection.SendRequest($searchRequest, $timeSpan)
Write-Host "Search completed successfully"

return $response.Entries
}
else {
Write-Host "Using DirectorySearcher for standard LDAP..."
$searcher = New-Object System.DirectoryServices.DirectorySearcher($Directory.Connection)
$searcher.Filter = $SearchFilter
$searcher.PropertiesToLoad.AddRange(@(
"userPrincipalName", "displayName", "mail", "department",
"title", "manager", "telephoneNumber", "mobile",
"whenCreated", "whenChanged", "memberOf", "userAccountControl"
))

return $searcher.FindAll()
}
}
catch {
Write-Host "Error in Get-LDAPUsers: $($_.Exception.Message)"
Write-Host "Stack trace: $($_.ScriptStackTrace)"
throw
}
}
17 changes: 11 additions & 6 deletions Functions/UI/O365/Initialize-O365Tab.ps1
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
function Update-O365Dropdowns {
Write-Host "Refreshing O365 dropdowns..."
# Add AD users to forwarding dropdown
Update-ForwardingUserList
# Add AD users to teamsowner dropdown
Update-TeamsOwnerList
# Initialize license target combobox
Update-LicenseTargetList
}

function Initialize-O365Tab {
param (
[System.Windows.Window]$Window,
Expand Down Expand Up @@ -83,12 +93,7 @@ function Initialize-O365Tab {
$script:lstProducts.Items.Clear()
$script:lstProducts.Items.Add("Please connect to O365 first...")
}
# Add AD users to forwarding dropdown
Update-ForwardingUserList
# Add AD users to teamsowner dropdown
Update-TeamsOwnerList
# Initialize license target combobox
Update-LicenseTargetList
Update-O365Dropdowns

# Add click handler for connect button
$script:btnConnectO365.Add_Click({
Expand Down
Loading