- AdminUser (representing a user of the administrative portal)
- AdminRole (a named entity representing a mapping of AdminUser to multiple AdminPerssions)
- AdminPermission (a named entity representing a specific Broadleaf permission)
The answer goes back to Spring Security. Spring Security provides an LDAP module. It also provides an extension to specifically deal with Active Directory. It is a simple matter of configuration to secure the application with Spring Security and Active Directory. However, we need the principal and roles that are returned from LDAP to map to Broadleaf-specific users. In order to facilitate this, Broadleaf has implemented a bean called BroadleafActiveDirectoryUserDetailsMapper and a Servlet Filter called AdminExternalLoginStateFilter. These beans provide a hook for Spring Security to authenticate against LDAP, map the appropriate user details and roles, look up the local admin user from the Broadleaf database and map the roles (or Granted Authorities) from Active Directory to Broadleaf-specific role, and provision a user record in the Broadleaf database if one does not exist.
Assuming a successful login, after authentication, the BroadleafActiveDirectoryUserDetailsMapper, will map the roles to the authenticated user. It will also create a new instance of BroadleafExternalAuthenticationUserDetails (which extends Spring's UserDetails) and set that as the details of the Authentication object. This allows us to pass some extra information to Broadleaf like first name, last name, email, etc. After authentication, the AdminExternalLoginStateFilter will take the Authentication object from Spring, associated with the current user, and:
There are some configuration options for this to control how this happens. In the application context file that defines security in Broadleaf (typically /WEB-INF/applicationContext-security.xml), we have three main beans that we need to change:
<bean id="blUserDetailsMapper" class="org.broadleafcommerce.profile.core.security.ldap.BroadleafActiveDirectoryUserDetailsMapper">
<property name="useEmailAddressAsUsername" value="true"/>
<property name="roleNameSubstitutions">
<map>
<entry key="Marketing_Admin" value="ADMIN,CRM"></entry>
</map>
</property>
</bean>
<bean id="adAuthProvider" class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
<constructor-arg value="mycompany.com"/>
<constructor-arg value="ldap://ldap.mycompany.com:389/"/>
<property name="userDetailsContextMapper" ref="blUserDetailsMapper"/>
<property name="useAuthenticationRequestCredentials" value="true" />
<property name="convertSubErrorCodesToExceptions" value="true" />
</bean>
<sec:authentication-manager alias="blAuthenticationManager">
<sec:authentication-provider ref="adAuthProvider" />
</sec:authentication-manager>
First, the blUserDetailsMapper is a custom Broadleaf hook that Spring LDAP invokes to provide custom functionality to map the user details. Typically there will only be one of these types of beans configured in an application. The "useEmailAddressAsUsername" property, if set to true, tells this component to use the "mail" attribute returned from LDAP as the user name rather than the user name returned from LDAP. This may be useful if you want to use email addresses as username identifiers in Broadleaf, regardless of the Active Directory user name. If set to false, the AD username will be used as the principal. The "roleNameSubstitutions" property is a map that allows you to override Granted Authorities from LDAP with more appropriate authorities in Broadleaf. In this example, if AD returns a Granted Authority of "Marketing_Admin", then the authorities presented to Broadleaf will include "ADMIN" and "CRM". Of course, the "ADMIN" and "CRM" roles need to be configured in the "BLC_ADMIN_ROLE" table.
Next, the bean named "adAuthProvider" is a standard Spring LDAP configuration. For more information on configuring Spring LDAP, look here. This bean is an authentication provider that knows how to talk to an Active Directory server, and specifically allows you to use authentication request credentials to bind to the AD server. It also allows mapping of specific Active Directory error codes to friendlier exceptions.
Finally, the configuration for the authentication-manager sets up a Spring authentication manager, which will use the "adAuthProvider" bean to do the authentication. All other configurations are standard Spring Security configurations. Check the documentation for more information on configuring Spring Security.
The "blAuthenticationManager" is a standard Spring Security component that allows for a number of AuthenticationProviders. In this case, we specify that the ActiveDirectoryLdapAuthenticationProvider is the only authentication provider to use. Spring will now delegate all username/password authentication requests to this Authentication Provider.
So, to recap the process, here's how it all works:
- Look up the user, by user name, from the database
- Create a new user if one does not exist
- Set the properties from the BroadleafExternalAuthenticationUserDetails
- Delete any roles that were associated with the user at last login
- Assign new roles to the user based on their current authentication
There are some configuration options for this to control how this happens. In the application context file that defines security in Broadleaf (typically /WEB-INF/applicationContext-security.xml), we have three main beans that we need to change:
<bean id="blUserDetailsMapper" class="org.broadleafcommerce.profile.core.security.ldap.BroadleafActiveDirectoryUserDetailsMapper">
<property name="useEmailAddressAsUsername" value="true"/>
<property name="roleNameSubstitutions">
<map>
<entry key="Marketing_Admin" value="ADMIN,CRM"></entry>
</map>
</property>
</bean>
<bean id="adAuthProvider" class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
<constructor-arg value="mycompany.com"/>
<constructor-arg value="ldap://ldap.mycompany.com:389/"/>
<property name="userDetailsContextMapper" ref="blUserDetailsMapper"/>
<property name="useAuthenticationRequestCredentials" value="true" />
<property name="convertSubErrorCodesToExceptions" value="true" />
</bean>
<sec:authentication-manager alias="blAuthenticationManager">
<sec:authentication-provider ref="adAuthProvider" />
</sec:authentication-manager>
First, the blUserDetailsMapper is a custom Broadleaf hook that Spring LDAP invokes to provide custom functionality to map the user details. Typically there will only be one of these types of beans configured in an application. The "useEmailAddressAsUsername" property, if set to true, tells this component to use the "mail" attribute returned from LDAP as the user name rather than the user name returned from LDAP. This may be useful if you want to use email addresses as username identifiers in Broadleaf, regardless of the Active Directory user name. If set to false, the AD username will be used as the principal. The "roleNameSubstitutions" property is a map that allows you to override Granted Authorities from LDAP with more appropriate authorities in Broadleaf. In this example, if AD returns a Granted Authority of "Marketing_Admin", then the authorities presented to Broadleaf will include "ADMIN" and "CRM". Of course, the "ADMIN" and "CRM" roles need to be configured in the "BLC_ADMIN_ROLE" table.
Next, the bean named "adAuthProvider" is a standard Spring LDAP configuration. For more information on configuring Spring LDAP, look here. This bean is an authentication provider that knows how to talk to an Active Directory server, and specifically allows you to use authentication request credentials to bind to the AD server. It also allows mapping of specific Active Directory error codes to friendlier exceptions.
Finally, the configuration for the authentication-manager sets up a Spring authentication manager, which will use the "adAuthProvider" bean to do the authentication. All other configurations are standard Spring Security configurations. Check the documentation for more information on configuring Spring Security.
The "blAuthenticationManager" is a standard Spring Security component that allows for a number of AuthenticationProviders. In this case, we specify that the ActiveDirectoryLdapAuthenticationProvider is the only authentication provider to use. Spring will now delegate all username/password authentication requests to this Authentication Provider.
So, to recap the process, here's how it all works:
- User browses to login page
- User submits username and password
- Spring Security delegates to the ActiveDirectoryLdapAuthenticationProvider
- If authentication is successful, Spring delegates to the BroadleafActiveDirectoryUserDetailsMapper to map the specific user details and roles from LDAP to a Broadleaf Principal
- The AdminExternalLoginStateFilter queries the Spring Security API, retrieves the BroadleafExternalAuthenticationUserDetails, creates a new Broadleaf Admin User if one doesn't exist, deletes all existing roles and permissions if one does exist, and then creates new roles and permissions based on the most recent LDAP credentials
Of course, this functionality is especially suited for use with Admin Users. Many companies will want their internal administrators' credentials stored in LDAP, and their customer profiles stored directly in Broadleaf's tables. That said, there is currently no functionality to update the LDAP server or create new users in LDAP from within Broadleaf. As for using this approach with customers, it is almost the same setup. The only changes would be that the roles would be mapped differently, and that the a different Servlet Filter would have to be created, similar to the AdminExternalLoginStateFilter, to provision a new Customer in the Broadleaf database if one didn't exist.
Because Broadleaf uses Spring Security, which is a pluggable security model, and because Broadleaf allows you to override and control the components and configurations, you can effectively use any security mechanism that you like. I've discussed using LDAP and Active Directory here. However, using a similar approach, custom security, single sign on, or almost any other authentication mechanism can be used with Broadleaf.
Because Broadleaf uses Spring Security, which is a pluggable security model, and because Broadleaf allows you to override and control the components and configurations, you can effectively use any security mechanism that you like. I've discussed using LDAP and Active Directory here. However, using a similar approach, custom security, single sign on, or almost any other authentication mechanism can be used with Broadleaf.