This project has moved. For the latest updates, please go here.

Documentation MFA Identity Server 1.x

 

Edit configdata.xml

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 general params

<MFAConfig DeliveryWindow="300" TOTPShadows="2" MailEnabled="true" SMSEnabled="false" AppsEnabled="true" Algorithm="SHA1" Issuer="your company" UseActiveDirectory="true" CustomUpdatePassword="true" KeyGenerator="ClientSecret512">

  • DeliveryWindow : Duration max between send on TOTP code and signing, in seconds, this parameter is only used in mail notifications, for authenticator apps it’s by default 30 seconds to be compatible with Google and Microsoft      
  • SMSEnabled : True if you want to implement your own external OTP provider, or use the Azure MFA demo (new in version 1.1.0.0) 
  • MailEnabled : True by default, if you want to use email validation
  • AppsEnabled : True if you want to use authenticators applications
  • Algorithm : SHA1  always this value if you want to be compatible with Google and Microsoft implementations (gmail, live, Synology, etc… the protocol can be strongest, but… they all respect your privacy)
  • Issuer : Your company Name  this is used in email for example (eg: neos-sdi)
  • UseActiveDirectory : True   if your want to store each user secret key in ADDS, False if you want to use SQL-Server Database.
  • CustomUpdatePassword : True  if you want to use our custom pwd form, False to use MS updatepassord form.
  • KeyGenerator :  When registering, the option choose to generate the secret key (Guid, ClientSecret128, ClientSecret256, ClientSecret384, ClientSecret512)
  • TOTPShadows : when time is not really accurate, use the current code and 2 prior and next totp codes.

MFAConfig email params

<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.

MFAConfig SQL Server params

<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”

MFAConfig ADDS params

<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 enabled
attribute="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>

  • Company : Your company Name, this is used in the sms text (eg: neos-sdi)
  • DefaultCountryCode : the default country code for national phone numbers (eg: US, FR)
  • Sha1Salt : string used as salt for SHA1 hash
  • FullQualifiedImplementation : ref to your assembly and class type implementing IExternalOTPProvider
  • Parameters : Your parameters as CDATA, you can provide any kind of parameters, remember that it’s to your code to parse these values.

 

For more information see :

  • Implementing an External OTP Provider (sms)
  • Configuring the Azure MFA demo (sms)

Installing MFA IdentityServer

  1. On each ADFS Server launch a PowerShell instance as administrator
  2. Run this script "one line at time" (see register multi factor.txt in source code)

# 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

UnInstall MFA IdentityServer

  1. On each ADFS Server launch a PowerShell instance as administrator
  2. Run this script "one line at time" (see register multi factor.txt in source code)

# 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:

  • Provide you a basis for implementing your own solution.
  • To compensate for the different demands of customers not wishing to rely on a third party service, concerned with issues of confidentiality or security.

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?

  • You must create a new project with Visual Studio (2012, 2013, 2015) of type assembly .net (Framework 4.5.2 and up)
  • Reference Neos.IdentityServer.MultiFactor.Common.dll and implement the interface "IExternalOTPProvider"

There is only one method to encode with the provided parameters you must return a valid code or even zero to indicate an error.

  • int GetUserCodeWithExternalSystem (string upn, string phonenumber, string email, ExternalOTPProvider externalsys, CultureInfo culture);
  • Parameters
    • upn : user id;
    • phonenumber : Phone number for the user if provided.
    • email : email address for the user if provided
    • Culture : a CultureInfo object, can be used for Globalization scenarios.
    • ExternalOTPProvider : a wrapper class (Neos.IdentityServer.MultiFactor.Common.dll) used to deserialize metadata stored in configuration file used by ADFS
      • Company : string describing your company
      • DefaultCountryCode : default country code for sms calls, if not provided in the user’s phone number
      • Sha1Salt : your salt for hashing the message.
      • FullQualifiedImplementation :  Full description for your assembly and class (implementing IExternalOTPProvider), this type will be dynamically loaded and executed at runtime
      • Parameters : Your custom parameters, are stored in CDATA in configuration file. it’s up to you to parse, decrypt, deserialize this value.

// Basic Sample

public class SMSCall : IExternalOTPProvider
{
public int GetUserCodeWithExternalSystem(string upn, string phonenumber, string email, ExternalOTPProvider externalsys, CultureInfo culture)
{
    // Compute and send your TOTP code and return his value if everything goes right
     resstrings.Culture = culture;
     if (true)
        return 1230;
     else
        return 0; // return 0 if an error
}
}

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.

You can of course use the solution provided by Microsoft, in this case there is no need of our component.
 
The demo provided uses the MFA Azure SDK. You must follow the explanations given in the following link: https://azure.microsoft.com/en-us/documentation/articles/multi-factor-authentication-sdk/
 

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 will notice that the example does not use the certificate that is stored on disk as in the SDK, it's not very secure...
so you need to retrieve the thumbprint of the certificate when this one will be deployed correctly in the certificate store.

You’re Done !

ADFS Additional Tasks

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

Some Screen Shots

See ScreenShots

Last edited Jun 16 at 9:01 PM by redhook, version 3