maplibre / martin

Blazing fast and lightweight PostGIS, MBtiles and PMtiles tile server, tile generation, and mbtiles tooling.
https://martin.maplibre.org
Apache License 2.0
2.27k stars 213 forks source link

Enabling CORS via Martin #931

Open nouryf opened 1 year ago

nouryf commented 1 year ago

Hi,

I'm trying to prevent access to resources on a website (from any other not supposed to) by using CORS on Nginx. I did setup a reverse proxy to direct tiles requests to Martin (localhost:3000). On Nginx I tried : add_header "Access-Control-Allow-Origin" "https://www.myWebsite.com";

Looking at the response header I don't see that. So I went and edited Martin to enable it there by modifying "server.rs": line 16:

 use actix_web::{
    http, middleware, route, web, App, HttpMessage, HttpRequest, HttpResponse, HttpServer, Responder,
     Result,
 };

line 422:

 let server = HttpServer::new(move || {
     let cors_middleware = Cors::default()
        .allowed_origin("https://www.myWebsite.com")
        .allowed_origin_fn(|origin, _req_head| {
           origin.as_bytes().ends_with(b".myWebsite.com")
        })
        .allowed_methods(vec!["GET"])
       .allowed_headers(vec![http::header::AUTHORIZATION, http::header::ACCEPT])
        .allowed_header(http::header::CONTENT_TYPE)
        .max_age(3600);

I rebuilt Martin and started it. Then I looked at the response header and I'm not seeing the allow origin there still: HTTP/1.1 200 OK Server: nginx/1.18.0 (Ubuntu) Date: Tue, 10 Oct 2023 10:49:33 GMT Content-Type: image/jpeg Content-Length: 19397 Connection: keep-alive vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers X-Cache-Status: MISS

My ngnix config for the reverse proxy is:

              proxy_set_header  X-Rewrite-URL $uri;
                proxy_set_header  X-Forwarded-Host $host:$server_port;
                proxy_set_header  X-Forwarded-Proto $scheme;
                proxy_redirect    off;

                proxy_connect_timeout   5m;
                proxy_send_timeout      5m;
                proxy_read_timeout      5m;
                send_timeout            5m;

                proxy_cache             backend_cache;
                proxy_cache_lock        on;
                proxy_cache_revalidate  on;
                proxy_cache_valid       200 204 302 1d;
                proxy_cache_valid       404 1m;
                proxy_cache_use_stale   error timeout http_500 http_502 http_503 http_504;
                add_header              X-Cache-Status $upstream_cache_status;
                proxy_pass http://127.0.0.1:3000/;

I must be doing some thing wrong. Thanks for any light you can shed on this.

lefuturiste commented 1 year ago

For more debug insight, can you curl directly the martin server to see from which server the missing header is coming from. Also on the martin code, Is the allowed_origin_fn method is supposed to be ran after allowed_origin? I think it's probably either allowed_origin or allowed_origin_fn

nouryf commented 1 year ago

Thanks @lefuturiste. If i curl the website with one tile request (nginx) or directly the Martin server, I get the same response:

Inside the Martin Server box: curl -v "http://127.0.0.1:3000/../../15634/13390"

From outside the Martin server box: curl -v "https://www.MyWebSite.com/../../15634/13390"

< HTTP/1.1 200 OK < Server: nginx/1.18.0 (Ubuntu) < Date: Tue, 10 Oct 2023 15:09:54 GMT < Content-Type: image/jpeg < Content-Length: 22757 < Connection: keep-alive < vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers < X-Cache-Status: HIT

This seems to mean that the response I get is coming from Martin server ?

nyurik commented 1 year ago

Just FYI - the only CORs related code is here - enabling actix_cors middleware: https://github.com/maplibre/martin/blob/8b34cd374c707548f9e1dccd9385aad0e804f62c/martin/src/srv/server.rs#L424-L434

nouryf commented 1 year ago

Thanks @nyurik. I think that is the code section I edited (must be different commits between what is currently in github and last time I pulled the code: few days ago).

nyurik commented 1 year ago

Note that this code hasn't changed in a while, so probably still the same

nouryf commented 1 year ago

I pulled the latest from github and its same lines u pointed out @nyurik (lines starting at 422). I edited my original post to reflect that line number.

@lefuturiste I removed allowed_origin_fn and got the same result as before.

nyurik commented 1 year ago

So how can we act on this? Should Martin CORS handling be changed in any way? How is it different from the other similar ones like pg_tiles or geoserver?

nouryf commented 1 year ago

Ideally this should be configurable through the .yaml to avoid editing and rebuilding. GeoServer appears to use "web.xml" to configures CORS.

nyurik commented 1 year ago

Do you see it as a bool, or a more advanced setting? What config is actually needed?

nouryf commented 1 year ago

A string should do it. A default value would be: access-control-allow-origin: *. Eventualy one can set their access control to a specific domain. Example: access-control-allow-origin: https://www.example.com

nyurik commented 1 year ago

The Actix Cors support is fairly involved, and has many configuration params. We may actually need to expose more than just origin wildcard. I started a https://github.com/actix/actix-extras/issues/359 to document various common params users may need, and we should pick which of these should be configurable by Martin users, and how to translate them into the Cors middleware configuration.

robjtede commented 12 months ago

If i curl the website with one tile request (nginx) or directly the Martin server, I get the same response:

Inside the Martin Server box: curl -v "http://127.0.0.1:3000/../../15634/13390"

@nouryf This is expected behavior for this invocation of cURL. To trigger CORS handling, you need to add an Origin header to the request; browsers do this automatically.

$ curl -v "http://127.0.0.1:3000/../../15634/13390" --header "Origin: http://127.0.0.1"