Spring MVC and Security - Error 404 page not found after login - spring

I need some help with this Spring test project. I have a simple log in page with security check, Spring detect good or bed login but gives 404 Page not fount error when redirect into login-succes page or login-faild page.
Configurations are
APPLCATION CONTEXT
<!--
Most controllers will use the ControllerClassNameHandlerMapping above, but
for the index controller we are using ParameterizableViewController, so we must
define an explicit mapping for it.
-->
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="login.htm">LoginController</prop>
</props>
</property>
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" />
<!--
The index controller.
-->
<bean name="LoginController"
class="org.springframework.web.servlet.mvc.ParameterizableViewController"
p:viewName="login" />
</beans>
SECURITY
<http auto-config="true">
<intercept-url pattern="/welcome*" access="ROLE_USER" />
<form-login login-page="/login" default-target-url="/welcome"
authentication-failure-url="/loginfailed" />
<logout logout-success-url="/logout" />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="mkyong" password="123456" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
WEB.XML
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/dispatcher-servlet.xml,
/WEB-INF/spring-security.xml
</param-value>
</context-param>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>redirect.jsp</welcome-file>
</welcome-file-list>
<!-- 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>
The login controller is
#Controller
public class LoginController {
#RequestMapping(value="/welcome", method = RequestMethod.GET)
public String printWelcome(ModelMap model, Principal principal ) {
String name = principal.getName();
model.addAttribute("username", name);
model.addAttribute("message", "Spring Security Custom Form example");
return "hello";
}
#RequestMapping(value="/login", method = RequestMethod.GET)
public String login(ModelMap model) {
return "login";
}
#RequestMapping(value="/loginfailed", method = RequestMethod.GET)
public String loginerror(ModelMap model) {
model.addAttribute("error", "true");
return "login";
}
#RequestMapping(value="/logout", method = RequestMethod.GET)
public String logout(ModelMap model) {
return "login";
}
}
Where is the error? TK.

Related

Spring security error while creating bean expected single matching bean but found 2

I am trying to implementing spring security with My Rest easy web services in spring application.I tried some basic authentications and it works perfectly.Next step I tried to create custom filters My security-context.xml is
<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"
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.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<!-- SPRING SECURITY SETUP -->
<beans:bean id="userDao" class="com.cheasyy.cofinding.dao.UserDAO">
</beans:bean>
<beans:bean id="passwordEncoder"
class="org.springframework.security.crypto.password.StandardPasswordEncoder">
<beans:constructor-arg value="ThisIsASecretSoChangeMe" />
</beans:bean>
<security:authentication-manager id="authenticationManager">
<security:authentication-provider
user-service-ref="userDao">
<security:password-encoder ref="passwordEncoder"></security:password-encoder>
</security:authentication-provider>
</security:authentication-manager>
<security:http realm="Protected API" use-expressions="true"
auto-config="false" create-session="stateless" entry-point-ref="unauthorizedEntryPoint"
authentication-manager-ref="authenticationManager">
<security:custom-filter ref="authenticationTokenProcessingFilter"
position="FORM_LOGIN_FILTER" />
<security:intercept-url pattern="/loginService/authenticate"
access="permitAll" />
<security:intercept-url method="GET"
pattern="/profileService/**" access="hasRole('user')" />
<security:intercept-url method="PUT"
pattern="/profileService/**" access="hasRole('admin')" />
<security:intercept-url method="POST"
pattern="/profileService/**" access="hasRole('admin')" />
<security:intercept-url method="DELETE"
pattern="/profileService/**" access="hasRole('admin')" />
</security:http>
<beans:bean id="unauthorizedEntryPoint"
class="com.cheasyy.cofinding.util.UnauthorizedEntryPoint" />
<beans:bean
class="com.cheasyy.cofinding.util.AuthenticationTokenProcessingFilter"
id="authenticationTokenProcessingFilter">
<beans:constructor-arg ref="userDao" />
</beans:bean>
</beans:beans>
My web.xml is
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- Context Param -->
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/appServlet/servlet-context.xml
/WEB-INF/spring/appServlet/security-context.xml
</param-value>
</context-param>
<!-- Enables 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>/profileService/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<!-- This SpringCotextLoader absolutely has to come after the reasteasy
configuration -->
<listener>
<listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class>
</listener>
<!-- Servlets -->
<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
</servlet>
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value> /WEB-INF/spring/appServlet/servlet-context.xml </param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Error pages -->
<error-page>
<error-code>400</error-code>
<location>/400</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/404</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/500</location>
</error-page>
<!-- ALL NEW SERVICE PATHS MUST BE SPECIFIED HERE. WHENEVER A NEW SERVICE
IS INTRODUCED INTO THE API IT MUST BE ADDED INTO THE RESTEASY SERVLET-MAPPING -->
<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>/deal/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>securedapp</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
</web-app>
My LoginLogoutServiceImpl is
#Service
#Path("/loginService")
public class LoginLogoutServiceImpl extends BaseService {
#Autowired
private UserDetailsService userService;
#Autowired
#org.springframework.beans.factory.annotation.Qualifier("authenticationManager")
private AuthenticationManager authManager;
/**
* Authenticates a user and creates an authentication token.
*
* #param username
* The name of the user.
* #param password
* The password of the user.
* #return A transfer containing the authentication token.
*/
#Path("authenticate")
#POST
#Produces(MediaType.APPLICATION_JSON)
public TokenTransfer authenticate(#FormParam("username") String username,
#FormParam("password") String password) {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
username, password);
Authentication authentication = this.authManager
.authenticate(authenticationToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
/*
* Reload user as password of authentication principal will be null
* after authorization and password is needed for token generation
*/
UserDetails userDetails = this.userService.loadUserByUsername(username);
return new TokenTransfer(TokenUtils.createToken(userDetails));
}
}
When I run application it gives error like
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.springframework.security.core.userdetails.UserDetailsService] is defined: expected single matching bean but found 2: [loginLogoutBusinessServiceImpl, userDao]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:800)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:707)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:478)
... 25 more
Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
unique bean of type
[org.springframework.security.core.userdetails.UserDetailsService] is
defined: expected single matching bean but found 2:
[loginLogoutBusinessServiceImpl, userDao]
Looking at the error it seems there are two beans loginLogoutBusinessServiceImpl and userDao both referring implementing of the interface UserDetailsService.
Either two different classes (both spring managed) are implementing UserDetailsService or single class implementing it but configured twice as two different beans with Spring.
So spring is not able to decide which needs to be injected.
Use #Qualifer annotation in LoginLogoutServiceImpl to tell spring which one needs to be injected.
Ex:
#Autowired()
#Qualifier("loginLogoutBusinessServiceImpl") or #Qualifier("userDao")
private UserDetailsService userService;

Spring security filter blocking restful api calls

I have a web application using Spring 4. I'm using Spring security here. In the mean time I need to open a restful api with no security. Issue is till the security filter is enabled my rest rest POST calls get a 405 Method Not Allowed response(Still the GET works). In mean time server log says
.11:27:13.058 [http-bio-8080-exec-5] WARN o.s.web.servlet.PageNotFound - Request method 'POST' not supported
When I comment the security filter from the web.xml POST works fine. I tried adding following line to security xml but didn't help.
<intercept-url pattern="/rest**" access="permitAll" />
My web.xml , security filter is and the end which when commented POST start working.
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>Counter Web Application</display-name>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- Loads Spring Security config file -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/application-security.xml,
/WEB-INF/application-database.xml
</param-value>
</context-param>
<!--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>
My application-security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
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.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<security:http security="none" pattern="**/resources/**"/>
<!-- enable use-expressions -->
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/admin**" access="hasRole('ROLE_ADMIN')" />
<intercept-url pattern="/rest**" access="permitAll" />
<!-- access denied page -->
<access-denied-handler error-page="/access-denied" />
<form-login
login-page="/login"
default-target-url="/admin/dashboard"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password" />
<logout logout-success-url="/login?logout" />
<!-- enable csrf protection -->
<csrf/>
</http>
<!-- Select users and user_roles from database -->
<authentication-manager>
<authentication-provider>
<password-encoder ref="encoder" />
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="select username,password, enabled from users where username=?"
authorities-by-username-query="select username, role from user_roles where username =?" />
</authentication-provider>
</authentication-manager>
<beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="10" />
</beans:bean>
My Rest Controller. I have other controllers as well. I have just dummy date here. Tying to get things working first.
#RestController
#RequestMapping("/rest/orders")
public class OrderRestController {
#Autowired
private FoodItemService foodItemService;
#RequestMapping(value = "", method = RequestMethod.POST)
public Order addOrder(Order orderDto) {
return orderDto;
}
#RequestMapping(value = "", method = RequestMethod.GET)
public Order getOrder() {
FoodItem foodItem = foodItemService.findOne(1, Boolean.TRUE);
Order orderDto = new Order();
orderDto.setRoomId(23);
OrderItem orderItem = new OrderItem();
orderItem.setFoodItem(foodItem);
orderItem.setAmount(4);
List<OrderItem> orderItems = new LinkedList<OrderItem>();
orderItems.add(orderItem);
orderDto.setOrderItemList(orderItems);
return orderDto;
}
Issue was csrf being enabled. Should do a further research of disabling csrf and security but for the moment disabling it is the solution.
By giving a look to your controoler, it seems you have 2 methods with no value and they are trying to respond on the URL ..../rest/orders; I'd write it in this way:
#RestController
#RequestMapping("/rest/orders")
public class OrderRestController {
#Autowired
private FoodItemService foodItemService;
#RequestMapping(value = "addOrder", method = RequestMethod.POST)
public Order addOrder(Order orderDto) {
return orderDto;
}
#RequestMapping(value = "getOrder", method = RequestMethod.GET)
public Order getOrder() {
FoodItem foodItem = foodItemService.findOne(1, Boolean.TRUE);
Order orderDto = new Order();
orderDto.setRoomId(23);
OrderItem orderItem = new OrderItem();
orderItem.setFoodItem(foodItem);
orderItem.setAmount(4);
List<OrderItem> orderItems = new LinkedList<OrderItem>();
orderItems.add(orderItem);
orderDto.setOrderItemList(orderItems);
return orderDto;
}
after that, if I want to call the addOrder method I'd do a REST call to the URL /rest/orders/addOrder (using POST method), if I want to call the getOrder method, i'd do a REST call to the URL /rest/orders/getOrder. Morevoer I'd pass a parameter (orderId for example) to the getOrder method so I can load the selected order
Did you try this:
<intercept-url pattern="/rest/**" access="permitAll" />

Spring Security 3.1: after logging-out catches session expired

I'm developing a webapp with Java + Spring MVC + Hibernate + Spring Security 3.1. When I log out instead of just redirect to the log in page it goes to the session expired method so it shows the log in page but with a "Session expired!" message...
Here's security-context.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
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.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<security:debug />
<!-- preauthentication -->
<security:global-method-security pre-post-annotations="enabled">
</security:global-method-security>
<security:http auto-config="false" use-expressions="true" entry-point-ref="http403EntryPoint" access-denied-page="/errores/accesodenegado">
<security:intercept-url pattern="/" access="permitAll"/>
<security:intercept-url pattern="/error.jsp" access="permitAll"/>
<!-- Allow non-secure access to static resources -->
<security:intercept-url pattern="/resources/**" access="permitAll"/>
<security:intercept-url pattern="/autenticacion/**" access="permitAll"/>
<security:intercept-url pattern="/errores/**" access="permitAll"/>
<!-- URLs que dependen de perfiles -->
<security:intercept-url pattern="/gestion/facturas/**" access="hasAnyRole('ROLE_ADMIN','ROLE_S_CEN','ROLE_CONSL')"/>
<security:intercept-url pattern="/gestion/tarifas/**" access="hasAnyRole('ROLE_ADMIN','ROLE_S_CEN','ROLE_CONSL')"/>
<security:intercept-url pattern="/gestion/envios/**" access="hasAnyRole('ROLE_ADMIN','ROLE_S_CEN')"/>
<security:intercept-url pattern="/gestion/perfiles/**" access="hasRole('ROLE_ADMIN')"/>
<security:intercept-url pattern="/gestion/usuarios/**" access="hasRole('ROLE_ADMIN')"/>
<security:intercept-url pattern="/consulta/**" access="hasAnyRole('ROLE_CONSL','ROLE_ADMIN','ROLE_S_CEN')"/>
<security:intercept-url pattern="/importacion/**" access="hasAnyRole('ROLE_ADMIN','ROLE_S_CEN')"/>
<!-- Pantalla a la que redirige el logout -->
<security:logout logout-success-url="/" delete-cookies="JSESSIONID"/>
<!-- El session timeout lleva a la pantalla de login -->
<security:session-management invalid-session-url="/errores/sesionexpirada" />
</security:http>
<bean id="http403EntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint">
</bean>
<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
<security:filter-chain-map path-type="ant">
<security:filter-chain pattern="/**" filters="j2eePreAuthFilter"/>
</security:filter-chain-map>
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref='preAuthenticatedAuthenticationProvider'/>
</security:authentication-manager>
<bean id="preAuthenticatedAuthenticationProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService" ref="preAuthenticatedUserDetailsService"/>
</bean>
<bean id="preAuthenticatedUserDetailsService"
class="org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesUserDetailsService"/>
<bean id="j2eePreAuthFilter" class="es.myApp.security.MyAppUserJ2eePreAuthenticatedProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationDetailsSource" ref="authenticationDetailsSource"/>
<property name="continueFilterChainOnUnsuccessfulAuthentication" value="false"/>
</bean>
<bean id="authenticationDetailsSource" class="org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource">
<property name="mappableRolesRetriever" ref="j2eeMappableRolesRetriever"/>
<property name="userRoles2GrantedAuthoritiesMapper" ref="j2eeUserRoles2GrantedAuthoritiesMapper"/>
</bean>
<bean id="j2eeMappableRolesRetriever" class="org.springframework.security.web.authentication.preauth.j2ee.WebXmlMappableAttributesRetriever">
</bean>
<bean id="j2eeUserRoles2GrantedAuthoritiesMapper" class="org.springframework.security.core.authority.mapping.SimpleAttributes2GrantedAuthoritiesMapper">
<property name="attributePrefix" value="test"/>
</bean>
</beans>
The log out button calls:
#Controller
#RequestMapping("/autenticacion")
public class AutenticacionController {
[...]
#RequestMapping(value = "salir")
public String salir(Model model, HttpServletRequest request, HttpServletResponse response) {
// request.getSession().removeAttribute(Constantes.USUARIO_SESION);
// request.getSession().invalidate();
return "redirect:/j_spring_security_logout";
}
}
I tried commenting out those lines and using them, but the behaviour is exactly the same... Constantes.USUARIO_SESION stores the name of the user variable in session.
The log in method executes, among other things:
request.getSession().setAttribute(Constantes.USUARIO_SESION, usuario);
UserDetails userDetails = myAppUserDetailsService.loadUserByUsername(usuario.getLogin());
Authentication auth = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);
Session expired goes through:
#RequestMapping("sesionexpirada")
public String sesionExpirada(Model model, HttpServletRequest request, HttpServletResponse response) {
MessageManager msgManager = new MessageManager();
msgManager.addError("error.sesion.expirada");
request.getSession().setAttribute("messageManager", msgManager);
return "inicio";
}
And web.xml
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Aplicación Web MyApp</display-name>
<!-- Define la localización de los ficheros de configuración de Spring -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/classes/applicationContext.xml
</param-value>
</context-param>
<!-- Reads request input using UTF-8 encoding -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<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>
<filter>
<filter-name>myAppUserJ2eePreAuthenticatedProcessingFilter</filter-name>
<filter-class>es.myApp.security.XiscoUserJ2eePreAuthenticatedProcessingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myAppUserJ2eePreAuthenticatedProcessingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Handles all requests into the application -->
<servlet>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<servlet-class>es.myApp.controller.XiscoDispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- del. welcome files -->
<!-- useful for Servlet 3 container (Tomcat 7 and Jetty 6) -->
<welcome-file-list>
<welcome-file></welcome-file>
</welcome-file-list>
<!-- Página de error -->
<error-page>
<error-code>404</error-code>
<location>/errores/error</location>
</error-page>
<!-- Tiempo de sesión -->
<session-config>
<session-timeout>15</session-timeout>
</session-config>
<listener>
<listener-class>
org.springframework.security.web.session.HttpSessionEventPublisher
</listener-class>
</listener>
<!-- Referencia a recursos jndi WAS -->
<resource-ref id="ResourceRef_MyApp>
<res-ref-name>jdbc/myApp</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
</web-app>
I tested it on Tomcat 6 and WAS 8.5...
EDIT: If I get rid of Spring Security's logout and implement my own it works as expected:
I erase: <security:logout logout-success-url="/" delete-cookies="JSESSIONID"/> from security-context.xml and change the method that is called on logout:
#RequestMapping("salir")
public String salir(Model model, HttpServletRequest request, HttpServletResponse response) {
request.getSession().removeAttribute(Constantes.USUARIO_SESION);
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
SecurityContextHolder.clearContext();
return "inicio";
}
Why is it working now? These lines of code are taken from Spring's logout code...
You need add
<security:session-management session-fixation-protection="none"/>
to you security:http section.
I don't understand what you are trying to accomplish. You wrote your own controller that invalidates the session then redirects to the spring security logout url. The controller is unnecessary, just use the spring logout url directly, by default it will invalidate the session for you. If you need to add special behavior on logout, either write your own LogoutSuccessHandler or extend one of the spring handlers and add it to the LogoutFilter.

Spring Security not working. What am I doing wrong?

as the title implies I experience slight problems with a simple Spring Security Test. This is my project structure (maven webapp 2.5):
main
java
de
cochu
spring
controller
HomeController
webapp
WEB-INF
jsp
home.jsp
index.jsp
security-context.xml
spring-servlet.xml
web.xml
The web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/security-context.xml
</param-value>
</context-param>
<filter>
<filter-name>filterChainProxy</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>filterChainProxy</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>/spring/*</url-pattern>
</servlet-mapping>
spring-servlet.xml
<context:annotation-config/>
<context:component-scan base-package="de.cochu.spring.controller"/>
<bean id="internalViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
security-context.xml
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/**" access="ROLE_USER"/>
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="test" password="test" authorities="ROLE_USER"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
HomeController.java
#Controller
#RequestMapping( "/" )
public class HomeController {
#RequestMapping( method = RequestMethod.GET )
public String show() {
return "index";
}
#RequestMapping( value = "/secure", method = RequestMethod.GET )
public String secure() {
return "home";
}
}
The exact problem: No login form or whatsoever is opening. It just displays the page. I tried almost every url-pattern combination/intercept-url combination, but no reaction. What is wrong?
The FilterChainProxy bean is registered with the alias springSecurityFilterChain so try modifying your web.xml and change this
<filter>
<filter-name>filterChainProxy</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
to this
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
That's the config I usually use (using spring security 3.1.0.RELEASE)

Spring Security UserDetailsService Not Validating Password

I'm implementing spring security 3.0.5 and in my form based login im extending the spring UserDetailsService. Currently my login form is only validating user name and not password. Where does spring security validate the password being posted to /j_spring_security_check?
security config:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
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/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="dc" />
<global-method-security />
<http access-denied-page="/auth/denied.html">
<intercept-url filters="none" pattern="/javax.faces.resource/**" />
<intercept-url filters="none" pattern="/services/rest-api/1.0/**" />
<intercept-url filters="none" pattern="/preregistered/*"/>
<intercept-url
pattern="/**/*.xhtml"
access="ROLE_NONE_GETS_ACCESS" />
<intercept-url
pattern="/auth/**"
access="ROLE_ANONYMOUS,ROLE_USER" />
<intercept-url
pattern="/auth/*"
access="ROLE_ANONYMOUS" />
<intercept-url
pattern="/registered/*"
access="ROLE_USER" />
<intercept-url
pattern="/*"
access="ROLE_ANONYMOUS" />
<form-login
login-processing-url="/j_spring_security_check.html"
login-page="/auth/login.html"
default-target-url="/home.html"
authentication-failure-url="/login.html" />
<logout invalidate-session="true"
logout-url="logout.html"
success-handler-ref="SuccessHandler"/>
<anonymous username="guest" granted-authority="ROLE_ANONYMOUS"/>
<remember-me user-service-ref="userManager" key="dfdfdfdff"/>
<custom-filter after="FORM_LOGIN_FILTER" ref="xmlAuthenticationFilter"/>
</http>
<!-- Configure the authentication provider -->
<authentication-manager alias="am">
<authentication-provider user-service-ref="userManager">
<password-encoder ref="passwordEncoder" />
</authentication-provider>
<authentication-provider ref="xmlAuthenticationProvider" />
</authentication-manager>
</beans:beans>
beans:
<?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:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.dc"/>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="springContextHolder" class="SpringContextHolder" factory-method="getInstance" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="MYSQL" />
<property name="showSql" value="true" />
</bean>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/webapp" />
<property name="username" value="userid" />
<property name="password" value="password" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="false"/>
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="localhost"/>
<property name="port" value="25"/>
</bean>
<bean id="utilities" class="UtilitiesImpl"/>
<bean id="xmlAuthenticationFilter" class="com.dc.api.service.impl.XMLAuthenticationFilter">
<property name="authenticationManager" ref="am" />
<property name="utilities" ref="utilities"/>
</bean>
<bean id="xmlAuthenticationProvider" class="com.dc.api.service.impl.XMLAuthenticationProvider">
<property name="userManager" ref="userManager"/>
</bean>
<bean id="DCLogoutSuccessHandler" class="LogoutSuccessHandler"/>
</beans>
UserDetails Implementation:
import javax.inject.Inject;
import org.springframework.dao.DataAccessException;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.dc.api.dao.AuthorityDAO;
import com.dc.api.dao.UserDAO;
import com.dc.api.exception.ApiDataException;
import com.dc.api.exception.EmailNotFoundException;
import com.dc.api.helper.MailContentHelper;
import com.dc.api.model.Users;
import com.dc.api.model.vo.APIResponse;
import com.dc.api.service.UserManager;
import com.dc.api.service.Utilities;
#Service("userManager")
public class UserManagerImpl extends UserDetailsService {
#Inject
UserDAO userDAO;
#Inject
AuthorityDAO authorityDAO;
#Inject
PasswordEncoder passwordEncoder;
#Inject
Utilities utilities;
private void encodePassword(Users user) {
if (user.getPassword() == null && user.getRawPassword() != null) {
user.setPassword(passwordEncoder.encodePassword(user.getRawPassword(), null));
user.setRawPassword(null);
}
}
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
Users user = null;
try {
user = userDAO.findByUsername(username);
if (user != null) {
}
} catch (DataAccessException ex) {
throw new UsernameNotFoundException("Invalid login", ex);
}
if (user == null) {
throw new UsernameNotFoundException("User not found.");
}
return user;
}
public Users getUser(String username) {
try {
return userDAO.findByUsername(username);
} catch (DataAccessException ex) {
// ignore
log.warn("Duplicate username: " + username);
}
return null;
}
public boolean isUsernameTaken(String username) {
try {
if (userDAO.findByUsername(username) == null) {
return false;
} else {
return true;
}
} catch (DataAccessException ex) {
// ignore
log.warn("Duplicate username: " + username);
}
return true;
}
public boolean isLoginValid(String username, String password) throws ApiDataException {
Users user = null;
try {
user = userDAO.findByUsername(username);
} catch (DataAccessException ex) {
throw new ApiDataException("Data Access Exception while verifying login");
}
if (user == null) {
return false;
}
if (passwordEncoder.isPasswordValid(user.getPassword(), password, null)) {
return true;
}
return false;
}
#Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
public void saveUser(Users user) {
encodePassword(user);
userDAO.save(user);
}
#Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
public void updateUser(Users user) {
encodePassword(user);
userDAO.update(user);
}
#Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
public void resetPassword(String username, MailContentHelper mailContentHelper) {
String newPassword = utilities.generateSecret(8);
this.changePassword(username, newPassword, mailContentHelper);
}
#Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
public void changePassword(String username, String password, MailContentHelper mailContentHelper) {
Users user = userDAO.findByUsername(username);
user.setPassword(null);
user.setRawPassword(password);
encodePassword(user);
userDAO.update(user);
String firstName = user.getFirstName();
firstName = (firstName == null) ? user.getUsername() : firstName;
//SimpleMailMessage message = mailContentHelper.retrieveContent(new Object[]{firstName, password, user.getEmail()});
//utilities.sendMail(message);
}
}
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_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/facelet/dc.taglib.xml</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
WEB-INF/dc-context-api.xml
WEB-INF/dc-context-security.xml
</param-value>
</context-param>
<context-param>
<param-name>resteasy.resource.method-interceptors</param-name>
<param-value>org.jboss.resteasy.core.ResourceMethodSecurityInterceptor</param-value>
</context-param>
<context-param>
<param-name>resteasy.resources</param-name>
<param-value>
com.dc.web.actions.GlobalWebService</param-value>
</context-param>
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/services/rest-api</param-value>
</context-param>
<context-param>
<param-name>resteasy.media.type.mappings</param-name>
<param-value>json : application/json, xml : application/xml</param-value>
</context-param>
<context-param>
<param-name>resteasy.resources</param-name>
<param-value>
com.WebService
</param-value>
</context-param>
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>none</param-value>
</context-param>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/log4j.properties</param-value>
</context-param>
<context-param>
<param-name>log4jRefreshInterval</param-name>
<param-value>1000</param-value>
</context-param>
<context-param>
<param-name>primefaces.PRIVATE_CAPTCHA_KEY</param-name>
<param-value>6LeL-MISAAAAAG6k07ch22oy-mxXBUi1MXKmrWiD</param-value>
</context-param>
<context-param>
<param-name>primefaces.PUBLIC_CAPTCHA_KEY</param-name>
<param-value>6LeL-MISAAAAAPTK5lYI9tK0SWWY2BqC2Hun7sH3</param-value>
</context-param>
<filter>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<filter-class>org.primefaces.webapp.filter.FileUploadFilter </filter-class>
<init-param>
<param-name>thresholdSize</param-name> <param-value>51200</param-value>
</init-param>
<init-param>
<param-name>uploadDirectory</param-name>
<param-value>url/upload</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
<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>*.html</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>*.xhtml</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/dc_security_check</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<listener>
<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<listener>
<listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
</servlet>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>api/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
</web-app>
It compares the password you submit to the password returned by the UserDetails object returned by your UserDetailsService. Please post your config and your UserDetailsService if you need more help.
EDIT: Thanks for the info. It does exactly what you're guessing. The ProviderManager (which is used by default) has the following in its JavaDoc:
If a subsequent provider successfully
authenticates the request, the earlier
authentication exception is
disregarded and the successful
authentication will be used.
So your problem is the latter provider "overruling" the decision of the first one.

Resources