My final solution is "BookStoreDbAuthPopulator.java" implements "UserDetailsContextMapper".
public class BookStoreDbAuthPopulator implements UserDetailsContextMapper {
// populating roles assigned to the user from AUTHORITIES table in DB
private List<SimpleGrantedAuthority> loadRolesFromDatabase(String username) {
//"SELECT ROLE FROM AUTHORITIES WHERE LCASE(USERNAME) LIKE ?"
...
}
@Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {
List<SimpleGrantedAuthority> allAuthorities = new ArrayList<SimpleGrantedAuthority>();
for (GrantedAuthority auth : authorities) {
if (auth != null && !auth.getAuthority().isEmpty()) {
allAuthorities.add((SimpleGrantedAuthority) auth);
}
}
// add additional roles from the database table
allAuthorities.addAll(loadRolesFromDatabase(username));
return new User(username, "", true, true, true, true, allAuthorities);
}
@Override
public void mapUserToContext(UserDetails user, DirContextAdapter ctx) {
}
}
Then in spring-security.xml
<!-- AuthenticationManager: AuthenticationProvider, LDAP server details -->
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="ldapActiveDirectoryAuthProvider" />
</security:authentication-manager>
<beans:bean id="ldapActiveDirectoryAuthProvider" class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
<!-- the domain name (may be null or empty). If no domain name is configured, it is assumed that the username will always contain the domain name. -->
<beans:constructor-arg value="${ldap.domain}" />
<!-- an LDAP url (or multiple URLs) -->
<beans:constructor-arg value="${ldap.url}" />
<!-- Determines whether the supplied password will be used as the credentials in the successful authentication token. -->
<beans:property name="useAuthenticationRequestCredentials" value="true" />
<!-- by setting this property to true, when the authentication fails the error codes will also be used to control the exception raised. -->
<beans:property name="convertSubErrorCodesToExceptions" value="true" />
<!-- for customizing user authorities -->
<beans:property name="userDetailsContextMapper" ref="myUserDetailsContextMapper" />
</beans:bean>
<!-- Customizing UserDetail -->
<beans:bean id="myUserDetailsContextMapper" class="com.mybookstore.mywebcomp.w.BookStoreDbAuthPopulator">
</beans:bean>