I have a sprinc core + spring mvc + security up and running, using XML configuration and these are the versions I am currently using within my pom.xml:
<spring.version>4.0.1.RELEASE</spring.version>
<spring.security.version>3.2.0.RELEASE</spring.security.version>
So I decided to go ahead and move all my xml configuration to java based configuration. What happens is that the login-processing-url for Spring security stopped working and now gives me an error 405, saying that POST is not allowed. For instance, this is my spring security xml file:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<!-- Satic content -->
<http pattern="/assets/**" security="none" />
<http pattern="/css/**" security="none" />
<http pattern="/img/**" security="none" />
<http pattern="/js/**" security="none" />
<!--http://docs.spring.io/spring-security/site/docs/3.2.0.RELEASE/reference/htmlsingle/#ns-global-method-->
<global-method-security pre-post-annotations="enabled" />
<!-- Protected Requests -->
<http auto-config="true" use-expressions="true" authentication-manager-ref="authenticationManager">
<intercept-url pattern="/login/**" access="permitAll" />
<intercept-url pattern="/api/**" access="permitAll" />
<intercept-url pattern="/**" access="isRememberMe() or isFullyAuthenticated()" />
<form-login login-processing-url="/loginCheck"
login-page="/login"
authentication-failure-url="/loginFailure"
default-target-url="/"
always-use-default-target="true"
password-parameter="password"
username-parameter="username"/>
<logout delete-cookies="JSESSIONID" logout-url="/logout" logout-success-url="/login" />
<access-denied-handler error-page="/403" />
<session-management invalid-session-url="/login" session-fixation-protection="newSession" />
<headers>
<frame-options/>
<xss-protection/>
</headers>
<remember-me services-ref="rememberMeServices" />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="mongoDashAuthenticationProvider" />
<authentication-provider ref="rememberMeAuthenticationProvider" />
</authentication-manager>
<beans:bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
<beans:constructor-arg value="${security.app.key}" />
<beans:constructor-arg ref="userServiceImpl" />
<beans:constructor-arg ref="mongoDashPersistentTokenRepository" />
<beans:property name="tokenValiditySeconds" value="172800" />
<beans:property name="parameter" value="remember" />
<beans:property name="cookieName" value="REMEMBER_ME" />
</beans:bean>
<beans:bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider" >
<beans:property name="key" value="${security.app.key}" />
</beans:bean>
<!-- Way better than SHA -->
<beans:bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="15" />
</beans:bean>
and this is my java configuration file for spring security:
#Configuration
#EnableWebMvcSecurity
#PropertySource("classpath:app.properties")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${security.app.key}")
String appKey;
#Autowired
UserService userService;
#Autowired
MongoDashPersistentTokenRepository mongoDashPersistentTokenRepository;
#Autowired
public void registerGlobalAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth
.eraseCredentials(true)
.authenticationProvider(new MongoDashAuthenticationProvider())
.authenticationProvider(rememberMeAuthenticationProvider());
//.build();
/**
<authentication-manager alias="authenticationManager">
<authentication-provider ref="mongoDashAuthenticationProvider" />
<authentication-provider ref="rememberMeAuthenticationProvider" />
</authentication-manager>
*/
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/assets/**")
.antMatchers("/css/**")
.antMatchers("/img/**")
.antMatchers("/js/**")
.antMatchers("/fonts/**");
/**
<http pattern="/assets/**" security="none" />
<http pattern="" security="none" />
<http pattern="" security="none" />
<http pattern="" security="none" />
**/
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.xssProtection()
.frameOptions()
.and()
.authorizeRequests()
.antMatchers("/login/**").permitAll()
.antMatchers("/api/**").permitAll()
.antMatchers("/**").access("isRememberMe() or isFullyAuthenticated()")
.and()
.formLogin()
.loginProcessingUrl("/loginCheck")
.loginPage("/login")
//.failureUrl("/loginFailure")
.defaultSuccessUrl("/", true)
.passwordParameter("password")
.usernameParameter("username")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/login")
.logoutUrl("/logout")
.deleteCookies("JSESSIONID")
.and()
.sessionManagement()
.invalidSessionUrl("/login")
.sessionFixation().newSession()
.and()
.exceptionHandling()
.accessDeniedPage("/403")
.and()
.rememberMe()
.rememberMeServices(rememberMeServices());
}
#Bean
public RememberMeAuthenticationProvider rememberMeAuthenticationProvider() {
RememberMeAuthenticationProvider provider = new RememberMeAuthenticationProvider(appKey);
return provider;
/**
<beans:bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider" >
<beans:property name="key" value="${security.app.key}" />
</beans:bean>
**/
}
#Bean
public PersistentTokenBasedRememberMeServices rememberMeServices() {
PersistentTokenBasedRememberMeServices rememberMeServices = new PersistentTokenBasedRememberMeServices(appKey, userService,
mongoDashPersistentTokenRepository);
rememberMeServices.setCookieName("REMEMBER_ME");
rememberMeServices.setParameter("remember");
rememberMeServices.setTokenValiditySeconds(172800);
return rememberMeServices;
/**
<beans:bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
<beans:constructor-arg value="${security.app.key}" />
<beans:constructor-arg ref="userServiceImpl" />
<beans:constructor-arg ref="mongoDashPersistentTokenRepository" />
<beans:property name="tokenValiditySeconds" value="172800" />
<beans:property name="parameter" value="remember" />
<beans:property name="cookieName" value="REMEMBER_ME" />
</beans:bean>
**/
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(15);
return passwordEncoder;
/**
<beans:bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="15" />
</beans:bean>
**/
}
}
And this is my AppConfig
#Configuration
#Import({SecurityConfig.class})
//#ImportResource("classpath:spring/security-context.xml")
#ComponentScan(basePackages = { "com.mongom" }, excludeFilters = { #ComponentScan.Filter(Controller.class),
#ComponentScan.Filter(Configuration.class) })
#PropertySource(value = { "classpath:app.properties" })
#EnableMBeanExport
#EnableAspectJAutoProxy
public class AppConfig {
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames("validation", "messages");
return messageSource;
}
#Bean
public PropertiesFactoryBean properties() {
PropertiesFactoryBean ppc = new PropertiesFactoryBean();
ppc.setLocations(new Resource[] { new ClassPathResource("app.properties") });
ppc.setIgnoreResourceNotFound(false);
return ppc;
}
}
web.xml
<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">
<display-name>MongoDASH</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.mongom.spring.AppConfig</param-value>
</context-param>
<servlet>
<servlet-name>mongodash</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.mongom.spring.WebConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mongodash</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 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>
<env-entry>
<description>JNDI logging context for this app</description>
<env-entry-name>logback/contextName</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>mongom</env-entry-value>
</env-entry>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<error-page>
<error-code>400</error-code>
<location>/404</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/404</location>
</error-page>
<error-page>
<error-code>403</error-code>
<location>/403</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/500</location>
</error-page>
Console output:
02/06 11:53:26.678 [http-bio-8080-exec-7] WARN o.s.web.servlet.PageNotFound Request method 'POST' not supported
02/06 11:53:50.023 [http-bio-8080-exec-5] WARN o.s.web.servlet.PageNotFound Request method 'POST' not supported
02/06 11:53:53.408 [http-bio-8080-exec-5] WARN o.s.web.servlet.PageNotFound Request method 'POST' not supported
02/06 11:53:55.504 [http-bio-8080-exec-5] WARN o.s.web.servlet.PageNotFound Request method 'POST' not supported
Login form:
<form class="form-signin" action="loginCheck" method="POST">
<h2 class="form-signin-heading">sign in now</h2>
<div class="login-wrap">
<input type="text" name="username" class="form-control" placeholder="User ID" autofocus value="guest" />
<input type="password" name="password" class="form-control" placeholder="Password" value="!Guest2014!" />
<label class="checkbox">
<input type="checkbox" name="remember" />Remember me
<span class="pull-right">
<a data-toggle="modal" href="#myModal"> Forgot Password?</a>
</span>
</label>
<button class="btn btn-lg btn-login btn-block" type="submit">Sign in</button>
</div>
</form>
Spring Security logs:
02/06 15:57:34.202 [localhost-startStop-1] INFO o.s.s.web.DefaultSecurityFilterChain Creating filter chain: Ant [pattern='/assets/**'], []
02/06 15:57:34.202 [localhost-startStop-1] INFO o.s.s.web.DefaultSecurityFilterChain Creating filter chain: Ant [pattern='/css/**'], []
02/06 15:57:34.203 [localhost-startStop-1] INFO o.s.s.web.DefaultSecurityFilterChain Creating filter chain: Ant [pattern='/img/**'], []
02/06 15:57:34.203 [localhost-startStop-1] INFO o.s.s.web.DefaultSecurityFilterChain Creating filter chain: Ant [pattern='/js/**'], []
02/06 15:57:34.203 [localhost-startStop-1] INFO o.s.s.web.DefaultSecurityFilterChain Creating filter chain: Ant [pattern='/fonts/**'], []
02/06 15:57:34.264 [localhost-startStop-1] INFO o.s.s.web.DefaultSecurityFilterChain Creating filter chain: org.springframework.security.web.util.matcher.AnyRequestMatcher#1, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter#28562791, org.springframework.security.web.context.SecurityContextPersistenceFilter#1f33b16a, org.springframework.security.web.header.HeaderWriterFilter#12504e0, org.springframework.security.web.csrf.CsrfFilter#7ff12373, org.springframework.security.web.authentication.logout.LogoutFilter#40e9e799, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#334362d9, org.springframework.security.web.savedrequest.RequestCacheAwareFilter#892b7c2, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#d0da1d8, org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter#5eba06ff, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#303fb547, org.springframework.security.web.session.SessionManagementFilter#a5ae1e7, org.springframework.security.web.access.ExceptionTranslationFilter#13883d5f, org.springframework.security.web.access.intercept.FilterSecurityInterceptor#52ecba8]
Spring security longs when posting login form:
02/06 17:04:33.642 [http-bio-8080-exec-10] DEBUG o.s.s.w.u.m.AntPathRequestMatcher Checking match of request : '/logincheck'; against '/assets/**'
02/06 17:04:33.643 [http-bio-8080-exec-10] DEBUG o.s.s.w.u.m.AntPathRequestMatcher Checking match of request : '/logincheck'; against '/css/**'
02/06 17:04:33.644 [http-bio-8080-exec-10] DEBUG o.s.s.w.u.m.AntPathRequestMatcher Checking match of request : '/logincheck'; against '/img/**'
02/06 17:04:33.644 [http-bio-8080-exec-10] DEBUG o.s.s.w.u.m.AntPathRequestMatcher Checking match of request : '/logincheck'; against '/js/**'
02/06 17:04:33.645 [http-bio-8080-exec-10] DEBUG o.s.s.w.u.m.AntPathRequestMatcher Checking match of request : '/logincheck'; against '/fonts/**'
02/06 17:04:33.645 [http-bio-8080-exec-10] DEBUG o.s.security.web.FilterChainProxy /loginCheck at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
02/06 17:04:33.645 [http-bio-8080-exec-10] DEBUG o.s.security.web.FilterChainProxy /loginCheck at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
02/06 17:04:33.646 [http-bio-8080-exec-10] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository HttpSession returned null object for SPRING_SECURITY_CONTEXT
02/06 17:04:33.700 [http-bio-8080-exec-10] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade#705ebc6e. A new one will be created.
02/06 17:04:33.701 [http-bio-8080-exec-10] DEBUG o.s.security.web.FilterChainProxy /loginCheck at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
02/06 17:04:33.701 [http-bio-8080-exec-10] DEBUG o.s.security.web.FilterChainProxy /loginCheck at position 4 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
02/06 17:04:33.702 [http-bio-8080-exec-10] DEBUG o.s.security.web.csrf.CsrfFilter Invalid CSRF token found for http://localhost:8080/mongodash/loginCheck
02/06 17:04:33.703 [http-bio-8080-exec-10] DEBUG o.s.web.servlet.DispatcherServlet DispatcherServlet with name 'mongodash' processing POST request for [/mongodash/403]
02/06 17:04:33.704 [http-bio-8080-exec-10] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping Looking up handler method for path /403
02/06 17:04:33.719 [http-bio-8080-exec-10] DEBUG o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
02/06 17:04:33.719 [http-bio-8080-exec-10] DEBUG o.s.w.s.m.a.ResponseStatusExceptionResolver Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
02/06 17:04:33.720 [http-bio-8080-exec-10] DEBUG o.s.w.s.m.s.DefaultHandlerExceptionResolver Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
02/06 17:04:33.720 [http-bio-8080-exec-10] WARN o.s.web.servlet.PageNotFound Request method 'POST' not supported
02/06 17:04:33.721 [http-bio-8080-exec-10] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
02/06 17:04:33.721 [http-bio-8080-exec-10] DEBUG o.s.web.servlet.DispatcherServlet Null ModelAndView returned to DispatcherServlet with name 'mongodash': assuming HandlerAdapter completed request handling
02/06 17:04:33.721 [http-bio-8080-exec-10] DEBUG o.s.web.servlet.DispatcherServlet Successfully completed request
02/06 17:04:33.722 [http-bio-8080-exec-10] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
02/06 17:04:33.722 [http-bio-8080-exec-10] DEBUG o.s.s.w.c.SecurityContextPersistenceFilter SecurityContextHolder now cleared, as request processing completed
My question is: Am I missing anything here? I see that the application is working fine as I can see the login page and resources (js, css, img) being shown on that page, its just the login-processing-url that, when invoked with POST thru the login form, it doesnt work.
Thank you
TL
edit #1: updated with login form and spring security logs
edit #2: updated with spring security logs when posting login information
Based upon the logs you posted, the issue appears to be that you are not including the CSRF token in the login request.
DEBUG o.s.security.web.csrf.CsrfFilter Invalid CSRF token found for http://localhost:8080/mongodash/loginCheck
This did not happen with the XML based configuration, because CSRF is not on by default with XML configuration (to be passive). Since there is no CSRF token in the login request, Spring Security is forwarding to the /403 error page (this is what is configured as the access denied page in your Java Config). It appears the MVC controller that processes /403 does not allow for HTTP POST and is logging the error message you see.
To fix this, first I would ensure that /403 can processes other methods. This will help to troubleshoot any other similar issues you might have (i.e. at that point you should get a proper error message rather than seeing the error that the method is not supported).
Second, you have a choice:
Include the CSRF token in all POST, PUT, DELETE, etc forms. This will ensure you are protected against CSRF attacks.
UPDATE: If you are using #EnableWebMvcSecurity and Spring's JSP tag library or Thymeleaf 2.1+ to render your forms then the CSRF token is included automatically for you. See the Include CSRF Token section of the reference for details about automatic inclusion and for examples of how to include the token manually.
Alternatively, you can disable CSRF protection. This is NOT recommended, but can help be a stop gap if you want to upgrade to Spring Security's Java Configuration.
You can read more about CSRF protection in the CSRF section of the reference.
A few additional items:
Is there a reason you are explicitly configuring the headers? The configuration you have specified disables some of the default headers that will assist in protecting your application. The explicit configuration does not include the cache control header.
UPDATE: For example, you have the following:
http
.headers()
.xssProtection()
.frameOptions()
.and()
.authorizeRequests()
If you simply remove the headers declaration, all the default headers are added by default.
http
.authorizeRequests()
For the XML configuration you can include the <headers/> element with no children to get all the default headers. This explicit setup for XML is necessary to remain passive.
More information about the headers can be found in the Security HTTP Response Headers section of the reference.
There is quite a bit of configuration you can safely remove from your code since the Java Configuration will default to these values. For example, the username and password parameter configuration is unnecessary since this is the default value.
Related
I have configured spring security with spring mvc and its working.
But problem is after successful login authentication spring security loads index page every time after returning new ModelAndView in default-target-url.
spring-security.xml
<?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: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">
<!-- This is where we configure Spring-Security -->
<http auto-config="true" use-expressions="true" access-denied-page="/denied.htm" >
<intercept-url pattern="/login.htm" access="permitAll"/>
<form-login
login-page="/login.htm"
login-processing-url="/j_spring_security_check.htm"
authentication-failure-url="/login.htm?error=true"
default-target-url="/dashboard.htm"/>
<logout
invalidate-session="true"
logout-success-url="/login.htm"
logout-url="/logout.htm"/>
</http>
<!-- Enable the use of pre/post annotation -->
<global-method-security pre-post-annotations="enabled">
<expression-handler ref="expressionHandler" />
</global-method-security>
<!-- Enable permission evaluator in annotation -->
<beans:bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<beans:property name="permissionEvaluator" ref="customPermissionEvaluator" />
</beans:bean>
<!-- Declare a custom PermissionEvaluator interface -->
<beans:bean id="customPermissionEvaluator" class="com.imobdev.util.CustomPermissionEvaluator"/>
<!-- Declare an authentication-manager to use a custom userDetailsService -->
<authentication-manager>
<authentication-provider user-service-ref="customUserDetailsService">
<!-- <password-encoder ref="passwordEncoder"/> -->
</authentication-provider>
</authentication-manager>
<!-- Use a Md5 encoder since the user's passwords are stored as Md5 in the database -->
<!-- <beans:bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/> -->
<!-- A custom service where Spring will retrieve users and their corresponding access levels -->
<beans:bean id="customUserDetailsService" class="com.imobdev.service.CustomUserDetailsService"/>
<!-- <beans:bean id="customUserDetailsService" class="com.imobdev.service.ImderpServiceImpl"/> -->
</beans:beans>
this is my controller method
#RequestMapping(value="/dashboard")
public ModelAndView loadDashboard(#ModelAttribute("eReg") EregForm eReg,Map<String, Object> model) throws Exception{
return new ModelAndView("dashboard");
}
this is my console
[30/10/2015 19:19:56 INFO MyLogger:21] START : LoginController.loadIndex
[30/10/2015 19:19:56 INFO MyLogger:39] END : LoginController.loadIndex
[30/10/2015 19:19:59 INFO MyLogger:21] START : CustomUserDetailsService.loadUserByUsername
[30/10/2015 19:19:59 INFO MyLogger:21] START : ImderpDaoImpl.getUserByUserName
Hibernate: select usermst0_.u_id as u_id1_30_, usermst0_.u_type_id as u_type_18_30_, usermst0_.u_created_by as u_create2_30_, usermst0_.u_created_date as u_create3_30_, usermst0_.u_dept_id as u_dept_i4_30_, usermst0_.u_email as u_email5_30_, usermst0_.u_fname as u_fname6_30_, usermst0_.u_last_login_date as u_last_l7_30_, usermst0_.u_lname as u_lname8_30_, usermst0_.u_modified_date as u_modifi9_30_, usermst0_.u_parent_u_id as u_paren10_30_, usermst0_.u_password as u_passw11_30_, usermst0_.u_photo as u_photo12_30_, usermst0_.u_recovery_token as u_recov13_30_, usermst0_.u_role_id as u_role_14_30_, usermst0_.u_status as u_statu15_30_, usermst0_.u_type as u_type16_30_, usermst0_.u_username as u_usern17_30_ from tbUser usermst0_ where usermst0_.u_status<>? and usermst0_.u_username=?
Hibernate: select employeems0_.emp_id as emp_id1_6_0_, employeems0_.emp_bio_id as emp_bio_2_6_0_, employeems0_.emp_birth_date as emp_birt3_6_0_, employeems0_.emp_comp_id as emp_comp4_6_0_, employeems0_.emp_contact_no as emp_cont5_6_0_, employeems0_.emp_created_by as emp_crea6_6_0_, employeems0_.emp_created_date as emp_crea7_6_0_, employeems0_.emp_dept_id as emp_dept8_6_0_, employeems0_.emp_fname as emp_fnam9_6_0_, employeems0_.emp_gender as emp_gen10_6_0_, employeems0_.emp_is_report_enabled as emp_is_11_6_0_, employeems0_.emp_joining_date as emp_joi12_6_0_, employeems0_.emp_lname as emp_lna13_6_0_, employeems0_.emp_mname as emp_mna14_6_0_, employeems0_.emp_modified_date as emp_mod15_6_0_, employeems0_.emp_p_email as emp_p_e16_6_0_, employeems0_.emp_photo as emp_pho17_6_0_, employeems0_.emp_relieving_date as emp_rel18_6_0_, employeems0_.emp_role_id as emp_rol19_6_0_, employeems0_.emp_shift_id as emp_shi20_6_0_, employeems0_.emp_status as emp_sta21_6_0_ from a_employees employeems0_ where employeems0_.emp_id=?
[30/10/2015 19:19:59 INFO MyLogger:39] END : ImderpDaoImpl.getUserByUserName
[30/10/2015 19:19:59 INFO MyLogger:39] END : CustomUserDetailsService.loadUserByUsername
[30/10/2015 19:19:59 INFO MyLogger:21] START : ErpController.loadDashboard
[30/10/2015 19:19:59 INFO MyLogger:39] END : ErpController.loadDashboard
[30/10/2015 19:19:59 INFO MyLogger:21] START : LoginController.loadIndex
[30/10/2015 19:19:59 INFO MyLogger:39] END : LoginController.loadIndex
as we can see that after completeing dashboard.htm it calls index page.
so whats wrong here??!
I have switched from Spring security 3.x to 4.0 and am now facing some issues with my custom login form.
My Security Config:
#Configuration
#EnableWebSecurity
#ComponentScan(basePackageClasses = {CustomUserDetailsService.class, CustomPermissionEvaluator.class})
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Resource(name = "authService")
private UserDetailsService userDetailsService;
private BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
static class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
#Autowired
private CustomPermissionEvaluator permissionEvaluator;
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler handler
= new DefaultMethodSecurityExpressionHandler();
handler.setPermissionEvaluator(permissionEvaluator);
return handler;
}
public CustomPermissionEvaluator getPermissionEvaluator() {
return permissionEvaluator;
}
public void setPermissionEvaluator(CustomPermissionEvaluator permissionEvaluator) {
this.permissionEvaluator = permissionEvaluator;
}
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/pages/unsecure/**", "/layouts/**", "/resources/**", "/javax.faces.resource/**", "/uploads/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/pages/unsecure/login.xhtml")
.permitAll()
.and()
.logout()
.permitAll()
.deleteCookies()
.logoutSuccessUrl("/pages/unsecure/login.xhtml")
.invalidateHttpSession(true)
.and()
.csrf()
.disable();
}
#Autowired
public void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = passwordEncoder();
auth
.userDetailsService(userDetailsService)
.passwordEncoder(encoder);
}
My CustomUserDetailsService:
#Override
public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException {
System.out.println("----------------"+login+"-------------------");
com.redast.model.User domainUser = getUserDAO().findByLogin(login);
if(domainUser == null){
throw new UsernameNotFoundException("could not find user"+login);
}
return new UserDAOUserDetails(domainUser);
}
My LoginBean:
public String login() {
try {
System.out.println("Login Action: "+this.getUserName());
Authentication request = new UsernamePasswordAuthenticationToken(this.getUserName(), this.getPassword());
Authentication result = getAuthenticationManager().authenticate(request);
SecurityContextHolder.getContext().setAuthentication(result);
} catch (AuthenticationException e) {
return "/pages/unsecure/login";
}
return "/pages/unsecure/welcomePage?faces-redirect=true";
}
And finaly my Login Form:
<h:form id="loginFormId" prependId="false">
<h:panelGrid columns="3" cellpadding="3" id="loginGrid">
<h:outputLabel id="outTxtUserNameId" value="Username: " for="username"/>
<p:inputText id="username" required="true" value="#{loginMgmtBean.userName}" requiredMessage="Please enter username" label="Name"></p:inputText>
<p:message for="username" />
<h:outputLabel id="outTxtPasswordId" value="Password: " for="password"/>
<p:password id="password" required="true" value="#{loginMgmtBean.password}" requiredMessage="Please enter password"></p:password>
<p:message for="password" />
<p:commandButton id="btnLoginId" value="Login" action="#{loginMgmtBean.login}" styleClass="loginPanelBtn" validateClient="true" update="loginGrid" />
</h:panelGrid>
</h:form>
My Problem is, that the click on btnLoginId executes the method loadUserByUsername directly in CustomUserDetailsService and not login in the Login Bean. This used to work with the old version. Any ideas on how to fix this?
Additionally I switched from XML based configuration to Java Based Configuration. So here is my OLD XML:
<!-- Enable method level Spring Security by annotations -->
<sec:global-method-security pre-post-annotations="enabled">
<sec:expression-handler ref="expressionHandler"/>
</sec:global-method-security>
<sec:http auto-config="true" use-expressions="true">
<!-- Page level Spring Security : Intercept access to resources in /pages/secure/** -->
<sec:intercept-url pattern="/pages/secure/**" access="hasRole('ROLE_USER')" />
<!-- Page level Spring Security : Permit access to resources in /pages/unsecure/** -->
<sec:intercept-url pattern="/pages/unsecure/**" access="permitAll"/>
<!-- Page level Spring Security : Permit access to resources in /layouts/** -->
<sec:intercept-url pattern="/layouts/**" access="permitAll"/>
<!-- Page level Spring Security : Permit access to resources in /resources/** -->
<sec:intercept-url pattern="/resources/**" access="permitAll"/>
<!-- Page level Spring Security : Permit access to resources in /uploads/** -->
<sec:intercept-url pattern="/uploads/**" access="permitAll"/>
<!-- Page level Spring Security : Enable Primefaces -->
<sec:intercept-url pattern="/javax.faces.resource/**" access="permitAll"/>
<!-- Page level Spring Security : Intercept access to resources in /** -->
<sec:intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"/>
<!-- Define login page for Spring Security -->
<sec:form-login login-page="/pages/unsecure/login.xhtml"/>
<!-- Define logout properties for Spring Security -->
<sec:logout invalidate-session="true" delete-cookies="true" logout-success-url="/pages/unsecure/login.xhtml"></sec:logout>
<sec:access-denied-handler error-page="/pages/unsecure/error.xhtml" />
</sec:http>
<!-- Set customUserDetailsService class as the authentication Manager for Spring Security-->
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider user-service-ref="customUserDetailsService">
<sec:password-encoder hash="bcrypt"></sec:password-encoder>
</sec:authentication-provider>
</sec:authentication-manager>
<beans:bean id="customUserDetailsService"
class="com.redast.service.CustomUserDetailsService">
</beans:bean>
<beans:bean id="expressionHandler"
class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<beans:property name="permissionEvaluator" ref="myPermissionEvaluator"/>
</beans:bean>
<beans:bean id="myPermissionEvaluator" name="myPermissionEvaluator" class="com.redast.security.CustomPermissionEvaluator">
</beans:bean>
<!-- Inject authentication Manager to our LoginBean -->
<beans:bean id="loginBean" name="loginBean" class="com.redast.managedController.LoginBean" scope="prototype">
<beans:property name="authenticationManager" ref="authenticationManager"></beans:property>
</beans:bean>
Thanks.
bwright
You need to remove the permitAll() method call after formLogin() and logout() method calls:
http
.authorizeRequests()
.antMatchers("/pages/unsecure/**", "/layouts/**", "/resources/**", "/javax.faces.resource/**", "/uploads/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/pages/unsecure/login.xhtml")
.and()
.logout()
.deleteCookies()
.logoutSuccessUrl("/pages/unsecure/login.xhtml")
.invalidateHttpSession(true)
.and()
.csrf()
.disable();
I would like to prevent spring security from forwarding to the default "j_spring_security_check" after successful login,instead after successful login I would like to forward to custom welcome page "/auth/welcome.jsp" , attempted 2 approaches:
Diagram of my desired flow:
Approach # 1 (used xml configuration)
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_3_0.xsd" version="3.0">
<display-name>Toyota Relocation App</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>
<!-- load spring security -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml,/WEB-INF/security.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<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>
</web-app>
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.2.xsd">
<!-- spring security should ignore "/" & "/resources/**" paths -->
<http pattern="/" security="none" auto-config="true"
use-expressions="true" />
<http pattern="/resources/**" security="none" auto-config="true"
use-expressions="true" />
<!-- spring security configuration -->
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/auth**" access="hasRole('ROLE_USER')" />
<form-login login-page="/login" authentication-failure-url="/login?error"
username-parameter="emailInputField" password-parameter="pinInputField"
default-target-url="/auth/welcome" always-use-default-target="true" />
<logout logout-success-url="/login?logout" />
</http>
<!-- user accounts -->
<authentication-manager>
<authentication-provider>
<user-service>
<user name="naim#test.com" password="12345" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
login.jsp: (relevant snippet)
<div class="mycontent">
<div id="logo_div">
<img src="resources/images/01_toyota_logo_small.png">
</div>
<div class="login_form_wrapper">
<c:if test="${not empty error}">
<div class="error">${error}</div>
</c:if>
<c:if test="${not empty msg}">
<div class="msg">${msg}</div>
</c:if>
<!-- content-->
<form name='loginForm' action="<c:url value='j_spring_security_check' />" method='POST'>
<!-- <FORM name='loginForm' action="auth" method="post">-->
<ul class="mylistview" data-role="listview">
<li>
<div><img id="email_input_icon" src="resources/images/01_login_email_icon_small.png"></div><div id="email_input" ><input name="emailInputField"" id="email_input_field" type="email" data-role="none" /></div></li>
<li>
<div><img id="pin_input_icon"src="resources/images/01_login_password_icon_small.png"></div><div id="pin_input" ><input name="pinInputField" id="pin_input_field" type="password" data-role="none" /></div></li>
<li>
<div id="login_button">
<button id="login" class="button" type="submit">LOGIN</button>
</div>
</li>
</ul>
</FORM>
</div>
HomeController:
package com.xyz.thedallasapp_poc;
//removed imports
#Controller
public class HomeControler {
public HomeControler() {
super();
// TODO Auto-generated constructor stub
}
/* serves the login landing/home page view*/
#RequestMapping("/")
public String printWelcome(ModelMap model) {
return "login";
}
/*process login request from login view */
#RequestMapping (value="/login**", method = RequestMethod.GET)
public ModelAndView processLogin(
#RequestParam(value = "error", required = false) String error,
#RequestParam(value = "logout", required = false) String logout) {
ModelAndView model = new ModelAndView();
model.addObject("previousView", "/login");
if (error != null) {
model.addObject("error", "Invalid username and password!");
}
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
model.setViewName("login");
return model;
}
/* forward /auth/welcome request to /auth/welcome.jsp*/
#RequestMapping(value = "/auth/welcome")
public ModelAndView authWelcome() {
ModelAndView model = new ModelAndView();
//if reffer is /login than view is auth/welcome
//else view is reffer
model.setViewName("/auth/welcome");
return model;
}
}//end controller
Result:
Successful authentication & failure happen correctly, however I'm forwarded "j_spring_security_check" view which after careful inspection is actually the previous view/page with a new URL , instead of /auth/welcome.jsp view.
The logs have no error.
Approach # 2 (used xml configuration & implemented AuthenticationSuccessHandler )
I implemented AuthenticationSuccessHandler in order to redirect to "auth/welcome.jsp after successful login.
The web.xml, HomeController.java are not changed compared to approach #1.
spring.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.2.xsd">
<!-- spring security should ignore "/" & "/resources/**" paths -->
<http pattern="/" security="none" auto-config="true"
use-expressions="true" />
<http pattern="/resources/**" security="none" auto-config="true"
use-expressions="true" />
<!-- spring security configuration -->
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/auth**" access="hasRole('ROLE_USER')" />
<form-login login-page="/login" authentication-failure-url="/login?error"
username-parameter="emailInputField" password-parameter="pinInputField"
default-target-url="/auth/welcome" always-use-default-target="true"
authentication-success-handler-ref="myAuthSuccessHandler"/>
<logout logout-success-url="/login?logout" />
</http>
<!-- user accounts -->
<authentication-manager>
<authentication-provider>
<user-service>
<user name="naim#test.com" password="12345" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
<!-- custom bean used to override spring security page redirection after successful authentication -->
<beans:bean id="myAuthSuccessHandler"
class="com.hitachi.thedallasapp_poc.security.MyAuthSuccessHandler" />
</beans:beans>
**MyAuthSuccessHandler: **
package com.hitachi.thedallasapp_poc.security;
//removed imports
public class MyAuthSuccessHandler implements AuthenticationSuccessHandler {
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
System.out.println("Class onAuthenticationSuccess request: "+request.getRequestURL());
System.out.println("Class onAuthenticationSuccess response status: "+response.getStatus());
handle(request, response, authentication);
clearAuthenticationAttributes(request);
}
protected void handle(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) throws IOException {
String targetUrl = determineTargetUrl(authentication,request);
if (response.isCommitted()) {
return;
}
System.out.println("Class onAuthenticationSuccess ,request.getContextPath(): " + request.getContextPath());
System.out.println("Class onAuthenticationSuccess ,targetUrl: " + targetUrl);
redirectStrategy.sendRedirect(request, response, targetUrl);
}
/** check the Role of the user that was granted access, based on the role redirect to success page */
protected String determineTargetUrl(Authentication authentication, HttpServletRequest request) {
boolean isUser = false;
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
String redirectURL = null;
for (GrantedAuthority grantedAuthority : authorities) {
if (grantedAuthority.getAuthority().equals("ROLE_USER")) {
System.out.println("Class MyAuthSuccessHandler, grantedAuthority.getAuthority():" +grantedAuthority.getAuthority());
isUser = true;
break;
}
}//end for
//if user is USER_ROLE redirect to "/auth/welcome"
if (isUser) {
System.out.println("Class MyAuthSuccessHandler, request.getRequestURL():" +request.getRequestURL().toString());
redirectURL = "/auth/welcome";
}
//else redirect to default
else
{
redirectURL = request.getRequestURL().toString();
}
return redirectURL;
}
protected void clearAuthenticationAttributes(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session == null) {
return;
}
session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
}
public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
}
protected RedirectStrategy getRedirectStrategy() {
return redirectStrategy;
}
}//end class MyAuthSuccessHandler
Result:
After successful login the user is still redirected to previous page but again with path "j_spring_security_check", rather than desired "auth/welcome.jsp"
Logs show no error.
My System.println results:
Class MyAuthSuccessHandler, grantedAuthority.getAuthority():ROLE_USER
Class MyAuthSuccessHandler, request.getRequestURL():http://theda
llasapp_poc/j_spring_security_check
Class onAuthenticationSuccess ,request.getContextPath(): /thedallasapp_poc
Class onAuthenticationSuccess ,targetUrl: /auth/welcome
Thanks any help would be appreciated.
I am trying to use Spring security default login mechanism and this is what I have configured in security.xml file
<http pattern="/customer/**" auto-config="true" use-expressions="true" authentication-manager-ref="customerAuthenticationManager">
<intercept-url pattern="/customer" access="hasRole('AUTH_CUSTOMER')" />
<intercept-url pattern="/customer/" access="hasRole('AUTH_CUSTOMER')" />
<intercept-url pattern="/customer/*.html" access="hasRole('AUTH_CUSTOMER')" />
<intercept-url pattern="/customer/*/*.html" access="hasRole('AUTH_CUSTOMER')" />
<intercept-url pattern="/shop/customer/logon.html*" access="permitAll" />
<intercept-url pattern="/shop/customer/denied.html" access="permitAll"/>
<intercept-url pattern="/shop/customer/j_spring_security_check" access="permitAll"/>
<form-login login-processing-url="/shop/customer/j_spring_security_check" login-page="/shop/home.html"
authentication-success-handler-ref="webshopAuthenticationSuccessHandler"
/>
<logout invalidate-session="true"
logout-success-url="/customer/home.html"
logout-url="/customer/j_spring_security_logout" />
<access-denied-handler error-page="/customer/denied.html"/>
</http>
This is how I have configured spring security in web.xml
<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>
And this is how I am submitting my form using ajax
var data = $(this).serializeObject();
$.ajax({
'type': "POST",
'url': "<c:url value="/shop/customer/j_spring_security_check"/>",
'data': data,
'success': function(result) {
}
});
return false;
});
But no authentication is getting triggered and I am getting 404 error, but have seen following information in console
DEBUG org.springframework.security.web.util.AntPathRequestMatcher: Checking match of request : '/shop/customer/j_spring_security_check'; against '/admin/**'
DEBUG org.springframework.security.web.util.AntPathRequestMatcher: Checking match of request : '/shop/customer/j_spring_security_check'; against '/customer/**'
DEBUG org.springframework.security.web.util.AntPathRequestMatcher: Checking match of request : '/shop/customer/j_spring_security_check'; against '/shop/services/private/**'
DEBUG org.springframework.security.web.FilterChainProxy: /shop/customer/j_spring_security_check has no matching filters
DEBUG org.springframework.web.servlet.DispatcherServlet: DispatcherServlet with name 'appServlet' processing POST request for [/sm-shop/shop/customer/j_spring_security_check]
DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping: Looking up handler method for path /shop/customer/j_spring_security_check
DEBUG org.springframework.security.web.util.AntPathRequestMatcher: Checking match of request : '/resources/img/loading.gif'; against '/admin/**'
DEBUG org.springframework.security.web.util.AntPathRequestMatcher: Checking match of request : '/resources/img/loading.gif'; against '/customer/**'
DEBUG org.springframework.security.web.util.AntPathRequestMatcher: Checking match of request : '/resources/img/loading.gif'; against '/shop/services/private/**'
....
DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping: Did not find handler method for [/shop/customer/j_spring_security_check]
WARN org.springframework.web.servlet.PageNotFound: No mapping found for HTTP request with URI [/sm-shop/shop/customer/j_spring_security_check] in DispatcherServlet with name 'appServlet'
any idea?
Are you having multiple http configurations? If not, you do not need to specify <http pattern="/customer/**"...>.
If you have multiple http configuration sections and using Spring Security 3.1+, from the reference:
Defining a pattern for the http element controls the requests which
will be filtered through the list of filters which it defines.
This means that you should define multiple security filters with the same pattern so that Spring will match them separately. And, if no pattern is defined for http, it defaults to /* which you've defined in your web.xml. So, if you do not have a specific restriction, it may be easier to first test if this work for you with all http configuration in one element and then extend to multiple ones.
Try to configure from most specific to more general patterns.
Try to use to use wildcard option towards the end of the configuration.
And I believe the one with pattern="/customer/*/*.html" should be pattern="/customer/**/*.html". It is missing one *.
So based on what I said:
<http auto-config="true" use-expressions="true" authentication-manager-ref="customerAuthenticationManager">
<intercept-url pattern="/shop/customer/logon.html*" access="permitAll" />
<intercept-url pattern="/shop/customer/denied.html" access="permitAll"/>
<intercept-url pattern="/shop/customer/j_spring_security_check" access="permitAll"/>
<intercept-url pattern="/customer" access="hasRole('AUTH_CUSTOMER')" />
// XXX: bring in also your /admin configuration before the wildcards
<intercept-url pattern="/customer/*.html" access="hasRole('AUTH_CUSTOMER')" />
<intercept-url pattern="/customer/**/*.html" access="hasRole('AUTH_CUSTOMER')" />
...
Hope this helps.
I'm trying to do a basic spring security D/B authentication program.I tried this by two ways i.e.
Method 1 : Using custom tables for Spring Security authentication.
Method 2 : Using Spring security specific database tables for user authentication and authorization.
File Locations:
1. index.jsp -> webapp/index.jsp
2. welcome.jsp -> webapp/pages/welcome.jsp
3. login.jsp -> webapp/pages/login.jsp
For method 1,Spring security was not intercepting request and i didn't see errors in console.Instead of intercepting the request i was directly taken to welcome.jsp.
P.S - Since i was not trying authorization, i didn't use 'authorities-by-username-query' attribute below in security context xml. I'm not sure if its mandatory to create a table for authorization as well.
Below is my security-context.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:jee="http://www.springframework.org/schema/jee"
xmlns:security="http://www.springframework.org/schema/security"
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/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<security:http auto-config="true">
<security:intercept-url pattern="/welcome.html" />
<security:form-login login-page="/login.html"
default-target-url="/welcome.html" authentication-failure-url="/loginfailed.html" />
<security:logout logout-success-url="/logout.html" />
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:jdbc-user-service data-source-ref="dataSource"
users-by-username-query="select FIRST_NAME,LAST_NAME,PASSWORD from USER_AUTHENTICATION where FIRST_NAME=?" />
</security:authentication-provider>
</security:authentication-manager>
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" id="WebApp_ID" version="2.5">
<display-name>SpringPOC</display-name>
<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>*.html</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContextDirect.xml
/WEB-INF/applicationContext-security.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>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
BaseController
//#RequestMapping(value="/login", method = RequestMethod.GET)
#RequestMapping("/login")
public ModelAndView login(Model model) {
//System.out.println("Inside /login...");
return new ModelAndView("login");
}
/*public String login(ModelMap model) {
System.out.println("Inside /login...");
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";
}
login.jsp
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>Login Page</title>
<style>
.errorblock {
color: #ff0000;
background-color: #ffEEEE;
border: 3px solid #ff0000;
padding: 8px;
margin: 16px;
}
</style>
</head>
<body onload='document.f.j_username.focus();'>
<h3>Login with Username and Password (Authentication with Database)</h3>
<c:if test="${not empty error}">
<div class="errorblock">
Your login attempt was not successful, try again.<br /> Caused :
${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message}
</div>
</c:if>
<form name='f' action="<c:url value='j_spring_security_check' />"
method='POST'>
<table>
<tr>
<td>User:</td>
<td><input type='text' name='j_username' value=''>
</td>
</tr>
<tr>
<td>Password:</td>
<td><input type='password' name='j_password' />
</td>
</tr>
<tr>
<td colspan='2'><input name="submit" type="submit"
value="submit" />
</td>
</tr>
<tr>
<td colspan='2'><input name="reset" type="reset" />
</td>
</tr>
</table>
</form>
index.jsp
<body>
<div id="content">
<h1>Home Page</h1>
<p>
Anyone can view this page.
</p>
<p>Login page</p>
</div>
</body>
For method 2, i created spring specific database tables in the name of “USERS” and “AUTHORITIES” after following the below link. Here SQL query is not used in xml as shown below.
http://www.raistudies.com/spring-security-tutorial/authentication-authorization-spring-security-mysql-database/
Every thing remains same except for security-context.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:jee="http://www.springframework.org/schema/jee"
xmlns:security="http://www.springframework.org/schema/security"
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/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<security:http realm="Project Realm" auto-config="true">
<security:intercept-url pattern="/welcome.html" access="ROLE_USER"/>
<security:form-login login-page="/login.html"
default-target-url="/welcome.html" authentication-failure-url="/loginfailed.html" />
<security:logout logout-success-url="/logout.html" />
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:password-encoder hash="md5"/>
<security:jdbc-user-service data-source-ref="dataSource"/>
</security:authentication-provider>
</security:authentication-manager>
</beans>
when i tried the above way, even though i enter correct user name & password, i was getting 'bad credentials' message [But yes, in this case spring security is intercepting the request]. I'm using Oracle database.
[Update]: I enabled spring debug logging to find the root cause of errors in both methods. I couldn't figure out or understand what exactly is wrong from logs, so i compared logs i got after trying both methods.As,for method 1 Spring security was not intercepting request and for method 2 i was able to login (Spring security was atleast intercepting request) but i was getting 'Bad credential' message even after entering correct username & password.
Below is the code snippet for method 2[ Here i get login page,but authentication is failing]
firing Filter: 'FilterSecurityInterceptor'
DEBUG: org.springframework.security.web.util.AntPathRequestMatcher - Checking match of request : '/welcome.html'; against
'/welcome.html'
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Secure object: FilterInvocation: URL:
/welcome.html; Attributes: [ROLE_USER]
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Previously Authenticated:
org.springframework.security.authentication.AnonymousAuthenticationToken#9055c2bc: Principal: anonymousUser; Credentials:
[PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#b364:
RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
DEBUG: org.springframework.security.access.vote.AffirmativeBased - Voter:
org.springframework.security.access.vote.RoleVoter#19432e0, returned: -1
DEBUG: org.springframework.security.access.vote.AffirmativeBased - Voter:
org.springframework.security.access.vote.AuthenticatedVoter#9830bc, returned: 0
DEBUG: org.springframework.security.web.access.ExceptionTranslationFilter - Access is denied (user is anonymous);
redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation
(AbstractSecurityInterceptor.java:206)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke
(FilterSecurityInterceptor.java:115)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter
(FilterSecurityInterceptor.java:84)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter
(AnonymousAuthenticationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter
(SecurityContextHolderAwareRequestFilter.java:54)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter
(BasicAuthenticationFilter.java:150)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter
(AbstractAuthenticationProcessingFilter.java:183)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter
(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:662)
DEBUG: org.springframework.security.web.savedrequest.HttpSessionRequestCache - DefaultSavedRequest added to Session:
DefaultSavedRequest[http://localhost:8080/itrade-web/welcome.html]
DEBUG: org.springframework.security.web.access.ExceptionTranslationFilter - Calling Authentication entry point.
DEBUG: org.springframework.security.web.DefaultRedirectStrategy - Redirecting to 'http://localhost:8080/itrade-
web/login.html;jsessionid=3FD72892F4F4EF2E65B0C90ABE115354'
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext is empty or contents
are anonymous - context will not be stored in HttpSession.
DEBUG: org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as
request processing completed
DEBUG: org.springframework.security.web.FilterChainProxy - /login.html at position 1 of 10 in additional filter chain;
firing Filter: 'SecurityContextPersistenceFilter'
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - HttpSession returned null object for SPRING_SECURITY_CONTEXT
firing Filter: 'UsernamePasswordAuthenticationFilter'
...
DEBUG: org.springframework.security.web.FilterChainProxy - /login.html at position 7 of 10 in additional filter chain;
firing Filter: 'AnonymousAuthenticationFilter'
DEBUG: org.springframework.security.web.authentication.AnonymousAuthenticationFilter - Populated SecurityContextHolder with
anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken#6fa8940c: Principal:
anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details:
org.springframework.security.web.authentication.WebAuthenticationDetails#fffde5d4: RemoteIpAddress: 0:0:0:0:0:0:0:1;
SessionId: 3FD72892F4F4EF2E65B0C90ABE115354; Granted Authorities: ROLE_ANONYMOUS'
...
DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Request is to process
authentication
DEBUG: org.springframework.security.authentication.ProviderManager - Authentication attempt using
org.springframework.security.authentication.dao.DaoAuthenticationProvider
DEBUG: org.springframework.security.provisioning.JdbcUserDetailsManager - Query returned no results for user 'admin'
DEBUG: org.springframework.security.authentication.dao.DaoAuthenticationProvider - User 'admin' not found
DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Authentication request
failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Updated SecurityContextHolder
to contain null Authentication
DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Delegating to authentication
failure handler org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler#1882c1a
DEBUG: org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler - Redirecting to
/loginfailed.html
DEBUG: org.springframework.security.web.DefaultRedirectStrategy - Redirecting to '/itrade-web/loginfailed.html'
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext is empty or contents
are anonymous - context will not be stored in HttpSession.
DEBUG: org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as
request processing completed
[Update] For method 1 ,i added 'authorities-by-username-query' tag after creating a custom table for 'authorization'. Now i'm getting login screen, so i got to know inorder for spring security to intercept i need to have 'authorities-by-username-query' tag .But after entering user name and password i get following error mesage :
Caused : PreparedStatementCallback; uncategorized SQLException for SQL [select FIRST_NAME,LAST_NAME,PASSWORD from USER_AUTHENTICATION where FIRST_NAME=?]; SQL state [null]; error code [17059]; Fail to convert to internal representation; nested exception is java.sql.SQLException: Fail to convert to internal representation
i see following lines in debug mode :
DEBUG: org.springframework.security.authentication.ProviderManager - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Authentication request failed: org.springframework.security.authentication.AuthenticationServiceException: PreparedStatementCallback; uncategorized SQLException for SQL [select FIRST_NAME,LAST_NAME,PASSWORD from USER_AUTHENTICATION where FIRST_NAME=?]; SQL state [null]; error code [17059]; Fail to convert to internal representation; nested exception is java.sql.SQLException: Fail to convert to internal representation
DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Updated SecurityContextHolder to contain null Authentication
DEBUG: org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter - Delegating to authentication failure handler org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler#e7736c
DEBUG: org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler - Redirecting to /loginfailed.html
DEBUG: org.springframework.security.web.DefaultRedirectStrategy - Redirecting to '/itrade-web/loginfailed.html'
[Update]: Now for both methods i'm getting same error though i enter correct user name & password.Also,since i could fetch data from D/B i'm sure that I'm not going wrong because of data not present in D/B.
DEBUG: org.springframework.security.provisioning.JdbcUserDetailsManager - Query returned no results for user 'user'
I feel there should be any other reason behind this error.
[Edit] Now I've following 'users_detail' table in D/B :
USER_ID INTEGER
USERNAME VARCHAR2 (50 Byte)
PASSWORD VARCHAR2 (50 Byte)
ENABLED INTEGER
Data in the 'users_detail' table :
USER_ID USERNAME PASSWORD ENABLED
100 user 123456 1
My query is in security-context.xml :
"select username,password, enabled from users_detail where username=?"
when i execute the query manually i.e. select username,password,enabled from users_detail where username='user'. i get the resultsets.
Where am i going wrong ? Why is it that JdbcUserDetailsManager class always return 'Query returned no results for user 'user' ' even though there is an entry for the same in D/B.
Debug mode doesn't show which method of JdbcUserDetailsManager class is being executed when i get the above error. How can i know that? Also, does spring internally do any encryption/decryption technique while saving password field?
The log message "User 'admin' not found" seems pretty clear as a reason for authentication failure, when using the default schema. Why not just execute the command manually and see if it returns the user data?
Also, whether the login screen is shown doesn't depend on whether you set "'authorities-by-username-query" or not. It only depends on whether what intercept-url values apply for the URL you request. The only exception would be if you have customized the access-denied behaviour (for an authenticated user with insufficient rights) to show the login page (not the case here).
Your SQL exception is probably due to your custom table having the wrong column types. You need to end up with something compatible with the result set obtained from the standard schema. Better to stick with the default unless you have a good reason not to.
Better still, forget about Oracle completely until you can get the basics working with a simple test database like HSQLDB.