While trying to troubleshoot some application issues using SSL to connect to an ADLS/ADAM instance over LDAPS, I was curious if extended logging was available. A quick post to the ActiveDir.org mailing list provided this nugget of Active Directory goodness for future reference.
I tend to run into many JAVA coded applications which are coded simply for LDAP access, but do not utilize Active Directory as well as they could be. Here are some resources JAVA developers can utilize to create more effective integrations.
I came upon a blog post on Scott Lowe’s blog suggesting a solution to resolve AD integration issues where more than 1,000 results are returned in a query on some UNIX/LINUX systems. I will try to explain why this is a less than optimal solution, which could cause performance issues with the directory server.
What is MaxPageSize, and how does it affect me?
The problem at hand is, that certain LDAP clients can only receive the first 1,000 results when they make an LDAP query to Active Directory, when more results exist that satisfy the query scope. If there are 1,200 results to be returned, the client will receive the "Size Limit Exceeded" error when the paging control is not used.
The default LDAP Policy settings for Active Directory limit the amount of results returned in a single page to 1,000 results. So clients that do not implement paging support, will only be able to retrieve the first page of 1,000 results.
Microsoft lists MaxPageSize as:
MaxPageSize – This value controls the maximum number of objects that are returned in a single search result, independent of how large each returned object is. To perform a search where the result might exceed this number of objects, the client must specify the paged search control. This is to group the returned results in groups that are no larger than the MaxPageSize value. To summarize, MaxPageSize controls the number of objects that are returned in a single search result.
Default value: 1,000
What is Paging Support?
LDAP was designed with extensibility in mind, allowing for controls and extensions to be implemented to enhance the functionality of the directory. Active Directory (ADDS and ADLDS) is a LDAP v3 compliant directory, which implements the LDAP Control Extension for Simple Paged Results Manipulation (RFC2696).
This control extension allows the client to make a query to the LDAP server, inspect the first page of data, and be told the entire result set count. The client can process the results, and request the next page of results until all results are complete. This prevents a query which matches a large set of objects, from returning more results than the client is prepared to handle, and also protects the server from returning large result sets as a single operation.
Microsoft also lists these as benefits of using paging:
- Lower network traffic
- The client can be more responsive to the user because the client returns only one page of data rather than all of the data in the result set.
- Fewer resources are needed by the client and server
- The client can abandon the search before completion
I suppose a good way to explain it is, a throttle control the client has in retrieving the results that satisfied the query. The client processes the first page of results, then makes a request for the next page from the server when the client is ready.
Should I change the Default Value to a higher value?
A common request from application owners which either do not enable paging, or are using an LDAP library which does not implement paging, is why can’t we just increase the MaxPageSize to a higher number?
My first reaction is, if 1,000 is not enough, what is the right number it should be? 1,001 or maybe 5,000? What if you still have 5,001 results in your query?
For example, IBM recommends changing the MaxPageSize to 100,000 since their Lotus Sametime product does not support paging. This would pretty much nullify paging ability except in the largest of directories, since most queries would not return a result set this large. Yet, what if 100,001 results existed that you wanted to retrieve without receiving the "Size Limit Exceeded" error?
Unfortunately many applications seem to think it’s a good idea to alter the entire infrastructure because the application does not support paging, which I feel is a bad design concept.
For some queries, 2,000 is enough, while others it is still not large enough to return all the satisfying objects.
It becomes a moving target as application needs and populations change within the directory. If you change it for one application, how do you satisfy all applications without adversely affecting the server?
Query policies are effective for the entire server, so any every LDAP query will return results with the maxPageSize. It is not on a per user, or client server basis, but can be applied at the Forest, Site or Domain Controller level.
By increasing the maxPageSize to satisfy the application, you risk the chance of overloading the server which could yield a self induced denial of service as the server responds to queries.
So if I shouldn’t increase MaxPageSize, what can I do to get all the results?
I hope I have swayed some readers from increasing the default value, but unfortunately this does not resolve the application issue at hand.
So instead of changing the value here are some suggestions to attempt to return the entire results for the application.
- Implement Paging Support in the application – This seems like the most obvious, as if you can utilize paging on the application client you will be able to return the complete result set without adversely affecting the AD server. I tried to provide links below which might help application developers. It might be possible that the application already supports paging, but it is not enabled by default, so consult your application developer as well.
- Refine your Query to return less results - Evaluate the query attempted and see if it can be refined to return a smaller, more exact, set of results which may be under the MaxPageSize. Instead of looking for all the "John Smith"’s, maybe also ask for the John Smith’s in a specific OU subtree, or with more specific attributes like location or country. This is not always possible especially in large directories where the intention is to return a broad scope of objects.
- Isolate your problem applications – The LDAP query policies are defined on the Forest, Site, and Domain Controller scope. So you can specify an LDAP query policy in an isolated site or specific server you have setup just for the applications which do not utilize paging. You can increase the MaxPageSize values for these specific instances, without affecting all of your instances. This does not insulate the server from having performance issues, but it can isolate other applications and NOS services from being affected. If possible also remove it’s SRV records so other clients cannot discover it for other services.
If you can think of any other potential work around’s when paging is not supported on the application, please let me know within the comments.
While reading about some of the new enhancements in Windows Vista, this struck me as a potentially useful feature.
Essentially, it provides a way to display certain logon statistics to the logged on user after a successful interactive logon to the workstation.
These statistics include:
- Date and time of the last successful logon by that user
- Date and time of the last unsuccessful logon attempt with the same user name
- The number of failed logon attempts since the last successful logon with the same user name
I believe the purpose is to make the end user aware that someone/something is attempting to use their credentials with the user’s knowledge if it doesn’t match their known personal usage history. This could alert the user to someone who might be using their account without their knowledge, and make them aware of such activity. This information has always existed in Active Directory in various attributes, but it’s not easily visible to an end user for them to compare to their own usage.
Unfortunately, this feature is only available when using a Vista machine, which is authenticating to a Windows 2008 Functional Level Domain. If this setting is on, and the domain is not in Windows 2008 mode, it will block the user from being able to logon since this information is not available in the domain to be retrieved by Vista. The message given to the user will be "Security policies on this computer are set to display information about the last interactive logon. Windows could not retrieve this information. Please contact your network administrator for assistance". An example of this can be found here.
When the forest is prepped for the Windows 2008 schema extensions, the previous logon information will be stored in the following new attributes to be used by Vista:
In order to allow this information to be recorded, a specify GPO must be set on the domain controllers to preserve this information.
Computer ConfigurationAdministrative TemplatesWindows ComponentsWindows Logon OptionsDisplay information about previous logons during user logon = ENABLED
Information can be collected for administrative use, and not have the Vista client enabled to display it as well, but having the Vista GPO not configured or disabled.
This feature also has the potential to cause fear and confusion to your end users, as they may not remember the last time they miss-typed their password, and may interpret the statistics as a security issue. I also can see how this would be seen as a user hindrance, and users would just clicking through it while ignoring the information. I am also not sure what kind of training, as suggested by the MS link, would be adequate at quelling false alarms, but still add value at identifying potential attacks. I suppose if you could also provide some help text to convey to the user who is logging in instructions, it might be more useful.
You can see a screen shot of what the post logon dialog box that displays the information here
You will notice, that it is specific about "interactive Logon", which differentiates from the logon types available. I am going to take this as a replicated version of the lastLogon attribute based upon the attributes reference to a "C-A-D logon" which is a Ctrl-Alt-Delete logon process.
So since this is may not not record application logons which may use LDAP simple binds, more like lastLogonTimestamp, it might give limited visibility to the accounts actual usage.
I also wonder what the replication impact of this attribute will have in large environments since it doesn’t appear to have the update damper that lastLogonTimestamp has. I suppose a common user has less CAD logons in a day than application/network logons, which may not mean the attribute is updated as frequently to be replicated compared to lastLogonTimestamp. But if so, why not have just replicated the original lastLogon in windows 2000?
I guess I will see more once I play with this in the lab, but overall adding the ability to better track account usage is definitely a good thing.
A friend pointed out that the Active Directory specifications are available online for those who have ever wanted to down to the details on the protocols used.
As he said “…all of it downloadable for personal reading pleasure”.
In a discussion on the ActiveDir.org mailing list today, it came up about searching Active Directory in Windows. From a Windows 2000, or Windows XP, this can be done from the start menu Find People dialog, but in Windows Vista this feature appears to be completely absent. The new search feature does not have a "Find People" function.
According to this article, based on a pre-release version of Vista, it does appear that searching Active Directory was built into the network explorer, but this feature does not seem to exist on my Windows Vista Enterprise x64 SP1 machine. So either this feature was removed prior to release, or I do not have this enabled. I imagine there maybe a group policy or registry key to allow this, but I have not been able to find one as of yet. I also thought that maybe something in Network explorer checks my network to see if an Active Directory server exists before making the option available, which may being blocked by a client firewall, but no luck.
So why would you want to search Active Directory from within Windows? One of the benefits is easy access to information stored within Active Directory, but it also served as a very simple self service update utility for contact information for end users. The defaultSecurityDescriptor for the user object in a new domain allows the SELF (the user account) the ability to read/write phone and contact via the Write Personal information, and the Write Phone and Mail options ACL.
A user could lookup his account in AD, and update his phone and contact information since by default he has the ability to modify these properties on his own account. Of course this was a free form update, so no data validation is done upon the update leaving a wide margin for error or garbage data entry.
This could be done through the Windows Address Book (wab.exe), which you could tell to search Active Directory for people which was a simple interface for LDAP searches. In Windows Vista, wab.exe directs you to Windows Contacts, which does appear to have the ability to search external directories.
Also this could be done on previous versions of Windows if you had the Administrative Tools (Adminpak) installed, and used the Active Directory Users and Computers to browse and search. The new Remote Server Administration Tools (RSAT) should be released soon now that SP1 is available, but this not something you would want to deploy to end users.
So I am left wondering if the Search Active Directory feature exists for me, or if somehow I have it disabled and can’t figure out how to enable it. I see references to "Search Active Directory" in the MUIcache registry keys suggesting the feature is in the network explorer, but no luck on finding it on this machine. If this feature was removed prior to release, then why?
Overall I wouldn’t recommend using the self update without better data controls such as with a web based self update tool, but if someone is used to using the Find People to manage their AD properties, this could be a feature they may miss. If you know how to enable this feature, please let me know so I can give up on trying to find it. I’m sure it’s something so obvious that I’ll feel dumb, but at least I would know
It appears that the "Find People" dialog is included in the Windows Mail client in Windows Vista. This does seem like an obscure place for this to exist since I don’t think many users within an enterprise with AD would be using Windows Mail. However it appears you can open the "Find People" dialog outside of Windows Mail by using the "/Find" command argument of wab.exe (wab /Find). Thanks to Michael Smith for pointing this out for me.
Another interesting thing, is that the "Search Active Directory" function appeared when I was on the same local LAN as my Active Directory, but did not appear when I had logged into my cached credentials and then opened up a RAS connection to the network.
Recently I was looking to help an application built on ColdFusion’s CFLDAP module, which relied upon LDAP for “authentication”, and could only be used with simple binds as a mechanism for presenting a username/password.
I am working ain a multi-forest, and multi-domain environment, to which I try to minimize the number user accounts needed by applications to access resources across the domain/forest boundary. LDAP using a SASL bind has the ability to use protocols which can walk the trust model, but unfortunately many applications never implement the SASL ability and rely on SIMPLE binds to “integrate” into Active Directory which do not have this ability.
I know that I can logon with a user’s UPN value via a simple bind to/from any domain in the same forest, but what about cross forest? Unfortunately in testing this, it does not appear to be possible and I am assuming due to how the simple bind finds the user principle in the directory to authenticate as.
If I am user1@DomainA.ForestA.com and I try to authenticate to DomainB.ForestB.com via a simple bind, it does not work. I thought that maybe adding crossRef objects to each forest pointing to each other might offer this ability, but this is also not the case. There are Kerberos Name Routing records you can set on a Forest trust, which I thought might enable this scenario, but these do nothing for simple binds as well.
So to sum it up, from what I can tell here are the scenarios that work and don’t work and I an assumption as too why when using the UPN. In the scenario a 2-way Forest trust exists between 2 forests
|user1@DomainA.ForestA.com||DomainA.ForestA.com||Success||Local Domain User|
|user1@DomainA.ForestA.com||DomainB.ForestA.com||Success||I am going to assume there is a search done on the Global Catalog to resolve the user|
|user1@DomainA.ForestA.com||Domain1.Forest1.com||Failure||The Simple bind cannot resolve the user across the forest boundary.|
|user2@Domain1.Forest1.com||DomainA.ForestA.com||Failure||The same as above, but in reverse.|
Unfortunately this is yet another example of how reliance on Simple LDAP binds for integration in complex directory environments break down, yet many applications still rely on them for enterprise integration. This leads to potential workaround infrastructure solutions such as aggregated directories and virtual directories to avoid needing multiple redundant accounts. Thanks for the insight to those on DirectoryProgramming.net forums for setting my expectations correctly that this was not going to be a valid solution to the problem.
If there are other things I overlooked which might make this a reality, please go ahead and drop me a line in the comments.
There appears to be a scenario where you might have a success based on the displayName, as per this conversation.
I had an interesting afternoon today, trying to identify an issue that occurred while working on a user migration project. This is a solution I have used for many apps that only support a single Domain/Naming context when in a distributed directory environment. The benefits and issues with this for long term use will be for another post all together.
Some background on the plan, is that due to an acquisition, there is a planned migration from a legacy Active Directory domain, into a new Active Directory forest/domain. Ultimately we want to use the same username from the OldDomain in the NewDomain, so that the user experience for the applications are pretty seamless to the users of the applications. Many of these applications only require a username and a password which is used to BIND to an LDAP directory for a success/failure status, and then a possible query for any user metadata or groups.
Things to note:
- A single Big Bang migration is not possible, and needs to be a phase migration of users
- Many applications only support a simple BIND to a single LDAP directory
- Users are domains in different forests (Sorry, no GCs )
- User Names are unique between OldDomain and NewDomain
During this migration period, applications will need to authenticate and do LDAP queries for user information, but many of the applications only support 1 domain/Naming context. They also only support Simple LDAP binds, and rarely a SASL bind among them.
One of the solutions for these single NC dependent applications, was to utilize Identity Life Cycle Manager (ILM) and Active Directory in Application Mode (ADAM) to give these applications the ability to authenticate users from multiple domains, but still provide a single BIND point.
This can be accomplished by using ILM to import the user data from OldDomain and NewDomain, and provision userProxy objects into an ADAM instance which becomes the central point of application Binding. The userProxy object (it does not need to be userProxy, it just needs to support the msDS-bindProxy aux class) does not contain a password like a normal user object, but instead proxies the simple bind authentication request to the Active Directory Domain that the userProxy is linked too. This linking is done by populating the objectSid property of the ADAM user with the SID of the parent AD user. When the SIMPLE bind to ADAM for that username, the request is sent to AD using the local Security API (More on this later). You can read more about Bind Redirection for ADAM Proxy Objects here. The benefit is that all your auditing/compliance/support is managed at the Active Directory level, and not at the ADAM level. This avoids having to sync user passwords to ADAM, and all the issues that may arise with that.
The export/provision rules from ILM to ADAM can be summarized as:
- Filter out DISABLED users from entering the Metaverse. This insures that we only have the enabled accounts, or the ones which could be used for authentication.
- If the same userName is enabled in both domains, Join on samAccountName.
- Set the NewDomain user data as a higher precedence for contribution. This means if both user accounts are enabled, the NewDomain data replaces OldDomain Data when exported to ADAM.
- The assumption is, that NewDomain accounts are to be enabled once the user has been completely migrated and is actively using the NewDomain account for primary account.
- Since ADAM is keyed on samAccountName, only one account with the same name can be in the ADAM directory at one time. The objectSid associated with that name will belong to the ENABLED account of the pair.
- The ADAM directory is in newDomain Domain.
So LDAP applications pointing to ADAM request the userName and the Password from the endUser. Users in OldDomain who are yet to be migrated continue to use their existing userName and password and authenticate against OldDomain. Users who have been migrated, and Enabled, use the same userName and password, but authenticate toward NewDomain. As long as the passwords are synced at time of Enabling the NewDomain user account, the transition can be seamless. In the end, all the users will be migrated to NewDomain, but the applications will be able to authenticate users from both domains, because they appear as single Domain when Binding.
Here is a quick example of how this works below. (I didn’t have Visio handy, so I had to user Power Point)
Now that I have tried to explain all of that (in a long winded way), let me get back to the issue that was found out today. The solution above has been working as designed with much success. It has allowed the phased migration of users while the applications can authenticate users from both domains.
Today I receive a call that all of sudden the users are getting told they cannot logon when pointing to ADAM. I quickly checked the users in ADAM and everything looked fine as far as user properties are concerned. When using this solution I find it’s helpful to flow the string value of the Domain and Username that belong to the objectSid of the userProxy object because it may not be visually evident that what the ADAM user will proxy back as. (I usually create an attribute called parentADuser for this). The user in question was showing a value of “OldDomainmyUser” since the user had not been migrated to newDomain yet, this seemed correct. So I decided to check with ADfind, and the -resolveSids switch, which will translate the objectSid to the textual representation of the domain and user that matches that objectSid. Instead of seeing “OldDomainmyUser” I now see “NewDomainmyUser”, but why?
I checked ILM and indeed the objectSid in the userProxy object was from OldDomainmyUser, but it resolved as “NewDomainmyUser”. I checked to see if the newDomain user had been enabled since that SID would take precedence in the exporting to ADAM, but it indeed was Disabled.
So the oldDomain SID now translates to the NewDomain user, which means that when an authentication request comes in, it is being proxied to the NewDomain user, which is disabled. This would explain why the user could not logon.
So why was this happening? It turns out that the migration team in an effort to pre-stage the migration had added the oldDomain SID to the sidHistory of the NewDomain user. Now since ADAM uses the LSA API’s to authenticate the userProxy object, it was sending the OldDomain SID, to the newDomain. the newDomain would realize it now has a user matching that SID (in sidHistory) and attempt to proxy the auth to the newDomain user.
The solution? Remove sidHistory from disabled user accounts in NewDomain, until the user was ready to be migrated and enabled. This means that Proxied Auth from ADAM would go to the oldDomain user account and not the disabled newDomain user account. Of course this should have been tested by the migration team earlier, but it was an interesting hour or so today as I pieced together the puzzle to find out what was going on.
So what did I learn from this situation? When using ADAM bind redirection, to remember that the authentication uses the local security API of the ADAM server. This means it will attempt to resolve the SIDs from the Domain the server belongs too. If sidHistory is contained on that user object in AD, for the SID from the foreign domain, it will authenticate to the local Domain first before going to the foreign domain. This seems very logical when you think about it, but obviously it has implications when using this solution for a migration project.
I also learned it’s quite hard to summarize everything in a single Blog post, and still have it make sense.
Comment posted by Jef
at 1/31/2008 6:10:00 PM
September 06 10:54 PM
Comment posted by (namnlös)
at 1/31/2008 3:04:00 AM
September 03 4:07 AM
Comment posted by Jef
at 6/27/2008 12:18:00 AM
June 27 12:18 PM
Comment posted by Dmitri Gavrilov [MSFT]
at 6/27/2008 11:31:00 AM
June 27 11:31 AM
Today I have to help troubleshoot another application with poor LDAP performance, so I figured I’d tag this here for later reference.
Unfortunately LDAP has become the lowest common denominator when applciations say they integrate into Active Directory for “Authentication”. It seems it’s more of a “Hey we have this feature!” more of “hey we really thought out how this will be used and put time into it to make it perform well”
This is just a post to store a good reference on Active Directory Trusts for future use.