I am trying to develop an app using Spring 3.1.1 with spring security with LDAP authentication. Also, for front-end I will use JSF 2.0 with PrimeFaces.
I have configured my LDAP server and navigation rules like so:
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/**" access="permitAll"/>
<security:intercept-url pattern="/pages/**" access="hasRole('ROLE_ADMIN')"/>
<security:form-login login-page="/login.xhtml" default-target-url="/index.xhtml"/>
</security:http>
<security:authentication-manager>
<security:authentication-provider ref = "authProvider"/>
</security:authentication-manager>
<bean id="authProvider"
class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
<constructor-arg value="xxx" />
<constructor-arg value="ldap://xxx:389"/>
<property name="userDetailsContextMapper" ref = "customUserContextMapper"></property>
</bean>
<bean id="customUserContextMapper" class="CustomUserDetailsMapper"></bean>
I have written a custom UserDetailsMapper which extends LdapUserDetailsMapper because I'm not sure where else to put a "handler" after a login is done:
public class CustomUserDetailsMapper extends LdapUserDetailsMapper{
private static final String ROLE_NORMAL_USER = "Normal User";
private static final String ROLE_ADMIN = "Administrator";
@Override
public UserDetails mapUserFromContext(DirContextOperations ctx,
String username, Collection<? extends GrantedAuthority> authority) {
UserDetails originalUser = super.mapUserFromContext( ctx, username, authority );
originalUser.getAuthorities();
Set<AndaAuthority> roles = EnumSet.noneOf(AndaAuthority.class);
roles.add(AndaAuthority.ROLE_ADMIN);
for (GrantedAuthority auth : authority) {
if (ROLE_NORMAL_USER.equalsIgnoreCase(auth.getAuthority())) {
roles.add(AndaAuthority.ROLE_USER);
} else if (ROLE_ADMIN.equalsIgnoreCase(auth.getAuthority())) {
roles.add(AndaAuthority.ROLE_ADMIN);
}
}
SecurityContextHolder.getContext().getAuthentication().getCredentials();
User newUser =
new User(
originalUser.getUsername(),
originalUser.getPassword() != null? originalUser.getPassword():"",
originalUser.isEnabled(),
originalUser.isAccountNonExpired(),
originalUser.isCredentialsNonExpired(),
originalUser.isAccountNonLocked(),
roles );
return newUser;
}
}
I have a login.xhtml page that is in the root of WEB-INF and I set is as the welcome page. here is my web.xml:
[..]
<!-- Welcome page -->
<welcome-file-list>
<welcome-file>login.xhtml</welcome-file>
</welcome-file-list>
<!-- JSF mapping -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<!-- Spring Context Configuration' s Path definition -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
/WEB-INF/spring-security.xml
</param-value>
</context-param>
[..]
<!-- Spring security related configs -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
[..]
Below is the login form:
<h:form action="j_spring_security_check" method="post">
<h:panelGrid columns="2">
<h:outputText value="Username" />
<h:inputText id="j_username" />
<h:outputText value="Password" />
<h:inputSecret id="j_password" />
</h:panelGrid>
<div class="submit">
<button type="submit" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only">
<span class="ui-button-text">Login</span>
</button>
</div>
I got the idea for the login page from this question. I am not sure how to set the action, be it j_spring_security_check or ../j_spring_security_check. I tried with both and the same result...
What happens: When I open the app in Tomcat, the login page is displayed. After I enter my credentials, I am redirected again to login.xhtml, with only the username filled in. And so on...
The login part was working when I tried it with my config in a sample Spring security LDAP integration application. There, the mapUserFromContext method was called every time. Now, the breakpoint is never entered.
Also, in the sample app - the user.password was always null and the authority list was always empty. Is that normal? Could anyone suggest a better way of overriding the normal login to know where something is broken?
The sample app was working because it was made with JSP maybe and I messed something up with JSF...
I believe it's a JSF issue from my part but can't figure out why. Also, do you have any idea how to implement a better "login success handler" for this case?
Thanks a lot