How to mock security context in tests if I disabled authorizarion
Asked Answered
U

1

8

I have tests like this:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
@ActiveProfiles("test")
public class MyTests {

    @Autowired
    private TestRestTemplate restTemplate;
    ....

In tests I disabled authentification/authorizaton

But in code I use following:

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

But it is reason why tests fails.

How can I mock it my tests?

P.S.

This one doesn't work:

@Test
public void testUpdateWithoutNameAndEmail() {
    Authentication authentication = Mockito.mock(Authentication.class);
    SecurityContext securityContext = Mockito.mock(SecurityContext.class);
    Mockito.when(securityContext.getAuthentication()).thenReturn(authentication);
    SecurityContextHolder.setContext(securityContext);
    Mockito.when(authentication.getName()).thenReturn("aName");

    restTemplate.exchange(..

SecurityContextHolder.getContext().getAuthentication() returns null in code

and this one too:

@Autowired
private TestRestTemplate restTemplate;
@Test
@WithMockUser(username = "aUser", roles = { "ADMIN" })
public void testUpdateWithoutNameAndEmail() {
   ...
Ulland answered 11/9, 2017 at 11:7 Comment(7)
you can use SecurityContextHolder.getContext().setAuthentication() and pass to it some Authentication mock (or a real instance if you want)Shirberg
@RC. Where need I write this code?Ulland
@RC. please read topic updateUlland
That's why you should post minimal reproducible example, if you use a restTemplate then you are querying some real server. So you need to use a real authentication (username password basic auth maybe).Shirberg
@RC, I use TestRestTemplate and I wrote it in initial postUlland
From the javadoc "If you are using the @SpringBootTest annotation, a TestRestTemplate is automatically available and can be @Autowired into your test. If you need customizations (for example to adding additional message converters) use a RestTemplateBuilder @Bean." So build a TestRestTemplare with some authentication (username / password)Shirberg
@RC. But how to use WithMockUser annotation ? Which classes should I use?Ulland
I
16

You can mock Spring's Authentication:

Authentication authentication = Mockito.mock(Authentication.class);

And tell Spring's SecurityContextHolder to store this Authentication instance:

SecurityContext securityContext = Mockito.mock(SecurityContext.class);
Mockito.when(securityContext.getAuthentication()).thenReturn(auth);
SecurityContextHolder.setContext(securityContext);

Now, if your code needs Authentication to return something (the user name perhaps) you just set some expectations on the mocked Authentication instance in the usual way e.g.

Mockito.when(authentication.getName()).thenReturn("aName");

There's also a Spring test annotation (org.springframework.security.test.context.support.WithMockUser) which does this for you...

@Test
@WithMockUser(username = "aUser", roles = { "anAuthority" })
public void aTest(){
    // any usage of `Authentication` in this test will get an instance withe the user name "aUser" and a granted authority "anAuthority"
    // ...
}
Insignificance answered 11/9, 2017 at 11:19 Comment(5)
I have created objects according your description. I did it in the test begining. But SecurityContextHolder.getContext().getAuthentication() still returns nullUlland
I have added details to topicUlland
@WithMockUser doesn't wor tooUlland
Might need some more details. The above approaches are valid ways of mocking SecurityContext and I cannot reproduce a NPE given the information in your question.Insignificance
1. Do you understand that I use TestRestTemplate for testing? SecurityContextHolder.getContext().getAuthentication() returns null equals NPE in my topic updateUlland

© 2022 - 2024 — McMap. All rights reserved.