dunglas / mercure

🪽 An open, easy, fast, reliable and battery-efficient solution for real-time communications
https://mercure.rocks
GNU Affero General Public License v3.0
3.9k stars 289 forks source link

No 'Access-Control-Allow-Origin' header is present on the requested resource #442

Closed JSmythSSG closed 3 years ago

JSmythSSG commented 3 years ago

I've just moved over from the legacy to the new Caddy version and getting has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Is this an issue with the cors on the mercure server side or is it something to do with the requesting server not sending the correct header. Currently its hosted on an nginx docker and uses Cloudflare for dns routing

{"level":"info","ts":1610116467.3811321,"logger":"http.log.access","msg":"handled request","request":{"remote_addr":"188.114.110.34:29984","proto":"HTTP/1.1","method":"GET","host":"XXXXXXXXX:8443","uri":"/.well-known/mercure?topic=https%3A%2F%2FXXXXXXXXX%2Fv1%2Fmanage%2Fcontacts%2F4311","headers":{"Cf-Request-Id":["078404a26b0000ff6867993000000001"],"Cdn-Loop":["cloudflare"],"Origin":["https://192.168.1.170"],"Referer":["https://192.168.1.170/"],"Accept-Language":["en-GB,en-US;q=0.9,en;q=0.8,nl;q=0.7"],"Sec-Fetch-Site":["cross-site"],"Cf-Connecting-Ip":["86.134.113.95"],"X-Forwarded-Proto":["https"],"Cf-Visitor":["{\"scheme\":\"https\"}"],"Accept":["text/event-stream"],"Cache-Control":["no-cache"],"User-Agent":["Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4356.6 Safari/537.36"],"Sec-Fetch-Mode":["cors"],"Sec-Fetch-Dest":["empty"],"Connection":["Keep-Alive"],"Accept-Encoding":["gzip"],"X-Forwarded-For":["86.134.113.95"],"Cf-Ipcountry":["GB"],"Cf-Ray":["60e6a3b0ad41ff68-MAD"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"","proto_mutual":true,"server_name":"XXXXXXXXX"}},"common_log":"188.114.110.34 - - [08/Jan/2021:14:34:27 +0000] \"GET /.well-known/mercure?topic=https%3A%2F%2FXXXXXXXXX%2Fv1%2Fmanage%2Fcontacts%2F4311 HTTP/1.1\" 0 0","duration":0.00000684,"size":0,"status":0,"resp_headers":{"Server":["Caddy"],"Alt-Svc":["h3-32=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000"]}}

dunglas commented 3 years ago

Could you paste your config please?

JSmythSSG commented 3 years ago

The caddy file is

 {

    {$DEBUG}

    servers {
        protocol {
            experimental_http3
        }
    }
}

{$SERVER_NAME:localhost}

tls /etc/ssl/private/xxx.pem /etc/ssl/private/xxx.key

log

route {
    encode zstd gzip

    mercure {

        transport_url {$MERCURE_TRANSPORT_URL:bolt://mercure.db}

        publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}

        subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}

        cors_origins *
        subscriptions

        {$MERCURE_EXTRA_DIRECTIVES}

    }

    respond "Not Found" 404
} 

the compose file


 mercure:
    container_name: api-mercure
    image: dunglas/mercure:v0.11
    environment:
      - MERCURE_PUBLISHER_JWT_KEY=XXX
      - MERCURE_SUBSCRIBER_JWT_KEY=XXX
      - DEBUG=debug 
    ports:
    - "8443:443"
    volumes: 
     - ../ssl:/etc/ssl/private
     - ./mercure/caddy:/etc/caddy 
dunglas commented 3 years ago

That's weird, I'm not able to reproduce using Caddy and no reverse proxy.

I get this result:

2021/01/18 21:53:18.977 INFO    http.log.access handled request {"request": {"remote_addr": "[::1]:54739", "proto": "HTTP/2.0", "method": "POST", "host": "localhost", "uri": "/.well-known/mercure", "headers": {"Authorization": ["Bearer eyJhbGciOiJIUzI1NiJ9.eyJtZXJjdXJlIjp7InB1Ymxpc2giOlsiKiJdLCJzdWJzY3JpYmUiOlsiaHR0cHM6Ly9leGFtcGxlLmNvbS9teS1wcml2YXRlLXRvcGljIiwie3NjaGVtZX06Ly97K2hvc3R9L2RlbW8vYm9va3Mve2lkfS5qc29ubGQiLCIvLndlbGwta25vd24vbWVyY3VyZS9zdWJzY3JpcHRpb25zey90b3BpY317L3N1YnNjcmliZXJ9Il0sInBheWxvYWQiOnsidXNlciI6Imh0dHBzOi8vZXhhbXBsZS5jb20vdXNlcnMvZHVuZ2xhcyIsInJlbW90ZUFkZHIiOiIxMjcuMC4wLjEifX19.z5YrkHwtkz3O_nOnhC_FP7_bmeISe3eykAkGbAl5K7c"], "Sec-Fetch-Mode": ["cors"], "Sec-Fetch-Dest": ["empty"], "Accept-Encoding": ["gzip, deflate, br"], "Content-Length": ["218"], "Content-Type": ["application/x-www-form-urlencoded;charset=UTF-8"], "Accept": ["*/*"], "Origin": ["https://localhost"], "Referer": ["https://localhost/.well-known/mercure/ui/"], "Sec-Ch-Ua": ["\"Google Chrome\";v=\"87\", \" Not;A Brand\";v=\"99\", \"Chromium\";v=\"87\""], "Sec-Ch-Ua-Mobile": ["?0"], "Cookie": ["Phpstorm-c69683e0=a4ac2a0a-45e7-4dbb-95eb-ad136b6410d3"], "Dnt": ["1"], "User-Agent": ["Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36"], "Sec-Fetch-Site": ["same-origin"], "Accept-Language": ["en,fr-FR;q=0.9,fr;q=0.8,en-US;q=0.7,de;q=0.6"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "h2", "proto_mutual": true, "server_name": "localhost"}}, "common_log": "::1 - - [18/Jan/2021:22:53:18 +0100] \"POST /.well-known/mercure HTTP/2.0\" 200 45", "duration": 0.035590991, "size": 45, "status": 200, "resp_headers": {"Alt-Svc": ["h3-32=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000"], "X-Frame-Options": ["DENY"], "X-Content-Type-Options": ["nosniff"], "X-Xss-Protection": ["1; mode=block"], "Content-Security-Policy": ["default-src 'self' mercure.rocks cdn.jsdelivr.net"], "Access-Control-Allow-Credentials": ["true"], "Access-Control-Allow-Origin": ["*"], "Server": ["Caddy"]}}

(The Access-Control-Allow-Origin is present).

dunglas commented 3 years ago

Is the NGINX server in front of Caddy? If yes could you also paste its configuration?

gdis commented 3 years ago

I can confirm that something is wrong with cors. I have exact the same config, running on linux native, here a response

2021/01/25 13:08:58.529 INFO http.log.access handled request {"request": {"remote_addr": "xxx.xxx.xxx.xxx:62304", "proto": "HTTP/2.0", "method": "HEAD", "host": "xxx.xxx.xxx", "uri": "/", "headers": {"User-Agent": ["curl/7.64.1"], "Accept": ["*/*"]}, "tls": {"resumed": false, "version": 771, "cipher_suite": 49200, "proto": "h2", "proto_mutual": true, "server_name": "xxx.xxx.xxx"}}, "common_log": "xxx.xxx.xxx - - [25/Jan/2021:13:08:58 +0000] \"HEAD / HTTP/2.0\" 0 0", "duration": 0.00000543, "size": 0, "status": 0, "resp_headers": {"Server": ["Caddy"], "Alt-Svc": ["h3-32=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000"]}}

switched to 0.10.4 and is working again

dunglas commented 3 years ago

Can you paste you Caddyfile (if modified), the environment variables set and the command used to start Caddy please? Without a reproducer it's very hard to debug (I tried, but didn't manage to do it).

JSmythSSG commented 3 years ago

Caddy

 # Learn how to configure the Mercure.rocks Hub on https://mercure.rocks/docs/hub/config
{
    # Debug mode (disable it in production!)
    {$DEBUG}

    # HTTP/3 support
    servers {
        protocol {
            experimental_http3
        }
    }
}

{$SERVER_NAME:localhost}

# TLS
tls /etc/ssl/private/xxx.pem /etc/ssl/private/xxx.key

log

route {
    encode zstd gzip

    mercure {
        # Transport to use (default to Bolt)
        transport_url {$MERCURE_TRANSPORT_URL:bolt://mercure.db}
        # Publisher JWT key
        publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
        # Subscriber JWT key
        subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
        # Cors
        cors_origins *
        subscriptions
        # Extra directives
        {$MERCURE_EXTRA_DIRECTIVES}

    }

    respond "Not Found" 404
} 

NGINX


server {
    listen 80 ;

    server_name ${SERVER_NAME};

    return 301 https://$host$request_uri;
}
server {

    listen 443 ssl ;
    listen [::]:443 ssl ;
    ssl_certificate /etc/ssl/private/${SSL_PEM};
    ssl_certificate_key /etc/ssl/private/${SSL_KEY};

    server_name ${SERVER_NAME};
    root ${SRC_ROOT};
    index index.php index.html index.htm;

    location / {
         try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        try_files $uri /index.php =404;
        fastcgi_pass php-upstream;
        fastcgi_index index.php;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        #fixes timeouts
        fastcgi_read_timeout 600;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }

}
finnef commented 3 years ago

I have the same problem when specifying a cors host. with * it works, anything else the header is missing.

My docker-compose: ` caddy: image: dunglas/mercure:v0.11.0 ports:

my Caddyfile: ` { local_certs default_sni 127.0.0.1 }

127.0.0.1:443 tls internal

log

route { redir / /.well-known/mercure/ui/ encode zstd gzip

mercure {
    demo
    publisher_jwt <key>
    subscriber_jwt <key>
    cors_origins https://127.0.0.1:8000
    publish_origins https://127.0.0.1:8000
    subscriptions
}

respond /healthz 200
respond "Not Found" 404

} `

finnef commented 3 years ago

followup: I now use a workaround with ` header Access-Control-Allow-Origin https://127.0.0.1:8000 header Access-Control-Allow-Credentials true

`

in my Caddyfile

dunglas commented 3 years ago

I tried to create a reproducer, but it works for me. Here is my repository: https://github.com/dunglas/mercure-reproducer-cors It would help me a lot to figure out the problem if someone manage to open a PR on this repo containing a config reproducing the issue.

Note: I tried with an explicit domain and with *, both work for me.

dunglas commented 3 years ago

I also tried to create a reproducer with NGINX in front of Mercure in the nginx branch, but it also works as expected on my machine.

finnef commented 3 years ago

Note: I tried with an explicit domain and with *, both work for me.

If I do a docker-compose up on the https://github.com/dunglas/mercure-reproducer-cors repo I get a

domain1_1  | 2021/02/16 08:01:48 invalid config: one of "jwt_key" or "publisher_jwt_key" configuration parameter must be defined

changing the image to a more specific dunglas/mercure:v0.11.0 allows me to run the setup. (could be a docker caching thing, but it might be good to specify the image more precisely .

With that image the explicit cors works. The only difference from my setup is you are using the default Caddyfile in the mercure image, and I'm specifying the Caddyfile externally.

(I need this to use the symfony CLI root CA in caddy, so all requests are trusted SSL requests. This way I can locally test web technology that requires SSL to work).

finnef commented 3 years ago

Hmm followup: if I visit https://domain1.local/.well-known/mercure/ui/ on the setup of this repo, my response headers are access-control-allow-origin *, while in the docker-compose file it states cors_origins https://domain2.local:4443

mslavov commented 3 years ago

Not sure if it helps, but it seems the issue at least in our case was related to whether or not who try to subscribe over HTTP or HTTPS. Initially we were trying with HTTP and we got CORS issues and headers not presented. But I notice the debug console redirects to HTTPS and gets the headers set. So, the way to fix it was to use HTTPS initially. For references we were using the latest docker image with default/dev and external config (modified dev version to set cors_origins to the proper value in our case http://localhost:3000)

dunglas commented 3 years ago

This looks related to https://github.com/symfony/cli/issues/424. You should try without Symfony CLI.

acelaya commented 3 years ago

I'm experiencing the same issue, but only with mercure 0.11, if I use 0.10, it works fine (I have noticed this when updating from 0.10 to 0.11).

With 0.10 I used to use CORS_ALLOWED_ORIGINS: "*", but my understanding is that this is no longer allowed. I have tried to set the origins explicitly, but still doesn't work.

I serve mercure behind an nginx reverse proxy, so I have also set USE_FORWARDED_HEADERS: "1" and these directives in nginx config:

location / {
    proxy_set_header Host $host;
    proxy_pass http://localhost:8091;
    proxy_read_timeout 24h;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
}

I continue investigating. I'll drop a message here if I find the combination that doesn't work.

dunglas commented 3 years ago

Are you using the legacy or the caddy build? The config format pr the caddy version ins't the same as the one for the legacy hub.

acelaya commented 3 years ago

Thanks @dunglas, it was because of that. I added the legacy- prefix in the image version and it works fine now.

Where can I find the documentation for the new caddy-based image?

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

dxlbnl commented 3 years ago

This seems still broken, using this config with the docker container.

# Learn how to configure the Mercure.rocks Hub on https://mercure.rocks/docs/hub/config
{
    # Debug mode (disable it in production!)
    {$DEBUG:debug}
    # HTTP/3 support
    servers {
        protocol {
            experimental_http3
        }
    }
}

{$SERVER_NAME:localhost}

log

route {
    redir / /.well-known/mercure/ui/
    encode zstd gzip

    mercure {
        # Transport to use (default to Bolt)
        transport_url {$MERCURE_TRANSPORT_URL:bolt://mercure.db}
        # Publisher JWT key
        publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
        # Subscriber JWT key
        subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
        # Permissive configuration for the development environment
        cors_origins http://votes.wolbodo/
        publish_origins *
        demo
        anonymous
        subscriptions
        # Extra directives
        {$MERCURE_EXTRA_DIRECTIVES}
    }

    respond /healthz 200

    respond "Not Found" 404
}
hamza-abed commented 2 years ago

I have the same problem when using jwt token with caddy

mercure {

Transport to use (default to Bolt)

    transport_url {$MERCURE_TRANSPORT_URL:bolt://database.db?bucket_name=demo&size=1000&cleanup_frequency=0.5}
    # Publisher JWT key
    publisher_jwt wimoTeam
    # Subscriber JWT key
    subscriber_jwt wimoTeam
    # Extra directives
    {$MERCURE_EXTRA_DIRECTIVES}
    cors_origins "https://mydomain.com"
    publish_origins "https://mydomain.com"
}

always the same error : Access to XMLHttpRequest at 'https://mydomain.com/.well-known/mercure?topic=ping&lastEventId=&r=3506130692331408' from origin 'https://mydomain.com' has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response.

dunglas commented 2 years ago

Could you provide a reproducer? Is mydomain.com the domain you're really using?

CreaDEV commented 2 years ago

I had a similar problem and solved it by:

Serzhanov commented 2 years ago

Hello @CreaDEV , I am sorry for bothering you, but could you explain how can I provide the FQDN with Schema to CORS, thanks in advance!