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

Window validation time elapsed.

Mar 25, 2016 at 1:03 AM
Hello,

I have installed the Multifactor Authenication and enabled it in ADFS.
It has been enabled on a test relay trust. The the screens for MFA are appearing, and the necessary information is being written to AD.

My issue is when I attempt to use the PIN/Code from either the TOTP application (I am using google authenticator) or via the email sent with the code I receive a message on the form of

"Window validation time elapsed."

The codes are being entered with 20 secs of the request. Does anyone have insight into what may be wrong? The ADFS event log shows no errors, and I can verify The AD information is being read and appears correct.
Coordinator
Mar 31, 2016 at 4:47 PM
Hello,

The Window validation time is for email validation specified in your configuration file : <MFAConfig DeliveryWindow="300" SMSEnabled="false" ...
by default, it's 5 minutes.
For the TOTP code with Authenticator application it's 30 seconds (it's by default the choice that Google and Microsoft have made)

You can verify if your ADFS server is at the good time.
May 4, 2016 at 4:09 PM
I am having the sam issue as carl. My phone, client, adfs server, and domain controllers are all with in a single millisecond of each other. and I'm getting this error.

The adfs server and Domain controller is in PDT, the client and phone are in CDT.

I'm easily entering the code for the TOTP app in 30 seconds. and get the error there

I'm getting the error with the email as well and doing that with in 30 seconds as well.
Coordinator
May 5, 2016 at 9:56 PM
Hi, Kurtaggie

I will test next week with your DayLight Time (Utc -5 and Utc -7).

But, as i said, your must ensure that your device and your ADFS server are well synchonised with an ntp server or an atomic clock.
This is very important for your ADFS Platform, because a screwtime of 5 minutes for validating token.

I confirm, that the component is working only with Utc time, each local Daylight time is converted in Utc DateTime.

here is the code :
    /// <summary>
    /// GetUnixTimestamp method implementation
    /// </summary>
    private static Int64 GetUnixTimestamp()
    {
        return Convert.ToInt64(Math.Round((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds));
    }
I'am surprised, that with email validation (5 mn by default) you have problems !
Have you, verified the ADFS event Log ?

So, next week, i will ship an new version with 2 évolutions
  • ability to reset your secret Key
  • ability to specify "Shadow TOTP" before and after the time you push the code. I think that 30s is often to short when using my phone.
some usefull links
https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm
https://tools.ietf.org/html/rfc6238
May 5, 2016 at 10:39 PM
Hello,

Not sure if this will be of direct help. But I did get the Multi-Factor Authentication working by just changing the config over to using a sql repository as opposed to AD. I also installed a local version of sql express just to make sure there would be little time difference/drift for testing.

Further testing showed as long as I used the sql database option it did not matter if the database was local or on a remote server.

While I have only used it in a test environment so far there have been no issues, and works very well.
Coordinator
May 5, 2016 at 11:55 PM
Hello Carl, Kurt

Yes, you can see better to use an SQL database. because it's not advisable in absolute to write into Active Directory.
If you have multiple ADFS servers, you should use a remote instance of SQL Server.

The fact that it does not work properly with Active Directory certainly comes from misconfigured rights or invalid attributes
I confirm that the code calculating the TOTP is exactly the same (except the storage part) whether active directory or SQL Server.
Happy you have found a solution to your problem.
Make sure, that the access to your database is secure. the data is not encrypted.

The use of active directory, is simpler to implement and allows to use replication between domain controllers if necessary.
for example when using remote ADFS platforms (eg: OnPremise / Azure).

That's why, i have made 2 implementations
May 27, 2016 at 1:09 AM
We had the same problem using AD. It appears that when you do the notif.Checkdate.value > notif.ValidityDate comparison the ValidityDate is local and the CheckDate is UTC. We made the following change and it appears to be working now.

ret.ValidityDate = Convert.ToDateTime(DirEntry.Properties[_host.notifvalidityAttribute].Value).ToUniversalTime();
Coordinator
May 30, 2016 at 3:39 PM
Hi bhbeebe, and all others.

Thank you very much !, yes it was a bug !

I have made some changes, and tested with multiple time zones. it works correctly now with ADDS and SQL
The files version has changed to 1.0.2.0. you just had to replace files (assemblies) in the GAC.

I want to thanks everyone for their help.
If you want some new functionallities, please let me know !
May 31, 2016 at 6:31 PM
Thanks for the quick update.

Is it possible to only have it use the TOTP and not use email address at all? We have some security concerns about using email.
Coordinator
May 31, 2016 at 6:42 PM
Thanks,

At this time, it's not possible to disable email validation.

If the Key is lost or corrupted, this is the only way that the user have to login and regenerate the TOTP Key.
But, soon, i will add a parameter in the config file to disable email validation.
Jun 6, 2016 at 10:42 PM
I just tried the new code. It still has a problem with "Window validation time elapsed. " I reverted the change you made and add the above change and it is working on the primary. But the email change you made is working, thank you.



We have a primary and secondary federation server. It loads fine on the primary. But I cannot get it to load on the secondary. I keep getting the following error in event viewer:

An error occurred loading an authentication provider. Fix configuration errors using PowerShell cmdlets and restart the Federation Service.
Identifier: MultiFactorAuthenticationProvider
Context: Proxy device TLS pipeline

Additional Data
Exception details:
The external authentication method Neos.IdentityServer.MultiFactor.AuthenticationProvider, Neos.IdentityServer.MultiFactor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ade5901ee3fc1d69 could not be loaded. Exception has been thrown by the target of an invocation.


I have reregistered the GAC and I have stopped and started ADFS. It still comes up with this message. I am at a loss and where to look now.

Thanks,
Coordinator
Jun 6, 2016 at 11:47 PM
Edited Jun 6, 2016 at 11:58 PM
Hi bhbeebe

I don't see the changes you made for the "window validation time".
For the registration of the new version, you must deploy the assemblies on each federation server (not on Proxies eg : 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

Un-Register assemblies in the GAC, don't forget to change the path
$publish.GacRemove("your unzip path\Neos.IdentityServer.MultiFactor.dll")
$publish.GacRemove("your unzip path\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")

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\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")

net start adfssrv

you must execute these next commands on the primary federation server of the farm only.

Unregister ADFS Authentication Provider
UnRegister-AdfsAuthenticationProvider -Name "MultifactorAuthenticationProvider"
net stop adfssrv
net start adfssrv

Register ADFS Authentication Provider with your configdata.xml
$typeName = "Neos.IdentityServer.MultiFactor.AuthenticationProvider, Neos.IdentityServer.MultiFactor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=175aa5ee756d2aa2"
Register-AdfsAuthenticationProvider -TypeName $typeName -Name "MultiFactorAuthenticationProvider" -Verbose -ConfigurationFilePath ".\configdata.xml"

net stop adfssrv
net start adfssrv

Normally, you have just to do this on the primary federation server, because configuration replication occurs between the federation servers if you are using Windows Internal Database configuration, and if you are using an SQL instance (ADFS configuration) the Database is Shared.

Keep in mind, that the config file has been updated
  • a property was added : MailEnabled = "false" or "true"
  • a property default was changed : KeyGenerator="ClientSecret128" to KeyGenerator="ClientSecret512">
Another thing, remenber that in my build the PublicTokenKey for assemblies is "175aa5ee756d2aa2" and not "ade5901ee3fc1d69" that you have used to make you build.

I recommend that you uninstall and unregister the component and download an install the binaries from codeplex.

Let me know, if your problem goes away

Best Regards
Jun 7, 2016 at 12:43 AM
Sorry, I didn't submit the changes. I only made the changes in our local code. I can submit the changes if you would like.

I did follow this document several times exactly to be sure.

The only reason I am using the "ade5901ee3fc1d69" publicTokenKey was because I had made the change to Neos.IdentityServer.Common\Neos.IdentityServer.MultiFactor.ActiveDirectory.cs

ret.ValidityDate = Convert.ToDateTime(DirEntry.Properties[_host.notifvalidityAttribute].Value).ToUniversalTime();

And I had created a new build.

I did not check to see whether your build binaries were able to load without error. I only saw the time validation error. I will try it right now.
Jun 7, 2016 at 12:59 AM
It does not have the error when I use your build. I am not sure what I am doing wrong with my build because it works fine on the primary. But I still have the problem with the "Time Elapsed". I did not put it through the remote debugger this time.

Here are the changes I made to fix this problem.

Neos.IdentityServer.Common\Neos.IdentityServer.MultiFactor.ActiveDirectory.cs
                        ret.CreationDate = Convert.ToDateTime(DirEntry.Properties[_host.notifcreatedateAttribute].Value).ToUniversalTime();
                        ret.ValidityDate = Convert.ToDateTime(DirEntry.Properties[_host.notifvalidityAttribute].Value).ToUniversalTime();
Neos.IdentityServer.MultiFactor.Provider.cs
                        if (notif.CheckDate.Value > notif.ValidityDate)
Thank you for your help. I feel that it is almost there.
Jun 7, 2016 at 6:42 PM
I was testing this again today. And I must have looked at the wrong server. I have never been able to get any the dll to load on the secondary. I keep getting

An error occurred loading an authentication provider. Fix configuration errors using PowerShell cmdlets and restart the Federation Service.
Identifier: MultiFactorAuthenticationProvider
Context: Proxy device TLS pipeline

Additional Data
Exception details:
The external authentication method Neos.IdentityServer.MultiFactor.AuthenticationProvider, Neos.IdentityServer.MultiFactor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=175aa5ee756d2aa2 could not be loaded. Exception has been thrown by the target of an invocation.
Coordinator
Jun 7, 2016 at 8:32 PM
Edited Jun 7, 2016 at 9:49 PM
It seems that you haven't unregister/register correctly the Adapter Assemblies.
As an example, you can look at this post : http://c7solutions.com/2016/04/upgrading-mfa-6-3-1-to-version-7 .
the Microsoft Azure Adapter in this case.
Coordinator
Jun 7, 2016 at 8:58 PM
For the "Window Validation Time" it seems that you code is working well.
But, the changes that i made (files version 1.0.2.0) are not the same.
  • in Neos.IdentityServer.Multifactor.ActiveDirectory.cs
    All the Dates are Read are stored in local time of the ADFS Server (Like in the SQL implementation)
using (DirectorySearcher dsusr = new DirectorySearcher(rootdir, qryldap))
                {
                    dsusr.PropertiesToLoad.Clear();
                    dsusr.PropertiesToLoad.Add("objectGUID");
                    dsusr.PropertiesToLoad.Add(_host.notifcreatedateAttribute);
                    dsusr.PropertiesToLoad.Add(_host.notifvalidityAttribute);
                    dsusr.PropertiesToLoad.Add(_host.totpAttribute);

                    SearchResult sr = dsusr.FindOne();
                    if (sr != null)
                    {
                        isok = true;
                        using (DirectoryEntry DirEntry = GetDirectoryEntry(sr))
                        {
                            DirEntry.Properties[_host.notifcreatedateAttribute].Value = notif.CreationDate.ToString("u");
                            DirEntry.Properties[_host.notifvalidityAttribute].Value = notif.ValidityDate.ToString("u");
                            DirEntry.Properties[_host.totpAttribute].Value = notif.OTP.ToString();
                            DirEntry.CommitChanges();
                        };
                    }
                }
And
using (DirectorySearcher dsusr = new DirectorySearcher(rootdir, qryldap))
                {
                    dsusr.PropertiesToLoad.Clear();
                    dsusr.PropertiesToLoad.Add("objectGUID");
                    dsusr.PropertiesToLoad.Add(_host.notifcreatedateAttribute);
                    dsusr.PropertiesToLoad.Add(_host.notifvalidityAttribute);
                    dsusr.PropertiesToLoad.Add(_host.notifcheckdateattribute);
                    dsusr.PropertiesToLoad.Add(_host.totpAttribute);

                    SearchResult sr = dsusr.FindOne();
                    if (sr != null)
                    {
                        ret = new Notification();
                        using (DirectoryEntry DirEntry = GetDirectoryEntry(sr))
                        {
                            ret.ID = new Guid((byte[])DirEntry.Properties["objectGUID"].Value).ToString();
                            ret.RegistrationID = ret.ID;
                            ret.CreationDate = Convert.ToDateTime(DirEntry.Properties[_host.notifcreatedateAttribute].Value);
                            ret.ValidityDate = Convert.ToDateTime(DirEntry.Properties[_host.notifvalidityAttribute].Value);
                            ret.CheckDate = notif.CheckDate;
                            ret.OTP = Convert.ToInt32(DirEntry.Properties[_host.totpAttribute].Value.ToString());

                            DirEntry.Properties[_host.notifcheckdateattribute].Value = notif.CheckDate.Value.ToString("u");
                            DirEntry.CommitChanges();
                        };
                    }
                }
  • in Neos.IdentityServer.Multifactor.Provider.cs
    The Check if made in UTC
 if (notif.CheckDate.Value.ToUniversalTime() > notif.ValidityDate.ToUniversalTime())  // Always check with Universal Time
                                {
                                    UIM = ProviderPageMode.locking;
                                    return new AdapterPresentation(this, errors_strings.ErrorValidationTimeWindowElapsed, true);
                                }
                                if (CheckPin(pin, notif, UserRegistration))
                                {
...
I Agree that the "Windows Validation Time" is only usefull when using email validation.
I have made intensive testing, played with Daylight zones, tested with new users and different authent methods. but perhaps there is some side effect since last update ??.
I going to check this problem as soon as possible.

Does someone else has encountered the same problem ?

Regards
Apr 13 at 5:04 PM
I'm still experiencing this problem. 2012r2 DC / ADFS server, clocks are in sync. Doesn't seem to matter how loose I set the TOTP shadows / deliverywindow.
Marked as answer by redhook on 6/21/2017 at 10:46 AM