SpringSecurity WithSecurityContext MockMvc OAuth2 всегда не авторизован

Я перешел по следующим ссылкам, чтобы попробовать и протестировать OAuth2 @PreAuthorise(hasAnyRole('ADMIN', 'TEST') например, но я не могу ни один из тестов пройти или даже пройти аутентификацию.

Когда я пытаюсь получить доступ к конечной точке с правами администратора (или любой роли), она никогда не будет правильно аутентифицироваться. Я пропустил что-то очевидное, кажется, у меня все так же, как в примерах. Я также пробовал другую альтернативу фабрике WithSecurityContext со специальной аутентификацией OAuth, и мне все еще не повезло. Любая помощь будет оценена по достоинству.

https://stackoverflow.com/a/31679649/2594130 и http://docs.spring.io/spring-security/site/docs/4.0.x/reference/htmlsingle/#test

Мой контроллер, который я тестирую

@RestController
@RequestMapping("/bookmark/")
public class GroupBookmarkController {

    @Autowired
    BookmarkService bookmarkService;

    /**
    * Get list of all bookmarks
    */
    @RequestMapping(value = "{groupId}", method = RequestMethod.GET)
    @PreAuthorize("hasAnyRole(['ADMIN', 'USER'])")
    public ResponseEntity<List<Bookmark>> listAllGroupBookmarks(@PathVariable("groupId") String groupId) throws BookmarkNotFoundException {
        List<Bookmark> bookmarks = bookmarkService.findAllBookmarksByGroupId(groupId);
        return new ResponseEntity<>(bookmarks, HttpStatus.OK);
    }
    ...
}

Мой тестовый класс

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = BookmarkServiceApplication.class)
@WebAppConfiguration
public class BookmarkServiceApplicationTests {

    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext webApplicationContext;

    @Before
    public void loadData() {
        this.mockMvc = MockMvcBuilders
                .webAppContextSetup(webApplicationContext)
                .apply(springSecurity())
                .alwaysDo(print())
                .build();
    }

    @Test
    @WithMockCustomUser(username = "test")
    public void getBookmarkAuthorised() throws Exception {
        mockMvc.perform(get("/bookmark/nvjdbngkjlsdfngkjlfdsnlkgsd"))
                .andExpect(status().is(HttpStatus.SC_OK));
        // always 401 here
    }
}

Приложение My BookmarkService

@SpringBootApplication
@EnableResourceServer
public class BookmarkServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(BookmarkServiceApplication.class, args);
    }
}

Мой WithSecurityContextFactory

public class WithMockCustomUserSecurityContextFactory implements WithSecurityContextFactory<WithMockCustomUser> {
    @Override
    public SecurityContext createSecurityContext(WithMockCustomUser customUser) {
        SecurityContext context = SecurityContextHolder.createEmptyContext();

        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));

        UserDetails principal = new User(customUser.username(), "password", true, true, true, true, grantedAuthorities);


        Authentication authentication = new UsernamePasswordAuthenticationToken(
                principal, principal.getPassword(), principal.getAuthorities());
        context.setAuthentication(authentication);

        return context;
    }
}

Моя аннотация WithSecurityContext

@Retention(RetentionPolicy.RUNTIME)
@WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory.class)
public @interface WithMockCustomUser {

    String username() default "user";

    String name() default "Test User";
}

Согласно ответу @RobWinch

Привет @RobWinch. Я попробовал ваше предложение с флагом без гражданства, это помогло с частью ответа. Однако в вашем ответе на этот вопрос [Spring OAuth и тест интеграции загрузки] (https://stackoverflow.com/a/31679649/2594130) вы упоминаете

Вам больше не нужно беспокоиться о работе в режиме без сохранения состояния или нет.

Почему мне все еще нужно добавить false без сохранения состояния, это ошибка или мы используем ее немного по-другому?

Еще одна вещь, которую мне нужно было сделать, чтобы заставить это работать, это добавить OAuth2Request и OAuth2Authentication в WithSecurityContextFactory, как вы можете видеть в следующем

public class WithMockCustomUserSecurityContextFactory implements WithSecurityContextFactory<WithMockOAuthUser> {

    @Override
    public SecurityContext createSecurityContext(WithMockOAuthUser withClient) {
        // Get the username
        String username = withClient.username();
        if (username == null) {
            throw new IllegalArgumentException("Username cannot be null");
        }

        // Get the user roles
        List<GrantedAuthority> authorities = new ArrayList<>();
        for (String role : withClient.roles()) {
            if (role.startsWith("ROLE_")) {
                throw new IllegalArgumentException("roles cannot start with ROLE_ Got " + role);
            }
            authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
        }

        // Get the client id
        String clientId = withClient.clientId();
        // get the oauth scopes
        String[] scopes = withClient.scope();
        Set<String> scopeCollection = Sets.newSet(scopes);

        // Create the UsernamePasswordAuthenticationToken
        User principal = new User(username, withClient.password(), true, true, true, true, authorities);
        Authentication authentication = new UsernamePasswordAuthenticationToken(principal, principal.getPassword(),
                principal.getAuthorities());


        // Create the authorization request and OAuth2Authentication object
        OAuth2Request authRequest = new OAuth2Request(null, clientId, null, true, scopeCollection, null, null, null,
                null);
        OAuth2Authentication oAuth = new OAuth2Authentication(authRequest, authentication);

        // Add the OAuth2Authentication object to the security context
        SecurityContext context = SecurityContextHolder.createEmptyContext();
        context.setAuthentication(oAuth);
        return context;
    }

}

comment
Где код для WithMockOAuthUser и связанного с ним WithSecurityContextFactory?   -  person Rob Winch    schedule 02.06.2016
comment
@RobWinch Извините, это опечатка, на самом деле это WithMockCustomUser, который был опечаткой, когда я возился, такая же проблема существует. У меня был другой интерфейс, который создавал аутентификацию OAuth вместо UsernamePasswordAuthentication.   -  person revilo    schedule 03.06.2016
comment
Как выглядит ваша конфигурация безопасности? В частности, как выглядит конфигурация безопасности сети и метода?   -  person Rob Winch    schedule 03.06.2016
comment
@RobWinch На самом деле у меня нет конфигурации, работающей по умолчанию, это микросервис и связь за шлюзом к службе аутентификации, которая несет конфигурацию. Эти тесты выполняются изолированно от AuthService. Должен ли я по-прежнему иметь конфигурацию?   -  person revilo    schedule 07.06.2016
comment
@revilo Если я могу спросить, можете ли вы поделиться репозиторием с вашей тестовой средой? Я пытаюсь протестировать spring-security-oauth2 и не могу получить ничего, кроме 401. Ваш пост больше всего помог мне понять. Тест проекта с spring-security и spring-security-oauth2 еще не существует. Было бы супер красиво. заранее спасибо   -  person Dimitri Kopriwa    schedule 18.11.2017


Ответы (2)


Проблема в том, что OAuth2AuthenticationProcessingFilter очистит SecurityContext, если он помечен как не имеющий состояния. Чтобы обойти это, настройте его, чтобы разрешить внешнее заполнение состояния (т. е. без сохранения состояния = false).

person Rob Winch    schedule 03.06.2016
comment
Привет @RobWinch. Я попробовал ваше предложение с флагом без гражданства, это помогло с частью ответа. Однако в вашем ответе на этот вопрос [Тест интеграции Spring OAuth и загрузки] (stackoverflow.com/a/31679649/2594130) вы упоминаете Вам больше не нужно беспокоиться о работе в режиме без сохранения состояния или нет Почему это необходимо Мне это нужно, это ошибка или мы используем это немного по-другому. Я обновил ответ, так как здесь закончились символы - person revilo; 21.06.2016
comment
Spring Security OAuth обрабатывает данные без сохранения состояния иначе, чем Spring Security, поэтому это утверждение неприменимо для OAuth (к сожалению). - person Rob Winch; 01.07.2016
comment
Как именно вы устанавливаете это = false в приведенном выше примере? - person PaulNUK; 02.11.2016
comment
@RobWinch Дорогой Роб, мы несколько дней пытались протестировать spring-security-oauth2, но также получили 401 ошибку. В Spring-security-oauth2 нет примера, а он нам нужен. Есть ли способ получить пример или дополнительную информацию? - person Dimitri Kopriwa; 18.11.2017

чтобы добавить дополнительную информацию о том, как установить без гражданства значение false:

в вашем ResourceServerConfigurerAdapter сделайте следующее:

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.stateless(false);
    }

который работал для меня.

person David Steiman    schedule 01.07.2016