DiscourseConnect génère des redirections HTTP même avec force_https activé

Je fais tourner Discourse derrière Traefik dans une configuration personnalisée - donner à Discourse sa propre VM n’est pas une option ici.

Mon Discourse n’a pas les modèles SSL/Let’s Encrypt activés, car Traefik ne laisse pas les requêtes HTTP simples atteindre le conteneur - il est configuré pour rediriger les requêtes HTTP vers HTTPS.

J’ai des problèmes pour configurer DiscourseConnect, car, puisque la requête Traefik -> nginx[Discourse] est envoyée en texte brut HTTP (parce que nginx n’a pas de SSL configuré), la règle dans /etc/nginx/conf.d/discourse.conf qui essaie de préserver le proto, doit être dans le contexte http fait que Discourse (l’application Rails) reçoit une requête HTTP en texte brut, renvoyant ainsi une redirection HTTP en texte brut vers /session/sso - même si j’ai force_https activé.

Je pense que c’est le bug : indépendamment de ma configuration, avec force_https activé, Discourse devrait toujours générer des URL HTTPS - ce qu’il ne fait pas.

Je pense que le code fautif est application_controller#redirect_to_login, mais je n’ai pas beaucoup creusé le code source de Discourse pour en être sûr.

Est-ce que cela peut être résolu dans le code lui-même ?

Comme solution de contournement, j’essaie d’ajouter une règle patchant le discourse.conf de nginx pour supprimer cette règle.

Nous devrions avoir un certain support pour les en-têtes transférés que vous utiliseriez pour signaler à NGINX quelle est l’origine.

Avez-vous défini
proxy_set_header X-Forwarded-Proto https;

Ce qui a été le plus facile pour moi, c’est d’ajouter une étiquette supplémentaire dans app.yml de Discourse pour dire à mon Traefik d’ajouter un en-tête X-Forwarded-Proto: https, mais ensuite nginx remplacerait ce paramètre par sa propre version.

Et la configuration nginx de Discourse joue un rôle ici :

Là, Discourse essaie de deviner le protocole de la requête d’origine (qui, dans ma configuration, est toujours en texte brut puisque c’est ce que Traefik envoie). Et l’utilise ensuite pour définir le X-Forwarded-Proto plusieurs fois.

Finalement, j’ai modifié mon containers/app.yml pour coder en dur ces en-têtes en https :

run:
  - exec: echo "Beginning of custom commands"
  ## If you want to set the 'From' email address for your first registration, uncomment and change:
  ## After getting the first signup email, re-comment the line. It only needs to run once.
  # - exec: rails r "SiteSetting.notification_email='no-reply@forum.cabana.network'"
  - replace:
     filename: "/etc/nginx/conf.d/discourse.conf"
     from: /# attempt to preserve the proto, must be in http context\nmap $http_x_forwarded_proto $thescheme {\n  default $scheme;\n  "~https$" https;\n}/\n
     to: |
       # force https scheme so Discourse generates HTTPs links and redirects (ie, `/login`)
  - replace:
     filename: "/etc/nginx/conf.d/discourse.conf"
     from: "$thescheme"
     global: "true"
     to: "https"
  - exec: echo "End of custom commands"

Encore une fois, je pense que s’il existait un réglage force_https, Discourse-l’application-rails devrait le respecter, indépendamment de ce que le proxy inverse ou d’autres parties gèrent ou non.

C’est ainsi que nous procédons sur notre plateforme d’hébergement ; nous avons une couche d’équilibrage de charge qui définit X-Forwarded-Proto pour que le nginx+Discourse en aval puisse le consommer.

Nous n’avons pas besoin de tours de passe-passe supplémentaires pour que cela fonctionne - je ne suis pas sûr de ce qui ne va pas pour vous ici.

C’est effectivement ce qui se passe :

  def self.generate_sso(return_path = "/", secure_session:)
    sso = new(secure_session: secure_session)
    sso.nonce = SecureRandom.hex
    sso.register_nonce(return_path)
    sso.return_sso_url = Discourse.base_url + "/session/sso_login"
    sso
  end

et base_url provient de :

  def self.base_protocol
    SiteSetting.force_https? ? "https" : "http"
  end

  def self.base_url_no_prefix
    "#{base_protocol}://#{current_hostname_with_port}"
  end

  def self.base_url
    base_url_no_prefix + base_path
  end
1 « J'aime »