This post is part of the “ITworks Design Journal” series.
Where I work, we authenticate against an Active Directory server. In an effort to help the consolidation of usernames and passwords, I decided that users of the ITworks app should also authenticate against the AD, and that the user’s role, or permissions, in the app should be determined by groups they are members of in the directory. A bonus advantages of this system is that I don’t have to design any sort of user management piece!
I developed a very simple class, LdapUser, that logs into the AD with a privileged user and search for a user with a sAMAccountName that is the same as what the user entered in the login dialog:
If found, the class attempts to re-bind to the server with that user’s name and the password they entered. If successful, the user entered valid AD credentials. The class then queries the server for an array of groups the user is in, and checks against a known list of valid groups.
If found, the server returns some JSON indicating the user’s proper name, access level, and session-specific API key.
API Key
In order to insure that request for information is coming from a user that has successfully authenticated, every user that logs in is given an API key that is valid until their session ends. Every time the client requests information from the server, the API key must be passed, and is validated against the one the server generated when the user first logged in.
Login Throttling
One thing I was concerned about was brute-force attacks on the site. Since we authenticate against our AD server, it would be a bad thing™ if someone was able to brute-force their way into an IT staff member’s password. Thus, a login throttling system was born.
The system I designed is very simple–it limits unsuccessful login attempts on a specific user. Each time an invalid username and password combination is entered, that username’s "incorrect login count" is incremented in the database. Depending on how many bad login attempts have been recorded, subsequent attempts will issue an error message that the user must wait before logging in again. (I considered making the server thread sleep() for a while, to make it more frustrating, but I feared that the potential to consume a large number of threads was too high, effectively increasing vulnerability to a DoS attack). The time required gets exponentially longer as the number of attempts increases.
Once a user enters a correct username and password (assuming they are not currently in the "wait" period triggered by multiple incorrect combos), their count is reset to zero.
Again, the system is simple, but provides enough security for basic brute-force attacks–which was the goal.
Conclusion
In the end, I ended up with a simple authentication script that authenticates against Active Directory and prevents basic brute-force password hacking. The system works fairly well–if anyone sees any flaws in my logic, or has any comments, please do not hesitate to comment below!
#1 by Matthew Morgan - April 2nd, 2009 at 08:22
Does php have a built-in api for AD, or did you have to use some third party thing?
The whole idea of this system is perfect. The possibility of implementing something like this is one of the strengths AD has over the workgroup network design.
#2 by Brandon Tilley - April 2nd, 2009 at 14:43
AD is a type of LDAP, so I can use PHP’s built-in LDAP functions.
It really does have some strengths; but, like anything, it has its downsides too.
#3 by Matthew Morgan - April 6th, 2009 at 05:02
I was wondering if that was it.