# Spring Security's SecurityContext get unexpectedly cleared in a MockMvc Test

# Background

At work, there’s some test written where I wanted to query the database (repository) after `mockMvc` request has been made to verify the result. This is a very simple illustration of what it looks like.

```java
@SpringBootTest
@AutoConfigureMockMvc
class SomeTests {
    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private UserRepository repository;

    @Test
    @WithMockUser(value = "bwgjoseph")
    void test() {
        this.mockMvc.perform(post("/api/v1/users/{name}", "bwgjoseph")
            .accept(MediaType.APPLICATION_JSON)
            .contentType(MediaType.APPLICATION_JSON))
        .andExpect(status().isOk());

        // extract data from repository
        var user = this.repository.findByName();

        // verify result
        assertThat(user.get()).extracting("name").isEqualTo("bwgjoseph");
    }
}
```

> Please note that for simplicity, I have configured my Spring Security `user.name` as `bwgjoseph`. And that is why the code above for `@WithMockUser` is also defined as such. This is to facilitate the `@Query` used in `UserRepository` to extract the correct username via the `principal?.username`.

Once run, the following exception will be thrown `java.lang.IllegalArgumentException: Authentication object cannot be null`.

```verilog
org.springframework.expression.spel.SpelEvaluationException: EL1021E: A problem occurred whilst attempting to access the property 'principal': 'EL1022E: The function 'principal' mapped to an object of type 'class org.springframework.security.access.expression.SecurityExpressionRoot' cannot be invoked'
<omitted>
Caused by: java.lang.IllegalArgumentException: Authentication object cannot be null
	at org.springframework.util.Assert.notNull(Assert.java:181)
	at org.springframework.security.access.expression.SecurityExpressionRoot.lambda$new$1(SecurityExpressionRoot.java:92)
	at org.springframework.util.function.SingletonSupplier.get(SingletonSupplier.java:106)
	at org.springframework.security.access.expression.SecurityExpressionRoot.getAuthentication(SecurityExpressionRoot.java:130)
	at org.springframework.security.access.expression.SecurityExpressionRoot.getPrincipal(SecurityExpressionRoot.java:170)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	... 44 more
```

After some digging, I found out that the reason was because `SecurityContext` is cleared at the end of the filter chain after the `mockMvc` request, hence, if we were to perform any method call to the repository layer which requires `principal (Authentication)` object, it will fail.

```java
public interface UserRepository extends CrudRepository<User, String> {
    @Query("SELECT * FROM \"USER\" WHERE name = :#{ principal?.username }")
    Optional<User> findByName();
}
```

To fix this, we simply just need to export the `SecurityContext` for use after the `mockMvc` request

```java
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultHandlers.exportTestSecurityContext;

@Test
@WithMockUser(value = "bwgjoseph")
void test() throws Exception {
    this.mockMvc.perform(post("/api/v1/users/{name}", "bwgjoseph")
                    .accept(MediaType.APPLICATION_JSON)
                    .contentType(MediaType.APPLICATION_JSON))
            .andDo(exportTestSecurityContext()) // to export security context
            .andExpect(status().isCreated());

    var user = this.repository.findByName();

    assertThat(user.get()).extracting("name").isEqualTo("bwgjoseph");
}
```

Note that one could manually export the context, but I can’t think of any reason why one would want to do it this way.

```java
@Test
@WithMockUser(value = "bwgjoseph")
void test() throws Exception {
    this.mockMvc.perform(post("/api/v1/users/{name}", "bwgjoseph")
            .accept(MediaType.APPLICATION_JSON)
            .contentType(MediaType.APPLICATION_JSON)
            .andExpect(status().isOk());

    SecurityContextHolder.setContext(TestSecurityContextHolder.getContext());

    var user = this.repository.findByName();

    assertThat(user.get()).extracting("name").isEqualTo("bwgjoseph");
}
```

# Tips

If you encounter the following error

```java
org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'principal' cannot be found on object of type 'java.lang.Object[]' - maybe not public or not valid?
```

Please ensure that you have the following dependency added in your project

```xml
<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-data</artifactId>
</dependency>
```

# Conclusion

We looked at how to “re-use” the SecurityContext in order to be able to verify our test by querying the database after `mockMvc` request. As simple as it looks, figuring this out at a larger code base took a while to realize that this is the root cause, but luckily, the solution is pretty straight-forward.

# References:

* [https://stackoverflow.com/questions/51622300/mockmvc-seems-to-be-clear-securitycontext-after-performing-request-java-lang-il](https://stackoverflow.com/questions/51622300/mockmvc-seems-to-be-clear-securitycontext-after-performing-request-java-lang-il)
    
* [https://github.com/spring-projects/spring-data-mongodb/issues/2906](https://github.com/spring-projects/spring-data-mongodb/issues/2906)
    
* [https://github.com/spring-projects/spring-security/issues/9565](https://github.com/spring-projects/spring-security/issues/9565)
    
* [Exporting the SecurityContext](https://docs.spring.io/spring-security/reference/servlet/test/mockmvc/result-handlers.html#_exporting_the_securitycontext)
    

# Source Code

As usual, the full source code is available on [**GitHub**](https://github.com/bwgjoseph/tutorials/tree/main/spring-security-securitycontext-mockmvc)
