The issues I have can probably be summarised as follows:
1. Ben recently suggested a move to using an LDAP template implementation internally (similar to Spring's JDBC template) to do the actual directory access work, and handle exceptions. This raises the issue of passing javax.naming.Attributes instances through our APIs, as any code enumerating these is also forced to deal with NamingExceptions. Currently the user's attributes are retrieved during authentication and returned together with the DN using an LdapUserInfo instance. They are then passed to the to the configured LdapAuthoritiesPopulator which is responsible for mapping any role attributes from the user's entry to GrantedAuthority instances.
2. Another thing which has come up is the potential use of LDAP controls as part of the authentication process, for example to access account settings (enabled/disabled etc). See
http://opensource.atlassian.com/projects/spring/browse/SEC-214
for example. The current API isn't rich enough for this kind of information to be used.
3. For some time, I've been trying to come up with a suitable balance between what's done at authentication time and what's done subsequently, and also with the possibility of using LDAP purely as a UserDetailsService, with other authentication providers.
To get round these issues, I'd like to introduce an LDAP version of the UserDetails interface, something like:
public interface LdapUserDetails extends UserDetails {
String getDn();
Attributes getAttributes();
Control[] getControls();
}
and change the authenticator interface to:
LdapUserDetails authenticate(String username, String password);
The mapping of an LDAP entry for the user's account will be handled by an LdapEntryMapper, which is supplied with the DN and attributes of the the entry (analogous to the mapping of a DB row in Spring's JdbcTemplate). A default implementation (LdapUserDetailsMapper) would be used, but users could supply a customized version or an alternative configuration of the default bean. The same mapping strategy would be used in the UserSearch interface.
The handling of role attributes from the user's entry would be dealt with in the mapper, so that the LdapUserDetails object returned from the authenticator could potentially be used directly by Acegi. The DefaulLdapAuthoritiesPopulator would then only be responsible for additional role searches (i.e. other roles which were not part of the user's entry) and an authorities populator would no longer be required as part of the configuration.
The changes should require only minimal changes for most users, unless they are using a lot of customization. I don't think many (if any) people will have written custom authenticators, so the changes there shouold be transparent. The main LdapAuthoritiesPopulator interface will probably change to
GrantedAuthority[] getGrantedAuthorities(LdapUserDetails userDetails);
Any code which wishes to use the LDAP attributes will still be able to access them via the LdapUserDetails instance. There will just (potentially) be more information available. There have also been some Jira issues raised about making the DefaultLdapAuthoritiesPopulator more extensible, e.g.
http://opensource.atlassian.com/projects/spring/browse/SEC-231
This is mainly a code reuse issue, and would probably be better served by the move to a templated implementation, rather than the introduction of additional methods. There are so many different ways that Ldap could be used that it is better to stick with a simple interface and push different utility implementations into the template class as they arise (in the issue the user would use the same template calls as the default implementation, but with different arguments). So rather than having a method to extract authorities from the user's attributes and another to do the group search, there would probably be an internal one which does the role search (the equivalent of the current "getGroupMembershipRoles()" method), and an extra one "getAdditionalRoles(LdapUserDetails)" which could be overridden to do any LdapTemplate calls that might be needed to get hold of extra roles.