-
Notifications
You must be signed in to change notification settings - Fork 0
AD Provider: Enforce strict attribute validation with explicit contract #179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
blindzero
merged 8 commits into
main
from
copilot/define-supported-attributes-ad-provider
Feb 11, 2026
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
884fb96
Initial plan
Copilot b05aefb
Add attribute contract definitions and strict validation for AD Provider
Copilot 895274b
Fix EventSink property check and update contract test to use 'Descrip…
Copilot b1ab304
Add attribute validation integration tests and update documentation
Copilot 73dcac9
Remove private function tests - validation tested via integration tests
Copilot c1499b7
Address code review feedback - remove Ignored field and add Manager t…
Copilot 07092e2
Update AD joiner example to demonstrate OtherAttributes feature
Copilot 9466b43
Address code review feedback: dynamic error messages, Manager resolut…
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
86 changes: 86 additions & 0 deletions
86
src/IdLE.Provider.AD/Private/Get-IdleADAttributeContract.ps1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| function Get-IdleADAttributeContract { | ||
| <# | ||
| .SYNOPSIS | ||
| Returns the supported attribute contract for AD Provider operations. | ||
|
|
||
| .DESCRIPTION | ||
| Defines which attributes are supported for CreateIdentity and EnsureAttribute operations. | ||
| This contract serves as the single source of truth for attribute validation. | ||
|
|
||
| .PARAMETER Operation | ||
| The operation to get the contract for: 'CreateIdentity' or 'EnsureAttribute'. | ||
|
|
||
| .OUTPUTS | ||
| System.Collections.Hashtable | ||
| Returns a hashtable where keys are supported attribute names and values contain metadata. | ||
|
|
||
| .EXAMPLE | ||
| $contract = Get-IdleADAttributeContract -Operation 'CreateIdentity' | ||
| $supportedKeys = $contract.Keys | ||
| #> | ||
| [CmdletBinding()] | ||
| [OutputType([hashtable])] | ||
| param( | ||
| [Parameter(Mandatory)] | ||
| [ValidateSet('CreateIdentity', 'EnsureAttribute')] | ||
| [string] $Operation | ||
| ) | ||
|
|
||
| if ($Operation -eq 'CreateIdentity') { | ||
| return @{ | ||
| # Identity Attributes | ||
| SamAccountName = @{ Target = 'Parameter'; Type = 'String'; Required = $false } | ||
| UserPrincipalName = @{ Target = 'Parameter'; Type = 'String'; Required = $false } | ||
| Path = @{ Target = 'Parameter'; Type = 'String'; Required = $false } | ||
|
|
||
| # Name Attributes | ||
| Name = @{ Target = 'Parameter'; Type = 'String'; Required = $false } | ||
| GivenName = @{ Target = 'Parameter'; Type = 'String'; Required = $false } | ||
| Surname = @{ Target = 'Parameter'; Type = 'String'; Required = $false } | ||
| DisplayName = @{ Target = 'Parameter'; Type = 'String'; Required = $false } | ||
|
|
||
| # Organizational Attributes | ||
| Description = @{ Target = 'Parameter'; Type = 'String'; Required = $false } | ||
| Department = @{ Target = 'Parameter'; Type = 'String'; Required = $false } | ||
| Title = @{ Target = 'Parameter'; Type = 'String'; Required = $false } | ||
|
|
||
| # Contact Attributes | ||
| EmailAddress = @{ Target = 'Parameter'; Type = 'String'; Required = $false } | ||
|
|
||
| # Relationship Attributes | ||
| Manager = @{ Target = 'Parameter'; Type = 'String'; Required = $false } | ||
|
|
||
| # Password Attributes | ||
| AccountPassword = @{ Target = 'Parameter'; Type = 'SecureString|String'; Required = $false } | ||
| AccountPasswordAsPlainText = @{ Target = 'Parameter'; Type = 'String'; Required = $false } | ||
|
|
||
| # State Attributes | ||
| Enabled = @{ Target = 'Parameter'; Type = 'Boolean'; Required = $false } | ||
|
|
||
| # Extension Container | ||
| OtherAttributes = @{ Target = 'Container'; Type = 'Hashtable'; Required = $false } | ||
| } | ||
| } | ||
| elseif ($Operation -eq 'EnsureAttribute') { | ||
| return @{ | ||
| # Name Attributes | ||
| GivenName = @{ Target = 'Parameter'; Type = 'String' } | ||
| Surname = @{ Target = 'Parameter'; Type = 'String' } | ||
| DisplayName = @{ Target = 'Parameter'; Type = 'String' } | ||
|
|
||
| # Organizational Attributes | ||
| Description = @{ Target = 'Parameter'; Type = 'String' } | ||
| Department = @{ Target = 'Parameter'; Type = 'String' } | ||
| Title = @{ Target = 'Parameter'; Type = 'String' } | ||
|
|
||
| # Contact Attributes | ||
| EmailAddress = @{ Target = 'Parameter'; Type = 'String' } | ||
|
|
||
| # Identity Attributes | ||
| UserPrincipalName = @{ Target = 'Parameter'; Type = 'String' } | ||
|
|
||
| # Relationship Attributes | ||
| Manager = @{ Target = 'Parameter'; Type = 'String' } | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
122 changes: 122 additions & 0 deletions
122
src/IdLE.Provider.AD/Private/Test-IdleADAttributeContract.ps1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| function Test-IdleADAttributeContract { | ||
| <# | ||
| .SYNOPSIS | ||
| Validates attributes against the AD Provider attribute contract. | ||
|
|
||
| .DESCRIPTION | ||
| Performs strict validation of provided attributes against the supported attribute contract. | ||
| Throws an exception if unsupported attributes are detected. | ||
|
|
||
| .PARAMETER Attributes | ||
| Hashtable of attributes to validate. | ||
|
|
||
| .PARAMETER Operation | ||
| The operation context: 'CreateIdentity' or 'EnsureAttribute'. | ||
|
|
||
| .PARAMETER AttributeName | ||
| For EnsureAttribute, the specific attribute name being set. | ||
|
|
||
| .OUTPUTS | ||
| System.Collections.Hashtable | ||
| Returns a hashtable with validation results: | ||
| - Requested: array of requested attribute keys | ||
| - Supported: array of supported attribute keys | ||
| - Unsupported: array of unsupported attribute keys | ||
|
|
||
| .EXAMPLE | ||
| $result = Test-IdleADAttributeContract -Attributes $attrs -Operation 'CreateIdentity' | ||
| # Throws if unsupported attributes found | ||
|
|
||
| .EXAMPLE | ||
| $result = Test-IdleADAttributeContract -Operation 'EnsureAttribute' -AttributeName 'InvalidAttr' | ||
| # Throws if attribute not supported for EnsureAttribute | ||
| #> | ||
| [CmdletBinding()] | ||
| [OutputType([hashtable])] | ||
| param( | ||
| [Parameter()] | ||
| [AllowNull()] | ||
| [hashtable] $Attributes, | ||
|
|
||
| [Parameter(Mandatory)] | ||
| [ValidateSet('CreateIdentity', 'EnsureAttribute')] | ||
| [string] $Operation, | ||
|
|
||
| [Parameter()] | ||
| [string] $AttributeName | ||
| ) | ||
|
|
||
| $contract = Get-IdleADAttributeContract -Operation $Operation | ||
|
|
||
| if ($Operation -eq 'CreateIdentity') { | ||
| if ($null -eq $Attributes) { | ||
| return @{ | ||
| Requested = @() | ||
| Supported = @() | ||
| Unsupported = @() | ||
| } | ||
| } | ||
|
|
||
| $requestedKeys = @($Attributes.Keys) | ||
| $supportedKeys = @($contract.Keys) | ||
| $unsupportedKeys = @($requestedKeys | Where-Object { $_ -notin $supportedKeys }) | ||
|
|
||
| if ($unsupportedKeys.Count -gt 0) { | ||
| $errorMessage = "AD Provider: Unsupported attributes in CreateIdentity operation.`n" | ||
| $errorMessage += "Unsupported attributes: $($unsupportedKeys -join ', ')`n`n" | ||
| $errorMessage += "Supported attributes for CreateIdentity:`n" | ||
|
|
||
| # Generate supported attributes list from contract | ||
| $supportedAttributesList = ($supportedKeys | Sort-Object | ForEach-Object { " - $_" }) -join "`n" | ||
| $errorMessage += "$supportedAttributesList`n`n" | ||
|
|
||
| if ('OtherAttributes' -in $supportedKeys) { | ||
| $errorMessage += "To set custom LDAP attributes, use the 'OtherAttributes' container." | ||
| } | ||
|
|
||
| throw $errorMessage | ||
| } | ||
|
|
||
| # Validate OtherAttributes if present | ||
| if ($Attributes.ContainsKey('OtherAttributes')) { | ||
| $otherAttrs = $Attributes['OtherAttributes'] | ||
| if ($null -ne $otherAttrs -and $otherAttrs -isnot [hashtable]) { | ||
| throw "AD Provider: 'OtherAttributes' must be a hashtable. Received type: $($otherAttrs.GetType().FullName)" | ||
| } | ||
| } | ||
|
|
||
| return @{ | ||
| Requested = $requestedKeys | ||
| Supported = @($requestedKeys | Where-Object { $_ -in $supportedKeys }) | ||
| Unsupported = $unsupportedKeys | ||
| } | ||
| } | ||
| elseif ($Operation -eq 'EnsureAttribute') { | ||
| if ([string]::IsNullOrWhiteSpace($AttributeName)) { | ||
| throw "AD Provider: AttributeName is required for EnsureAttribute validation." | ||
| } | ||
|
|
||
| $supportedKeys = @($contract.Keys) | ||
|
|
||
| if ($AttributeName -notin $supportedKeys) { | ||
| $errorMessage = "AD Provider: Unsupported attribute in EnsureAttribute operation.`n" | ||
| $errorMessage += "Attribute: $AttributeName`n`n" | ||
| $errorMessage += "Supported attributes for EnsureAttribute:`n" | ||
|
|
||
| # Generate supported attributes list from contract | ||
| $supportedAttributesList = ($supportedKeys | Sort-Object | ForEach-Object { " - $_" }) -join "`n" | ||
| $errorMessage += "$supportedAttributesList`n`n" | ||
|
|
||
| $errorMessage += "Note: Custom LDAP attributes and password attributes are not supported in EnsureAttribute.`n" | ||
| $errorMessage += "For custom attributes, use CreateIdentity with OtherAttributes." | ||
|
|
||
| throw $errorMessage | ||
| } | ||
|
|
||
| return @{ | ||
| Requested = @($AttributeName) | ||
| Supported = @($AttributeName) | ||
| Unsupported = @() | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.