spring 2.0 security configuration - spring

I'm trying configure Request-Header Authentication using spring 2.0 security, and I'm a complete newbie at it so please bear with me. From the doc, they give an example config file using siteminder.
In my scenario, there will be a username and usergroup in the request header, using keys of CC_USER and CC_USER_GROUP respectively. So I adjusted the file to be as follows (see below).
I know that in the external system the user will already have been authenticated using some type of single sign on, and when control reaches my app, we just need to check the request headers for the CC_USER and CC_USER_GROUP.
Question1: The example below uses a "userDetailsService". Is this something I need to implement? Is this where I will check the request headers for CC_USER and CC_USER_GROUP?
Question2: Is there a complete example I can download somewhere that uses request header authentication? I did a lot of googling, but didn't really find a lot of help.
Question3: I would like to just harcode some dummy users in for testing, like they do in the docs. How would I incorporate the following into my request header configuration?
<authentication-provider>
<user-service>
<user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="bob" password="bobspassword" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
My modified sample config file (based on siteminder file from docs):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">
<bean id="ssoFilter"
class="org.springframework.security.ui.preauth.header.RequestHeaderPreAuthenticatedProcessingFilter">
<security:custom-filter position="PRE_AUTH_FILTER" />
<property name="principalRequestHeader" value="CC_USER" />
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<bean id="preauthAuthProvider"
class="org.springframework.security.providers.preauth.PreAuthenticatedAuthenticationProvider">
<security:custom-authentication-provider />
<property name="preAuthenticatedUserDetailsService">
<bean id="userDetailsServiceWrapper"
class="org.springframework.security.userdetails.UserDetailsByNameServiceWrapper">
<property name="userDetailsService" ref="userDetailsService" />
</bean>
</property>
</bean>
<security:authentication-manager
alias="authenticationManager" />
</beans>

UserDetailsService is just an Interface, you need to implement. It has only one method to load user from DB by username and returns UserDetails object with user info(here you can also keep the user group information). This service have nothing with request headers. I think, the best place to check the request headers - is RequestHeaderPreAuthenticatedProcessingFilter
Are you talking about RequestHeaderAuthenticationFilter? The documentation is very clearly, I think.
Hardcoded users in xml will not work if you implement own user-service

Related

Authenticating ldap user with multiple suffix value/domain

I am trying to authenticate and then query AD tree using Spring Ldap Security and Spring Ldap.
Following is my configuration file -
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:ldap="http://www.springframework.org/schema/ldap"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/ldap
http://www.springframework.org/schema/ldap/spring-ldap.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<http use-expressions="true">
<form-login login-page="/myApp/ldap" default-target-url="/myApp/ldap/config"
authentication-failure-url="/myApp/ldap?error=true" />
<logout />
</http>
<beans:bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<beans:property name="location">
<beans:value>classpath:/ldap.properties</beans:value>
</beans:property>
<beans:property name="SystemPropertiesMode">
<beans:value>2</beans:value>
</beans:property>
</beans:bean>
<beans:bean id="adAuthenticationProvider" scope="prototype"
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 index="0" value="${sample.ldap.domain}" />
<!-- an LDAP url (or multiple URLs) -->
<beans:constructor-arg index="1" value="${sample.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" />
</beans:bean>
<authentication-manager erase-credentials="false">
<authentication-provider ref="adAuthenticationProvider" />
</authentication-manager>
<beans:bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<beans:property name="location">
<beans:value>classpath:/ldap.properties</beans:value>
</beans:property>
<beans:property name="SystemPropertiesMode">
<beans:value>2</beans:value> <!-- OVERRIDE is 2 -->
</beans:property>
</beans:bean>
<ldap:context-source id="contextSource"
url="${sample.ldap.url}"
base="${sample.ldap.base}"
referral="follow"
authentication-source-ref="authenticationSource"
base-env-props-ref="baseEnvironmentProperties"/>
<util:map id="baseEnvironmentProperties">
<beans:entry key="com.sun.jndi.ldap.connect.timeout" value="60000" />
<beans:entry key="java.naming.ldap.attributes.binary" value="objectGUID objectSid"/>
</util:map>
<beans:bean id="authenticationSource"
class="org.springframework.security.ldap.authentication.SpringSecurityAuthenticationSource" />
<ldap:ldap-template id="ldapTemplate"
context-source-ref="contextSource" />
</beans:beans>
And property file is -
sample.ldap.url=ldap://xxx.xxx.xxx.xxx:3268
sample.ldap.base=dc=example,dc=com
sample.ldap.clean=true
sample.ldap.directory.type=AD
sample.ldap.domain=example.com
These setting works fine for following login -
username - example#example.com or example
Password - blah
but fails when i try -
username - example2#example.net or example
Password - blah2
These both are valid logins, and have been validated by login using AD Explorer.
Seems like i need to update my configuration to support UPN suffix/domains as default works fine and other do not.
Is there a way i can append to this config file to support this logic, supporting authenticating/querying multiple domains?
Reason it's not allowing me to login with configured UPN suffix is because ActiveDirectoryLdapAuthenticationProvider seems to be making assumption that UPN suffix is always same as Domain Name.
Please refer this post - https://github.com/spring-projects/spring-security/issues/3204
I think there should be a better way to handle this though, or maybe better library for authentication.
To explain #NewBee's solution:
1 ActiveDirectoryLdapAuthenticationProvider:
Specialized LDAP authentication provider which uses Active Directory configuration conventions.
It will authenticate using the Active Directory userPrincipalName or sAMAccountName (or a custom searchFilter) in the form username#domain. If the username does not already end with the domain name, the userPrincipalName will be built by appending the configured domain name to the username supplied in the authentication request. If no domain name is configured, it is assumed that the username will always contain the domain name.
The user authorities are obtained from the data contained in the memberOf attribute.
2 LDAP authentication in Spring Security:
Obtaining the unique LDAP Distinguished Name, or DN, from the login name.
This will often mean performing a search in the directory, unless the exact mapping of usernames to DNs is known in advance. So a user might enter his/her name when logging in, but the actual name used to authenticate to LDAP will be the full DN, such as uid=(username),ou=users,dc=springsource,dc=com.
Authenticating the user, either by binding as that user or by performing a remote compare operation of the user's password against the password attribute in the directory entry for the DN.
Loading the list of authorities for the user.
For a reference to How to configure multiple UPN Suffixes. Plus in ActiveDirectoryLdapAuthenticationProvider you could write a function for reading multiple suffixes, as the library is adaptable.

Avoid clear text passwords in JNDI datasource in Tomcat

I am using a JNDI datasource that is configured in tomcat server. I want to avoid storing the password as clear text and also i have an existing encryption logic available in the application used which i want to use to encrypt the database password.
<Resource name="jdbc/testdb" auth="Container"
factory="com.zaxxer.hikari.HikariJNDIFactory"
type="javax.sql.DataSource"
minimumIdle="5"
maximumPoolSize="50"
connectionTimeout="300000"
driverClassName="org.mariadb.jdbc.Driver"
jdbcUrl="jdbc:mysql://localhost:3307/testdb"
dataSource.implicitCachingEnabled="true"
connectionTestQuery="Select 1" />
Considering this use case and the possible solutions available online i decided to use org.springframework.jdbc.datasource.UserCredentialsDataSourceAdapter for providing the username and password for the database using the code
<bean id="dataSource1" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/testdb" />
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.UserCredentialsDataSourceAdapter">
<property name="targetDataSource" ref="dataSource1"/>
<property name="username" value="${dataSource.username}"/>
<property name="password" value="#{passwordDecryptor.decryptedString}"/>
</bean>
This approach works for me for making connections to MSSQL database but quite strangely fails on MariaDB with the error "Access denied for user ''#'localhost' (Using Password :NO)". I wonder if this issue has got anything to do with the HikariCP connection pool, as the same works with C3P0 implementation without any issues.
Also I would like to know if this is the right approach and please suggest if this can improved for getting better performance.
Ok, I've taking a peek around, give this a shot:
<Resource name="jdbc/testdb" auth="Container"
factory="org.apache.naming.factory.BeanFactory"
type="com.zaxxer.hikari.HikariDataSource"
minimumIdle="5"
maximumPoolSize="50"
connectionTimeout="300000"
driverClassName="org.mariadb.jdbc.Driver"
jdbcUrl="jdbc:mysql://localhost:3307/testdb"
connectionTestQuery="Select 1" />
What is different? We're not using the com.zaxxer.hikari.HikariJNDIFactory. Why? Because the HikariJNDIFactory uses the HikariDataSource(HikariConfig config) constructor, which immediately instantiates the underlying datasource, after which the configuration can no longer be changed.
Using the BeanFactory, we call the default constructor, which does not instantiate the underlying datasource until the first call to getConnection(), which means we are free to set the username/password after the JNDI lookup.
On the Spring side:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd">
<jee:jndi-lookup id="dataSource"
jndi-name="jdbc/testdb"
cache="true"
lookup-on-startup="true"
expose-access-context="true">
<property name="dataSourceProperties">
<props>
<prop key="user">${dataSource.username}</prop>
<prop key="password">${passwordDecryptor.decryptedString}</prop>
</props>
</property>
</jee:jndi-lookup>
I believe this should work, or something very close to it. I am going to make an addition to HikariCP too honor the passing of the JNDI environment so that <jee:environment> can be used inside of the <jee:jndi-lookup> tag for a cleaner solution.

Spring configuration issues not easy to find solution for

I have found several really awkward problems which took me 3hr+ to resolve. I was wondering if anyone could explain me why this is the case. I believe both of them belong to the very much same context so I have two questions. I hope reader will have patience as for me this is both intimidating and interesting behavior of sf.
I only know the error and resolution, but not satisfied until I understand:
Guidance I follow: Have one configuration file - use package scan inside of your root customConfig only(declared via mapping in web.xml), make sure servlet-context.xml only scans controllers' package. All other context files import via import directive at the very beginning of your customConfig.
1.1 Error if you do it other way: Dependency injection(of various components) will dramatically fail with multiple overlapping config package scanning.
1.2 Error if you do it other way: Transaction during service request of transactionManager in context with entityManagerFactory will fail if servlet-context.xml scans the same package. (i.e. same service package as your customConfig scans)
2: LocaleChangeInterceptor can only be declared in servlet-context - won't work in custom root configuration, reason unknown(doesn't work even if adding package scan for controllers package inside customConfig however now funny bit - SessionLocaleResolver on the other hand will work ok if defined in custom config! )
Q1: So it is me to blame who as human was mistakenly adding overlapping context-component package scan or it would be logical for Spring to resolve these collisions? Or they should be resolved but it doesn't work for me for some reason?
I observed fellow developer and smiled when he told it is best not to touch spring configuration nor try to improve it nor try to update it. I smiled, now I clearly don't(I now find myself intimated by this sf config violence), after all of this do you think it is ok to place everything inside just a single configuration file like servlet-context.xml ?
Q2: What is the magic behind LocaleChangeInterceptor, I've spent around 5 hours fixing it until just moved in "try-and-fail" mood it into servlet-context and it worked.
Second is a pure mystery to solve. Nothing fancy inside customConfig
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<!--
<import resource="securityContext.xml"/> -->
<import resource="jpaContext.xml"/>
<context:annotation-config />
<context:component-scan base-package="com.org.app" />
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="/WEB-INF/messages" />
<property name="defaultEncoding" value="UTF-8"/>
</bean>
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<property name="defaultLocale" value="en_GB" />
</bean>
<mvc:interceptors>
<bean
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"
p:paramName="lang" />
</mvc:interceptors> ...
After firing ?lang=locale_LOCALE request nothing will happen - no error, no indication , app will load successfully and page will just be reloaded under the same locale.
However placing this interceptor code inside servlet-context.xml below will resolve on locale request successfully.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing
infrastructure -->
<!-- Enables the Spring MVC #Controller programming model -->
<annotation-driven />
<context:component-scan base-package="com.org.app.controller" />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by #Controllers to .jsp resources
in the /WEB-INF/views directory -->
<beans:bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<interceptors>
<beans:bean
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"
p:paramName="lang" />
</interceptors>
</beans:beans>
Your LocalChangeInterceptor and LocaleResolver must be defined in the servlet-context.xml. <context:annotation-driven /> is already implied by the use of <context:component-scan />
In your root context you are also scanning for #Controller you need to exclude them.
<context:component-scan base-package="com.org.app">
<context:exclude-filter type="annotation" value="org.springframework.stereotype.Controller" />
</context:compoment-scan>
Basically all the web related things (and the things which are used by the DispatcherServlet) must be loaded by the DispatcherServlet. Due to its nature it will only look into its own local application context for the beans it needs instead of in its parents.
The reason for this is that you can have multiple DispatcherServlets each with its own configuration, this would break if it would load the configuration from the root application context.

spring security redirect by using excel hyperlink

I use Spring Security for my web application
By default, the authentication mechanism redirect the user on the "home", but it's possible to access directly to one screen of the application by its URL.
Everything is working well if you fill the URL in your web-browser.
BUT, if I have an hyperlink in Excel sheet, with the same URL, I get the login page, and then I'm forward to the "home" whereas I wanted to access my specific screen.
If I open the Excel sheet with OpenOffice, everything is working well ; as if I were filling the URL in the web browser.
Here is my configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<security:http auto-config="true" access-denied-page="/accessDenied.jsp" use-expressions="true" access-decision-manager-ref="accessDecisionManager" entry-point-ref="entryPoint">
<security:intercept-url pattern="/css/*.css" access="permitAll" />
<security:intercept-url pattern="/images/**" access="permitAll" />
<security:intercept-url pattern="/javascript/*.js" access="permitAll" />
<security:intercept-url pattern="/j_spring_security_check" access="permitAll"/>
<security:intercept-url pattern="/register.*" access="permitAll" />
<security:intercept-url pattern="/registerUser.*" access="permitAll" />
<security:intercept-url pattern="/login.*" access="permitAll" />
<security:intercept-url pattern="/restore/*" access="permitAll" />
<security:intercept-url pattern="/customer/**" access="permitAll" />
<security:intercept-url pattern="/logout.*" access="isAuthenticated()" />
<security:intercept-url pattern="/j_spring_security_logout" access="isAuthenticated()"/>
<security:intercept-url pattern="/index.*" access="isAuthenticated()" />
<security:intercept-url pattern="/admin/**" access="hasRole('ADMIN')" />
<security:intercept-url pattern="/template/*" access="isAuthenticated()" />
<security:intercept-url pattern="/editor/*" access="hasRole('EDITOR')" />
<security:intercept-url pattern="/creator/*" access="hasRole('CREATOR')" />
<security:intercept-url pattern="/task/*" access="hasAnyRole('CREATOR','EDITOR')"/>
<security:intercept-url pattern="/ajax/*" access="hasAnyRole('CREATOR','EDITOR')"/>
<security:intercept-url pattern="/**" access="isAuthenticated()" />
<security:form-login default-target-url="/index.jsp" authentication-failure-url="/login.jsp?login_error=true"/>
<security:logout invalidate-session="true" logout-url="/logout.jsp" logout-success-url="/login.jsp"/>
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="userEnvironmenttStatisticService" />
</security:authentication-manager>
<security:global-method-security secured-annotations="enabled" pre-post-annotations="enabled">
<security:expression-handler ref="expressionHandler" />
</security:global-method-security>
<bean id="userEnvironmenttStatisticService" class="com.epam.crs.security.UserEnvironmenttStatisticService">
<property name="userDetailsService" ref="userDetailsService" />
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<constructor-arg>
<list>
<ref bean="notDeletedVoter" />
</list>
</constructor-arg>
</bean>
<bean id="notDeletedVoter" class="com.epam.crs.security.NotDeletedVoter" />
<bean id="entryPoint" class="com.epam.crs.security.ParameterizedLoginUrlAuthenticationEntryPoint">
<constructor-arg value="/login.jsp"/>
</bean>
<bean id="customPermissionEvaluator" class="com.epam.crs.security.CustomPermissionEvaluator" />
<bean id="expressionHandler"
class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<property name="permissionEvaluator" ref="customPermissionEvaluator" />
</bean>
</beans>
Anybody can help me?
Maybe you have any idea how to fix it?
I got the same issue on a similar system. Here is how I fixed it and a bit more details behind my investigation.
How I fixed it for my similar app
I updated the entrypoint so it uses forwarding. Your updated code would be:
<bean id="entryPoint" class="com.epam.crs.security.ParameterizedLoginUrlAuthenticationEntryPoint">
<constructor-arg value="/login.jsp"/>
<property name="useForward" value="true" />
</bean>
Note: this requires that your entrypoint derives from LoginUrlAuthenticationEntryPoint
More details..
Typical flow of execution:
This is the typical flow of execution of a Spring Security setup like yours:
Anonymous user hits a secured page.
An AccessDeniedException is thrown and is captured by the ExceptionTranslationFilter. That filter adds the request coming from the anonymous user in the session.
The security entrypoint (that's your ParameterizedLoginUrlAuthenticationEntryPoint bean) then redirects the user to the login page. This redirection is done as a HTTP 302 redirect.
The user enters valid credentials.
The default SavedRequestAwareAuthenticationSuccessHandler is called. This handler loads the saved request (stored in the session in step 2) & redirects the user to that page (again with a HTTP 302 redirect.)
How Excel messes with that
Excel, for reasons that are out of scope, uses a simple http client before passing the url to your default browser.
That http client will pass the first url that returns a HTTP 200 code.
The http client will trigger the 3 first steps in the flow, landing on the login page.
Since the login page emits a HTTP 200, that is the url that Excel's http client will send to your browser.
The browser opens the login page, but it receives a new session id: it does not share the session cookie of Excel's http client.
When the user enters valid credentials, the SuccessHandler is called, just like in step 5, except that there is no saved request in the user's session (that saved request was saved in Excel's http client's session, not in the user's one). The handler defaults to sending the user to the default page: your home page.
Why does forwarding fixes this?
Forwarding simply handles the redirection on the server-side, excluding the browser/client from the process. So in the typical flow example, all of the redirections are done as forwards on the server-side.
Concretely, this means that the URL will not change. This allows Excel's http client to pass the right url to the browser, allowing your user to complete the 5 steps process without any hickups.
I had the same problem and for me this helped me:
http://support.microsoft.com/kb/218153
Install the Microsoft Fix it 50655:
http://go.microsoft.com/?linkid=9769998
Everything is working well if you fill the URL in your webbrowser.
BUT, if I have an hyperlink in Excel sheet, with the same URL, I get
the login page, and then I'm forward to the "home" whereas I wanted to
access my specific screen.
This is simply not determined by spring. Your URL's must be different, or you session expired.

Access a controller before authentication Spring Security

I've been trying to implement a solution for multiple login pages. I currently have a unique LoginController, and all it does is to retrieve the login jsp when somebody request /app_name/login.htm. I want that to stay that way, but also add two more locations: /app_name/customers/login.htm and /app_name/employees/login.htm each one with an individual controller CustomerLoginController and EmployeeLoginController.
So my idea is that employees access through their URL and customer using theirs, but if someone try to access the old login.htm the controller redirects him/her to their respective login using an stored cookie and customer as default.
To me it sounds good, but when I tried to access /app_name/customers/login.htm or /app_name/employees/login.htm it just redirects me to login.htm when I'm not authenticated.
I really don't know why it's not resolving them. Any opinion, suggestion, guide, tutorial, example code or link would be helpful.
The project I'm working on has this configs
Web.xml
<!-- Spring Security -->
<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>
servlet-config.xml
<!-- Controllers Mapping -->
<context:component-scan base-package="com.company.project.controllers">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
security-context.xml
<sec:http auto-config="false" entry-point-ref="authenticationProcessingFilterEntryPoint" access-denied-page="/warning/accessDenied.htm" >
<sec:intercept-url pattern="/employees/login.htm" filters="none" />
<sec:intercept-url pattern="/customers/login.htm" filters="none" />
<sec:intercept-url pattern="/login**" filters="none" />
</sec:http>
<bean id="authenticationProcessingFilterEntryPoint" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/login.htm" />
<property name="forceHttps" value="false" />
</bean>
<bean id="authenticationProcessingFilter" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
<property name="authenticationFailureUrl" value="/login.htm?login_error=1"/>
<property name="defaultTargetUrl" value="/home.htm"/>
<property name="alwaysUseDefaultTargetUrl" value="true"/>
<property name="filterProcessesUrl" value="/j_spring_security_check"/>
</bean>
PD: using Spring 2.5.4 and Spring Security 2.0.4 -_- I Know, but is a fairly sized project and it's been in production for a while
Multiple login pages can be done with 2 separate http declarations:
<http pattern="/customers/**" authentication-manager-ref="customerAuthenticationManager">
<form-login login-page="/customers/login" default-target-url="/customers" login-processing-url="/customers/j_spring_security_check"/>
<logout logout-url="/customers/logout"/>
...
</http>
<http pattern="/employees/**" authentication-manager-ref="employeeAuthenticationManager">
<form-login login-page="/employees/login" default-target-url="/employees" login-processing-url="/employees/j_spring_security_check"/>
<logout logout-url="/employees/logout"/>
...
</http>

Resources