コード例 #1
0
        private void NewConnectionHandler()
        {
            var server = new TcpListener(ip, port);

            server.Start();

            var policy = new TokenValidationPolicyBuilder()
                         .RequireSignature(SymmetricJwk.FromBase64Url(confWebSocket.JwsKey), SignatureAlgorithm.HmacSha512)
                         .RequireIssuer("Leierkasten Backend")
                         .Build();
            var reader = new JwtReader();

            while (running)
            {
                TcpClient client;
                if (server.Pending())
                {
                    client = server.AcceptTcpClient();
                }
                else
                {
                    Thread.Sleep(100);
                    continue;
                }

                var stream = client.GetStream();
                stream.WriteTimeout = 10;

                while (client.Available < 3)
                {
                    Thread.Sleep(100);
                }

                var bytes = new byte[client.Available];
                stream.Read(bytes, 0, bytes.Length);

                // This is a textual request, decode it
                var request = Encoding.UTF8.GetString(bytes);

                // Check if this is a websocket handshake. If no, skip.
                if (!new Regex("^GET").IsMatch(request))
                {
                    Log.Warn("Denied websocket because client used wrong method.");
                    stream.Write(AccessDeniedResponse, 0, AccessDeniedResponse.Length);
                    continue;
                }

                const string eol  = "\r\n";
                const string guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

                // HTML headers are case insensitive
                var match = new Regex("Sec-WebSocket-Key: (.*)", RegexOptions.IgnoreCase).Match(request);
                if (!match.Success)
                {
                    Log.Warn("Sec-WebSocket-Key was not found in request.");
                    Log.Trace("Request was (base64-encoded): " + Convert.ToBase64String(Encoding.ASCII.GetBytes(request)));
                    stream.Write(AccessDeniedResponse, 0, AccessDeniedResponse.Length);
                    continue;
                }

                if (match.Groups.Count != 2)
                {
                    InvalidMatchNumber(match, stream);
                    continue;
                }
                string key             = match.Groups[1].Value.Trim();
                byte[] hashedAcceptKey = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(key + guid));
                string base64AcceptKey = Convert.ToBase64String(hashedAcceptKey);

                Log.Trace("Received Sec-WebSocket-Key: " + key);
                if (Log.IsTraceEnabled)
                {
                    StringBuilder hex = new StringBuilder(hashedAcceptKey.Length * 2);
                    foreach (byte b in hashedAcceptKey)
                    {
                        hex.AppendFormat("{0:x2}", b);
                    }
                    Log.Trace("Hashed Sec-WebSocket-Key: " + hex);
                }

                Log.Trace("Base64 if Sec-WebSocket-Key Hash: " + base64AcceptKey);
                string responseStr = "HTTP/1.1 101 Switching Protocols" + eol
                                     + "Connection: Upgrade" + eol
                                     + "Upgrade: websocket" + eol
                                     + "Sec-WebSocket-Accept: " + base64AcceptKey + eol + eol;
                byte[] response = Encoding.UTF8.GetBytes(responseStr);

                // Get cookie
                match = new Regex("lk-session=([^;\r\n]*)", RegexOptions.IgnoreCase).Match(request);
                if (!match.Success)
                {
                    Log.Warn("Denied websocket because session cookie is missing.");
                    stream.Write(AccessDeniedResponse, 0, AccessDeniedResponse.Length);
                    continue;
                }

                if (match.Groups.Count != 2)
                {
                    InvalidMatchNumber(match, stream);
                    continue;
                }

                // Validate session cookie of user
                var sessionCookie = match.Groups[1].ToString();
                var result        = reader.TryReadToken(sessionCookie, policy);
                if (!result.Succedeed)
                {
                    Log.Warn($"Denied websocket because JWS token could not be validated: {result.ErrorHeader}, {result.ErrorClaim}.");
                    stream.Write(AccessDeniedResponse, 0, AccessDeniedResponse.Length);
                    continue;
                }

                if (result.Token?.Payload == null)
                {
                    Log.Warn("Denied websocket because JWS token payload is empty.");
                    stream.Write(AccessDeniedResponse, 0, AccessDeniedResponse.Length);
                    continue;
                }

                var uid = JsonConvert.DeserializeObject <Dictionary <string, string> >(result.Token.Payload.ToString())["uid"];

                // Send handshake response
                stream.Write(response, 0, response.Length);

                // Start handler for the connection
                var handler = new WebSocketConnection(client, uid);

                if (!ConnectedClients.TryAdd(clientCounter++, handler))
                {
                    handler.Stop();
                }
                else
                {
                    OnClientConnected?.Invoke(this, new ClientConnectedEventArgs(handler));
                }
            }

            server.Stop();
        }
コード例 #2
0
 public ClientConnectedEventArgs(WebSocketConnection client)
 {
     Client = client;
 }