This article will guide you through syncing with Azure AD. This configuration is recommended if no on-premise Active Directory exists. If you have on-premise AD servers it is recommended to use the on-premise AD integration.
Contents
Install the Azure modules in PowerShell
- Login to a computer you will run a scheduled PowerShell script from, this is usually a domain controller or file server.
- Open PowerShell ISE and run the following commands
a. install-module msonline and select "Yes to All" at the prompt
b. Install-Module AzureAD and select "Yes to All" at the prompt
Create an Azure Secure application connection
- In PowerShell ISE create a new file
- Copy the below script into the file
- Save the File As "Azure-App-Setup.ps1"
- Run the script and follow the prompts in the script, it will ask you to authenticate to your Azure instance as well as some variable names.
You will be prompted for the following information:- Choose a password for the Azure secure application
- Your AzureAD secure login
- A PFX folder path file name
- A name you would like to use or your Dashlane Connection in Azure
-
Run the following script:
#Connect to AzureAD using the GUI prompt Write-Host "Connecting to AzureAD..." -foregroundcolor yellow Connect-AzureAD Write-Host "Connected to AzureAD" -foregroundcolor green #Enter your environment specific details. Write-Host "Requesting a secure password..." -foregroundcolor yellow $pwd_secure_string = Read-host "Choose a secure password for the Azure App" -AsSecureString # This is the password used to secure your Azure App Connection $ThisServerDNSName = $env:computername+"."+$env:userdnsdomain # The server this sync script will be scheduled to run on. $FilePathPFX = Read-Host "Enter a filename and path for saving the .pfx file EG C:\filepath\cert.pfx" # Enter in a filepath & name where the generated cert will be saved. $DashlaneAppName = Read-host "Enter a name for the Dashlane Azure App, it can be anything" $DashlaneURI = "https://$DashlaneAppName" #Display the variables Write-Host "." Write-Host "." Write-Host "." Write-Host "A self-signed certificate will be created for a secure connection to this server" -foregroundcolor Yellow Write-Host "$ThisServerDNSName" -foregroundcolor green Write-Host "" Write-host "PFX save location & name" -foregroundcolor yellow Write-Host "$FilepathPFX" -foregroundcolor green Write-Host "" Write-Host "Azure App Name" -foregroundColor Yellow Write-Host "$DashlaneAppName" -foregroundcolor green Write-Host "" Write-Host "Azure APP URI Display Name" -ForegroundColor yellow Write-Host "$DashlaneURI" -foregroundcolor green Write-Host "" Write-Host "By Continuing the Azure Application will be created with the above variables" -foregroundcolor yellow Pause Write-Host "Working..." -foregroundcolor green # Create the self signed cert $currentDate = Get-Date $endDate = $currentDate.AddYears(1) $notAfter = $endDate.AddYears(50) $pwd = $pwd $thumb = (New-SelfSignedCertificate -CertStoreLocation cert:\localmachine\my -DnsName win2016-ad.passwordlabs.com -KeyExportPolicy Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -NotAfter $notAfter).Thumbprint $pwd = ConvertTo-SecureString -String $pwd -Force -AsPlainText start-sleep -s 5 #Give time to finish the self-signed cert creationg Export-PfxCertificate -cert "cert:\localmachine\my\$thumb" -FilePath $FilePathPFX -Password $pwd_secure_string # Load the certificate $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate("$FilePathPFX", $pwd_secure_string) $keyValue = [System.Convert]::ToBase64String($cert.GetRawCertData()) # Create the Azure Active Directory Application $application = New-AzureADApplication -DisplayName "$DashlaneAppName" -IdentifierUris "$DashlaneURI" New-AzureADApplicationKeyCredential -ObjectId $application.ObjectId -CustomKeyIdentifier "$DashlaneAppName" -StartDate $currentDate -EndDate $endDate -Type AsymmetricX509Cert -Usage Verify -Value $keyValue # Create the Service Principal and connect it to the Application $sp = New-AzureADServicePrincipal -AppId $application.AppId # Give the Service Principal Reader access to the current tenant (Get-AzureADDirectoryRole) $ADDirectoryRoleObjectID = Get-AzureADDirectoryRole | Where-Object {$_.displayName -eq 'Company Administrator'} $ADDirectoryRoleObjectID = $ADDirectoryRoleObjectID.ObjectID Add-AzureADDirectoryRoleMember -ObjectId "$ADDirectoryRoleObjectID" -RefObjectId $sp.ObjectId Write-Host "Creating Azure App, this can take up to 60 seconds" -foregroundcolor green start-sleep -s 20 #Give the app a moment to be created # Get Tenant Detail $tenant = Get-AzureADTenantDetail # Now you can login to Azure PowerShell with your Service Principal and Certificate Connect-AzureAD -TenantId $tenant.ObjectId -ApplicationId $sp.AppId -CertificateThumbprint $thumb #Display the Results write-host "" Write-host "" Write-Host "TenantID" -foregroundcolor Yellow Get-AzureADTenantDetail | Ft DisplayName, ObjectID Write-Host "AppID " -ForegroundColor Yellow get-AzureADApplication | Ft DisplayName,AppID Write-Host "Thumbprint for $DashlaneAppName : $Thumb" -ForegroundColor Yellow
- Once you enter your information you will be prompted to review and press enter to continue.
- The script will finish and provide some outputs you will use in the AD sync script.
- Leave the Output window open, and create a new file in PowerShell ISE.
Set the environment variables
- Copy the following script to the new file in PowerShell ISE and Save AS "Azure-AD-Sync-Script.ps1"
# Dashlane Azure AD Sync Script # This script is to be used after you have registered a secure Azure Application to securely connect. #Define your variables $INSTALL_TOKEN = "TextString" #Line 42 from the AD sync script from the Admin Console $TEAM_ID = "NumberString" #Line 43 from your AD sync script from the Admin Console $TenantID = "NumberString" #Your tenantID from the Azure App connection script $AppID = "NumberString" #Your AppID from the Azure app connection script $Thumb = "NumberString" #your Thumbprint ID from the previous script Connect-AzureAD -TenantId $TenantID -ApplicationId $AppID -CertificateThumbprint $thumb #Give a moment for the connection to be established before continuing Start-sleep 10 # Enter each Groups ObjectID that you would like to sync with Dashlane. # caution: filter using the ObjectId values, NOT the friendly DisplayName values # caution: each ObjectId value must be enclosed by double quotation marks # #Groups key. DashlaneUsers = ObjectID # $Groups = @( "GroupObjectID1", "GroupObjectID2" ) $DASHLANE_LOGIN_ATTR = "UserPrincipalName" Import-Module AzureAD Write-Host "Running Dashlane Azure AD synchronization" $GroupMembers = @() $GroupInfos = @() $CSV_TEMP_PATH = $env:TEMP + "dashlane_export.csv" foreach ($Group in $Groups) { Try { $GroupInfo = Get-AzureADGroup -ObjectId $Group | Select DisplayName, ObjectId $GroupInfo | Add-Member Members @() $Members = Get-AzureADGroupMember -Top 1000 -ObjectId $Group | Get-AzureADUser | select UserPrincipalName # Roughly filtering out users with invalid emails. # A user with an invalid email is filtered out by Dashlane servers: it will therefore not # be included in the verified data, which will lead to an invalid signature check if it is # included in the signed data. $ValidMembers = $Members | Where-Object {($_ | Select -ExpandProperty $DASHLANE_LOGIN_ATTR) -like '*@*.*' } $measure = $ValidMembers | measure $count = $measure.count Write-Host "Exporting $count valid members from $Group" -ForegroundColor Green if ($count -gt 0) { foreach ($Member in $ValidMembers) { # Dashlane servers are also downcasing emails, see comment about invalid emails above. $Member = $Member | Select @{ name=$DASHLANE_LOGIN_ATTR; expression={($_ | Select -ExpandProperty $DASHLANE_LOGIN_ATTR).ToLower()} } $Member | Add-Member GroupName $GroupInfo.DisplayName $Member | Add-Member GroupGUID $GroupInfo.ObjectId $DashlaneLogin = $Member | Select -ExpandProperty $DASHLANE_LOGIN_ATTR $GroupMembers += $Member $GroupInfo.Members += $Member } $GroupInfos += $GroupInfo } } Catch { $ErrorMessage = $_.Exception.Message $FailedItem = $_.Exception.GetType().FullName Write-Host "Error: $FailedItem - $ErrorMessage" -ForegroundColor Red Write-Host "Message: It seems there is no account on this Group: $Group." -ForegroundColor Red } } ## writing temp CSV Write-Host "" Write-Host "Writing debug information to $CSV_TEMP_PATH" $GroupMembers | Export-Csv -Path $CSV_TEMP_PATH -NoTypeInformation -Encoding UTF8 # Generate signature Try { $CspParameters = New-Object -TypeName System.Security.Cryptography.CspParameters $CspParameters.KeyContainerName = "DashlaneDirectorySyncKey53" $RSA = New-Object -TypeName System.Security.Cryptography.RSACryptoServiceProvider -ArgumentList $CspParameters $PublicKey = $RSA.ToXmlString($false) $PublicKeyHash = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($PublicKey)) Write-Host "" Write-Host "---------- Provide your Dashlane admin with this key on setup: -----------" Write-Host "" Write-Host $PublicKeyHash -ForegroundColor Green Write-Host "" Write-Host "--------------------------------------------------------------------------" Write-Host "" $RSAFormatter = New-Object -TypeName System.Security.Cryptography.RSAPKCS1SignatureFormatter -ArgumentList $RSA $RSAFormatter.SetHashAlgorithm("SHA256") $DataStr = $TEAM_ID foreach ($GroupInfo in $GroupInfos | Sort-Object -Property ObjectId) { $DataStr += $GroupInfo.ObjectId $DataStr += $GroupInfo.DisplayName foreach ($Member in $GroupInfo.Members | Sort-Object -Property $DASHLANE_LOGIN_ATTR) { $DashlaneLogin = $Member | Select -ExpandProperty $DASHLANE_LOGIN_ATTR $DataStr += $DashlaneLogin } } $DataBytes = [System.Text.Encoding]::UTF8.GetBytes($DataStr) $SHA256 = New-Object -TypeName System.Security.Cryptography.SHA256CryptoServiceProvider $DataHash = $SHA256.ComputeHash($DataBytes) $SignatureBytes = $RSAFormatter.CreateSignature($DataHash) $SignatureHash = [System.Convert]::ToBase64String($SignatureBytes) } Catch { $ErrorMessage = $_.Exception.Message $FailedItem = $_.Exception.GetType().FullName Write-Host "Failed: $FailedItem - $ErrorMessage" -ForegroundColor Red } # Send data to Dashlane $FileContent = Get-Content $CSV_TEMP_PATH | Out-String $FileContentBytes = [System.Text.Encoding]::UTF8.GetBytes($FileContent) $FileContentEncoded = [System.Convert]::ToBase64String($FileContentBytes) [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; $URL = "https://ws1.dashlane.com/1/teamPlans/syncFromDirectory" $Method = "POST" $ContentType = "application/x-www-form-urlencoded" $Payload = @{adLogins=$FileContentEncoded;adToken=$INSTALL_TOKEN;teamId=$TEAM_ID;signature=$SignatureHash;publicKey=$PublicKeyHash} Try { $Response = Invoke-WebRequest -Uri $URL -Method $Method -Body $Payload -ContentType $ContentType Write-Host "Dashlane sync responded with: $Response" -ForegroundColor Green } Catch { $ErrorMessage = $_.Exception.Message $FailedItem = $_.Exception.GetType().FullName Write-Host "" Write-Host "Dashlane sync error: $FailedItem - $ErrorMessage" -ForegroundColor Red } # Cleaning up temp CSV Remove-Item $CSV_TEMP_PATH }
- Login to Console.Dashlane.com > Settings > Active Directory
- Turn on the option for Automatic User Provisioning and Group Syncing
- Click the Copy button next to the AD Script and paste it in a new tab in PowerShell ISE
- Save the file and name it "Default-AD-Script.ps1"
- You should have 3 scripts open now in PowerShell ISE, as well as the output window
- Edit lines 5-9 in the AzureAD-Sync-Script using the environment variables below. After you have entered your variables it will look something like the image above.
$INSTALL_TOKEN = "BIvG4Jd6Y8PWX7Gli0nQAkHYoozzzzzz0CxMncY6dDvm6z5cbWZYVD-"
From line 42 of the Default-AD-Script$TEAM_ID = "123456"
From line 43 of the Default-AD-script$TenantID = "60f8366e-282f-460f-91ef-4zzzbbe6445"
From the tenantID from the Azure App-Setup script$AppID = "c0023c85-9358-46e7-8a71-aezzzz4c9606"
From the output of the AppID from the Azure App Setup script$Thumb = "6BA63A586294299Fzzzzz15939445A115A4C"
From the output of the Thumbprint ID from the Azure App Setup script - Enter the Azure Groups you would like to sync using the ObjectID of the group on line 22
- Run the script and ensure it sync's successfully
- Ensure the script returns "code":200,"message":"OK"
- Copy the text string between the dashes to your clipboard
- Navigate back to http://console.dashlane.com and Refresh the page
- In the "Verify the security key..." pop-up, click Continue
- Enter the text string from your clipboard you copied from step 10 into the text field and click Verify now
- Success! You will receive this message when the key has been verified
Run the Azure AD sync script
- In the Admin Console view the Users tab and validate that any new users have an invite pending status
- On the Groups tab view the groups that have synced
- You can view your AD sync status in the Admin Console in Settings > Active Directory
- It is recommended to turn on Automatic Deprovisioning once you have confirmed that all synced users are included in the Active Directory sync groups.
Scheduling regular Sync with Task Scheduler
With the script saved to your domain, you can schedule it to run automatically at an interval you define.
Note that the user account set to run this task must be able to read Organizational Units (OU's) and user accounts in your Active Directory environment.
- Open Task Scheduler on a Windows Server that will run the script
- Select Task Scheduler Library
- Click the Action tab in the top left menu
- Then click “Create Task”
- Next click the General tab
- Type Dashlane AD Sync in the "Name:" text box
- Next select Security Options
- Within Security Options: Check the boxes for "Run whether user is logged in or not" and "Run with highest privileges"
- Please set a schedule for the script to run by creating a new trigger. In the example shown below, it will run daily at 1:00 AM.
-
Then, click the Actions tab.
a. Click New Action
b. Under "Program/script," type in powershell
c. Under "Add arguments (optional)", paste -file C:\FilePathtoPowershellScript\dashlane-ad-sync.ps1
Some considerations
- Once sync is configured, we recommend managing your Dashlane groups and users exclusively via your Active Directory.
- All users considered by the script must have a specified email address in Active Directory
- Admins cannot deprovision all admin users, as there must be at least one active admin for every business plan.
- Admins also cannot deprovision billing admins, as there must be at least one active billing admin for every business plan.
- The number of users in the synced groups must not be higher than the available seats in your business account.