После того, как сервер авторизации обновлений Spring Boot 2 вернет сообщение «У клиента должен быть зарегистрирован как минимум один redirect_uri». - PullRequest
0 голосов
/ 27 марта 2019

Я обновил наш сервер авторизации с Spring Boot 1.5.13.RELEASE до 2.1.3.RELEASE, и теперь я могу проходить аутентификацию, но больше не могу получить доступ к сайту. Вот результирующий URL и ошибка после POST в /login.

https://auth-service-test-examle.cfapps.io/oauth/authorize?client_id=proxy-service&redirect_uri=http://test.example.com/login&response_type=code&state=QihbF4

   OAuth Error

   error="invalid_request", error_description="At least one redirect_uri must be registered with the client."

Для устранения неполадок я запустил новый проект, основанный на образце Spring Security 5.1.4.RELEASE «oauth2authorizationserver». Я разделил функции, используемые на нашем сервере авторизации Spring Boot 1.5.13, чтобы убедиться, что юнит-тесты пройдены (за исключением одного класса тестирования). Если я @ игнорирую неудачные тесты и внедряю код, я получаю описанную выше проблему.

Проблема воспроизводима в тесте JUnit AuthenticationTests.loginSucceeds (), который прошел перед обновлением. Он ожидает 302, но теперь он получает 403, потому что он идет к корню сервера аутентификации. Я опубликовал весь пример на GitHub весна-безопасности 5-upgrade_sso-Auth-сервер

Клонируйте проект и запустите модульные тесты, и вы увидите сбои.

Вот некоторые ключевые настройки, которые можно найти в проекте на GitHub.

  public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {

  private final String privateKey;

  private final String publicKey;

  private final AuthClientDetailsService authClientDetailsService;

  private final AuthenticationManager authenticationManager;

  private final AuthUserDetailsService authUserDetailsService;

  @Autowired
  public AuthServerConfig(
      @Value("${keyPair.privateKey}") final String privateKey,
      @Value("${keyPair.publicKey}") final String publicKey,
      final AuthClientDetailsService authClientDetailsService,
      final AuthUserDetailsService authUserDetailsService,
      final AuthenticationConfiguration authenticationConfiguration) throws Exception {
    this.privateKey = privateKey;
    this.publicKey = publicKey;
    this.authClientDetailsService = authClientDetailsService;
    this.authUserDetailsService = authUserDetailsService;
    this.authenticationManager = authenticationConfiguration.getAuthenticationManager();
  }

  @Override
  public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
    clients.withClientDetails(authClientDetailsService);
  }

  @Override
  public void configure(final AuthorizationServerEndpointsConfigurer endpoints) {
    endpoints
        .authenticationManager(authenticationManager)
        .accessTokenConverter(accessTokenConverter())
        .userDetailsService(authUserDetailsService)
        .tokenStore(tokenStore());

  }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }


  @Bean
  public JwtAccessTokenConverter accessTokenConverter() {
    final JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setSigningKey(privateKey);
    converter.setVerifierKey(publicKey);
    return converter;
  }

}

public class GlobalAuthenticationConfig extends GlobalAuthenticationConfigurerAdapter {

  private final AuthUserDetailsService authUserDetailsService;

  @Autowired
  public GlobalAuthenticationConfig(final AuthUserDetailsService authUserDetailsService) {
    this.authUserDetailsService = authUserDetailsService;
  }

  @Override
  public void init(AuthenticationManagerBuilder auth) throws Exception {
    auth
        .userDetailsService(authUserDetailsService)
        .passwordEncoder(new BCryptPasswordEncoder());
  }
}

  @Configuration
  @Order(-20)
  protected class LoginConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

      // @formatter:off
      http
          .requestMatchers().antMatchers(LOGIN, "/oauth/authorize", "/oauth/confirm_access")
            .and()
            .logout().permitAll()
            .and()
         .authorizeRequests().anyRequest().authenticated()
            .and()
         .formLogin().loginPage(LOGIN).permitAll();
      // @formatter:on
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
      auth.parentAuthenticationManager(authenticationManager);
    }
  }

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  private final AuthUserDetailsService authUserDetailsService;

  @Autowired
  public WebSecurityConfig(AuthUserDetailsService authUserDetailsService) {
    this.authUserDetailsService = authUserDetailsService;
  }

  @Override
  public void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth
        .userDetailsService(authUserDetailsService)
        .passwordEncoder(new BCryptPasswordEncoder());
  }

}

Что еще нужно сделать в Spring Boot 2.1.3.RELEASE, чтобы перенаправить пользователя обратно на исходную веб-страницу?

1 Ответ

2 голосов
/ 08 апреля 2019

Важно, чтобы клиенты OAuth 2.0 регистрировали redirect_uri на серверах авторизации как для защиты от переадресации .Таким образом, Spring Boot 2.1.x имеет поведение по умолчанию , поэтому вы видите ошибку.

Вы можете сделать одну из двух вещей:

Добавьте redirect_uri s, по одному на каждого клиента

В идеале вы должны обновить своих клиентов, чтобы у каждого был зарегистрирован redirect_uri, который, вероятно, будет получен в реализации ClientDetailsService:

public class MyClientDetailsService implements ClientDetailsService {
    private final MyRespository myRepository;

    public ClientDetails loadClientByClientId(String clientId) {
        return new MyClientDetails(this.myRepository.getMyDomainObject(clientId));
    }

    private static class MyClientDetails extends MyDomainObject implements ClientDetails {
        private final MyDomainObject mine;

        public MyClientDetails(MyDomainObject delegate) {
            this.delegate = delegate;
        }

        // implement ClientDetails methods, delegating to your domain object

        public Set<String> getRegisteredRedirectUri() {
            return this.delegate.getRedirectUris();
        }
    }
}

Эта установка с закрытым подклассом - хотя и не обязательна - хороша тем, что не привязывает объект домена непосредственно к Spring Security.

Добавление пользовательского RedirectResolver

Или вы можете настроить RedirectResolver, хотя это не защитит от открытых переадресаций, что было первоначальной причиной изменения.

public MyRedirectResolver implements RedirectResolver {
    private final RedirectResolver delegate = new DefaultRedirectResolver();

    public String resolveRedirect(String redirectUri, ClientDetails clientDetails) {
        try {
            return this.delegate.resolveRedirect(redirectUri, clientDetails);
        } catch ( InvalidRequestException ire ) {
            // do custom resolution
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...