X-Guardian / AdfsDsc

DSC resources for deployment and configuration of Active Directory Federation Services
MIT License
9 stars 5 forks source link

Reusing instances of MSFT_AdfsIssuanceTransformRule #56

Closed CNBoland closed 1 year ago

CNBoland commented 2 years ago

Is there a way to create instances of MSFT_AdfsIssuanceTransformRule and reuse them in a configuration? I'm creating an AdfsApplicationGroup that contains several AdfsWebApiApplication. I use a standard set of issuance transform rules with each of them and would like to define that set once (e.g. as a variable) and reuse that set with each application. As it stands, I'm having to redefine the collection in AdfsWebApiApplication.IssuanceTransformRules of each application definition.

X-Guardian commented 2 years ago

Hi @CNBoland, yes there is, using an array of CIMInstance objects. You can see an example of this in the AdfsWebApiApplication unit tests: https://github.com/X-Guardian/AdfsDsc/blob/master/Tests/Unit/MSFT_AdfsWebApiApplication.Tests.ps1

CNBoland commented 2 years ago

Thank you, @X-Guardian. I tried that approach from the test project. This is what my code looks like:

$ClaimSet_Primary_Claims = [CIMInstance[]]@(
    New-CimInstance `
        -ClassName MSFT_AdfsIssuanceTransformRule `
        -Namespace root/microsoft/Windows/DesiredStateConfiguration `
        -ClientOnly `
        -Property @{
            TemplateName = 'CustomClaims'
            Name         = 'Token-Groups - Unqualified Names => Role'
            CustomRule   = 'c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
                              => issue(store = "Active Directory", types = ("http://schemas.microsoft.com/ws/2008/06/identity/claims/role"), query = ";tokenGroups;{0}", param = c.Value);'}
    );

AdfsWebApiApplication APAGoService2
{
    . . .
    [IssuanceTransformRules](url)        = $ClaimSet_Primary_Claims
    . . .
}

and receive the following error when generating the .mof:

Compilation errors occurred while processing configuration 'APAGo_AppGroup'. Please review the errors 
reported in error stream and modify your configuration code appropriately.
At C:\Windows\system32\WindowsPowerShell\v1.0\Modules\PSDesiredStateConfiguration\PSDesiredStateConfigur
ation.psm1:3917 char:5
+     throw $ErrorRecord
+     ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (APAGo_AppGroup:String) [], InvalidOperationException
    + FullyQualifiedErrorId : FailToProcessConfiguration

The localhost.mof.error contains this relevant content:

...
 IssuanceTransformRules = {
    "MSFT_AdfsIssuanceTransformRule"
};
...

However, when I use inline MSFT_AdfsIssuanceTransformRule:

AdfsWebApiApplication APAGoService2
{
    . . .
    <IssuanceTransformRules        = @(
        MSFT_AdfsIssuanceTransformRule
        {
            TemplateName = 'CustomClaims'
            Name         = 'Token-Groups - Unqualified Names => Role'
            CustomRule   = 'c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
                            => issue(store = "Active Directory", types = ("http://schemas.microsoft.com/ws/2008/06/identity/claims/role"), query = ";tokenGroups;{0}", param = c.Value);'
        }
    . . .
}

the localhost.mof file generates successfully and contains this relevant content:

...
instance of MSFT_AdfsIssuanceTransformRule as $MSFT_AdfsIssuanceTransformRule1ref
{
CustomRule = "c:[Type == \"http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname\", Issuer == \"AD AUTHORITY\"]\n                                        => issue(store = \"Active Directory\", types = (\"http://schemas.microsoft.com/ws/2008/06/identity/claims/role\"), query = \";tokenGroups;{0}\", param = c.Value);";
 Name = "Token-Groups - Unqualified Names => Role";
 TemplateName = "CustomClaims";

};
...
 IssuanceTransformRules = {
    $MSFT_AdfsIssuanceTransformRule1ref
};
...

Could it be that an array of CIMInstance is incompatible with AdfsWebApiApplication.IssuanceTransformRules property?

X-Guardian commented 1 year ago

For future reference, this can be achieved using the following pattern:

#Requires -module AdfsDsc

<#
    .DESCRIPTION
        This configuration will add a Web API application role to an application in Active Directory Federation
        Services (AD FS).
#>

$ConfigurationData = @{
    AllNodes       = @(
        @{
            Nodename = "localhost"
        }
    )

    TransformRules = @(
        @{
            TemplateName = 'LdapClaims'
            Name         = 'App1 Ldap Claims'
            LdapClaims   = @(
                @{
                    LdapAttribute     = 'mail'
                    OutgoingClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress'
                }
                @{
                    LdapAttribute     = 'sn'
                    OutgoingClaimType = 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname'
                }
            )
        }
    )
}

Configuration AdfsWebApiApplication_LdapClaims_IssuanceTransformRules_Config
{
    param()

    Import-DscResource -ModuleName AdfsDsc

    Node localhost
    {
        AdfsApplicationGroup AppGroup1 {
            Name        = 'AppGroup1'
            Description = "This is the AppGroup1 Description"
        }

        $issuanceTransformRules = @()
        foreach ($transformRule in $ConfigurationData.TransformRules) {
            $ldapMapping = @()
            foreach ($ldapClaim in $transformRule.LdapClaims) {
                $ldapMapping += MSFT_AdfsLdapMapping {
                    LdapAttribute     = $ldapClaim.LdapAttribute
                    OutgoingClaimType = $ldapClaim.OutgoingClaimType
                }
            }

            $issuanceTransformRules += MSFT_AdfsIssuanceTransformRule {
                TemplateName   = $transformRule.TemplateName
                Name           = $transformRule.Name
                AttributeStore = 'Active Directory'
                LdapMapping    = $ldapMapping
            }
        }

        AdfsWebApiApplication WebApiApp1 {
            Name                          = 'AppGroup1 - App1 Web API'
            ApplicationGroupIdentifier    = 'AppGroup1'
            Identifier                    = 'e7bfb303-c5f6-4028-a360-b6293d41338c'
            Description                   = 'App1 Web Api'
            AccessControlPolicyName       = 'Permit everyone'
            AlwaysRequireAuthentication   = $false
            AllowedClientTypes            = 'Public', 'Confidential'
            IssueOAuthRefreshTokensTo     = 'AllDevices'
            NotBeforeSkew                 = 0
            RefreshTokenProtectionEnabled = $true
            RequestMFAFromClaimsProviders = $false
            TokenLifetime                 = 0
            IssuanceTransformRules        = $issuanceTransformRules
        }

        AdfsWebApiApplication WebApiApp2 {
            Name                          = 'AppGroup1 - App2 Web API'
            ApplicationGroupIdentifier    = 'AppGroup1'
            Identifier                    = '809ec660-e89f-4ea6-8492-5e72df0dee9a'
            Description                   = 'App2 Web Api'
            AccessControlPolicyName       = 'Permit everyone'
            AlwaysRequireAuthentication   = $false
            AllowedClientTypes            = 'Public', 'Confidential'
            IssueOAuthRefreshTokensTo     = 'AllDevices'
            NotBeforeSkew                 = 0
            RefreshTokenProtectionEnabled = $true
            RequestMFAFromClaimsProviders = $false
            TokenLifetime                 = 0
            IssuanceTransformRules        = $issuanceTransformRules
        }
    }
}
CNBoland commented 1 year ago

Excellent! Thank you, @X-Guardian!