dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.6k stars 10.06k forks source link

SignalR Hub with Azure API Management #50418

Closed comc closed 1 year ago

comc commented 1 year ago

Is there an existing issue for this?

Describe the bug

Context:

A backend API with an integrated SignalR hub for server events sent from controller actions deployed as an app service to API Management.

Problem:

Negotiating through the API Management gateway URI returns 400 Bad Request with error Invalid websocket upgrade request.

curl -X POST "https://<APIM_Gateway>.azure-api.net/SignalR/negotiate"

Response:

*   Trying <ip_redacted>:443...
* Connected to <APIM_Gateway>.azure-api.net (<ip_redacted>) port 443 (#0)
* ALPN: offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/cert.pem
*  CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN: server did not agree on a protocol. Uses default.
* Server certificate:
*  subject: C=US; ST=WA; L=Redmond; O=Microsoft Corporation; CN=*.azure-api.net
*  start date: Aug 16 08:53:46 2023 GMT
*  expire date: Jun 27 23:59:59 2024 GMT
*  subjectAltName: host "<APIM_Gateway>.azure-api.net" matched cert's "*.azure-api.net"
*  issuer: C=US; O=Microsoft Corporation; CN=Microsoft Azure TLS Issuing CA 01
*  SSL certificate verify ok.
* using HTTP/1.x
> POST /job/Events/negotiate HTTP/1.1
> Host: <APIM_Gateway>.azure-api.net
> User-Agent: curl/8.1.2
> Accept: */*
> Content-Length: 128
> 
< HTTP/1.1 400 Bad Request
< Content-Length: 69
< Content-Type: application/json
< Request-Context: appId=cid-v1:<UUID>
< Date: Wed, 30 Aug 2023 00:04:57 GMT
< 
* Connection #0 to host <APIM_Gateway>.azure-api.net left intact
{ "statusCode": 400, "message": "Invalid websocket upgrade request" }

Negotiating directly through the app service URI works as expected.

curl -X POST "https://<App_Service>.azurewebsites.net/SignalR/negotiate"

*   Trying <ip_redacted>:443...
* Connected to <App_Service>.azurewebsites.net (<ip_redacted>) port 443 (#0)
* ALPN: offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/cert.pem
*  CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN: server accepted http/1.1
* Server certificate:
*  subject: C=US; ST=WA; L=Redmond; O=Microsoft Corporation; CN=*.azurewebsites.net
*  start date: Mar 10 03:05:55 2023 GMT
*  expire date: Mar  4 03:05:55 2024 GMT
*  subjectAltName: host "<App_Service>.azurewebsites.net" matched cert's "*.azurewebsites.net"
*  issuer: C=US; O=Microsoft Corporation; CN=Microsoft Azure TLS Issuing CA 02
*  SSL certificate verify ok.
* using HTTP/1.1
> POST /Events/negotiate HTTP/1.1
> Host: <App_Service>.azurewebsites.net
> User-Agent: curl/8.1.2
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Length: 273
< Content-Type: application/json
< Date: Wed, 30 Aug 2023 00:03:00 GMT
< Server: Kestrel
< Set-Cookie: ARRAffinity=<UUID>;Path=/;HttpOnly;Secure;Domain=<App_Service>.azurewebsites.net
< Set-Cookie: ARRAffinitySameSite=<UUID>;Path=/;HttpOnly;SameSite=None;Secure;Domain=<App_Service>.azurewebsites.net
< Request-Context: appId=cid-v1:<UUID>
< 
* Connection #0 to host <App_Service>.azurewebsites.net left intact
{"negotiateVersion":0,"connectionId":"<id>","availableTransports":[{"transport":"WebSockets","transferFormats":["Text","Binary"]},{"transport":"ServerSentEvents","transferFormats":["Text"]},{"transport":"LongPolling","transferFormats":["Text","Binary"]}]}

Expected Behavior

Expected to return a successful negotiation.

Steps To Reproduce

No response

Exceptions (if any)

No response

.NET Version

7.0

Anything else?

We are likely missing APIM configuration, but there does not appear to be any useful documentation on the subject anywhere.

comc commented 1 year ago

It turns out a dev had added a conflicting websocket API in the APIM on the same backend. Closing as resolved.