Spring MVC integration tests with Spring Security - spring-mvc

I'm trying to test my login page using mvc-test.
I was working pretty good before I added spring security.
My code is:
mockMvc.perform(
post("j_spring_security_check")
.param(LOGIN_FORM_USERNAME_FIELD, testUsernameValue)
.param(LOGIN_FORM_PASSWORD_FIELD, testPasswordValue))
.andDo(print())
.andExpect(status().isOk())
.andExpect(model().attribute(LOGIN_PAGE_STATUS_VALUE, LOGIN_PAGE_STATUS_FALSE_INDICATOR));
Test class has correct annotations added:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(locations = {"classpath:security-context.xml", "classpath:applicationContext.xml", "classpath:test-contexts/test-context.xml" })
My filter is defined (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>
When I try to add web.xml in #ContextConfiguration it fails, when I remove it I'm getting an Exception:
java.lang.AssertionError: Status expected:<200> but was:<405>
Is there any way to add DelegatingProxyFilter to test context with configuration defined in my security-context.xml to make it works? I tried few tutorials with injecting FilterProxyChain, but it is not working in my case.
Can someone help me with that?
Thanks in advance

UPDATE: Spring Security 4+ provides out of the box integration with MockMvc. In order to use it ensure you use apply(springSecurity()) as shown below:
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
#WebAppConfiguration
public class MockMvcSecurityTests {
#Autowired
private WebApplicationContext context;
private MockMvc mvc;
#Before
public void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
...
}
Original Answer
I'm not sure what you mean by "When I try to add web.xml in #ContextConfiguration it fails", however, you can use Spring Test MVC to validate Spring Security. There is a very good example outlined in the spring-test-mvc project.
The basic outline would look something like this:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(locations = {"classpath:security-context.xml", "classpath:applicationContext.xml", "classpath:test-contexts/test-context.xml" })
public class MyTests {
#Autowired
private FilterChainProxy springSecurityFilterChain;
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
.addFilters(this.springSecurityFilterChain).build();
}
}
The idea is that you #Autowire the FilterChainProxy (what the DelegatingProxyFilter delegates to) and instruct MockMvc to use the FilterChainProxy.
NOTE spring-test-mvc is integrated into spring-test-3.2+ and a separate project for Spring 3.1.x, so you can use the example fairly interchangeably (spring-test-mvc does not have support for #WebAppConfiguration and has to use WebContextLoader instead).

Add in pom.xml
<repository>
<id>spring-snaspho</id>
<url>http://repo.springsource.org/libs-milestone/</url>
</repository>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>4.0.0.M1</version>
</dependency>
and use org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors for authorization request. See the sample usage at https://github.com/rwinch/spring-security-test-blog (https://jira.spring.io/browse/SEC-2592)

Related

How do I inject an EJB in Spring MVC using annotations?

My dispatcher-servlet.xml has basically:
<context:component-scan base package="package.ejb" />
<mvc:annotation-driven />
In the #Controller class I have:
#Controller
public class ApplicationController {
#EJB(lookup="java:global/MyEarName/MyWebModuleName/BeanImplementation!package.ejb.morepackages.BeanImplementation")
private MyBeanInterface myBean;
This didn't work, it looks like Spring doesn't see the #EJB annotation and it gives an error at deploy time saying it doesn't find any Autowire candidate. So I added the following code:
#Autowired
#Qualifier("BeanImplementation")
public void setMyBean(MyBeanInterface myBean) {
this.myBean = myBean;
}
And on my bean implementation:
#Component("BeanImplementation")
#Stateless(mappedName = "BeanImplementation", name = "BeanImplementation")
#LocalBean
public class BeanImplementation implements MyBeanInterface {
It worked, but I need to use the lookup string of the EJB and I can't since Spring doesn't see #EJB. I was forced to revert to a non-Spring application to use #EJB(lookup="...").
So, to clarify the question: how do I inject an EJB in Spring MVC using annotations and using the EJB lookup string? Thanks.

Spring #EventListener annotation doesn't work with #Service annotation

Here are two objects I want to receive ContextRefreshedEvent
#Component
public class InitDB {
#EventListener
public void handleContextRefresh(ContextRefreshedEvent e) {
//
}
}
InitDB works as expected, but in this case not:
#Service
public class MyService implements IMyService{
#Autowired
private MyDao _dao; // Autowired WORKs
#EventListener
public void handleContextRefresh(ContextRefreshedEvent e) {
// DOESN'T WORK
}
[...]
}
Any Idea what I'm doing wrong?
Here are my maven properties
<properties>
<java-version>1.7</java-version>
<org.springframework-version>4.2.2.RELEASE</org.springframework-version>
<spring-security-web-version>3.2.5.RELEASE</spring-security-web-version>
<org.aspectj-version>1.7.2</org.aspectj-version>
<org.slf4j-version>1.5.10</org.slf4j-version>
<hibernate-version>4.3.6.Final</hibernate-version>
<json-jackson-version>2.4.1</json-jackson-version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<skipTests>true</skipTests>
</properties>
I had the same problem and for me, it proved my listener bean wasn't loaded in the dependencies by Spring.
If you use Spring Boot Actuator, you can check the loaded beans at https://localhost:8443/beans.
The bean wasn't detected by Spring because I had a namespace typo. My main namespace was com.foo (with packages like com.foo.security and com.foo.controllers), and when I added a new package logging, I introduced a typo in the namespace: com.ffoo.logging.
Because of this, Spring could not find the new Components/Services I was adding.
For this particular question, it doesn't matter if it's annotated with #Service, because #Service is a sub-class of #Component (see post)

Spring Security without web.xml

What is the recommended way to add Spring Security to a web application that is using Spring's new WebApplicationInitializer interface instead of the web.xml file? I'm looking for the equivalent of:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
UPDATE
The provided answers are reasonable but they both assume that I've got a servletContext instance. I've looked through the hierarchy of WebApplicationInitializers and I don't see any access to the servlet context unless I choose to override one of Spring's initializer methods. AbstractDispatcherServletInitializer.registerServletFilter seems like the sensible choice but it doesn't default to URL pattern mapping and I'd hate to change filter registration for everything if there is a better way.
This is the way that I have done it:
container.addFilter("springSecurityFilterChain", new DelegatingFilterProxy("springSecurityFilterChain"))
.addMappingForUrlPatterns(null, false, "/*");
container is an instance of ServletContext
The Spring Security Reference answers this question and the solution depends on whether or not you are using Spring Security in conjunction with Spring or Spring MVC.
Using Spring Security without Spring or Spring MVC
If you are not using Spring Security with Spring or Spring MVC (i.e. you do not have an existing WebApplicationInitializer) then you need to provide the following additional class:
import org.springframework.security.web.context.*;
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
public SecurityWebApplicationInitializer() {
super(SecurityConfig.class);
}
}
Where SecurityConfig is your Spring Security Java configuration class.
Using Spring Security with Spring or Spring MVC
If you are using Spring Security with Spring or Spring MVC (i.e. you have an existing WebApplicationInitializer) then firstly you need to provide the following additional class:
import org.springframework.security.web.context.*;
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
Then you need to ensure that your Spring Security Java configuration class, SecurityConfig in this example, is declared in your existing Spring or Spring MVC WebApplicationInitializer. For example:
import org.springframework.web.servlet.support.*;
public class MvcWebApplicationInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {SecurityConfig.class};
}
// ... other overrides ...
}
Dynamic securityFilter = servletContext.addFilter(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME, DelegatingFilterProxy.class);
securityFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
EnumSet.allOf(DispatcherType.class) to be sure that you add a mapping not only for default DispatcherType.REQUEST, but for DispatcherType.FORWARD, etc...
After a bit of work, I've discovered that it's actually quite simple:
public class Initialiser extends AbstractAnnotationConfigDispatcherServletInitializer implements WebApplicationInitializer {
#Override
protected Class< ? >[] getRootConfigClasses() {
return new Class[] { RootConfig.class };
}
#Override
protected Class< ? >[] getServletConfigClasses() {
return new Class[] { WebAppConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected Filter[] getServletFilters() {
return new Filter[] { new DelegatingFilterProxy("springSecurityFilterChain") };
}
}
The most important thing, though, is that you must have a root context (e.g. RootConfig in this case), and that must contain a reference to all the spring security information.
Thus, my RootConfig class:
#ImportResource("classpath:spring/securityContext.xml")
#ComponentScan({ "com.example.authentication", "com.example.config" })
#Configuration
public class RootConfig {
#Bean
public DatabaseService databaseService() {
return new DefaultDatabaseService();
}
#Bean
public ExceptionMappingAuthenticationFailureHandler authExceptionMapping() {
final ExceptionMappingAuthenticationFailureHandler emafh = new ExceptionMappingAuthenticationFailureHandler();
emafh.setDefaultFailureUrl("/loginFailed");
final Map<String, String> mappings = new HashMap<>();
mappings.put(CredentialsExpiredException.class.getCanonicalName(), "/change_password");
emafh.setExceptionMappings(mappings);
return emafh;
}
}
And spring/securityContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:noNamespaceSchemaLocation="http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<security:http security="none" pattern="/favicon.ico"/>
<!-- Secured pages -->
<security:http use-expressions="true">
<security:intercept-url pattern="/login" access="permitAll" />
<security:intercept-url pattern="/**" access="isAuthenticated()" />
<security:form-login default-target-url="/index" login-processing-url="/login_form" login-page="/login" authentication-failure-handler-ref="authExceptionMapping" />
</security:http>
<security:authentication-manager>
<security:authentication-provider ref="customAuthProvider" />
</security:authentication-manager>
</beans>
I could not get it to work if I merged the RootConfig and WebAppConfig classes into just WebAppConfig and had the following:
#Override
protected Class< ? >[] getRootConfigClasses() {
return null;
}
#Override
protected Class< ? >[] getServletConfigClasses() {
return new Class[] { WebAppConfig.class };
}
public class SIServerSecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
#Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
Dynamic registration = servletContext.addFilter("TenantServletFilter", TenantServletFilter.class);
EnumSet<DispatcherType> dispatcherTypes = getSecurityDispatcherTypes();
registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "/*");
}
}
This scenario is for executing a filter before executing other filters.
If you want to execute a filter after other filers pass true in registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");. Also check the DispatcherType ASYNC, FORWARD etc.
Faced with the same problem. Merge RootConfig and WebAppConfig - not best way - because this i did not try this solution. Tried all other solutions - everty time got "org.apache.catalina.core.StandardContext.startInternal Error filterStart". After some work, got something like this:
FilterRegistration.Dynamic enc= servletContext.addFilter("encodingFilter",
new CharacterEncodingFilter());
encodingFilter .setInitParameter("encoding", "UTF-8");
encodingFilter .setInitParameter("forceEncoding", "true");
encodingFilter .addMappingForUrlPatterns(null, true, "/*");
But is not working with DelegatingFilterProxy(). Continue finding for best common solution for all filters.
UPDATE:
I did it.
So, the main issue is: if you want add filters using java config, especially if you want to add security filter, such as DelegatingFilterProxy, then you have to create WebAppSecurityConfig:
#Configuration
#EnableWebSecurity
#ImportResource("classpath:security.xml")
public class WebAppSecurityConfig extends WebSecurityConfigurerAdapter {
}
In this case i create WebAppSecurityConfig and make import resource ("security.xml").
This let me to do that in Initializer class:
servletContext.addFilter("securityFilter", new DelegatingFilterProxy("springSecurityFilterChain"))
.addMappingForUrlPatterns(null, false, "/*");
This is related to those interested in Spring Boot with security: You don't need anything, Spring Boot picks up the #components and solves the other issues

In Spring 3.1 can <mvc:interceptors> be used in conjunction with #Configuration

I am migration from Spring 3.0.5 to 3.1 since I need to have custom RequestMappingHandlerMapping. I am facing problems in plug-in of extended RequestMappingHandlerMapping - I had existing servlet-conetxt.xml and I added WebConfig with #Configuration annotation. But, I always get error ambiguos mapping (since new annotation defined in ExtendedRequestMappingHandlerMapping is not takign in effect).
I have various levels of interceptors defined in servlet-context.xml which I want to keep in XML configuration. I want to use .
Is there a way to use conjunction of servlet-context.xml and at the same time extend RequestMappingHandlerMapping. If this has to be done using #COnfiguration - can I use both #COnfiguration and servlet-context.xml? Any help would be appreciated as I have been trying this since a long time.
<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.test.config</param-value>
</context-param>
Yes, you can use it:
Example:
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocalInterceptor());
registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
}
}
just refer to
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-config-interceptors
for more details.
if use
#EnableWebMvc
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Autowired
Anything anything;
#Override
public void addInterceptors(InterceptorRegistry registry) {
log.info(anything.toString());//this will exception,how to fix?
registry.addInterceptor(new LocalInterceptor());
registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
}
}
the #service can not be setting to Interceptor

How to define servlet filter order of execution using annotations in WAR

If we define webapp specific servlet filters in WAR's own web.xml, then the order of execution of the filters will be the same as the order in which they are defined in the web.xml.
But, if we define those filters using #WebFilter annotation, what is the order of execution of filters, and how can we determine the order of execution?
You can indeed not define the filter execution order using #WebFilter annotation. However, to minimize the web.xml usage, it's sufficient to annotate all filters with just a filterName so that you don't need the <filter> definition, but just a <filter-mapping> definition in the desired order.
For example,
#WebFilter(filterName="filter1")
public class Filter1 implements Filter {}
#WebFilter(filterName="filter2")
public class Filter2 implements Filter {}
with in web.xml just this:
<filter-mapping>
<filter-name>filter1</filter-name>
<url-pattern>/url1/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>filter2</filter-name>
<url-pattern>/url2/*</url-pattern>
</filter-mapping>
If you'd like to keep the URL pattern in #WebFilter, then you can just do like so,
#WebFilter(filterName="filter1", urlPatterns="/url1/*")
public class Filter1 implements Filter {}
#WebFilter(filterName="filter2", urlPatterns="/url2/*")
public class Filter2 implements Filter {}
but you should still keep the <url-pattern> in web.xml, because it's required as per XSD, although it can be empty:
<filter-mapping>
<filter-name>filter1</filter-name>
<url-pattern />
</filter-mapping>
<filter-mapping>
<filter-name>filter2</filter-name>
<url-pattern />
</filter-mapping>
Regardless of the approach, this all will fail in Tomcat until version 7.0.28 because it chokes on presence of <filter-mapping> without <filter>. See also Using Tomcat, #WebFilter doesn't work with <filter-mapping> inside web.xml
The Servlet 3.0 spec doesn't seem to provide a hint on how a container should order filters that have been declared via annotations. It is clear how about how to order filters via their declaration in the web.xml file, though.
Be safe. Use the web.xml file order filters that have interdependencies. Try to make your filters all order independent to minimize the need to use a web.xml file.
If Spring exists in your project you could use org.springframework.core.annotation.Order annotation over the class. F.e. #Order(0), #Order(1) etc.
Make the servlet filter implement the spring Ordered interface.
Declare the servlet filter bean manually in configuration class.
import org.springframework.core.Ordered;
public class MyFilter implements Filter, Ordered {
#Override
public void init(FilterConfig filterConfig) {
// do something
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// do something
}
#Override
public void destroy() {
// do something
}
#Override
public int getOrder() {
return -100;
}
}
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan
public class MyAutoConfiguration {
#Bean
public MyFilter myFilter() {
return new MyFilter();
}
}

Resources