<# $Id: windows-domain-controller-w-adfs.ps1 625 2016-02-21 15:52:54Z james $ This powershell script will turn the local Windows server into a Domain Contoller, install and set up AD FS server, create some local sample users and groups, and install a relying party into the AD FS server. Run as: administrator To run this as a script, you may need to adjust your ExecutionPolicy: set-executionpolicy -scope LocalMachine unrestricted -force Unblock-File windows-domain-controller-w-adfs.ps1 Parameters: * password - the safe mode password, and domain administrator initial passwd * domain - the domain name we'll use * spmetadataurl - a URL to a service provider metadata.xml * spname - A free form string describing the Service Provider Notes: * Ensure the password you select is sufficiently complex to meet complexity requirements. Copyright (c) James Bromberger 2014 - 2016. james@rcpt.to. #> param( [Parameter(Mandatory=$True)] [string]$password, [Parameter(Mandatory=$True)] [string]$domain, [Parameter(Mandatory=$True)] [string]$spmetadataurl, [Parameter(Mandatory=$True)] [string]$spname ) $safe_mode_password_text = $password $domain_name_text = $domain.ToLower() $saml_sp_metadata_url = $spmetadataurl function createMyUser($name, $firstName, $surname, $password) { $User = Get-ADUser -Filter {sAMAccountName -eq $name} if ($User -eq $Null) { $userpassword_secstr = ConvertTo-SecureString "$password" -AsPlainText -Force New-ADUser -Name $name -AccountPassword $userpassword_secsrt -Description "Test User" -EmailAddress $name@$domain_name_text -GivenName "$firstName" -Surname "$surname" -Enabled:$true } } function createMyGroup($name) { $Group = Get-ADGroup -Filter {name -eq $name } if ($Group -eq $Null) { New-ADGroup -name $name -groupscope Global } } function addUserToGroup($user, $group) { foreach ($name in Get-ADGroupMember -Identity $group | select name) { if ($name.name -eq $user) { return } } Add-ADGroupMember -Identity $group -Members $user } $safemodepassword_secstr = ConvertTo-SecureString -AsPlainText "$safe_mode_password_text" -Force $domaincredential = New-Object System.Management.Automation.PSCredential ("$domain_name_text\administrator", $safemodepassword_secstr) $ntp_peers = w32tm /query /peers | Measure-Object -Line if ($ntp_peers.lines -lt 10) { Write-Host "Setting up NTP peers..." Restart-Service w32time w32tm.exe /config /manualpeerlist:"0.us.pool.ntp.org 1.us.pool.ntp.org 2.us.pool.ntp.org 3.us.pool.ntp.org" /syncfromflags:manual /reliable:YES /update w32tm.exe /config /update Restart-Service w32time Write-Host "Done." } else { Write-Host "[OK] NTP peers already configured" } Write-Host "Setting password for $env:computername/Administrator..." $admin = [adsi]("WinNT://$env:computername/Administrator, user") $admin.SetPassword($safe_mode_password_text) $adds_status = Get-WindowsFeature AD-Domain-Services if (!$adds_status.Installed) { Write-Host "Installing AD Directory Services..." Add-WindowsFeature AD-Domain-Services -IncludeManagementTools Import-Module ADDSDeployment $install_adfs = Install-ADDSForest -DomainName $domain_name_text -CreateDnsDelegation:$false -DatabasePath C:\Windows\NTDS -DomainMode Win2012R2 -ForestMode Win2012R2 -InstallDns:$true -LogPath C:\Windows\NTDS -SysvolPath C:\Windows\SYSVOL -safemodeadministratorpassword $safemodepassword_secstr -NoRebootOnCompletion:$true -Force:$true Set-Service adfssrv -startuptype "automatic" Set-Service kdc -startuptype "automatic" if ($install_adfs.Status) { Write-Host "Done. Restarting computer..." Restart-Computer -Force } Write-Error "Cannot install AD DS Forrest" Exit } else { Write-Host "[OK] AD Directory Services: Already Installed" } $adfs_status = Get-WindowsFeature ADFS-Federation if (!$adfs_status.Installed) { Write-Host "Adding ADFS Services..." Add-WindowsFeature ADFS-Federation -IncludeManagementTools Add-KdsRootKey -EffectiveTime (Get-Date).AddHours(-10) } else { Write-Host "[OK] ADFS already installed" } $global:cert=Get-ChildItem -path cert:\LocalMachine\My -DnsName "auth.$domain_name_text" if (!$cert) { $sigAlgorithm = "SHA256" Write-Host "Creating self-signed certificate for SSL web site auth..." $name = new-object -com "X509Enrollment.CX500DistinguishedName.1" $name.Encode("CN=auth.$domain_name_text", 0) $key = new-object -com "X509Enrollment.CX509PrivateKey.1" $key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider" $key.KeySpec = 1 $key.Length = 2048 $key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)" $key.MachineContext = 1 $key.ExportPolicy = 1 $key.Create() $ekuoids = new-object -com "X509Enrollment.CObjectIds.1" $serverauthoid = new-object -com "X509Enrollment.CObjectId.1" $serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1") $ekuoids.add($serverauthoid) $ekuext = new-object -com "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1" $ekuext.InitializeEncode($ekuoids) $sigOID = New-Object -ComObject X509Enrollment.CObjectId $sigOID.InitializeFromValue(([Security.Cryptography.Oid]$SigAlgorithm).Value) Set-Variable -Name cert -Value (new-object -com "X509Enrollment.CX509CertificateRequestCertificate.1") -Scope Global $cert.InitializeFromPrivateKey(2, $key, "") $cert.Subject = $name $cert.Issuer = $cert.Subject $cert.NotBefore = get-date $cert.NotAfter = $cert.NotBefore.AddDays(1825) $cert.X509Extensions.Add($ekuext) $cert.SignatureInformation.HashAlgorithm = $SigOID $cert.Encode() $enrollment = new-object -com "X509Enrollment.CX509Enrollment.1" $enrollment.InitializeFromRequest($cert) $certdata = $enrollment.CreateRequest(0) $enrollment.InstallResponse(2, $certdata, 0, "") start-sleep 4 Set-Variable -Name cert -Value (Get-ChildItem -path cert:\LocalMachine\My -DnsName "auth.$domain_name_text") -Scope Global Write-Host "Installing ADFS Farm" Write-Host " - Thumbprint is $($cert.Thumbprint)" Install-AdfsFarm -CertificateThumbprint $cert.Thumbprint -FederationServiceName "auth.$domain_name_text" -ServiceAccountCredential $domaincredential } else { Write-Host "[OK] Self signed certificate already exists" Write-Host "[OK] ADFS Farm already installed" } $adfs_rely_party = Get-ADfsRelyingPartyTrust -Name $spname if ($adfs_rely_party.Count -eq 0) { Write-Host "Installing SP Metadata as " -nonewline Write-Host $spname Invoke-WebRequest $saml_sp_metadata_url -OutFile $env:temp\sp-metadata.xml Add-AdfsRelyingPartyTrust -Name $spname -EncryptionCertificateRevocationCheck None -MetadataFile $env:temp\sp-metadata.xml -SigningCertificateRevocationCheck None -SamlResponseSignature MessageAndAssertion Set-ADFSRelyingPartyTrust -TargetName $spname -SamlResponseSignature MessageAndAssertion } else { Write-Host "[OK] Already have a relying party" } $dns_entry = Get-DNSServerResourceRecord -Zone $domain_name_text -Name auth -RRType A if ($dns_entry.Count -eq 0) { Write-Host "Adding local DNS entry for auth" $eth0 = Get-NetIPAddress -AddressFamily IPv4 -InterfaceAlias Ethernet Add-DnsServerResourceRecordA -ZoneName "$domain_name_text" -Name auth -IPv4Address $eth0.IPAddress Write-Host "Adding Groups" createMyGroup("AWS-Admins") createMyGroup("AWS-Billing") createMyGroup("AWS-DBAs") Write-Host "Adding Users" createMyUser("alice", "Alice", "Admin", "al1c3") createMyUser("bob", "Bob", "Billing", "m0n3y") createMyUser("dave", "Dave", "DBA", "squ33l") Write-Host "Adding Users to Groups" addUserToGroup "alice" "AWS-Admins" addUserToGroup "bob" "AWS-Billing" addUserToGroup "dave" "AWS-DBAs" } else { Write-Host "[OK] Local DNS already has AUTH entry" } $adfs_sp = Get-ADFSRelyingPartyTrust -Name $spname if ($adfs_sp.IssuanceAuthorizationRules.Length -eq 0) { Write-Host "Setting claim rule sets" $rSet = New-ADFSClaimRuleSet -ClaimRule '=> issue(Type = "http://schemas.microsoft.com/authorization/claims/permit", Value = "true");' Set-ADFSRelyingPartyTrust -TargetName $spname -IssuanceAuthorizationRules $rSet.ClaimRulesString } else { Write-Host "[OK] Claim cules for auth already set" } if ($adfs_sp.IssuanceTransformRules.Length -eq 0) { Write-Host "Setting ADFS Claims and attributes" $rules = @' @RuleTemplate = "MapClaims" @RuleName = "Persistent User Id" c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"] => issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", Issuer = c.Issuer, OriginalIssuer = c.OriginalIssuer, Value = c.Value, ValueType = c.ValueType, Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"] = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"); @RuleName = "Get AD Groups" c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"] => add(store = "Active Directory", types = ("http://temp/variable"), query = ";tokenGroups;{0}", param = c.Value); @RuleName = "Roles" c:[Type == "http://temp/variable", Value =~ "(?i)^AWS-"] => issue(Type = "Role", Value = c.Value); @RuleTemplate = "LdapClaims" @RuleName = "User Attributes" c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"] => issue(store = "Active Directory", types = ("Display-Name", "Telephone-Number", "Given-Name", "Last-Name", "Title", "E-Mail"), query = ";displayName,telephoneNumber,givenName,sn,title,mail;{0}", param = c.Value); '@ Set-ADFSRelyingPartyTrust -TargetName $spname -IssuanceTransformRules $rules } else { Write-Host "[OK] Relying party claims and attributes already set" } Write-Host "Now visit https://auth.$($domain_name_text)/FederationMetadata/2007-06/FederationMetadata.xml to see your metadata.xml document; upload this to AWS as an Identity Provider." Write-Host "To login visit https://auth.$($domain_name_text)/adfs/ls/idpinitiatedsignon.aspx"