diff --git a/Example/bin/Debug/example.exe b/Example/bin/Debug/example.exe index e3ad430c..c68da2e6 100755 Binary files a/Example/bin/Debug/example.exe and b/Example/bin/Debug/example.exe differ diff --git a/Example/bin/Debug/websocket-sharp.dll b/Example/bin/Debug/websocket-sharp.dll index 243724f8..91ce13ec 100755 Binary files a/Example/bin/Debug/websocket-sharp.dll and b/Example/bin/Debug/websocket-sharp.dll differ diff --git a/Example/bin/Debug_Ubuntu/example.exe b/Example/bin/Debug_Ubuntu/example.exe index 2a213aa3..9c55fbba 100755 Binary files a/Example/bin/Debug_Ubuntu/example.exe and b/Example/bin/Debug_Ubuntu/example.exe differ diff --git a/Example/bin/Debug_Ubuntu/websocket-sharp.dll b/Example/bin/Debug_Ubuntu/websocket-sharp.dll index 40eed41c..86672634 100755 Binary files a/Example/bin/Debug_Ubuntu/websocket-sharp.dll and b/Example/bin/Debug_Ubuntu/websocket-sharp.dll differ diff --git a/Example/bin/Release/example.exe b/Example/bin/Release/example.exe index b66ef3a4..ec050864 100755 Binary files a/Example/bin/Release/example.exe and b/Example/bin/Release/example.exe differ diff --git a/Example/bin/Release/websocket-sharp.dll b/Example/bin/Release/websocket-sharp.dll index 404bacb2..6f9c4bc5 100755 Binary files a/Example/bin/Release/websocket-sharp.dll and b/Example/bin/Release/websocket-sharp.dll differ diff --git a/Example/bin/Release_Ubuntu/example.exe b/Example/bin/Release_Ubuntu/example.exe index c8a0295a..7658709f 100755 Binary files a/Example/bin/Release_Ubuntu/example.exe and b/Example/bin/Release_Ubuntu/example.exe differ diff --git a/Example/bin/Release_Ubuntu/websocket-sharp.dll b/Example/bin/Release_Ubuntu/websocket-sharp.dll index ceed25c1..597d54af 100755 Binary files a/Example/bin/Release_Ubuntu/websocket-sharp.dll and b/Example/bin/Release_Ubuntu/websocket-sharp.dll differ diff --git a/Example1/bin/Debug/example1.exe b/Example1/bin/Debug/example1.exe index 50f7638c..4caf51b9 100755 Binary files a/Example1/bin/Debug/example1.exe and b/Example1/bin/Debug/example1.exe differ diff --git a/Example1/bin/Debug/websocket-sharp.dll b/Example1/bin/Debug/websocket-sharp.dll index 243724f8..91ce13ec 100755 Binary files a/Example1/bin/Debug/websocket-sharp.dll and b/Example1/bin/Debug/websocket-sharp.dll differ diff --git a/Example1/bin/Debug_Ubuntu/example1.exe b/Example1/bin/Debug_Ubuntu/example1.exe index 8ba5faa4..cc15218d 100755 Binary files a/Example1/bin/Debug_Ubuntu/example1.exe and b/Example1/bin/Debug_Ubuntu/example1.exe differ diff --git a/Example1/bin/Debug_Ubuntu/websocket-sharp.dll b/Example1/bin/Debug_Ubuntu/websocket-sharp.dll index 40eed41c..86672634 100755 Binary files a/Example1/bin/Debug_Ubuntu/websocket-sharp.dll and b/Example1/bin/Debug_Ubuntu/websocket-sharp.dll differ diff --git a/Example1/bin/Release/example1.exe b/Example1/bin/Release/example1.exe index f08d541d..6afc86d4 100755 Binary files a/Example1/bin/Release/example1.exe and b/Example1/bin/Release/example1.exe differ diff --git a/Example1/bin/Release/websocket-sharp.dll b/Example1/bin/Release/websocket-sharp.dll index 404bacb2..6f9c4bc5 100755 Binary files a/Example1/bin/Release/websocket-sharp.dll and b/Example1/bin/Release/websocket-sharp.dll differ diff --git a/Example1/bin/Release_Ubuntu/example1.exe b/Example1/bin/Release_Ubuntu/example1.exe index feeffa89..f6f6713c 100755 Binary files a/Example1/bin/Release_Ubuntu/example1.exe and b/Example1/bin/Release_Ubuntu/example1.exe differ diff --git a/Example1/bin/Release_Ubuntu/websocket-sharp.dll b/Example1/bin/Release_Ubuntu/websocket-sharp.dll index ceed25c1..597d54af 100755 Binary files a/Example1/bin/Release_Ubuntu/websocket-sharp.dll and b/Example1/bin/Release_Ubuntu/websocket-sharp.dll differ diff --git a/Example2/bin/Debug/example2.exe b/Example2/bin/Debug/example2.exe index 6c139aff..1e60f8d6 100755 Binary files a/Example2/bin/Debug/example2.exe and b/Example2/bin/Debug/example2.exe differ diff --git a/Example2/bin/Debug/websocket-sharp.dll b/Example2/bin/Debug/websocket-sharp.dll index 243724f8..91ce13ec 100755 Binary files a/Example2/bin/Debug/websocket-sharp.dll and b/Example2/bin/Debug/websocket-sharp.dll differ diff --git a/Example2/bin/Debug_Ubuntu/example2.exe b/Example2/bin/Debug_Ubuntu/example2.exe index 5d39fd8d..110de5d5 100755 Binary files a/Example2/bin/Debug_Ubuntu/example2.exe and b/Example2/bin/Debug_Ubuntu/example2.exe differ diff --git a/Example2/bin/Debug_Ubuntu/websocket-sharp.dll b/Example2/bin/Debug_Ubuntu/websocket-sharp.dll index 40eed41c..86672634 100755 Binary files a/Example2/bin/Debug_Ubuntu/websocket-sharp.dll and b/Example2/bin/Debug_Ubuntu/websocket-sharp.dll differ diff --git a/Example2/bin/Release/example2.exe b/Example2/bin/Release/example2.exe index 6aa07061..2dfaee4d 100755 Binary files a/Example2/bin/Release/example2.exe and b/Example2/bin/Release/example2.exe differ diff --git a/Example2/bin/Release/websocket-sharp.dll b/Example2/bin/Release/websocket-sharp.dll index 404bacb2..6f9c4bc5 100755 Binary files a/Example2/bin/Release/websocket-sharp.dll and b/Example2/bin/Release/websocket-sharp.dll differ diff --git a/Example2/bin/Release_Ubuntu/example2.exe b/Example2/bin/Release_Ubuntu/example2.exe index a97924ed..91169ca2 100755 Binary files a/Example2/bin/Release_Ubuntu/example2.exe and b/Example2/bin/Release_Ubuntu/example2.exe differ diff --git a/Example2/bin/Release_Ubuntu/websocket-sharp.dll b/Example2/bin/Release_Ubuntu/websocket-sharp.dll index ceed25c1..597d54af 100755 Binary files a/Example2/bin/Release_Ubuntu/websocket-sharp.dll and b/Example2/bin/Release_Ubuntu/websocket-sharp.dll differ diff --git a/Example3/bin/Debug/Example3.exe b/Example3/bin/Debug/Example3.exe index b41f7d7b..7a8da71f 100755 Binary files a/Example3/bin/Debug/Example3.exe and b/Example3/bin/Debug/Example3.exe differ diff --git a/Example3/bin/Debug/websocket-sharp.dll b/Example3/bin/Debug/websocket-sharp.dll index 243724f8..91ce13ec 100755 Binary files a/Example3/bin/Debug/websocket-sharp.dll and b/Example3/bin/Debug/websocket-sharp.dll differ diff --git a/Example3/bin/Debug_Ubuntu/Example3.exe b/Example3/bin/Debug_Ubuntu/Example3.exe index 829b1a38..0a444e8d 100755 Binary files a/Example3/bin/Debug_Ubuntu/Example3.exe and b/Example3/bin/Debug_Ubuntu/Example3.exe differ diff --git a/Example3/bin/Debug_Ubuntu/websocket-sharp.dll b/Example3/bin/Debug_Ubuntu/websocket-sharp.dll index 40eed41c..86672634 100755 Binary files a/Example3/bin/Debug_Ubuntu/websocket-sharp.dll and b/Example3/bin/Debug_Ubuntu/websocket-sharp.dll differ diff --git a/Example3/bin/Release/Example3.exe b/Example3/bin/Release/Example3.exe index 6cb58465..817d7afd 100755 Binary files a/Example3/bin/Release/Example3.exe and b/Example3/bin/Release/Example3.exe differ diff --git a/Example3/bin/Release/websocket-sharp.dll b/Example3/bin/Release/websocket-sharp.dll index 404bacb2..6f9c4bc5 100755 Binary files a/Example3/bin/Release/websocket-sharp.dll and b/Example3/bin/Release/websocket-sharp.dll differ diff --git a/Example3/bin/Release_Ubuntu/Example3.exe b/Example3/bin/Release_Ubuntu/Example3.exe index d7fb5aea..8573f35c 100755 Binary files a/Example3/bin/Release_Ubuntu/Example3.exe and b/Example3/bin/Release_Ubuntu/Example3.exe differ diff --git a/Example3/bin/Release_Ubuntu/websocket-sharp.dll b/Example3/bin/Release_Ubuntu/websocket-sharp.dll index ceed25c1..597d54af 100755 Binary files a/Example3/bin/Release_Ubuntu/websocket-sharp.dll and b/Example3/bin/Release_Ubuntu/websocket-sharp.dll differ diff --git a/websocket-sharp/AuthenticationChallenge.cs b/websocket-sharp/AuthenticationChallenge.cs new file mode 100644 index 00000000..8ecae2cd --- /dev/null +++ b/websocket-sharp/AuthenticationChallenge.cs @@ -0,0 +1,205 @@ +#region License +/* + * AuthenticationChallenge.cs + * + * The MIT License + * + * Copyright (c) 2013 sta.blockhead + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#endregion + +using System; +using System.Text; + +namespace WebSocketSharp { + + internal class AuthenticationChallenge { + + #region Private Fields + + private string _algorithm; + private string _domain; + private string _nonce; + private string _opaque; + private string _qop; + private string _realm; + private string _scheme; + private string _stale; + + #endregion + + #region Private Constructors + + private AuthenticationChallenge() + { + } + + #endregion + + #region Public Properties + + public string Algorithm { + get { + return _algorithm ?? String.Empty; + } + + private set { + _algorithm = value; + } + } + + public string Domain { + get { + return _domain ?? String.Empty; + } + + private set { + _domain = value; + } + } + + public string Nonce { + get { + return _nonce ?? String.Empty; + } + + private set { + _nonce = value; + } + } + + public string Opaque { + get { + return _opaque ?? String.Empty; + } + + private set { + _opaque = value; + } + } + + public string Qop { + get { + return _qop ?? String.Empty; + } + + private set { + _qop = value; + } + } + + public string Realm { + get { + return _realm ?? String.Empty; + } + + private set { + _realm = value; + } + } + + public string Scheme { + get { + return _scheme ?? String.Empty; + } + + private set { + _scheme = value; + } + } + + public string Stale { + get { + return _stale ?? String.Empty; + } + + private set { + _stale = value; + } + } + + #endregion + + #region Public Methods + + public static AuthenticationChallenge Parse(string challenge) + { + var authChallenge = new AuthenticationChallenge(); + if (challenge.StartsWith("basic", StringComparison.OrdinalIgnoreCase)) + { + authChallenge.Scheme = "Basic"; + authChallenge.Realm = challenge.Substring(6).GetValueInternal("=").Trim('"'); + + return authChallenge; + } + + foreach (var p in challenge.SplitHeaderValue(',')) + { + var param = p.Trim(); + if (param.StartsWith("digest", StringComparison.OrdinalIgnoreCase)) + { + authChallenge.Scheme = "Digest"; + authChallenge.Realm = param.Substring(7).GetValueInternal("=").Trim('"'); + + continue; + } + + var value = param.GetValueInternal("=").Trim('"'); + if (param.StartsWith("domain", StringComparison.OrdinalIgnoreCase)) + { + authChallenge.Domain = value; + continue; + } + + if (param.StartsWith("nonce", StringComparison.OrdinalIgnoreCase)) + { + authChallenge.Nonce = value; + continue; + } + + if (param.StartsWith("opaque", StringComparison.OrdinalIgnoreCase)) + { + authChallenge.Opaque = value; + continue; + } + + if (param.StartsWith("stale", StringComparison.OrdinalIgnoreCase)) + { + authChallenge.Stale = value; + continue; + } + + if (param.StartsWith("algorithm", StringComparison.OrdinalIgnoreCase)) + { + authChallenge.Algorithm = value; + continue; + } + + if (param.StartsWith("qop", StringComparison.OrdinalIgnoreCase)) + authChallenge.Qop = value; + } + + return authChallenge; + } + + #endregion + } +} diff --git a/websocket-sharp/AuthenticationResponse.cs b/websocket-sharp/AuthenticationResponse.cs new file mode 100644 index 00000000..7f8b2747 --- /dev/null +++ b/websocket-sharp/AuthenticationResponse.cs @@ -0,0 +1,328 @@ +#region License +/* + * AuthenticationResponse.cs + * + * The MIT License + * + * Copyright (c) 2013 sta.blockhead + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#endregion + +using System; +using System.Security.Cryptography; +using System.Text; + +namespace WebSocketSharp { + + internal class AuthenticationResponse { + + #region Private Fields + + private string _algorithm; + private string _cnonce; + private string _method; + private string _nc; + private string _nonce; + private string _opaque; + private string _password; + private string _qop; + private string _realm; + private string _response; + private string _scheme; + private string _uri; + private string _userName; + + #endregion + + #region Private Constructors + + private AuthenticationResponse() + { + } + + #endregion + + #region Public Constructors + + public AuthenticationResponse(WsCredential credential) + { + _userName = credential.UserName; + _password = credential.Password; + _scheme = "Basic"; + } + + public AuthenticationResponse(WsCredential credential, AuthenticationChallenge challenge) + { + _userName = credential.UserName; + _password = credential.Password; + _scheme = challenge.Scheme; + _realm = challenge.Realm; + if (_scheme == "Digest") + initForDigest(credential, challenge); + } + + #endregion + + #region Public Properties + + public string Algorithm { + get { + return _algorithm ?? String.Empty; + } + + private set { + _algorithm = value; + } + } + + public string Cnonce { + get { + return _cnonce ?? String.Empty; + } + + private set { + _cnonce = value; + } + } + + public string Nc { + get { + return _nc ?? String.Empty; + } + + private set { + _nc = value; + } + } + + public string Nonce { + get { + return _nonce ?? String.Empty; + } + + private set { + _nonce = value; + } + } + + public string Opaque { + get { + return _opaque ?? String.Empty; + } + + private set { + _opaque = value; + } + } + + public string Qop { + get { + return _qop ?? String.Empty; + } + + private set { + _qop = value; + } + } + + public string Realm { + get { + return _realm ?? String.Empty; + } + + private set { + _realm = value; + } + } + + public string Response { + get { + return _response ?? String.Empty; + } + + private set { + _response = value; + } + } + + public string Scheme { + get { + return _scheme ?? String.Empty; + } + + private set { + _scheme = value; + } + } + + public string Uri { + get { + return _uri ?? String.Empty; + } + + private set { + _uri = value; + } + } + + public string UserName { + get { + return _userName ?? String.Empty; + } + + private set { + _userName = value; + } + } + + #endregion + + #region Private Methods + + private string a1() + { + var result = String.Format("{0}:{1}:{2}", _userName, _realm, _password); + return _algorithm != null && _algorithm.ToLower() == "md5-sess" + ? String.Format("{0}:{1}:{2}", hash(result), _nonce, _cnonce) + : result; + } + + private string a2() + { + return String.Format("{0}:{1}", _method, _uri); + } + + private static string createNonceValue() + { + var src = new byte[16]; + var rand = new Random(); + rand.NextBytes(src); + var nonce = new StringBuilder(32); + foreach (var b in src) + nonce.Append(b.ToString("x2")); + + return nonce.ToString(); + } + + private string createRequestDigest() + { + if (Qop == "auth") + { + var data = String.Format("{0}:{1}:{2}:{3}:{4}", + _nonce, _nc, _cnonce, _qop, hash(a2())); + return kd(hash(a1()), data); + } + + return kd(hash(a1()), String.Format("{0}:{1}", _nonce, hash(a2()))); + } + + private static string hash(string value) + { + var md5 = MD5.Create(); + var src = Encoding.UTF8.GetBytes(value); + var hashed = md5.ComputeHash(src); + var result = new StringBuilder(64); + foreach (var b in hashed) + result.Append(b.ToString("x2")); + + return result.ToString(); + } + + private void initForDigest(WsCredential credential, AuthenticationChallenge challenge) + { + _nonce = challenge.Nonce; + _method = "GET"; + _uri = credential.Domain; + _algorithm = challenge.Algorithm; + _opaque = challenge.Opaque; + foreach (var qop in challenge.Qop.Split(',')) + { + if (qop.Trim().ToLower() == "auth") + { + _qop = "auth"; + _nc = "00000001"; + break; + } + } + + _cnonce = createNonceValue(); + _response = createRequestDigest(); + } + + private static string kd(string secret, string data) + { + var concatenated = String.Format("{0}:{1}", secret, data); + return hash(concatenated); + } + + private string toBasicCredentials() + { + var userPass = String.Format("{0}:{1}", _userName, _password); + var base64UserPass = Convert.ToBase64String(Encoding.UTF8.GetBytes(userPass)); + + return "Basic " + base64UserPass; + } + + private string toDigestCredentials() + { + var digestResponse = new StringBuilder(64); + digestResponse.AppendFormat("username={0}", _userName.Quote()); + digestResponse.AppendFormat(", realm={0}", _realm.Quote()); + digestResponse.AppendFormat(", nonce={0}", _nonce.Quote()); + digestResponse.AppendFormat(", uri={0}", _uri.Quote()); + digestResponse.AppendFormat(", response={0}", _response.Quote()); + if (!_algorithm.IsNullOrEmpty()) + digestResponse.AppendFormat(", algorithm={0}", _algorithm); + + if (!_opaque.IsNullOrEmpty()) + digestResponse.AppendFormat(", opaque={0}", _opaque.Quote()); + + if (!_qop.IsNullOrEmpty()) + digestResponse.AppendFormat(", qop={0}", _qop); + + if (!_nc.IsNullOrEmpty()) + digestResponse.AppendFormat(", nc={0}", _nc); + + if (!_qop.IsNullOrEmpty()) + digestResponse.AppendFormat(", cnonce={0}", _cnonce.Quote()); + + return "Digest " + digestResponse.ToString(); + } + + #endregion + + #region Public Methods + + public static AuthenticationResponse Parse(string response) + { + throw new NotImplementedException(); + } + + public override string ToString() + { + return _scheme == "Basic" + ? toBasicCredentials() + : toDigestCredentials(); + } + + #endregion + } +} diff --git a/websocket-sharp/RequestHandshake.cs b/websocket-sharp/RequestHandshake.cs index d2b721ee..86c39505 100644 --- a/websocket-sharp/RequestHandshake.cs +++ b/websocket-sharp/RequestHandshake.cs @@ -183,6 +183,12 @@ namespace WebSocketSharp { AddHeader("Cookie", header.ToString()); } + public void SetAuthorization(AuthenticationResponse response) + { + var credentials = response.ToString(); + AddHeader("Authorization", credentials); + } + public override string ToString() { var buffer = new StringBuilder(64); diff --git a/websocket-sharp/ResponseHandshake.cs b/websocket-sharp/ResponseHandshake.cs index a9fe75d8..e38782b9 100644 --- a/websocket-sharp/ResponseHandshake.cs +++ b/websocket-sharp/ResponseHandshake.cs @@ -55,12 +55,26 @@ namespace WebSocketSharp { #region Public Properties + public AuthenticationChallenge AuthChallenge { + get { + return ContainsHeader("WWW-Authenticate") + ? AuthenticationChallenge.Parse(Headers["WWW-Authenticate"]) + : null; + } + } + public CookieCollection Cookies { get { return Headers.GetCookies(true); } } + public bool IsUnauthorized { + get { + return StatusCode == "401"; + } + } + public bool IsWebSocketResponse { get { return ProtocolVersion < HttpVersion.Version11 diff --git a/websocket-sharp/WebSocket.cs b/websocket-sharp/WebSocket.cs index 47200447..88057110 100644 --- a/websocket-sharp/WebSocket.cs +++ b/websocket-sharp/WebSocket.cs @@ -71,12 +71,14 @@ namespace WebSocketSharp { private CookieCollection _cookies; private CompressionMethod _compression; private WebSocketContext _context; + private WsCredential _credentials; private string _extensions; private AutoResetEvent _exitReceiving; private object _forClose; private object _forFrame; private object _forSend; private string _origin; + private bool _preAuth; private string _protocol; private string _protocols; private volatile WsState _readyState; @@ -99,6 +101,7 @@ namespace WebSocketSharp { _forFrame = new object(); _forSend = new object(); _origin = String.Empty; + _preAuth = false; _protocol = String.Empty; _readyState = WsState.CONNECTING; } @@ -261,6 +264,18 @@ namespace WebSocketSharp { } } + /// + /// Gets the credentials for HTTP authentication (Basic/Digest). + /// + /// + /// A that contains the credentials for HTTP authentication. + /// + public WsCredential Credentials { + get { + return _credentials; + } + } + /// /// Gets the WebSocket extensions selected by the server. /// @@ -675,6 +690,9 @@ namespace WebSocketSharp { req.AddHeader("Sec-WebSocket-Version", _version); + if (_preAuth && _credentials != null) + req.SetAuthorization(new AuthenticationResponse(_credentials)); + if (_cookies.Count > 0) req.SetCookies(_cookies); @@ -718,8 +736,7 @@ namespace WebSocketSharp { private bool doHandshake() { init(); - sendRequestHandshake(); - return processResponseHandshake(); + return processResponseHandshake(sendRequestHandshake()); } private static CompressionMethod getCompressionMethod(string value) @@ -1091,21 +1108,25 @@ namespace WebSocketSharp { } // As client - private bool processResponseHandshake() + private bool processResponseHandshake(ResponseHandshake response) { - var res = receiveResponseHandshake(); - if (!isValidResponseHandshake(res)) + var error = response.IsUnauthorized + ? String.Format("An HTTP {0} authorization is required.", response.AuthChallenge.Scheme) + : !isValidResponseHandshake(response) + ? "Invalid response to this WebSocket connection request." + : String.Empty; + + if (error.Length > 0) { - var msg = "Invalid response to this WebSocket connection request."; - onError(msg); - Close(CloseStatusCode.ABNORMAL, msg); + onError(error); + Close(CloseStatusCode.ABNORMAL, error); return false; } - processResponseProtocol(res.Headers["Sec-WebSocket-Protocol"]); - processResponseExtensions(res.Headers["Sec-WebSocket-Extensions"]); - processResponseCookies(res.Cookies); + processResponseProtocol(response.Headers["Sec-WebSocket-Protocol"]); + processResponseExtensions(response.Headers["Sec-WebSocket-Extensions"]); + processResponseCookies(response.Cookies); return true; } @@ -1275,10 +1296,25 @@ namespace WebSocketSharp { } // As client - private void sendRequestHandshake() + private ResponseHandshake sendRequestHandshake() { var req = createRequestHandshake(); - send(req); + var res = sendRequestHandshake(req); + if (!_preAuth && res.IsUnauthorized && _credentials != null) + { + var challenge = res.AuthChallenge; + req.SetAuthorization(new AuthenticationResponse(_credentials, challenge)); + res = sendRequestHandshake(req); + } + + return res; + } + + // As client + private ResponseHandshake sendRequestHandshake(RequestHandshake request) + { + send(request); + return receiveResponseHandshake(); } // As server @@ -1623,6 +1659,48 @@ namespace WebSocketSharp { } } + /// + /// Sets the credentials for HTTP authentication (Basic/Digest). + /// + /// + /// A that contains a user name associated with the credentials. + /// + /// + /// A that contains a password for associated with the credentials. + /// + /// + /// true if sends the credentials as a Basic authorization with the first request handshake; + /// otherwise, false. + /// + public void SetCredentials(string userName, string password, bool preAuth) + { + if (isOpened(true)) + return; + + if (userName == null) + { + _credentials = null; + _preAuth = false; + + return; + } + + var error = userName.Length > 0 && (userName.Contains(':') || !userName.IsText()) + ? "'userName' contains an invalid character." + : !password.IsNullOrEmpty() && !password.IsText() + ? "'password' contains an invalid character." + : String.Empty; + + if (error.Length > 0) + { + onError(error); + return; + } + + _credentials = new WsCredential(userName, password, _uri.PathAndQuery); + _preAuth = preAuth; + } + #endregion } } diff --git a/websocket-sharp/WsCredential.cs b/websocket-sharp/WsCredential.cs new file mode 100644 index 00000000..91875559 --- /dev/null +++ b/websocket-sharp/WsCredential.cs @@ -0,0 +1,119 @@ +#region License +/* + * WsCredential.cs + * + * The MIT License + * + * Copyright (c) 2013 sta.blockhead + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#endregion + +using System; + +namespace WebSocketSharp { + + /// + /// Provides the credentials for HTTP authentication (Basic/Digest). + /// + public class WsCredential { + + #region Private Fields + + string _domain; + string _password; + string _userName; + + #endregion + + #region Internal Constructors + + internal WsCredential() + { + } + + internal WsCredential(string userName, string password) + : this(userName, password, null) + { + } + + internal WsCredential(string userName, string password, string domain) + { + _userName = userName; + _password = password; + _domain = domain; + } + + #endregion + + #region Public Properties + + /// + /// Gets the name of the user domain associated with the credentials. + /// + /// + /// A that contains the name of the user domain associated with the credentials. + /// Currently, returns the request uri of a WebSocket opening handshake. + /// + public string Domain { + get { + return _domain ?? String.Empty; + } + + internal set { + _domain = value; + } + } + + /// + /// Gets the password for the user name associated with the credentials. + /// + /// + /// A that contains the password for the user name associated with the credentials. + /// + public string Password { + get { + return _password ?? String.Empty; + } + + internal set { + _password = value; + } + } + + /// + /// Gets the user name associated with the credentials. + /// + /// + /// A that contains the user name associated with the credentials. + /// + public string UserName { + get { + return _userName ?? String.Empty; + } + + internal set { + _userName = value; + } + } + + #endregion + } +} diff --git a/websocket-sharp/bin/Debug/websocket-sharp.dll b/websocket-sharp/bin/Debug/websocket-sharp.dll index 243724f8..91ce13ec 100755 Binary files a/websocket-sharp/bin/Debug/websocket-sharp.dll and b/websocket-sharp/bin/Debug/websocket-sharp.dll differ diff --git a/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll b/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll index 40eed41c..86672634 100755 Binary files a/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll and b/websocket-sharp/bin/Debug_Ubuntu/websocket-sharp.dll differ diff --git a/websocket-sharp/bin/Release/websocket-sharp.dll b/websocket-sharp/bin/Release/websocket-sharp.dll index 404bacb2..6f9c4bc5 100755 Binary files a/websocket-sharp/bin/Release/websocket-sharp.dll and b/websocket-sharp/bin/Release/websocket-sharp.dll differ diff --git a/websocket-sharp/bin/Release_Ubuntu/websocket-sharp.dll b/websocket-sharp/bin/Release_Ubuntu/websocket-sharp.dll index ceed25c1..597d54af 100755 Binary files a/websocket-sharp/bin/Release_Ubuntu/websocket-sharp.dll and b/websocket-sharp/bin/Release_Ubuntu/websocket-sharp.dll differ diff --git a/websocket-sharp/bin/Release_Ubuntu/websocket-sharp.xml b/websocket-sharp/bin/Release_Ubuntu/websocket-sharp.xml index a3b68197..a76fd58e 100644 --- a/websocket-sharp/bin/Release_Ubuntu/websocket-sharp.xml +++ b/websocket-sharp/bin/Release_Ubuntu/websocket-sharp.xml @@ -902,6 +902,14 @@ over the collection of cookies. + + + Gets the credentials for HTTP authentication (Basic/Digest). + + + A that contains the credentials for HTTP authentication. + + Gets the WebSocket extensions selected by the server. @@ -1122,6 +1130,21 @@ A that contains an HTTP Cookie to set. + + + Sets the credentials for HTTP authentication (Basic/Digest). + + + A that contains a user name associated with the credentials. + + + A that contains a password for associated with the credentials. + + + true if sends the credentials as a Basic authorization with the first request handshake; + otherwise, false. + + Provides the functions of the server that receives the WebSocket connection requests. @@ -5214,5 +5237,35 @@ One of the values that indicates the cause of the exception. + + + Provides the credentials for HTTP authentication (Basic/Digest). + + + + + Gets the name of the user domain associated with the credentials. + + + A that contains the name of the user domain associated with the credentials. + Currently, returns the request uri of a WebSocket opening handshake. + + + + + Gets the password for the user name associated with the credentials. + + + A that contains the password for the user name associated with the credentials. + + + + + Gets the user name associated with the credentials. + + + A that contains the user name associated with the credentials. + + diff --git a/websocket-sharp/doc/html/WebSocketSharp/WebSocket.html b/websocket-sharp/doc/html/WebSocketSharp/WebSocket.html index 88040efb..a9eabc48 100644 --- a/websocket-sharp/doc/html/WebSocketSharp/WebSocket.html +++ b/websocket-sharp/doc/html/WebSocketSharp/WebSocket.html @@ -299,6 +299,20 @@ IEnumerable<WebSocketSharp.Net.Cookie> . Gets the cookies used in the WebSocket opening handshake. + + + + [read-only]
+ + + Credentials + + + + + WsCredential + . + Gets the credentials for HTTP authentication (Basic/Digest). @@ -603,6 +617,18 @@ SetCookie (WebSocketSharp.Net.Cookie)
Sets a WebSocketSharp.Net.Cookie used in the WebSocket opening handshake. +
+ + + +
+
+ + + + SetCredentials + (string, string, bool)
+ Sets the credentials for HTTP authentication (Basic/Digest).
@@ -1017,6 +1043,26 @@ Namespace: WebSocketSharp
Assembly: websocket-sharp (in websocket-sharp.dll)
+

Credentials Property

+
+

+ Gets the credentials for HTTP authentication (Basic/Digest). +

+

Syntax

+
public WsCredential Credentials { get; }
+

Value

+
+ A WebSocketSharp.WsCredential that contains the credentials for HTTP authentication. +
+

Remarks

+
+ Documentation for this section has not yet been entered. +
+

Requirements

+
+ Namespace: WebSocketSharp
Assembly: websocket-sharp (in websocket-sharp.dll)
+
+

Dispose Method

@@ -1484,6 +1530,46 @@ Namespace: WebSocketSharp
Assembly: websocket-sharp (in websocket-sharp.dll)


+

SetCredentials Method

+
+

+ Sets the credentials for HTTP authentication (Basic/Digest). +

+

Syntax

+
public void SetCredentials (string userName, string password, bool preAuth)
+

Parameters

+
+
+
+ userName +
+
+ A string that contains a user name associated with the credentials. +
+
+ password +
+
+ A string that contains a password for userName associated with the credentials. +
+
+ preAuth +
+
+ true if sends the credentials as a Basic authorization with the first request handshake; + otherwise, false. +
+
+
+

Remarks

+
+ Documentation for this section has not yet been entered. +
+

Requirements

+
+ Namespace: WebSocketSharp
Assembly: websocket-sharp (in websocket-sharp.dll)
+
+

Url Property

diff --git a/websocket-sharp/doc/html/WebSocketSharp/WsCredential.html b/websocket-sharp/doc/html/WebSocketSharp/WsCredential.html new file mode 100644 index 00000000..e432ebe5 --- /dev/null +++ b/websocket-sharp/doc/html/WebSocketSharp/WsCredential.html @@ -0,0 +1,351 @@ + + + WebSocketSharp.WsCredential + + + + + +

+ +

WsCredential Class

+

+ Provides the credentials for HTTP authentication (Basic/Digest). +

+
+

Syntax

+
public class WsCredential
+
+
+

Remarks

+
+ Documentation for this section has not yet been entered. +
+

Requirements

+
+ Namespace: WebSocketSharp
Assembly: websocket-sharp (in websocket-sharp.dll)
+

Members

+
+

+ See Also: Inherited members from + object. +

+

Public Properties

+
+
+ + + + + + + + + + + + + + + + +
[read-only]
+ + Domain + + + + string + . + Gets the name of the user domain associated with the credentials. +
[read-only]
+ + Password + + + + string + . + Gets the password for the user name associated with the credentials. +
[read-only]
+ + UserName + + + + string + . + Gets the user name associated with the credentials. +
+
+
+
+
+
+

Member Details

+
+

Domain Property

+
+

+ Gets the name of the user domain associated with the credentials. +

+

Syntax

+
public string Domain { get; }
+

Value

+
+ A string that contains the name of the user domain associated with the credentials. + Currently, returns the request uri of a WebSocket opening handshake. +
+

Remarks

+
+ Documentation for this section has not yet been entered. +
+

Requirements

+
+ Namespace: WebSocketSharp
Assembly: websocket-sharp (in websocket-sharp.dll)
+
+
+

Password Property

+
+

+ Gets the password for the user name associated with the credentials. +

+

Syntax

+
public string Password { get; }
+

Value

+
+ A string that contains the password for the user name associated with the credentials. +
+

Remarks

+
+ Documentation for this section has not yet been entered. +
+

Requirements

+
+ Namespace: WebSocketSharp
Assembly: websocket-sharp (in websocket-sharp.dll)
+
+
+

UserName Property

+
+

+ Gets the user name associated with the credentials. +

+

Syntax

+
public string UserName { get; }
+

Value

+
+ A string that contains the user name associated with the credentials. +
+

Remarks

+
+ Documentation for this section has not yet been entered. +
+

Requirements

+
+ Namespace: WebSocketSharp
Assembly: websocket-sharp (in websocket-sharp.dll)
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/websocket-sharp/doc/html/WebSocketSharp/index.html b/websocket-sharp/doc/html/WebSocketSharp/index.html index 634afac8..951cb0c0 100644 --- a/websocket-sharp/doc/html/WebSocketSharp/index.html +++ b/websocket-sharp/doc/html/WebSocketSharp/index.html @@ -282,6 +282,14 @@ Represents the exception that occurred when attempting to perform an operation on the WebSocket connection. + + + WsCredential + + + Provides the credentials for HTTP authentication (Basic/Digest). + + WsState diff --git a/websocket-sharp/doc/html/index.html b/websocket-sharp/doc/html/index.html index ab79b747..fc95aafa 100644 --- a/websocket-sharp/doc/html/index.html +++ b/websocket-sharp/doc/html/index.html @@ -284,6 +284,14 @@ Represents the exception that occurred when attempting to perform an operation on the WebSocket connection. + + + WsCredential + + + Provides the credentials for HTTP authentication (Basic/Digest). + + WsState diff --git a/websocket-sharp/doc/mdoc/WebSocketSharp/WebSocket.xml b/websocket-sharp/doc/mdoc/WebSocketSharp/WebSocket.xml index 3adc61f9..44921ce7 100644 --- a/websocket-sharp/doc/mdoc/WebSocketSharp/WebSocket.xml +++ b/websocket-sharp/doc/mdoc/WebSocketSharp/WebSocket.xml @@ -272,6 +272,23 @@ To be added. + + + + Property + + WebSocketSharp.WsCredential + + + + Gets the credentials for HTTP authentication (Basic/Digest). + + + A that contains the credentials for HTTP authentication. + + To be added. + + @@ -651,6 +668,35 @@ To be added. + + + + Method + + System.Void + + + + + + + + + A that contains a user name associated with the credentials. + + + A that contains a password for associated with the credentials. + + + true if sends the credentials as a Basic authorization with the first request handshake; + otherwise, false. + + + Sets the credentials for HTTP authentication (Basic/Digest). + + To be added. + + diff --git a/websocket-sharp/doc/mdoc/WebSocketSharp/WsCredential.xml b/websocket-sharp/doc/mdoc/WebSocketSharp/WsCredential.xml new file mode 100644 index 00000000..7a33a041 --- /dev/null +++ b/websocket-sharp/doc/mdoc/WebSocketSharp/WsCredential.xml @@ -0,0 +1,71 @@ + + + + + websocket-sharp + + + System.Object + + + + + Provides the credentials for HTTP authentication (Basic/Digest). + + To be added. + + + + + + Property + + System.String + + + + Gets the name of the user domain associated with the credentials. + + + A that contains the name of the user domain associated with the credentials. + Currently, returns the request uri of a WebSocket opening handshake. + + To be added. + + + + + + Property + + System.String + + + + Gets the password for the user name associated with the credentials. + + + A that contains the password for the user name associated with the credentials. + + To be added. + + + + + + Property + + System.String + + + + Gets the user name associated with the credentials. + + + A that contains the user name associated with the credentials. + + To be added. + + + + diff --git a/websocket-sharp/doc/mdoc/index.xml b/websocket-sharp/doc/mdoc/index.xml index e7d89c82..3f6ba28c 100644 --- a/websocket-sharp/doc/mdoc/index.xml +++ b/websocket-sharp/doc/mdoc/index.xml @@ -1,6 +1,6 @@ - + [00 24 00 00 04 80 00 00 94 00 00 00 06 02 00 00 00 24 00 00 52 53 41 31 00 04 00 00 11 00 00 00 29 17 fb 89 fe c3 91 f7 2b cb 8b e2 61 d2 3f 05 93 6d 65 a8 9e 63 72 a6 f5 d5 2c f2 9d 20 fa 0b c0 70 6a f6 88 7e 8b 90 3f 39 f5 76 c8 48 e0 bb 7b b2 7b ed d3 10 a7 1a 0f 70 98 0f 7f f4 4b 53 09 d2 a5 ef 36 c3 56 b4 aa f0 91 72 63 25 07 89 e0 93 3e 3f 2e f2 b9 73 0e 12 15 5d 43 56 c3 f4 70 a5 89 fe f7 f6 ac 3e 77 c2 d8 d0 84 91 f4 0c d1 f3 8e dc c3 c3 b8 38 3d 0c bf 17 de 20 78 c1 ] @@ -44,6 +44,7 @@ + diff --git a/websocket-sharp/websocket-sharp.csproj b/websocket-sharp/websocket-sharp.csproj index 45c536bd..300bc6b7 100644 --- a/websocket-sharp/websocket-sharp.csproj +++ b/websocket-sharp/websocket-sharp.csproj @@ -123,6 +123,9 @@ + + +