Spring 5 Google OAuth2 требует URL-адрес перенаправления https, а не http

У меня есть размещенный сайт с Apache httpd (порты 80 и 443) и Wildfly 15 (порт 8080). Мой веб-сервер настроен для обработки http и https и настроен для связи с Wildfly с помощью этих команд.

ProxyPass        / http://myhost.com:8080/
ProxyPassReverse / http://myhost.com:8080/

У меня есть приложение Java 11 Spring 5, развернутое в Wildfly в виде файла WAR. Он настроен на использование Google OAuth, чтобы пользователи могли проходить аутентификацию в моем приложении. Я пытаюсь использовать некоторые API YouTube, для которых требуется специальная «область действия», что означает наличие только https в моем списке «Авторизованные URI перенаправления». Однако мне нужно иметь «http://myhost.com:8080/login/oauth2/code/google» в этом списке прямо сейчас, чтобы пользователи могли успешно войти в систему, что нарушает требования API YouTube.

Я понимаю, почему в этом URI есть «http» и «8080», потому что запрос поступает из моего приложения, развернутого в Wildfly. Но мне нужно изменить его на «https://myhost.com/login/oauth2/code/google».

Как мне это сделать?

Ниже приведены некоторые дополнительные настройки, но, похоже, их недостаточно.

@PropertySource("classpath:application.properties")
@Configuration
@EnableWebSecurity
public class SecurityConfiguration
{
  @Value("${spring.security.oauth2.client.registration.google.redirect-uri}")
  private String             redirectUri;

  @Bean
  public SecurityFilterChain filterChain(
    HttpSecurity http) throws Exception
  {
    http.cors().and().csrf().disable()//

    .authorizeRequests()//
    .antMatchers("/secure/**").authenticated()//
    .antMatchers("/api/**", "/login/**").permitAll()// for redirectUri
    .antMatchers("/**").permitAll()//
    .antMatchers("/logout").permitAll()//

    .and()//
    .sessionManagement()//
    .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)

    .and()//
    .userDetailsService(userDetailsManager())//
    .oauth2Login()// because we need to authorize our users, not just be a web client
    //.oauth2Client()// not this
    .redirectionEndpoint().baseUri(this.redirectUri)//
    .and()//
     .clientRegistrationRepository(this.securityService.getClientRegistrationRepository())//
    .authorizedClientService(this.securityService.getAuthorizedClientService())//
    .loginPage(SecurityController.LOGIN_PAGE_MAPPING)//
    .defaultSuccessUrl(loginSuccessUrl)//
    //.successHandler(this.loginSuccessHandler)//
    .failureUrl("/login-failure-page")//

    .and()//
    .logout()//
    .clearAuthentication(true)//
    .invalidateHttpSession(true)//
    .deleteCookies("JSESSIONID")//
    .logoutSuccessUrl(SecurityController.LOGOUT_PAGE_MAPPING).permitAll()

    // Gotta get back to the correct port after login.
    .and()//
    .requestCache().requestCache(requestCache()); // port mapper here

    // For Firefox and h2-console
    http.headers().frameOptions().disable();

    return http.build();
  }
}

application.properties:

spring.security.oauth2.client.registration.google.redirect-uri=https://myhost.com/login/oauth2/code/google
spring.security.oauth2.client.registration.google.redirectUri=https://myhost.com/login/oauth2/code/google
spring.security.oauth2.client.registration.google.preEstablishedRedirectUri=https://myhost.com/login/oauth2/code/google
spring.security.oauth2.client.use-current-uri=false

Я также определил это для CORS

@Bean
public WebMvcConfigurer corsConfigurer()
{
  return new WebMvcConfigurer()
  {
    @Override
    public void addCorsMappings(
      CorsRegistry registry)
    {
      registry.addMapping("/**")//
        .allowedOrigins(/*"http://myhost.com:8080",*/ "https://myhost.com",
            "https://myhost.com:8080")//
        .allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
    }
  };
}

Отключать защиту CSRF при включенном oauth2Login — очень плохая идея: запросы к вашему приложению авторизуются с помощью файлов cookie сеанса, что делает его уязвимым для атак CSRF.

ch4mp 17.09.2023 06:52

Если я это сделаю, то при попытке запустить JavaScript на своем сайте я получу сообщение «CORS Missing Allow Origin/Invalid CORS request».

Gary Kephart 17.09.2023 20:09

CSRF и CORS — это разные механизмы безопасности, решающие разные угрозы. Активация защиты CSRF не должна вызывать проблем с CORS, вы должны были изменить несколько вещей одновременно.

ch4mp 17.09.2023 20:20

да, было что-то еще, что было причиной этого. Нашёл и исправил это. Все еще нужна помощь по основной проблеме.

Gary Kephart 18.09.2023 07:56
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
4
83
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете обслуживать свое приложение Spring Boot с помощью SSL, используя свойства server.ssl.

Если у вас еще нет сертификата для myhost.com (например, в вашей среде разработки), вы можете найти то, что я размещаю там, полезным для создания самозаверяющего SSL-сертификата и добавления его в свой файл JDK/JREs cacerts. Вы также найдете инструкции по добавлению этого сертификата в доверенные корневые сертификаты вашей ОС.

Если вы работаете с приложениями-сервлетами, я предлагаю вам использовать любой порт, кроме 8080 при использовании https.

Дальнейшие действия из комментариев

Опция выше позволяет использовать https://myhost.com:8080 вместо http://myhost.com:8080 (но, как упоминалось выше, по историческим причинам использовать https://myhost.com:8443 в приложениях сервлетов было бы намного проще).

Если вы не хотите, чтобы трафик к вашему приложению Spring был защищен и хотите сохранить http://myhost.com:8080, вам необходимо настроить URI перенаправления кода авторизации на https://myhost.com/login/oauth2/code/google, как вы пытаетесь сделать в свойствах. Дело в том, что, поскольку вы предоставляете только часть своей конфигурации, мы не можем понять, почему это не работает.

Простое решение

Конфигурация, которую вы предоставляете, довольно запутана и небезопасна (например, приложения с входом OAuth2 подвергаются атакам CSRF, поэтому отключать защиту CSRF — большая ошибка). С помощью этого стартера, который я написал, ваша конфигурация может быть такой простой, как:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

<dependency>
    <groupId>com.c4-soft.springaddons</groupId>
    <artifactId>spring-addons-starter-oidc</artifactId>
    <version>7.1.8</version>
</dependency>
@Configuration
@EnableMethodSecurity
public class SecurityConfig {
}
oauth2-redirect-socket: https://myhost.com
oauth2-issuer: https://accounts.google.com
oauth2-client-id: change-me.apps.googleusercontent.com
oauth2-client-secret: change-me

spring:
  security:
    oauth2:
      client:
        provider:
          oauth2:
            issuer-uri: ${oauth2-issuer}
        registration:
          authorization-code:
            authorization-grant-type: authorization_code
            client-id: ${oauth2-client-id}
            client-secret: ${oauth2-client-secret}
            provider: oauth2
            scope:
            - openid
            - profile
            - email
            - offline_access

com:
  c4-soft:
    springaddons:
      oidc:
        ops:
        - iss: ${oauth2-issuer}
          # skipping issuer configuration which is not used in your case
        client:
          # this forces to build redirect URIs pointing to the SSL gateway
          client-uri: ${oauth2-redirect-socket}
          security-matchers:
          - /**
          permit-all:
          # what is not listed below requires requests to be authorized
          - /login/**
          - /oauth2/**
          - /
          cors:
          - path: "/**"
            allowed-origin-patterns:
            - ${oauth2-redirect-socket}

Если вы не хотите использовать «мой» стартер, обратитесь к этому параграфу README. Он содержит ссылки на руководства по написанию конфигурации безопасности самостоятельно.

У меня есть сертификат SSL для Apache. https сначала проходит через Apache через порт 443, а затем запросы передаются Wildfly.

Gary Kephart 17.09.2023 08:28

тогда почему бы вам не настроить свой Spring OAuth2-клиент так, чтобы он давал URI обратного вызова, указывающий на https-сервер Apache, а не на себя?

ch4mp 17.09.2023 20:22

Это именно то, с чем мне нужна помощь. Я пытался это сделать, но не нашел волшебной формулы. Вот почему я добавил в вопрос свою конфигурацию безопасности.

Gary Kephart 18.09.2023 17:02

Вы имеете в виду что-то вроде того, что написано во втором абзаце руководства по входу в систему OAuth2 ?

ch4mp 20.09.2023 04:13

Соответствует ли первая строка приведенного выше фрагмента файла application.properties тому, что говорится во втором абзаце? Если да, то да, я попробовал, и это не сработало.

Gary Kephart 20.09.2023 08:48

Я показал всем свой код, который уже получил в Интернете. Это не работает. Я ищу кого-нибудь, кто укажет на места в моем коде и скажет: «Это неправильно, вот что правильно».

Gary Kephart 20.09.2023 16:41

Ваша конфигурация запутана, а предоставленные вами фрагменты неполны. Например, там есть ссылка на this.redirectUri, но мы понятия не имеем, как это установлено. Также вы используете очень устаревшие свойства, а некоторые определены в формате double. Сделайте уборку.

ch4mp 20.09.2023 20:08

Я добавил еще немного кода конфигурации. Кроме того, я новичок в Spring Security, и я собрал это со всех веб-страниц, которые смог найти, пытаясь использовать самые последние версии. Однако я так и не нашел страницу, скажем, специально для Spring Security 5, где бы упоминалось, какие вещи устарели, а какие новые. Если вы знаете о такой странице, пожалуйста, дайте мне знать.

Gary Kephart 22.09.2023 08:31

У меня есть набор руководств на Github, но все они написаны с использованием Spring Boot 3/Security 6.

ch4mp 22.09.2023 09:05

Спасибо за помощь. Я отмечаю ваш ответ как правильный, поскольку вы предоставили мне все подробности, но я добавлю еще один ответ, показывающий, как все сложилось.

Gary Kephart 29.09.2023 07:43

Спасибо за голоса (думаю, вы попросили других людей из вашей команды тоже нажать стрелку вверх ;). Это заставило меня еще раз прочитать ответ и понять, что ссылки для написания конфы я не ставил без своего стартера. Я убежден, что этот стартер очень удобен, но я также считаю, что очень важно понимать, что он делает и что нужно сделать, чтобы отказаться, если вам когда-нибудь понадобится.

ch4mp 29.09.2023 08:44

ага, а команда? лол, это сольная работа. Впервые использую OAuth2, Google API, Spotify API и, может быть, еще 1-2 впервые, которые я не могу вспомнить навскидку.

Gary Kephart 29.09.2023 09:05

@ch4mp дал мне необходимую информацию, но я собираюсь рассказать здесь о том, что мне нужно было сделать, чтобы все заработало. Во-первых, я не думал о том, чтобы сделать Wildfly безопасным, но вы можете, и я это сделал. Моя хостинговая компания установила сертификаты с моего сервера Apache на Wildfly.

Затем я изменил свой файл конфигурации Apache, чтобы использовать это:

ProxyPass        / https://hostname.com:8443/
ProxyPassReverse / https://hostname.com:8443/

но дополнительным изменением было добавление следующего, потому что без него ничего не работало.

SSLProxyEngine on

Мне все еще нужно очистить конфигурацию безопасности OAuth2, но ch4mp дал мне много работы. Я рассматриваю это как второстепенную проблему, связанную с получением URI перенаправления Oauth2 для использования https вместо http.

Другие вопросы по теме