Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OPTIONS: ne pas retourner de code redirect (3xx) ou erreur #1359

Closed
abulte opened this issue May 2, 2024 · 22 comments · Fixed by opendatateam/udata#3046
Closed

OPTIONS: ne pas retourner de code redirect (3xx) ou erreur #1359

abulte opened this issue May 2, 2024 · 22 comments · Fixed by opendatateam/udata#3046
Labels
💙 Back Les tickets de back Bug Indique qu’il s’agit d’un problème

Comments

@abulte
Copy link
Contributor

abulte commented May 2, 2024

Conditions de reproduction :

  • Utiliser l'API data.gouv.fr dans une application web tierce
  • Etre connecté, i.e. envoyer un header Authorization
  • Accéder à un objet via son ancien slug

Dans ce cas :

  • l'API data.gouv.fr redirige vers le nouveau slug en 308 👍
  • le navigateur fait une requête preflight OPTIONS à cause de la présence du header Authorization
  • le backend data.gouv.fr assigne le code 308 à la réponse à la requête OPTIONS, pas seulement au GET ❌

Un code de redirect n'est pas acceptable pour une requête preflight (voir Spécifications, étape 7 : ok status). Chrome affiche une erreur Redirect is not allowed for a preflight request..

Il faudrait donc retourner une réponse de type 2xx (probablement 204) pour OPTIONS, même si la requête GET subséquente retournera bien un 3xx. Cf la conf simplifiée ici qui retourne toujours un 204.

Ci-dessous un exemple pour https://demo.data.gouv.fr/api/2/topics/plantabilite-des-arbres/ qui redirige vers https://demo.data.gouv.fr/api/2/topics/calque-de-plantabilite/.

Requête :

OPTIONS /api/2/topics/plantabilite-des-arbres/ HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7
Access-Control-Request-Headers: authorization
Access-Control-Request-Method: GET
Connection: keep-alive
Host: demo.data.gouv.fr
Origin: https://demo.ecologie.data.gouv.fr
Referer: https://demo.ecologie.data.gouv.fr/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36

Réponse :

HTTP/1.1 308 PERMANENT REDIRECT
server: nginx
date: Thu, 02 May 2024 10:22:47 GMT
content-type: text/html; charset=utf-8
content-length: 261
location: /api/2/topics/calque-de-plantabilite/
access-control-allow-origin: https://demo.ecologie.data.gouv.fr
access-control-allow-headers: authorization
access-control-allow-methods: DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT
vary: Origin
pragma: public
cache-control: public
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
x-frame-options: SAMEORIGIN
@maudetes maudetes added Bug Indique qu’il s’agit d’un problème 💙 Back Les tickets de back labels May 2, 2024
@maudetes
Copy link
Contributor

maudetes commented May 2, 2024

Merci pour le ticket déjà bien détaillé ! Vous avez une solution de contournement ou c'est vraiment très bloquant chez vous ?

@abulte
Copy link
Contributor Author

abulte commented May 2, 2024

Je vois deux contournements :

  1. faire un truc compliqué et moche pour faire une première requête non authentifiée et détecter s'il y a un redirect
  2. utiliser des ids au lieu des slugs dans les URLs

1/ je ne pense vraiment pas me lancer là-dedans 👹 et 2/ c'est triste 😢 surtout qu'on travaille sur le SEO en ce moment et que les slugs c'est bien mieux à ce niveau là (et pour les usagers au passage).

Donc ça dépend de ce que tu appelles très bloquant :-) Bloquant mais pas très ?

@abulte
Copy link
Contributor Author

abulte commented May 7, 2024

Idem 404

Access to XMLHttpRequest at 'https://demo.data.gouv.fr/api/2/topics/xxx/' from origin 'http://localhost:5173' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

@abulte
Copy link
Contributor Author

abulte commented May 15, 2024

@maudetes on a identifié un autre cas où ça nous bloque (ecolabdata/ecospheres#221) donc je change ma priorisation à très bloquant 👹 😉 🙏

@abulte abulte changed the title OPTIONS: ne pas retourner de code redirect (3xx) OPTIONS: ne pas retourner de code redirect (3xx) ou erreur May 15, 2024
@ThibaudDauce
Copy link

A priori le problème vient de la spécification de CORS plutôt que de Nginx ou Flask… Il y a quelques propositions ici sur la page de Firefox https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#preflighted_requests_and_redirects mais la spécification de CORS est en train de changer pour autoriser les redirections de ce que j'en comprends… Peut-être que la solution la plus simple dans ton cas c'est de ne pas envoyer le header Authorization pour ces requêtes là (qui ne le nécessitent pas ?)

@ThibaudDauce
Copy link

Précision, la section sur le site de Firefox parle d'une redirection après la requête pre-flight ce qui n'est peut-être pas la même chose qu'une redirection en retour de la requête pre-flight, mais je ne vois vraiment pas commet ça pourrait fonctionner côté Python où on a forcément la redirection… Dans tous les cas, ne pas envoyer le header Authorization devrait fonctionner je pense…

@ThibaudDauce
Copy link

J'ai push une PR opendatateam/udata#3046 qui corrige le problème mais je ne suis pas du tout sûr de la validité de faire ça et si ça posera pas de problème autre part…

@ThibaudDauce ThibaudDauce self-assigned this May 23, 2024
@abulte
Copy link
Contributor Author

abulte commented May 23, 2024

Effectivement ça marcherait de ne pas envoyer le header Authorization mais ce n'est pas trivial car il faudrait indiquer pour chaque appel à l'API si on a besoin de l'Authorization ou non. Discriminer sur le verbe ne suffirait pas (eg GET /me a besoin de Authorization). Possible aussi qu'on ait des cas où on a à la fois besoin d'être authentifié et de faire une requête sur une page qui atterrit en redirect. Par exemple sur un dataset supprimé (410) visible seulement pour un admin ou le owner.

Cool pour opendatateam/udata#3046 mais ça ne traite que le cas des redirections, on en aurait aussi besoin pour les 4xx, voire même les 5xx parce qu'on peut vouloir réagir de manière différente dans ces cas là (d'ailleurs dans ce cas, impossible de savoir à l'avance si on a besoin d'être authentifié ou non).

Je pense que le plus simple pour vous est de le gérer au niveau Nginx. Moins de code à maintenir et réglé une fois pour toute. Vous pourriez même désactiver Flask-Cors quand pas en mode DEBUG.

NB : quelques issues pas très intéressantes sur Flask-Cors

@ThibaudDauce
Copy link

@jordanguedj Tu as un avis sur ce problème ? On le fait côté Nginx ?

@ThibaudDauce
Copy link

Salut, j'ai déployé sur demo une nouvelle version avec les CORS corrigés. Est-ce que vous avez des pages spécifiques qui plantaient sur ecologie.data.gouv.fr que l'on pourrait tester sur demo.ecologie.data.gouv.fr et vérifier que ça fonctionne mieux ?

@abulte
Copy link
Contributor Author

abulte commented Jul 10, 2024

Hello ! Plus de page qui plante depuis opendatateam/udata-front-kit#464, on contourne la plupart des problèmes en n'envoyant pas le header d'authorization quand pas besoin.

C'est ok en démo sur les redirections

❯ curl -X OPTIONS -i https://demo.data.gouv.fr/api/2/topics/premier-slug/
HTTP/1.1 308 PERMANENT REDIRECT
server: nginx
date: Wed, 10 Jul 2024 07:39:34 GMT

Ok 401 sur /api/me

❯ curl -X OPTIONS -i https://demo.data.gouv.fr/api/1/me/
HTTP/1.1 200 OK
server: nginx
date: Wed, 10 Jul 2024 07:43:45 GMT

Mais pas sur les autres codes, comme 404 (logique, vu la PR).

❯ curl -X OPTIONS -i https://demo.data.gouv.fr/api/2/topics/not-a-topic/
HTTP/1.1 404 NOT FOUND
server: nginx
date: Wed, 10 Jul 2024 07:39:53 GMT

Je n'ai pas de endpoint pour tester les 5xx, mais ce serait bien qu'on puisse les gérer proprement dans la SPA et donc récupérer la "vraie" requête. Ce serait intéressant d'avoir un endpoint qui retourne arbitrairement une 500 d'ailleurs.

@ThibaudDauce
Copy link

ThibaudDauce commented Jul 10, 2024

Les requêtes preflight doivent contenir un header Access-Control-Request-Method et un Origin sinon elles ne sont pas valides (donc les tests avec uniquement -X OPTIONS n'exerce pas le nouveau code)

Mais tant que ça fonctionne pour vous, ça me va. Si vous rencontrez d'autres soucis n'hésitez pas à me les envoyer. (normalement le code fonctionne pour tous les codes d'erreurs 3xx, 4xx, 5xx…)

https://demo.data.gouv.fr/api/2/topics/premier-slug/

➜  udata git:(fix_cors) curl -X OPTIONS -H "Access-Control-Request-Method: GET" -H "Origin: demo.ecologie.data.gouv.fr" -i https://demo.data.gouv.fr/api/2/topics/premier-slug/
HTTP/1.1 204 NO CONTENT
server: nginx
date: Wed, 10 Jul 2024 07:59:29 GMT
content-type: text/html; charset=utf-8
access-control-allow-origin: demo.ecologie.data.gouv.fr
vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers, Access-Control-Request-Method, Origin
access-control-allow-credentials: true
access-control-allow-methods: GET
access-control-allow-headers: 
pragma: public
cache-control: public
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
x-frame-options: SAMEORIGIN

https://demo.data.gouv.fr/api/1/me/

➜  udata git:(fix_cors) curl -X OPTIONS -H "Access-Control-Request-Method: GET" -H "Origin: demo.ecologie.data.gouv.fr" -i https://demo.data.gouv.fr/api/1/me/
HTTP/1.1 204 NO CONTENT
server: nginx
date: Wed, 10 Jul 2024 07:59:03 GMT
content-type: text/html; charset=utf-8
access-control-allow-origin: demo.ecologie.data.gouv.fr
vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers, Access-Control-Request-Method, Origin
access-control-allow-credentials: true
access-control-allow-methods: GET
access-control-allow-headers: 
pragma: public
cache-control: public
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
x-frame-options: SAMEORIGIN

https://demo.data.gouv.fr/api/2/topics/not-a-topic/

➜  udata git:(fix_cors) curl -X OPTIONS -H "Access-Control-Request-Method: GET" -H "Origin: demo.ecologie.data.gouv.fr" -i https://demo.data.gouv.fr/api/2/topics/not-a-topic/ 
HTTP/1.1 204 NO CONTENT
server: nginx
date: Wed, 10 Jul 2024 08:00:15 GMT
content-type: text/html; charset=utf-8
access-control-allow-origin: demo.ecologie.data.gouv.fr
vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers, Access-Control-Request-Method, Origin
access-control-allow-credentials: true
access-control-allow-methods: GET
access-control-allow-headers: 
pragma: public
cache-control: public
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
x-frame-options: SAMEORIGIN

@abulte
Copy link
Contributor Author

abulte commented Jul 10, 2024

Ah ok, c'est opendatateam/udata#3074 que tu as mis sur démo ? Looks nice, je vais faire quelques tests depuis notre SPA et je te dis.

@abulte
Copy link
Contributor Author

abulte commented Jul 11, 2024

C'est KO même avec les contournements actuels sur démo.

Tu peux tester sur demo.ecologie.data.gouv.fr et essayer de te logguer. Au retour oauth, la requête vers https://demo.data.gouv.fr/oauth/token plante. A priori la requête preflight est bien passée puisque c'est le POST qui pose problème.

Access to XMLHttpRequest at 'https://demo.data.gouv.fr/oauth/token' from origin 'https://demo.ecologie.data.gouv.fr' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Request:

POST /oauth/token HTTP/1.1
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7
Connection: keep-alive
Content-Length: 872
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryC3qW654q1rZ54elU
Host: demo.data.gouv.fr
Origin: https://demo.ecologie.data.gouv.fr
Referer: https://demo.ecologie.data.gouv.fr/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36
sec-ch-ua: "Google Chrome";v="125", "Chromium";v="125", "Not.A/Brand";v="24"
sec-ch-ua-mobile: ?0

Response:

HTTP/1.1 200 OK
server: nginx
date: Thu, 11 Jul 2024 07:01:29 GMT
content-type: application/json
content-length: 178
cache-control: no-store
pragma: no-cache
pragma: public
cache-control: public
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
x-frame-options: SAMEORIGIN

@ThibaudDauce
Copy link

Peut-être que le problème ne vient pas de là mais j'ai activé CORS de façon open uniquement sur les endpoints API, j'avais oublié les endpoints OAuth, je viens de l'activer je redéploie et je reteste et je te dis

@ThibaudDauce
Copy link

C'est déployé et le flow OAuth fonctionne :-) N'hésite pas à me dire si tu vois d'autres problèmes

@abulte
Copy link
Contributor Author

abulte commented Jul 11, 2024

C'est toujours KO sur demo.ecologie.data.gouv.fr pour moi :-/

@ThibaudDauce
Copy link

Tu peux essayer en navigation privée pour voir si c'est pas un problème de cache ?

@abulte
Copy link
Contributor Author

abulte commented Jul 11, 2024

Oui j'ai fait ça, mais rien n'y fait. Testé sous Chrome et FF.

@abulte
Copy link
Contributor Author

abulte commented Jul 11, 2024

Je ne sais pas si tu as changé qqchose mais le login marche maintenant :-)

@ThibaudDauce
Copy link

Oui en fait j'avais déployé mon fix sur dev à la place de demo… :-(

@abulte
Copy link
Contributor Author

abulte commented Jul 11, 2024

Ca marche bien sans les contournements sur notre front (donc en envoyant toujours le header d'Authorization) : 308 et 404 ok 👌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
💙 Back Les tickets de back Bug Indique qu’il s’agit d’un problème
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

3 participants