This project is read-only.

Http Basic Authentication

Sep 12, 2012 at 1:10 PM

I'm looking into how to authenticate a socket.io connection (http basic authentication)

On the server side I have access to the request headers

https://github.com/LearnBoost/socket.io/wiki/Authorizing

but I'm failing to see how I can add a header on the socket client.

What would be the best way of doing that?

Coordinator
Sep 14, 2012 at 12:37 AM

I need to add the cookies & headers key/value pair properties back into the Client constructor - they were removed in the early stages due to issues in both socket.io & socketio4net.  Unfortunately, they never were added back.

In Client.cs, I need to call the overloaded ctor of WebSocket with the key/value pairs:

this.wsClient = new WebSocket( string.Format("{0}://{1}:{2}/socket.io/1/websocket/{3}", wsScheme, uri.Host, uri.Port, this.HandShake.SID),
string.Empty,
this.socketVersion);

The WebSocket constructor takes the following that I'm not passing:

WebSocket(string uri, string subProtocol = "", List<KeyValuePair<string, string>> cookies = null, List<KeyValuePair<string, string>> customHeaderItems = null, string userAgent = "", string origin = "", WebSocketVersion version = WebSocketVersion.None);

I'll get this updated over the next few days - I've been tied up with a couple of sites going live.  In the meantime, if you make changes yourself, please send a pull request and I'll get nuget updated as well!  Thanks for catching this.

Jim

Sep 14, 2012 at 7:44 AM
Edited Sep 14, 2012 at 1:01 PM

Hey Jim,

Thanks for your answer.

Actually where I'd like to see the Authorization header is on the handshake POST request. 

That's when the server authorization callback is gonna execute

io.configure(function (){
  io.set('authorization', function (handshakeData, callback) {
    callback(null, true); // error first callback style 
  });
});

After the handshake is completed, the client must use the handshake id issued from the handshake process for the rest of the session. 

As the handshake id can be sent through secure channels (https for the handshake, wss from that point on) it may not be necessary to do Http Basic Auth on the Websocket requests. 

What do you think?

Javier

Coordinator
Sep 17, 2012 at 2:27 PM

Agree completely, will post update later today.

Thanks for the correction.

Jim

Sep 20, 2012 at 6:38 PM

Works like a charm, thanks!

Coordinator
Sep 20, 2012 at 6:59 PM

Good to hear - I did update the error messages in event of rejection, to show 'rejected'.  What you probably want to do is register to a namespace 'error' message before you connect - so that you'll see any error message if/when the authentication is rejected:

socket.On("error", "/news", (msg) =>
      {
        ErrorMessage emsg = msg as ErrorMessage;
        if ( emsg != null)
              Console.WriteLine("Error Message: {0} : {1}", emsg.Event, emsg.Reason);
        });
socket.HandShake.Headers.Add("OrganizationId", "1034");
socket.HandShake.Headers.Add("UserId", "TestSample");
.......
socket.Connect();

I'm still cleaning up the samples and will have some documentation updates to follow up with.

Thanks again for your help in getting this feature covered.

Sep 26, 2012 at 12:00 PM

For the handshake error handling: Wouldn't it make more sense to add a callback parameter in the socket.connect?

Connection errors would be handled specifically there. 

It would be similar to the overload of the emit method that takes a callback action.

What do you think? Does that make sense?

Jan 13, 2013 at 8:37 AM

I made a little change to Client.cs for the global handshake in socket.io. I'm a complete beginner on c#, if i did something wrong, please let me know. 
I use cookie based authorization, so :

added this method:

public List<KeyValuePair<string, string>> cookies;

....
....
....

protected SocketIOHandshake requestHandshake(Uri uri, List<KeyValuePair<string, string>> cookies)
{
string value = string.Empty;
string errorText = string.Empty;
SocketIOHandshake handshake = null;
using (WebClient client = new WebClient())
  try {                   
string cookieBuild = "";
foreach (KeyValuePair<string, string> pair in cookies){
cookieBuild += pair.Key + "=" + pair.Value + ",";
}                   
client.Headers.Add(HttpRequestHeader.Cookie, cookieBuild);

value = client.DownloadString(string.Format("{0}://{1}:{2}/socket.io/1/{3}", uri.Scheme, uri.Host, uri.Port, uri.Query));  
if (string.IsNullOrEmpty(value))
errorText = "Did not receive handshake string from server";
} catch (Exception ex)
{
errorText = string.Format("Error getting handsake from Socket.IO host instance: {0}", ex.Message);
//this.OnErrorEvent(this, new ErrorEventArgs(errMsg));
}
  }
if (string.IsNullOrEmpty(errorText))
handshake = SocketIOHandshake.LoadFromString(value);
else
{
handshake = new SocketIOHandshake();
handshake.ErrorMessage = errorText;
  }
return handshake;
}

 

On : public void Connect() - Client.cs
........
if (cookies.Count == 0) 
{
this.wsClient = new WebSocket(string.Format("{0}://{1}:{2}/socket.io/1/websocket/{3}", wsScheme, uri.Host, uri.Port, this.HandShake.SID),                                    string.Empty,
this.socketVersion);
}else{
this.wsClient = new WebSocket(string.Format("{0}://{1}:{2}/socket.io/1/websocket/{3}", wsScheme, uri.Host, uri.Port, this.HandShake.SID),                                    string.Empty,
        cookies,
null,
"Prankos UA v0.1",
"",
this.socketVersion);
 } 

........

In application:

var directSocket = new Client("http://www.ssss.ro:8080/test/");
directSocket.cookies = listCookies;
directSocket.Connect();

listcookies - cookiecointainer() from (HttpWebRequest)WebRequest to my login page;

 

js code:

io.configure(function () {   
io.enable('browser client minification');
io.enable('browser client etag');
io.enable('browser client gzip');
io.set('log level', 3);
    io.set('transports', ['websocket']);       
io.set('authorization', function (data, callback) {       
if (data.headers.cookie) {
data.cookie = cookie.parse(data.headers.cookie);
data.sessionID = parseSignedCookie(data.cookie['connect.sid'], app_secret);
sessionStore.get(data.sessionID, function (err, session) {
if (err || !session || !session.auth) {
callback('Error', false);
} else {
data.session = session;
callback(null, true);
}
});
} else {
callback('No cookie', false);
}
});
}); 

 

Regards to all, hope this helps someone, i lost 1h just to figure out this 

May 31, 2013 at 8:13 PM
The version 0.6.26 could not authentication as socket.HandShake.Headers.Add ?
May 31, 2013 at 8:55 PM
Ok, HandShake.Headers only exists in head version, not in nuget.