SignalR + Node WebKit/Node fails to connect over websockets when authenticated - asp.net

This is a node webkit application that manages a bunch of webkit windows. Each webkit window uses signalR to connect to a MVC/webApi/signalR stack with no problems. Each window connects to 1-3 hubs over websockets. Everything works well.
My client wants to use SignalR inside the base node application that manages all the other windows. This is where things are getting 'interesting'...
So although the node app is running in a webkit environment it is served from the file system (header:origin=file://)
So i have started up signalR like (no JSONP as i'm targeting websockets)
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration();
map.RunSignalR(hubConfiguration);
});
So when i connect in the node app before the user logs into one of the windows spawned from Node, signalR connects over websockets fine, and i don't get any errors when they login(i.e. user has changed identity).
var connection = window.$.hubConnection("http://localhost");
connection.logging = true;
connection.start()
.done(function () { console.log('Now connected, connection ID=' + connection.id); })
.fail(function () { console.log('Could not connect'); });
the issue is i don't have the identity in the HubCallerConext serverside.
So if the user logs in first, then the node application has the cookies created in the other spawned window and this is where things get weird. SignalR fails to connect over websockets with the following error (from fiddler)
Unrecognized user identity. The user identity cannot change during an active SignalR connection.
Here is the negotiate call and then the failing call to connect (upgrade) over websockets.
I have a fiddler rule replacing Origin:file:// with localhost. just in case this was effecting it.
GET http://localhost/signalr/negotiate?clientProtocol=1.4&connectionToken=qs09pHGxr6x5fff1GJ%2FChWUnpSLX5ljV8FuS3h06P%2FhpS55cjNvh2uFHHTXukDI%2BK%2BcgsC6%2BWVJHba4xrkt6IVc2KwGIfm4eeyHrigNFRotjBYKb&connectionData=%5B%7B%22name%22%3A%22windowmanagementhub%22%7D%5D&_=1429572950768 HTTP/1.1
Host: localhost
Connection: keep-alive
Accept: text/plain, */*; q=0.01
X-DevTools-Emulate-Network-Conditions-Client-Id: 2E81759B-036D-4E92-ADF4-865AFBF59D2
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-us;q=0.8,en;q=0.6
Cookie: ASP.NET_SessionId=opyggkqxnudnuag5mtxy40ai; __APPLICATION_LANGUAGE=en-GB; __RequestVerificationToken=eoB...GHjTo1; .ASPXAUTH=6909...82ED0; WindowsAuthCookie.LoginName=userName
Origin: http://localhost
and response
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8
Expires: -1
Server: Microsoft-IIS/8.5
Access-Control-Allow-Origin: http://localhost
Access-Control-Allow-Credentials: true
X-Content-Type-Options: nosniff
Date: Mon, 20 Apr 2015 23:46:49 GMT
177
{"Url":"/signalr","ConnectionToken":"LwJz6Ev3+9C/NbKBqHkrI8KwYaz53qiBbzDJVlcse1qRXU3loCqOI68kUb4kpyk8gdQlkKRJ0wBrpb+VVtUMFtrtSQOEhGQE9ZNaMDBajyK2/Evz","ConnectionId":"68e7751b-aaee-4ed7-aa36-a2d1ab25107f","KeepAliveTimeout":20.0,"DisconnectTimeout":30.0,"ConnectionTimeout":110.0,"TryWebSockets":true,"ProtocolVersion":"1.4","TransportConnectTimeout":5.0,"LongPollDelay":0.0}
0
then the following connect headers, which is the request that gets the 403
GET http://localhost/signalr/connect?transport=webSockets&clientProtocol=1.4&connectionToken=LwJz6Ev3%2B9C%2FNbKBqHkrI8KwYaz53qiBbzDJVlcse1qRXU3loCqOI68kUb4kpyk8gdQlkKRJ0wBrpb%2BVVtUMFtrtSQOEhGQE9ZNaMDBajyK2%2FEvz&connectionData=%5B%7B%22name%22%3A%22windowmanagementhub%22%7D%5D&tid=0 HTTP/1.1
Host: localhost
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: http://localhost
Sec-WebSocket-Version: 13
User-Agent:
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-us;q=0.8,en;q=0.6
Sec-WebSocket-Key: HqfgeBw4svkTTpBK2CfaJA==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
and the 403 response
HTTP/1.1 403 Forbidden
Cache-Control: no-cache
Pragma: no-cache
Transfer-Encoding: chunked
Content-Type: text/html
Expires: -1
Server: Microsoft-IIS/8.5
Access-Control-Allow-Origin: http://localhost
Access-Control-Allow-Credentials: true
X-Content-Type-Options: nosniff
Date: Mon, 20 Apr 2015 23:46:49 GMT
61
Unrecognized user identity. The user identity cannot change during an active SignalR connection.
0
Here is the javascript error in the console (from jquery.signalR 2.1.2, different connection ids, tokens)
WebSocket connection to
'ws://localhost/signalr/connect?transport=webSockets&clientProtocol=1.4&connectionToken=xzGshRPvF1XvGnq2S2nDmGZ3TISMGEt01Au0z9J%2FAfMa2OtQUMW5XX5HgW0I4n2MK5UfGfpJ4%2Fl7OkiRpQlSIFrDkfy25WHScwpkubBsn5403%2Ba3&connectionData=%5B%7B%22name%22%3A%22windowmanagementhub%22%7D%2C%7B%22name%22%3A%22browserloghub%22%7D%5D&tid=1'
failed: Error during WebSocket handshake: Unexpected response code: 403
SignalR will then (correctly) fall back to SSE and connect successfully. I can see the Identity of the user serverside.
I would really like to understand why i can't connect over websockets when the user is authenticated. If i delay ALL windows from connecting to the server via signalR until the user is authenticated then i also see the same behavior.
any help or clues would be greatly appreciated.

Related

Cors fails even though set up to be permissive

I'm running GenHTTP server that is setup to to have CORS permissive (so allow all):
var inline = Inline.Create();
inline.Add(CorsPolicy.Permissive());
For some reason the request still fails by CORS. For context http://localhost:55409 is the server and http://localhost:55309 is the client.
Options (preflight):
Request URL: http://localhost:55409/api/v1//metadata
Request Method: OPTIONS
Status Code: 204 No Content
Remote Address: [::1]:55409
Referrer Policy: strict-origin-when-cross-origin
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: *
Access-Control-Allow-Methods: *
Access-Control-Allow-Origin: http://localhost:55309
Access-Control-Expose-Headers: *
Access-Control-Max-Age: 86400
Connection: Keep-Alive
Content-Length: 0
Date: Mon, 13 Jun 2022 13:05:34 GMT
Server: GenHTTP/6.3.4.0
Vary: Origin
This returns 204 OK.
Get:
Request URL: http://localhost:55409/api/v1//metadata
Referrer Policy: strict-origin-when-cross-origin
Provisional headers are shown
Learn more
Accept: application/json, text/plain, */*
Authorization: Bearer <token>
Referer: http://localhost:55309/
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="102", "Google Chrome";v="102"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36
Returns CORS error
This also feels weird as similar requests without Authorization header return 200 OK. The options seem to be correct in that it allows everything. Why does it fail then?
Also note that this works with the other server (more proper server running .Net Web Api), so client is not to blame. I think I'm missing some crucial server setup
Turns out I needed to specifically configure it to allow Authorization header, as if * does not include it?
inline.Add(new CorsPolicyBuilder().Default(new OriginPolicy(null, new List<string>() { "authorization" }, null, AllowCredentials: true, 86400u)));
This is the answer, but I'll mark the other answer whoever can explain why * does not include Authorization as OPTIONS has returned this
Access-Control-Allow-Headers: *
so I assume that should allow Authorization header as well

HTTP Get not using Port

I am trying to call a page in PHP with a http_get :
$url = "http://mysite.fr:9090/neolane-webservice/campagnesclient/Coclico=1135446";
http_get($url, $appelOptions, $appelInfos);
My problem is that it does not work every time.
I installed Wireshark to see what I'm really sending and I found an odd thing. Sometimes, the port is not used for the HTTP request.
When it works, I have :
Hypertext Transfer Protocol
GET http://mysite.fr:9090/neolane-webservice/campagnesclient/Coclico=1135446 HTTP/1.1\r\n
Request Method: GET
Request URI: http://mysite.fr:9090/neolane-webservice/campagnesclient/Coclico=1135446
Request Version: HTTP/1.1
User-Agent: PECL::HTTP/1.6.5 (PHP/5.2.4-2ubuntu5.7)\r\n
Host: mysite.fr:9090\r\n
Pragma: no-cache\r\n
Accept: */*\r\n
Proxy-Connection: Keep-Alive\r\n
Keep-Alive: 300\r\n
Connection: keep-alive\r\n
Date: Fri, 15 Jun 2012 16:40:46 +0200\r\n
Accept-Charset: utf-8\r\n
Accept-Encoding: gzip;q=1.0,deflate;q=0.5\r\n
\r\n
And when it's not :
Hypertext Transfer Protocol
GET http://mysite.fr:9090/neolane-webservice/campagnesclient/Coclico=1135446 HTTP/1.1\r\n
Request Method: GET
Request URI: http://mysite.fr:9090/neolane-webservice/campagnesclient/Coclico=1135446
Request Version: HTTP/1.1
User-Agent: PECL::HTTP/1.6.5 (PHP/5.2.4-2ubuntu5.7)\r\n
Host: mysite.fr\r\n
Pragma: no-cache\r\n
Accept: */*\r\n
Proxy-Connection: Keep-Alive\r\n
Keep-Alive: 300\r\n
Connection: keep-alive\r\n
Date: Fri, 15 Jun 2012 16:40:34 +0200\r\n
Accept-Charset: utf-8\r\n
Accept-Encoding: gzip;q=1.0,deflate;q=0.5\r\n
\r\n
I tried to call the page with wget and it's always working :
wget http://mysite.fr:9090/neolane-webservice/campagnesclient/Coclico=1135446
So I'm guessing that my problem id due to Apache config, but I don't know where to look. Could you help me please ?
You will need to set the port in the $appelOptions array.
$appelOptions['port']=9090;
http_get($url, $appelOptions, $appelInfos);
Unfortunately http_get does not seem to respect the :port syntax in the URL

Why doesn't a HTTP reply from server specify the GET request to which the reply corresponds?

hen a server replies to a HTTP GET request why doesn't it specify in say some new header, the GET request for which this response was generated?
GET /counter.gif HTTP/1.1
Host: www.subbu.org
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
HTTP/1.1 200 OK
Date: Mon, 19 Dec 2011 00:12:28 GMT
Server: Apache
Last-Modified: Thu, 08 Dec 2011 15:29:54 GMT
Accept-Ranges: bytes
Content-Length: 24523
Content-Type: image/png
**Get-request: /counter.gif**
This will help in case the requests are pipelined. The server can send the replies in the order they are generated and the browser can interpret what the reply is for. I know HTTP is stateless but this seems like a simple optimization. Why do you think it might be a problem to implement this?
Like that:
https://datatracker.ietf.org/doc/html/draft-nottingham-http-pipeline-00#section-5
?
If your using apache you may be referring to this functionnality: Trace
When trace is set to extended, it reflect the request body.
Regards

HTTP 500 error in wget

Take a look at this page:
http://www.ptmytrade.com/product.asp?id=61363
It's loading fine (at least here). Now I would like to grab it with wget.
$ wget http://www.ptmytrade.com/product.asp?id=61363 --debug
DEBUG output created by Wget 1.12 on linux-gnu.
--2011-05-21 18:24:51-- http://www.ptmytrade.com/product.asp?id=61363
Resolving www.ptmytrade.com... 205.209.150.134
Caching www.ptmytrade.com => 205.209.150.134
Connecting to www.ptmytrade.com|205.209.150.134|:80... connected.
Created socket 3.
Releasing 0x0890e260 (new refcount 1).
---request begin---
GET /product.asp?id=61363 HTTP/1.0
User-Agent: Wget/1.12 (linux-gnu)
Accept: */*
Host: www.ptmytrade.com
Connection: Keep-Alive
---request end---
HTTP request sent, awaiting response...
---response begin---
HTTP/1.1 500 Internal Server Error
Connection: keep-alive
Date: Sat, 21 May 2011 16:24:56 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Content-Length: 471822
Content-Type: text/html
Set-Cookie: ASPSESSIONIDSCACCAQA=FOCCMJODFHHMOKNKPAIHJCIL; path=/
Cache-control: private
---response end---
500 Internal Server Error
Stored cookie www.ptmytrade.com -1 (ANY) / <session> <insecure> [expiry none] ASPSESSIONIDSCACCAQA FOCCMJODFHHMOKNKPAIHJCIL
Registered socket 3 for persistent reuse.
Disabling further reuse of socket 3.
Closed fd 3
2011-05-21 18:24:57 ERROR 500: Internal Server Error.
OK, so I check the headers when fetching the page using my browser (using Live HTTP Headers add-on):
http://www.ptmytrade.com/product.asp?id=61361
GET /product.asp?id=61361 HTTP/1.1
Host: www.ptmytrade.com
User-Agent: Mozilla/5.0 (X11; Linux i686; rv:2.0) Gecko/20100101 Firefox/4.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Cookie: ASPSESSIONIDSCACBBRA=AMPBLLNDGMFLNPNCPEBPNNLB; ASPSESSIONIDSCACCAQA=FJNBMJODLHHJNDHPFBIEEPEM
HTTP/1.1 500 Internal Server Error
Date: Sat, 21 May 2011 16:20:46 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Content-Length: 471822
Content-Type: text/html
Cache-Control: private
----------------------------------------------------------
http://www.ptmytrade.com/images/index_117.jpg
GET /images/index_117.jpg HTTP/1.1
Host: www.ptmytrade.com
User-Agent: Mozilla/5.0 (X11; Linux i686; rv:2.0) Gecko/20100101 Firefox/4.0
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://www.ptmytrade.com/product.asp?id=61361
Cookie: ASPSESSIONIDSCACBBRA=AMPBLLNDGMFLNPNCPEBPNNLB; ASPSESSIONIDSCACCAQA=FJNBMJODLHHJNDHPFBIEEPEM
HTTP/1.1 404 Not Found
Content-Length: 1635
Content-Type: text/html
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Date: Sat, 21 May 2011 16:20:48 GMT
I'm not sure what's going on here. The page displays just fine, but I'm getting the 500 error code in the header.
The problem was solved by using curl (which was also getting a 500, but fetched the page just fine) instead, but I'm curious what's going here.
Hi everybody I had this huge problem too, I don't know why, but the solution was add this:
wget -U "Opera 11.0" "http://your_link" -O out.csv
I found it on
[Curl and wget return error 500 for helloworld.php on new install but browser is fine
Using this option will fix the issue:
--content-on-error
If this is set to on, wget will not skip the content when the
server responds with a http status code that indicates error.
So the command looks like this:
wget --content-on-error "https://stackoverflow.com"
NOTE: It's important to put the URL inside double-quotes, otherwise, wget will get stuck on Redirecting output to ‘wget-log’..
Or as stated in the comments and by OP, use curl instead.
But I should note that curl cannot download whole webpages (css, js, images etc.) because it cannot parse HTML. Source and Taken from.
It's a bug in the webpage. The HTTP status is indeed seemingly incorrectly set to HTTP 500. Firefox/Firebug also confirms this. Basically, you're facing a HTTP 500 error page with "normal" content.
Report it to the site admin.
Try enclosing it in quotes:
wget "http://www.ptmytrade.com/product.asp?id=61363"
instead of:
wget http://www.ptmytrade.com/product.asp?id=61363

Http protocol content-length

I am working on a simple download application. While making a request for the following file both firefox and my application doesn't get the content-length field. But if i make the request using wget server does send the content-length field. I did change wgets user agent string to test and it still got the content-length field.
Any ideas why this is happening?
wget request
---request begin---
GET /dc-13/video/2005_Defcon_V2-P_Zimmerman-Unveiling_My_Next_Big_Project.mp4 HTTP/1.0
User-Agent: test
Accept: */*
Host: media.defcon.org
Connection: Keep-Alive
---request end---
HTTP request sent, awaiting response...
---response begin---
HTTP/1.0 200 OK
Server: lighttpd
Date: Sun, 05 Apr 2009 04:40:08 GMT
Last-Modified: Tue, 23 May 2006 22:18:19 GMT
Content-Type: video/mp4
Content-Length: 104223909
Connection: keep-alive
firefox request
GET /dc-13/video/2005_Defcon_V2-P_Zimmerman-Unveiling_My_Next_Big_Project.mp4 HTTP/1.1
Host: media.defcon.org
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.0.8) Gecko/2009032608 Firefox/3.0.8
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://www.defcon.org/html/links/defcon-media-archives.html
Pragma: no-cache
Cache-Control: no-cache
HTTP/1.x 200 OK
Server: lighttpd
Date: Sun, 05 Apr 2009 05:20:12 GMT
Last-Modified: Tue, 23 May 2006 22:18:19 GMT
Content-Type: video/mp4
Transfer-Encoding: chunked
Update:
Is there a header that I can send that will tell Lighthttpd not to use chunked encoding.My original problem is that I am using urlConnection to grab the file in my java application which automatically sends HTTP 1.1 request.
I would like to know the size of the file so i can update my percentage.
GET
/dc-13/video/2005_Defcon_V2-P_Zimmerman-Unveiling_My_Next_Big_Project.mp4
HTTP/1.1
Firefox is performing an HTTP 1.1 GET request. Lighthttpd understands that the client will support chunked-transfer encoding and returns the content in chunks, with each chunk reporting its own length.
GET
/dc-13/video/2005_Defcon_V2-P_Zimmerman-Unveiling_My_Next_Big_Project.mp4
HTTP/1.0
Wget on the other hand performs an HTTP 1.0 GET request. Lighthttpd, understanding that the client doesn't support HTTP 1.1 (and thus chunked-transfer encoding), returns the content in one single chunk, with the length reported in the response header.
Looks like it's because of the chunked transfer encoding:
Transfer-Encoding: chunked
This will send the video down in chunks, each with its own size. This is defined in HTTP 1.1, which is what Firefox is using, while wget is using HTTP 1.0, which doesn't support chunked transfer encoding, so the server has to send the whole file at once.
I was having the same problem and found a solution regardless of which HTTP version:
First use a HEAD request to the server which correctly responds with just the HTTP header and no contents. This header correctly includes the wanted Content-Length: bytes size for the file to download.
Proceed with the GET request to download the file (the header from the GET response fails to include Content-length).
An Objective-C language example:
NSString *zipURL = #"http://1.bp.blogspot.com/_6-cw84gcURw/TRNb3PDWneI/AAAAAAAAAYM/YFCZP1foTiM/s1600/paragliding1.jpg";
NSURL *url = [NSURL URLWithString:zipURL];
// Configure the HTTP request for HEAD header fetch
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
urlRequest.HTTPMethod = #"HEAD"; // Default is "GET"
// Define response class
__autoreleasing NSHTTPURLResponse *response;
// Send HEAD request to server
NSData *contentsData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:nil];
// Header response field
NSDictionary *headerDeserialized = response.allHeaderFields;
// The contents length
int contents_length = [(NSString*)headerDeserialized[#"Content-Length"] intValue];
//printf("HEAD Response header: %s\n",headerDeserialized.description.UTF8String);
printf("HEAD:\ncontentsData.length: %d\n",contentsData.length);
printf("contents_length = %d\n\n",contents_length);
urlRequest.HTTPMethod = #"GET";
// Send "GET" to download file
contentsData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:nil];
// Header response field
headerDeserialized = response.allHeaderFields;
// The contents length
contents_length = [(NSString*)headerDeserialized[#"Content-Length"] intValue];
printf("GET Response header: %s\n",headerDeserialized.description.UTF8String);
printf("GET:\ncontentsData.length: %d\n",contentsData.length);
printf("contents_length = %d\n",contents_length);
return;
And the output:
HEAD:
contentsData.length: 0
contents_length = 146216
GET:
contentsData.length: 146216
contents_length = 146216
(Note: This example URL does correctly provides the header Content-Length from the GET response, but shows the idea if it failed to)

Resources