CABEM has a customer who uses Active Directory internally to authenticate users. A web application we wrote for them ties into their Active Directory setup using LDAP to authenticate internal users to the application, using their email as a login name.
The adLDAP PHP class makes that pretty easy, we just look for the user name matching the email address, then authenticate as that user. They have recently switched to a setup with multiple sub-domains, requiring the application to authenticate across the sub-domains. I found very little on using adLDAP or LDAP in general to authenticate in a multi-domain environment, so I'll document some of what I found here.
Within a single domain, any domain server can answer a query because they synchronize information with each other. The reason for using sub-domains is because the link between the sub-domains is assumed to be too slow to keep domain controllers in sync. Only information in Active Directory's Global Catalog are shared across domains.
Our client has configured Active Directory to put all their internal users into the Global Catalog. That way a user visiting a remote site will be able to log in to any windows machine. The login may take a little longer, but travel to a remote site are uncommon. To reduce the amount of information that needs to be shared between sites, not all user attributes are made global.
The first problem we ran into is that email addresses were not being made global. As a result email lookup failed outside the user's home domain. The straightforward way to fix the problem is to mark the email address as a global attribute.
The other issue is more subtle. The adLDAP library authenticates users by trying to bind to the server as the user. Active Directory expects the user name to be either an LDAP Distinguished Name or a User Principal Name. The distinguished name explicitly calls out information about the user. A typical name would be something like "OU=users, OU=accounting, cn=Bob Smith, dc=carolina, dc= example, dc=com" identifying a user named Bob who works in accounting at the Carolina office of example.com. The DN's are pretty cumbersome, and likely to change if Bob ever moves to a different location.
The User Principal Name can be formed by concatenating the user's Active Directory name to an '@' followed by the DNS domain name of his or her home domain server. In this case it would probably look something like "BSmith@carolina.example.com". Though, this looks like an email address, it is not necessarily. The company we are working with uses a convention that would make Bob's email address be "bob.smith@example.com".
Active Directory generally does not allow anonymous access, for security reasons. Since a single connection with adLDAP might deal with several users, adLDAP conveniently stores the sub-domain name in its
account_suffix
attribute. However, the account used to get Active Directory listings only exists in one sub-domain and the adLDAP::authenticate
method binds as both users within the same method call.The solution is to set
account_suffix
to the empty string and pass the full User Principal Name rather than just the SAM Account Name to adLDAP::authenticate
. Not using the account suffix really is not any more work. The code calling adLDAP just needs to as for userprincipalname
rather than samaccountname
.As is often the case, once you know what to do it's easy. It's figuring out what to do that is difficult.
No comments:
Post a Comment