4

I have a web application that uses Active Directory to authenticate. I want to add an option that will notify the users when their password is close to expiring. I managed to do something, but the problem I have is that the expiration days is negative (daysLeft parameter), yet I can still log in.

string domainAndUsername = @"LDAP://ldapUrl";

DirectoryEntry root = new DirectoryEntry(ldapServer, userID, userPwd, AuthenticationTypes.Secure);
DirectorySearcher mySearcher = new DirectorySearcher(root);
SearchResultCollection results;

string filter = "maxPwdAge=*";
mySearcher.Filter = filter;

results = mySearcher.FindAll();

long maxDays = 0;
if (results.Count >= 1)
{
    Int64 maxPwdAge = (Int64)results[0].Properties["maxPwdAge"][0];
    maxDays = maxPwdAge / -864000000000;
}

mySearcher = new DirectorySearcher(root);
mySearcher.Filter = "(&(objectCategory=user)(samaccountname=" + userID + "))";

results = mySearcher.FindAll();
long daysLeft = 0;
if (results.Count >= 1)
{
    var lastChanged = results[0].Properties["pwdLastSet"][0];
    daysLeft = maxDays - DateTime.Today.Subtract(
        DateTime.FromFileTime((long)lastChanged)).Days;
}

Since a user couldn't log in if it's account has expired, I am guessing my error is in calculating the days left until account expires...but I can't seem to find where it is.

relysis
  • 1,065
  • 1
  • 14
  • 27
  • 1
    Can you verify that `maxDays` is calculated correctly? For example, 0xFFFFE86D079B8000 should resolve to 30. – Alexey Jan 12 '16 at 10:58
  • 1
    @Alexey maxDays is calculated correctly. In fact the whole snippet is correct, but I had lost one thing from sight, the fact that there is a flag in useraccountcontrol - DONT_EXPIRE_PASSWORD that was checked and I didn't verify it. Your comment and below snippet made me reach that conclusion, so thanks a lot! – relysis Jan 12 '16 at 14:47

3 Answers3

1

This snippet works correctly, I have three days left to change my pw, including today:

    public static void Main(string[] args)
    {
        const ulong dataFromAD = 0xFFFFE86D079B8000;
        var ticks = -unchecked((long)dataFromAD);
        var maxPwdAge = TimeSpan.FromTicks(ticks);

        var pwdLastSet = new DateTime(2015,12,16,9,19,13);

        var pwdDeadline = (pwdLastSet + maxPwdAge).Date;

        Console.WriteLine(pwdDeadline);

        Console.WriteLine(pwdDeadline - DateTime.Today);

        Console.ReadKey(true);
    }

I also verified that TimeSpan.FromTicks(-(long)results[0].Properties["maxPwdAge"][0]) and DateTime.FromFileTime((long)results[0].Properties["pwdLastSet"][0]) are expressions correctly extracting the values from our AD.

Alexey
  • 1,354
  • 13
  • 30
0

I've used the following code in the past, and i think it's accurate. You may try it and see if it works for you:

    private static DateTime? getPwdExpiration(string usuario)
    {
        DirectoryEntry searchGroup = new DirectoryEntry("LDAP://ldapUrl");
        DateTime? dt=null;
        foreach (DirectoryEntry user in searchGroup.Children)
        {
            if (user.InvokeGet("userPrincipalName") != null)
            {
                string username = user.InvokeGet("userPrincipalName").ToString();
                username = username.Substring(0, username.IndexOf('@'));
                if (username == usuario)
                {
                    if (user.InvokeGet("PasswordExpirationDate") != null)
                    {
                        dt = (DateTime)user.InvokeGet("PasswordExpirationDate");
                        if (dt.Value.CompareTo(new DateTime(1970,1,1))==0)
                        {
                            //Password never expires
                            dt = null;
                        }
                    }
                    break;
                }
            }
        }
        return dt;
    }

Usage:

DateTime? expirationDate = getPwdExpiration(username);
Pikoh
  • 7,582
  • 28
  • 53
-1

With Node JS you can achieve the password expiry. Try Something like this

const modifyChange = [
        new ldap.Change({
            operation: 'replace',
            modification: {
                pwdMaxAge: 3600 //in seconds
            }
        })];
client.modify('cn=Manager,dc=mydomain,dc=local', modifyChange, (err) => {
       if(!err) {
            console.log('password age updated')// updated
        }
    });