Reputation: 356
When I try to use a custom login form with Spring Security it keeps returning me to the /admin/login page regardless of whether I enter the correct credentials or not. When I use an empty <form-login />
the security check works fine. But has soon as I add a custom <form-login login-page="/admin/login" />
I keep getting returned to the same page. I have attempted adding a default-target-url="admin/forSale" />
but I am still returned to the login page. After providing the correct credentials and being returned to the login page I attempt to access a protected url and I am returned to the login page again, therefore I am 99% sure the security check was not performed at all.
The action="<c:url value='j_spring_security_check' />"
in my jsp creates a url to http://localhost:8080/sharleepark/admin/j_spring_security_check
. I assume the filter should still pick this up and processes the security accordingly?
I am convinced there is a simple mistake in my Controller or JSP that I am not picking up. I am using Tiles2 templating as well, could this be part of the problem? I have spent a couple of days on this and tried all the spring security tutorials I can find to no avail so many thanks in advance for your help.
spring-servlet.xml
<?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:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="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-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd ">
<!-- Scans packages to auto declare the beans we require -->
<context:component-scan base-package="au.com.sharleepark.controller" />
<context:component-scan base-package="au.com.sharleepark.service" />
<context:component-scan base-package="au.com.sharleepark.hibernate" />
<context:component-scan base-package="au.com.sharleepark.helper" />
<mvc:annotation-driven />
<tx:annotation-driven />
<!-- Map our static resources to a friendly URL -->
<mvc:resources location="/static/" mapping="/static/**" />
<!-- Specify the view resolver that we wish to use -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView" />
</bean>
<!-- Tell the tiles configurator where our tiles configuration files are located -->
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tiles.xml</value>
</list>
</property>
</bean>
<!-- Our datasource -->
<!-- Defines our connection to the database -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.SingleConnectionDataSource"
destroy-method="destroy">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://blah blah" />
<property name="username" value="" />
<property name="password" value="" />
<property name="suppressClose" value="true" />
<property name="autoCommit" value="true" />
</bean>
<!-- Session Factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="au.com.sharleepark.domain" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<prop key="show_sql">true</prop>
</props>
</property>
</bean>
<!-- Data Access Objects -->
<!-- <bean id="hibernateDAO" class="au.com.sharleepark.hibernate.HibernateDaoImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean> -->
<!-- Transaction management -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- Spring exception translation post processor for the DAO layer -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
</beans>
spring-security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<http pattern="/static/**" security="none" />
<http use-expressions="true">
<intercept-url pattern="/admin/login" access="permitAll" />
<intercept-url pattern="/admin/**" access="isAuthenticated()" />
<intercept-url pattern="/**" access="permitAll" />
<form-login login-page="/admin/login" />
<logout /> <!-- Not there is currently a logout link anyway -->
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="rod" password="koala" authorities="supervisor, teller, user" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0" metadata-complete="true">
<display-name>Sharlee Park</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-security.xml
/WEB-INF/spring-servlet.xml
</param-value>
</context-param>
<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>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
adminLoginController.java (Controller)
package au.com.sharleepark.controller.admin;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
/**
* Controller class for the administration login
* @author Steve
* @version 1.00
*
* Change History
* 08/11/12 - Created
*/
@Controller
@RequestMapping(value="admin")
public class AdminLoginController {
private static final Logger logger = Logger.getLogger(AdminLoginController.class);
@RequestMapping(value="/login")
public ModelAndView doView(@RequestParam(value="error", required=false) boolean error) {
logger.info("processing Login");
ModelAndView mav = new ModelAndView();
mav.setViewName("admin/login");
if (error) {
logger.error("Invalid Credentials");
mav.addObject("error", "Invalid login credentials");
}
return mav;
}
}
adminLogin.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<div id="login">
<div id="loginContent">
<div class="error">${error}</div>
<form name='sharleeParkLoginForm' action="<c:url value='j_spring_security_check' />" method='POST'>
<fieldset>
<ul class="fieldUL">
<li>
<label class="inputLabel" for="j_username">Username</label>
<span>
<input class="inputField" type="text" tabindex="1" id="j_username" name="j_username" size="25" maxlength="25">
</span>
</li>
</ul>
<ul class="fieldUL">
<li>
<label class="inputLabel" for="spPassword">Password</label>
<span>
<input class="inputField" type="password" tabindex="2" id="j_password" name="j_password" size="25" maxlength="25">
</span>
</li>
</ul>
<ul class="fieldUL">
<li><input name="submit" type="submit" value="Login"></li>
</ul>
</fieldset>
</form>
</div>
</div>
tiles.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
"http://tiles.apache.org/dtds/tiles-config_2_0.dtd">
<tiles-definitions>
<definition name="base.definition" template="/WEB-INF/jsp/layout.jsp">
<put-attribute name="title" value="" />
<put-attribute name="header" value="/WEB-INF/jsp/header.jsp" />
<put-attribute name="body" value="" />
</definition>
....
<!-- ADMIN PAGES -->
<definition name="admin/login" extends="base.definition">
<put-attribute name="title" value="Administration Login" />
<put-attribute name="body" value="/WEB-INF/jsp/admin/adminLogin.jsp" />
</definition>
....
</tiles-definitions>
Upvotes: 5
Views: 8824
Reputation: 356
I have worked it out. What solved the problem was adding the login-processing-url="/admin/j_spring_security_check"
attribute to the <form-login>
tag. I haven't worked with Spring Security before and I guess I just assumed the filters would magically find j_spring_security_check
and process accordingly. Maybe the filters do pick it up if the j_spring_security_check
is from the root URI (ie /sharleepark/j_spring_security_check) of the application? I have never seen the need for login-processing-url
to be specified in any of the tutorials I have been looking at. Thanks again everyone for their input.
Upvotes: 0
Reputation: 1468
Generally we do not handle the /login
mapping in the controller. Spring security handles the login authentication and directs to the success Url. You can specify the view name for the login page in the spring-config.xml like this..
<mvc:view-controller path="/login" view-name="login"/>
and you can handle the success url mapping in the controller class. In this case if you specify the default-target-url="admin/forSale"
then write a method to handle the /forSale
mapping.
I think becaue you are handling the '/login' mapping in the controller its being directed to the login page for both success and failure..
ModelAndView mav = new ModelAndView();
mav.setViewName("admin/login");
But instead if there is no error then the view should be different mav.setViewName("admin/forSale")
Upvotes: 0
Reputation: 24396
Try to use <http auto-config="true" use-expressions="true">
.
From documentation about http
auto-config
attribute:
Automatically registers a login form, BASIC authentication, anonymous authentication, logout services, remember-me and servlet-api-integration. If set to "true", all of these capabilities are added (although you can still customize the configuration of each by providing the respective element). If unspecified, defaults to "false".
Upvotes: 8
Reputation: 8839
I bet something is wrong with your security configuration.
Why are you using use-expressions="true" in your http declaration? I do not see you use Spring-EL expressions... try to remove it and see if something changes.
Upvotes: 0