Как я могу убедиться в том, что Пользователь получил полномочия в тесте Spring Security? - PullRequest
0 голосов
/ 22 апреля 2020

У меня есть поток сброса пароля с 3 шагами: начать, продолжить, завершить sh. Как часть шага продолжения, текущему пользователю предоставляется временное право на изменение своего пароля. Однако, когда я пытаюсь проверить эти полномочия в тесте, объект аутентификации имеет значение null.

Мне интересно, как я могу проверить, что эти полномочия были предоставлены, как и ожидалось?

Конфигурация (извлечение ):

@Autowired
@Bean
public JdbcUserDetailsManager configureGlobal(AuthenticationManager authenticationManager,
                                              AuthenticationManagerBuilder auth) throws Exception {
    JdbcUserDetailsManagerConfigurer jdbcUserDetailsManagerConfigurer = auth.jdbcAuthentication()
            .dataSource(dataSource)
            .passwordEncoder(passwordEncoder())
            .withDefaultSchema();

    jdbcUserDetailsManagerConfigurer.withUser(User.withUsername("user1")
            .password(passwordEncoder().encode("user1"))
            .roles("USER"));

    JdbcUserDetailsManager jdbcUserDetailsManager = jdbcUserDetailsManagerConfigurer.getUserDetailsService();
    jdbcUserDetailsManager.setAuthenticationManager(authenticationManager);

    return jdbcUserDetailsManager;
}

Контроллер:

@RestController
@RequestMapping("/users")
public class UserController {
    private JdbcUserDetailsManager userDetailsManager;
    private PasswordResetTokenRepository passwordResetTokenRepository;


    public UserController(JdbcUserDetailsManager userDetailsManager,
                          PasswordResetTokenRepository passwordResetTokenRepository) {
        this.userDetailsManager = userDetailsManager;
        this.passwordResetTokenRepository = passwordResetTokenRepository;
    }

    @PostMapping("/password-reset/continue")
    public ResponseEntity<Void> continePasswordReset(@RequestBody ContinuePasswordChangeDto continuePasswordChangeDto) {
        String username = continuePasswordChangeDto.getUsername();
        String token = continuePasswordChangeDto.getToken();
        UserDetails userDetails = userDetailsManager.loadUserByUsername(username);
        PasswordResetToken passwordResetToken = passwordResetTokenRepository.findByToken(token);
        if (userDetails != null && !userDetails.isEnabled() &&
                passwordResetToken.getToken().equals(token) && passwordResetToken.getExpiryDate().isAfter(LocalDateTime.now())) {
            Authentication auth = new UsernamePasswordAuthenticationToken(
                    userDetails, null, Arrays.asList(
                    new SimpleGrantedAuthority("CHANGE_PASSWORD_PRIVILEGE"))); // verify this in test
            SecurityContextHolder.getContext().setAuthentication(auth);
            return ResponseEntity.noContent().build();
        }
        return ResponseEntity.badRequest().build();
    }
}

Тест:

@SpringBootTest(classes = Application.class)
@AutoConfigureMockMvc
@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL)
@DisplayName("UserController")
@Transactional
public class UserControllerTest {

    private final String pathPrefix = "/users";
    private MockMvc mvc;
    private final WebApplicationContext webApplicationContext;
    private PasswordResetTokenRepository passwordResetTokenRepository;
    private RandomStringGenerationService randomStringGenerationService;
    private ObjectMapper objectMapper;
    private JdbcUserDetailsManager jdbcUserDetailsManager;

    public UserControllerTest(MockMvc mvc, WebApplicationContext webApplicationContext,
                              PasswordResetTokenRepository passwordResetTokenRepository,
                              RandomStringGenerationService randomStringGenerationService,
                              JdbcUserDetailsManager jdbcUserDetailsManager,
                              ObjectMapper objectMapper) {
        this.mvc = mvc;
        this.webApplicationContext = webApplicationContext;
        this.passwordResetTokenRepository = passwordResetTokenRepository;
        this.randomStringGenerationService = randomStringGenerationService;
        this.jdbcUserDetailsManager = jdbcUserDetailsManager;
        this.objectMapper = objectMapper;
    }

    @BeforeEach
    public void setup() {
        mvc = MockMvcBuilders
                .webAppContextSetup(webApplicationContext)
                .apply(springSecurity())
                .build();
    }

    @DisplayName("A guest who has an account but isn't logged in can continue a password reset")
    @Test
    public void givenGuestWithAccount_whenPasswordResetContinued_thenAuthorityIsGranted() throws Exception {
        String username = "user1";
        String token = randomStringGenerationService.getRandomString();

        PasswordResetToken passwordResetToken = new PasswordResetToken(username, token);
        passwordResetTokenRepository.save(passwordResetToken);

        UserDetails user = jdbcUserDetailsManager.loadUserByUsername(username);
        UserDetails updated = User.withUserDetails(user).disabled(true).build();
        jdbcUserDetailsManager.updateUser(updated);

        // Continue the reset
        ContinuePasswordChangeDto continuePasswordChangeDto = new ContinuePasswordChangeDto(username, token);
        String jsonOfDto = objectMapper.writeValueAsString(continuePasswordChangeDto);

        mvc.perform(post(pathPrefix + "/password-reset/continue")
                .contentType(MediaType.APPLICATION_JSON)
                .content(jsonOfDto)
                .with(csrf())
        ).andExpect(status().isNoContent());

        // This isn't working as there seem to be several SecurityContexts and this particular one has null auth :(
        assertThat(SecurityContextHolder.getContext().getAuthentication().getAuthorities().contains(
                new SimpleGrantedAuthority("CHANGE_PASSWORD_PRIVILEGE"))).isTrue();
    }
}

Если я избавлюсь от части apply(springSecurity()) настройки теста, тест преуспевает ...

...