I have sprinc core + spring mvc + protection and work using XML configuration, and these are the versions that I use in 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 and move my whole xml configuration to java configuration. What happens is that the login password for spring protection stops working and now gives me a 405 error saying that POST is not allowed. For example, 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">
<http pattern="/assets/**" security="none" />
<http pattern="/css/**" security="none" />
<http pattern="/img/**" security="none" />
<http pattern="/js/**" security="none" />
<global-method-security pre-post-annotations="enabled" />
<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>
<beans:bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="15" />
</beans:bean>
and this is my spring 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());
}
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/assets/**")
.antMatchers("/css/**")
.antMatchers("/img/**")
.antMatchers("/js/**")
.antMatchers("/fonts/**");
}
@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")
.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;
}
@Bean
public PersistentTokenBasedRememberMeServices rememberMeServices() {
PersistentTokenBasedRememberMeServices rememberMeServices = new PersistentTokenBasedRememberMeServices(appKey, userService,
mongoDashPersistentTokenRepository);
rememberMeServices.setCookieName("REMEMBER_ME");
rememberMeServices.setParameter("remember");
rememberMeServices.setTokenValiditySeconds(172800);
return rememberMeServices;
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(15);
return passwordEncoder;
}
}
And this is my appconfig
@Configuration
@Import({SecurityConfig.class})
@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>
<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 when submitting a 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
: - ? , , (js, css, img), , URL- , POST .
.
TL
edit # 1: spring
edit # 2: spring