Test security with spring boot - java

I confused with configuration for unit test:
This's my test class:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public class MyTest {
private MockMvc mockMvc;
#Autowired
private MyController myController;
#Before
public void setUp() {
mockMvc = MockMvcBuilders
.standaloneSetup(myController)
.apply(SecurityMockMvcConfigurers.springSecurity())
.build();
}
#Test
public void test() {
}
#Configuration
static class Config {
#Bean
MyController myController() {
return new MyController();
}
}
}
When I run it, I get:
java.lang.IllegalStateException: springSecurityFilterChain cannot be
null. Ensure a Bean with the name springSecurityFilterChain
implementing Filter is present or inject the Filter to be used.
How to configure it properly?

Related

MockMvc Spring Boot springSecuirtyChainCannotBeNull issue

Can someone point me to what could be wrong in below code. It is a boot spring 2.6.7 application. When test profile is running, it throws error for all tests like below.
java.lang.IllegalStateException: springSecurityFilterChain cannot be null. Ensure a Bean with the name springSecurityFilterChain implementing Filter is present or inject the Filter to be used
#AutoConfigureMockMvc
#SpringBootTest(classes = some.class)
#ActiveProfiles("test")
public class someTest {
#Autowired
private MockMvc mvc;
#Autowired
private WebApplicationContext webAppContext;
#MockBean
private SomeBean someBean;
#SpyBean
private SomeSpyBean someSpyBean;
#BeforeEach
public void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(webAppContext)
.apply(springSecurity())
.build();
}
#Test
public void SomeTest1() throws Exception {
String text = "text1";
when(someBean.findStuff(text).thenReturn(Optional.of(new Thingie()));
mvc.perform(multipart("/api/somepath/")
.andExpect(status().isNotFound());
verify(someSpyBean).doStuff();
}
#Test
public void SomeTest2() throws Exception {
String text = "text2";
when(someBean.findStuff(text).thenReturn(Optional.of(new Thingie()));
mvc.perform(multipart("/api/somepath/")
.andExpect(status().isFound());
verify(someSpyBean).doStuff();
}
}

Autowiring ApplicationContext in Spring Webflux while writing junit test case

I am trying to write junit for the controller class which is written using spring webflux.
#ExtendWith(SpringExtension.class)
#WebFluxTest(SecurityApiHandler.class)
#ContextConfiguration(classes = { SecurityApiRouter.class, SecurityApiHandler.class })
public class SecurityApiHandlerTest {
#Autowired
private static ApplicationContext context;
private static WebTestClient webTestClient;
#MockBean
private SecurityApiService securityService;
#BeforeAll
public static void setUp() {
webTestClient = WebTestClient.bindToApplicationContext(context).build();
}
#Test
public void healthCheckTest() {
webTestClient.get().uri("/health-check").accept(MediaType.APPLICATION_JSON).exchange().expectStatus().isOk()
.expectBody(HealthCheck.class).value(response -> {
Assertions.assertThat(response.getApiName()).isEqualTo("security-service");
});
}
}
I am following this article to write my test case: https://blog.knoldus.com/spring-webflux-testing-your-router-functions-with-webtestclient/
ApplicationContext is not getting autowired due to which I am getting error IllegalArgumentException: ApplicationContext is required

Custom bean with #PreAuthorize

I have method:
#PreAuthorize("#securityManager.check(#uuid)")
#GetMapping(path = URL_SUBMISSION_ID)
#ControllerLogging
public Object showSomething(#PathVariable(value = "submissionId") UUID submissionId) {
return getData();
}
It works without problem, but I can't test it, because get error:
org.springframework.web.util.NestedServletException: Request
processing failed; nested exception is
java.lang.IllegalArgumentException: Failed to evaluate expression
'#securityManager.check(#uuid)'
My test class:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public class MyTest {
private MockMvc mockMvc;
#Autowired
private MyController myController;
#Before
public void setUp() {
mockMvc = MockMvcBuilders
.standaloneSetup(myController)
.apply(SecurityMockMvcConfigurers.springSecurity())
.build();
}
#Test
public void test() {
// Here some code with mvc mock
}
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
static class Config {
#Bean
MyController myController() {
return new MyController();
}
}
}
What do I miss?
The problem has to do with specifying stating "uuid" in the PreAuthorize method.
It should be rewritten to
#PreAuthorize("#securityManager.check(#submissionId)")

How to fix test failing with "No ModelAndView found"?

This class is in the top of my tests hierarchy:
#TestPropertySource("/test.properties")
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public abstract class ApplicationAbstractTest {
}
And few more test classes:
#WebAppConfiguration
#ActiveProfiles("mysql")
abstract public class AbstractControllerTest extends ApplicationAbstractTest {
protected MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#PostConstruct
private void postConstruct() {
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.apply(springSecurity())
.build();
}
}
JsonUserServiceTest:
#ActiveProfiles("json")
public class JsonUserServiceTest extends ApplicationAbstractTest {
#Before
public void setUp() throws Exception {
...
}
}
ContactControllerTest:
public class ContactControllerTest extends AbstractControllerTest {
#Test
public void testGet() throws Exception {
mockMvc.perform(get("/update-" + ID + "-contact")
.with(userAuth(USER)))
// .andExpect(status().isOk())
.andDo(print())
.andExpect(view().name("details"))
.andExpect(forwardedUrl("/WEB-INF/jsp/details.jsp"));
}
}
So, when I run ContactControllerTest along - it is successfull, and print method shows me:
Handler:
Type = com.telecom.web.ContactController
Method = public java.lang.String com.myApp.web.ContactController.details(java.lang.Integer,org.springframework.ui.ModelMap)
But when I run all tests, so JsonUserServiceTest runs first, ContactControllerTest fails. And print shows:
Handler:
Type = null
...
java.lang.AssertionError: No ModelAndView found
What is wrong in configuration? Or how troubleshoot it?
UPD:
at the same time, test like this, allways works fine:
public class UserControllerTest extends AbstractControllerTest {
#Test
public void testRegister() throws Exception {
mockMvc.perform(get("/register"))
.andDo(print())
.andExpect(view().name("profile"))
.andExpect(forwardedUrl("/WEB-INF/jsp/profile.jsp"));
}
}
UPD:
There is controller's method I'm testing:
#GetMapping("/update-{id}-contact")
public String details(#PathVariable Integer id, ModelMap model) {
Integer userId = AuthorizedUser.id();
LOG.info("get contact {} for User {}", id, userId);
Contact contact = service.get(id, userId);
model.addAttribute("contact", contact);
return "details";
}
I also have such bean:
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/jsp/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
UPD: I've tried configure mockMvc in separate class:
#Configuration
public class TestConfig {
#Autowired
private WebApplicationContext webApplicationContext;
#Bean
public MockMvc mockMvc() {
return MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.apply(springSecurity())
.build();
}
}
And added it here:
#WebAppConfiguration
#ContextConfiguration(classes = {TestConfig.class})
#ActiveProfiles("mysql")
abstract public class AbstractControllerTest extends ApplicationAbstractTest {
but I've received:
java.lang.IllegalStateException: springSecurityFilterChain cannot be
null. Ensure a Bean with the name springSecurityFilterChain
implementing Filter is present or inject the Filter to be used.
The WARN message doesn't cause the test cases to fail. It just says that Entity manager factory is registered twice. This will only be an issue if you cluster your application using the same Entity Manager Factory. For test case run it is not a cause for concern.
The root cause of the testcase failure is in these two lines
.andExpect(view().name("details"))
.andExpect(forwardedUrl("/WEB-INF/jsp/details.jsp"));
Please check if the project has a view named "details" and the forwardded url is "/WEB-INF/jsp/details.jsp"
Update
Could you please try this
#Configuration
public class TestConfig {
#Autowired
private Filter springSecurityFilterChain;
#Autowired
private WebApplicationContext webApplicationContext;
#Bean
public MockMvc mockMvc() {
return MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.apply(springSecurityFilterChain)
.build();
}
}
Create a configuration file that will initialize mocking objects for your test cases. And put at all test case classes.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {TestConfig.class})
It will initialize all your mocking objects only once and cached after that and reused for all test cases.
Or if you don't want to use mocking configuration, you can directly
pass the actual application configuration to ContextConfiguration as
below
For annotation based application configuration (here AppConfig and AppConfig2 are your configuration class)
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {AppConfig.class, AppConfig2.class})
For xml based application configuration (here appConfig.xml and appConfig2.xml are your configuration files)
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:pathTo/appConfig.xml","classpath:pathTo/appConfig2.xml"})
Reference : JUnit + Spring integration example

#Autowire in unit tests does not seem to work

I have a unit test setup using Mockito and Spring 4. My test looks like this:
#ContextConfiguration(classes = {
MyTestConfig.class,
SecurityConfig.class,
OAuth2Config.class
})
#RunWith(MockitoJUnitRunner.class)
public class ControllerAccessTests {
private MockMvc mockMvc;
#Autowired
private FilterChainProxy springSecurityFilterChain;
#Mock
private CreditCardPaymentService creditCardPaymentService;
#InjectMocks
private CreditCardRestController creditCardRestController;
#Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders
.standaloneSetup(creditCardRestController)
.apply(springSecurity(springSecurityFilterChain))
.build();
when(creditCardPaymentService.doPreAuthPayment(any())).thenReturn(null);
}
#Test
//.... some unit tests
With a configuration file that looks like this:
#Configuration
public class MyTestConfig {
#Bean
public FilterChainProxy springSecurityFilterChain(){
AntPathRequestMatcher matcher = new AntPathRequestMatcher("/**");
DefaultSecurityFilterChain chain = new DefaultSecurityFilterChain(matcher);
return new FilterChainProxy(chain);
}
}
When I start the unit test springSecurityFilterChain is null, so it seems the configuration file MyTestConfig does not seem to get loaded. Any ideas?
Cheers
Tom
If you want to use mockito annotations and spring injection then:
1) Use #RunWith(SpringJUnit4ClassRunner.class)
2) Create an init method:
#Before
public void init(){
MockitoAnnotations.initMocks(this);
}

Categories