this file is passed when registering the extension with ADFS, and these information are stored securely in ADFS configuration. this must be done on the primary ADFS Server, not on ADFS Proxies.
<MFAConfig DeliveryWindow="300" TOTPShadows="2" MailEnabled="true" SMSEnabled="false" AppsEnabled="true" Algorithm="SHA1" Issuer="your company" UseActiveDirectory="true" CustomUpdatePassword="true" KeyGenerator="ClientSecret512">
<SendMail Company="your company description" from="youremail@youcompany" username="youraccount" password="yourpassword" host="youmailserver" port="587" useSSL="true" />
All the parameters to connect to your mail server for sending an email to a secondary address for a user. remember, these informations are stored in the ADFS configuration Database.
<SQLServer ConnectionString="Password=tou password;Persist Security Info=True;User ID=youruser;Initial Catalog=yourdatabase;Data Source=yoursqlserver" />
The connection string used to connect to the MFA configuration DB (if UseActiveDirectory=False), you must create the database with the script provided “full-create-mfa-db.sql”
<ActiveDirectory
DomainAddress="ldap://dc=yourdomain, dc=com"
Account="your account allowed to read and write your ADDS"
Password="tour account password"
keyattribute="your secret key"
mailattribute="your mail attribute"
phoneattribute="your mobile attribute"
methodattribute="UI Method attribute"
notifcreatedateattribute="key creation date attribute"
notifvaliditydateattribute="TOTP validity date attribute"
notifcheckdateattribute"TOTP check date attribute"
totpattribute="totp code attribute" and enabledattribute="enabled status attribute"
/>
If you don’t specify any of the parameters, this will work if the ADFS service account have sufficient rights to read and write users properties, if not you must specify account related parameters. you can also change the attributes used to store some stuff, by default we used msDS-cloudExtensionAttribute10 to msDS-cloudExtensionAttribute17.
Be carefull ! these default attributes are valid only with ADDS Schema 2012 and up. if your ADDS schema is older you must modify the configuration and provide you own attributes set.
Property | Optional | AD Attribute | Comments |
DomainAddress | Yes | Your domain address - ldap://dc=yourdomain, dc=com | |
Account | Yes | Account allowed to read & write users properties in ADDS | |
Password | Yes | Account password | |
keyattribute | Yes | msDS-cloudExtensionAttribute10 | string – secret key |
mailattibute | Yes | msDS-cloudExtensionAttribute11 | string – mail address of the user (secondary) |
phoneattribute | Yes | msDS-cloudExtensionAttribute12 | string – mobile number |
methodattibute | Yes | msDS-cloudExtensionAttribute13 | int as string – UI method attribute |
notifycreatedateattribute | Yes | msDS-cloudExtensionAttribute14 | date as UTC string |
notifyvaliditydateattribute | Yes | msDS-cloudExtensionAttribute15 | date as UTC string |
notifycheckdateattribute | Yes | msDS-cloudExtensionAttribute16 | date as UTC string |
totpattribute enableattibute
|
Yes
Yes |
msDS-cloudExtensionAttribute17
msDS-cloudExtensionAttribute18 |
int as string – used for email validation otherwise –1
bool - user status (enabled/disabled) for MFA |
MFAConfig ExternalOTPProvider
<ExternalOTPProvider Company="your company description" DefaultCountryCode="FR" Sha1Salt="yoursalt" FullQualifiedImplementation="your assembly and classtype” >
<!-- sample : Neos.IdentityServer.Multifactor.SMS.SMSCall, Neos.IdentityServer.Multifactor.SMS.Azure, Version=1.2.0.0, Culture=neutral, PublicKeyToken=175aa5ee756d2aa2 –>
<Parameters>
<![CDATA[LICENSE_KEY = "YOUR_LICENCE_KEY", GROUP_KEY = "YOUR_GROUP_KEY", CERT_THUMBPRINT = "YOUR_CERT_THUMBPRINT"]]>
</Parameters>
</ExternalOTPProvider>
For more information see :
# change to the path where you unzip the binaries
Set-location "your unzip path"
[System.Reflection.Assembly]::Load("System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
$publish = New-Object System.EnterpriseServices.Internal.Publish
net stop adfssrv
# Register assemblies in the GAC, don't forget to change the path
$publish.GacInstall("your unzip path\Neos.IdentityServer.MultiFactor.dll")
$publish.GacInstall("your unzip path\fr\Neos.IdentityServer.MultiFactor.Resources.dll")
$publish.GacInstall("your unzip path\es\Neos.IdentityServer.MultiFactor.Resources.dll")
$publish.GacInstall("your unzip path\Neos.IdentityServer.MultiFactor.Common.dll")
$publish.GacInstall("your unzip path\Neos.IdentityServer.MultiFactor.QRCodeNet.dll")
# Install External OTP Provider (Sample And Azure MFA) assemblies
$publish.GacInstall("your unzip path\Neos.IdentityServer.Multifactor.SMS.Sample.dll")
$publish.GacInstall("your unzip path\Neos.IdentityServer.Multifactor.SMS.Azure.dll")
$publish.GacInstall("your unzip path\fr\Neos.IdentityServer.Multifactor.SMS.Azure.Resources.dll")
$publish.GacInstall("your unzip path\es\Neos.IdentityServer.Multifactor.SMS.Azure.Resources.dll")
$publish.GacInstall("your unzip path\libphonenumber_csharp_portable.dll")
net start adfssrv
# you must execute these next commands on the primary federation server of the farm only.
# Register ADFS Authentication Provider with your configdata.xml
$typeName = "Neos.IdentityServer.MultiFactor.AuthenticationProvider, Neos.IdentityServer.MultiFactor, Version=1.2.0.0, Culture=neutral, PublicKeyToken=175aa5ee756d2aa2"
Register-AdfsAuthenticationProvider -TypeName $typeName -Name "MultiFactorAuthenticationProvider" -Verbose -ConfigurationFilePath ".\configdata.xml"
net stop adfssrv
net start adfssrv
# you must execute these next command on the primary federation server of the farm only.
# Unregister ADFS Authentication Provider
UnRegister-AdfsAuthenticationProvider -Name "MultifactorAuthenticationProvider"
net stop adfssrv
net start adfssrv
# you must execute these next command on each federation server of the farm but not on the Proxies (WAP).
# change to the path where you unzip the binaries
Set-location "your unzip path"
[System.Reflection.Assembly]::Load("System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
$publish = New-Object System.EnterpriseServices.Internal.Publish
net stop adfssrv
# Unregister assemblies from the GAC, don't forget to change the path
$publish.GacRemove("your unzip path\Neos.IdentityServer.MultiFactor.dll")
$publish.GacRemove("your unzip path\fr\Neos.IdentityServer.MultiFactor.Resources.dll")
$publish.GacRemove("your unzip path\es\Neos.IdentityServer.MultiFactor.Resources.dll")
$publish.GacRemove("your unzip path\Neos.IdentityServer.MultiFactor.Common.dll")
$publish.GacRemove("your unzip path\Neos.IdentityServer.MultiFactor.QRCodeNet.dll")
# UnInstall External OTP Provider (Sample And Azure MFA) assemblies
$publish.GacRemove("your unzip path\Neos.IdentityServer.Multifactor.SMS.Sample.dll")
$publish.GacRemove("your unzip path\Neos.IdentityServer.Multifactor.SMS.Azure.dll")
$publish.GacRemove("your unzip path\fr\Neos.IdentityServer.Multifactor.SMS.Azure.Resources.dll")
$publish.GacRemove("your unzip path\es\Neos.IdentityServer.Multifactor.SMS.Azure.Resources.dll")
$publish.GacRemove("your unzip path\libphonenumber_csharp_portable.dll")
net start adfssrv
Updating MFA Server configuration data
# Change ADFS Authentication Provider Configuration Data (After modifying configdata.xml)
Import-AdfsAuthenticationProviderConfigurationData -Name "MultiFactorAuthenticationProvider" -FilePath ".\configdata.xml"
net stop adfssrv
net start adfssrv
Implementing an External OTP Provider
Why use this API?
- You need to get an access code for single use from an external source, an SMS provider, RSA appliance, Azure, Google or just a pin code stored in your information system.
In this case ADFS take the provided code to validate the two-factor authentication.
At this point, I remind you the original objectives of this project:
I remind you that there are a large number of solutions provided by third-party publishers and validated by Microsoft (Gemalto, EMC, Login People, Azure MFA (PhoneFactors), and many others)
https://TechNet.Microsoft.com/en-us/library/dn758113(v=WS.11).aspx
How to code your own solution?
There is only one method to encode with the provided parameters you must return a valid code or even zero to indicate an error.
// Basic Sample
Dont forget to update your config file with this
<ExternalOTPProvider Company="your company name" DefaultCountryCode="US" Sha1Salt="your salt" FullQualifiedImplementation="Neos.IdentityServer.Multifactor.SMS.SMSCall, Neos.IdentityServer.Multifactor.SMS.Sample, Version=1.2.0.0, Culture=neutral, PublicKeyToken=175aa5ee756d2aa2" />
And redeploy your config file with these PowerShell commands
Import-AdfsAuthenticationProviderConfigurationData -Name "MultiFactorAuthenticationProvider" -FilePath ".\configdata.xml"
net stop adfssrv
net start adfssrv
We hope that you can implement your extension according to you wishes and needs. feel free to tell us about your splendid connectors.
Configuring the Azure MFA demo
To use this demo, you must configure authentication multi-factor on your subscription Azure or Office 365 (AAD). Note, that this feature is subject to a payment either by user ($ 1.49 per month) or the number of queries (10 requests $ 1.49)
You must be administrator Global to set up MFA Azure. If you have a valid MSDN account, you can activate your subscription.
Once Azure configured, as well as the recovery of the SDK (asp.net).
Take your client certificate from SDK (aka: "c:\\cert_key.p12") and install it in the machine certificate store with the password in the provided source pf_auth.cs (CERT_PASSWORD)
In this file, please retrieve the values of the following constants:
private const string LICENSE_KEY = "Your license key";
private const string GROUP_KEY = "Your group key";
private const string CERT_PASSWORD = "client certificate password";
Next, modify the config file of the ADFS server. and change values according your Azure account
<ExternalOTPProvider Company="your company description" DefaultCountryCode="FR" Sha1Salt="yoursalt" FullQualifiedImplementation="Neos.IdentityServer.Multifactor.SMS.SMSCall, Neos.IdentityServer.Multifactor.SMS.Azure, Version=1.2.0.0, Culture=neutral, PublicKeyToken=175aa5ee756d2aa2'" >
<Parameters>
<![CDATA[LICENSE_KEY = "YOUR_LICENCE_KEY", GROUP_KEY = "YOUR_GROUP_KEY", CERT_THUMBPRINT = "YOUR_CERT_THUMBPRINT"]]>
</Parameters>
</ExternalOTPProvider>
You’re Done !
On the primary federation server of the farm only, launch a PowerShell instance as administrator
# Add Additional Authentication Rules for OAuth or Application like Outlook, Web Services etc...
Get-AdfsAdditionalAuthenticationRule
$rp = Get-AdfsRelyingPartyTrust –Name "Microsoft Office 365 Identity Platform" # your RelyingParty
$MfaClaimRule = 'c:[Type == "http://schemas.microsoft.com/ws/2012/01/insidecorporatenetwork", Value == "false"] && d:[Type == "http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-endpoint-absolute-path",
Value =~ "(/adfs/ls)|(/adfs/oauth2)"] => issue(Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod", Value = "http://schemas.microsoft.com/claims/multipleauthn");'
Set-AdfsRelyingPartyTrust –TargetRelyingParty $rp –AdditionalAuthenticationRules $MfaClaimRule
# Other Stuff
Set-AdfsAdditionalAuthenticationRule –TargetRelyingParty $rp -AdditionalAuthenticationRules 'c:[Type == "http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-endpoint-absolute-path",
Value =~ "(/adfs/ls)|(/adfs/oauth2)"] => issue(Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod",
Value = "http://schemas.microsoft.com/claims/multipleauthn");'
#Change Globally authentication rules, not only for a RL
Set-AdfsAdditionalAuthenticationRule -AdditionalAuthenticationRules 'c:[Type == "http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-endpoint-absolute-path", Value =~ "(/adfs/ls)|(/adfs/oauth2)"] => issue(Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod", Value = "http://schemas.microsoft.com/claims/multipleauthn");'
# Clear all additional authentication rules
Set-AdfsAdditionalAuthenticationRule -AdditionalAuthenticationRules $null
See ScreenShots