Как сделать Spring Security OAuth2 действительно без гражданства/избавиться от параметра состояния?

В настоящее время я работаю над проектом, в котором мы хотим, чтобы пользователь входил в систему через Facebook и других поставщиков OAuth2. Кроме того, REST API должен быть без гражданства. Поэтому не следует создавать/использовать файлы cookie/jsessionid. Для авторизации через API API выдает JWT после успешного входа через Facebook. Веб-приложение, использующее остальные API, построено с использованием AgularJS и сателлайзера. Я сократил свой код до минимального примера, доступного на github.

Идея рабочего процесса:

  1. Пользователь заходит на сайт, выбирает "войти через facebook"
  2. Веб-приложение открывает всплывающее окно со страницей входа в facebook.
  3. Пользователь входит в систему, принимает и перенаправляет facebook на веб-приложение
  4. Веб-приложение получает токен от Facebook и использует его для входа в остальные API (GET /login/facebook?code=XXXXXXXXXXXXXXXXXXX).
  5. Остальные API возвращают JWT.
  6. Веб-приложение использует JWT для авторизации остальных API для любых дальнейших запросов.

Пока работает

  • Веб-приложение может обрабатывать шаги с 1 по 4
  • Остальные API могут обрабатывать шаги 5 и 6, если вы используете перенаправление, которое вы получаете от OAuth2ClientContextFilter, выполняя GET на «/login/facebook» без параметра кода. (Это перенаправление идет на facebook, вы входите в систему, вы снова перенаправляетесь на API.)
  • Остальные API не имеют состояния, jsessionid/cookies не создаются/не требуются (отключен csrf и используется SessionCreationPolicy.STATELESS). За исключением вызова «login/facebook», здесь все еще создается jsessionid.

Проблема

Комбинация веб-приложения и остального API-вызова «login/facebook?code=XXX» не работает. Я узнал, что когда вы выполняете GET «логин/facebook», вы будете перенаправлены на facebook с дополнительным параметром состояния, прикрепленным к URL-адресу. Кроме того, этот параметр состояния также добавляется, когда facebook перенаправляет обратно на API. Судя по тому, что я нашел в Интернете, это похоже на защиту от CSRF, верно? И я предполагаю, что этот материал также создает файл cookie jsessionid?

Вопросы

  1. Является ли рабочий процесс, представленный выше, разумной идеей?
  2. Нужна ли мне эта защита CSRF в моем случае использования?
  3. Как я могу отключить это поведение? Я имею в виду, что я использовал SessionCreationPolicy.STATELESS, но Spring по-прежнему создает сеанс с jsessionid. Как я могу создать API для отдыха без сохранения состояния? (По крайней мере, в отношении файлов cookie...)
  4. Это правильный способ сделать это? Или я что-то упускаю?

Пример кода

Как уже было сказано, полный рабочий минимальный пример я выложил на GitHub. Здесь я опубликую только (надеюсь) самую важную часть WebSecurityConfigurerAdapter. полный файл здесь.

@EnableOAuth2Client
@Configuration
public class OAuth2ClientConfigurer extends WebSecurityConfigurerAdapter {

@Autowired
private OAuth2ClientContext oAuth2ClientContext;

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity
            .csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).enableSessionUrlRewriting(false).and()
            .antMatcher("/**").authorizeRequests()
            .antMatchers("/login/**").permitAll()
            .anyRequest().authenticated().and()
            .exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint()).and()
            .addFilterBefore(statelessJwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
            .addFilterBefore(createSsoFilter(facebook(), facebookSuccessHandler(), "/login/facebook"), BasicAuthenticationFilter.class);
}

private OAuth2ClientAuthenticationProcessingFilter createSsoFilter(ClientResourceDetails clientDetails, AuthenticationSuccessHandler successHandler, String path) {
    OAuth2ClientAuthenticationProcessingFilter ssoFilter = new OAuth2ClientAuthenticationProcessingFilter(path);
    ssoFilter.setAllowSessionCreation(false);
    OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(clientDetails.getClient(), oAuth2ClientContext);
    ssoFilter.setRestTemplate(restTemplate);
    ssoFilter.setTokenServices(new UserInfoTokenServices(clientDetails.getResource().getUserInfoUri(), clientDetails.getClient().getClientId()));
    ssoFilter.setAuthenticationSuccessHandler(successHandler);
    return ssoFilter;
}

@Bean // handles the redirect to facebook
public FilterRegistrationBean oAuth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
    FilterRegistrationBean registration = new FilterRegistrationBean();
    registration.setFilter(filter);
    registration.setOrder(-100);
    return registration;
}

Большое спасибо за вашу помощь!


person andy    schedule 15.12.2015    source источник
comment
Вы поняли это? Я структурировал свое приложение немного по-другому, но у меня та же проблема.   -  person KenavR    schedule 09.02.2016
comment
Вы нашли способ сделать его без гражданства?   -  person Andrew Nepogoda    schedule 16.09.2018


Ответы (1)


Это необязательная, но рекомендуемая функция OAuth 2.0. Он применяется сервером авторизации, и, как вы предполагали, его целью является предотвращение атак csrf.

Скопировано из OAuth 2.0 RFC:

state
     RECOMMENDED.  An opaque value used by the client to maintain
     state between the request and callback.  The authorization
     server includes this value when redirecting the user-agent back
     to the client.  The parameter SHOULD be used for preventing
     cross-site request forgery as described in Section 10.12.

https://tools.ietf.org/html/rfc6749#section-4.1. 1

person senjin.hajrulahovic    schedule 21.09.2018