private static bool IsNtlmAuthentication(HeyHttpRequest request) { if (String.IsNullOrEmpty(request.Authorization) || !request.Authorization.StartsWith("NTLM ")) { return(false); } return(true); }
private void ReadRequestHeaders() { using (FileStream logFileStream = File.OpenWrite(logFile.FullName)) { request = new HeyHttpRequest(logger); request.ReadHeaders(networkStream, logFileStream); } }
private static void AcceptCore() { requestHeaders = new HeyHttpRequest(logger); requestHeaders.ReadHeaders(networkStream, null); Upgrade(); //ReadRequestBody(); //ShowRequestDetails(); //SendResponse("200 OK", new List<string>()); }
private static bool IsAuthenticated(HeyHttpRequest request) { string authorization = request.GetHeader("Proxy-Authorization"); if (!String.IsNullOrEmpty(authorization)) { // Credentails are included. return(true); } return(false); }
private static bool IsNtlmMessage(HeyHttpRequest request, NtlmMessageType expectedMessageType) { if (!IsNtlmAuthentication(request)) { return(false); } string message = request.Authorization.Substring("NTLM ".Length); byte[] buffer = Convert.FromBase64String(message); // Validate signature. string signature = Encoding.ASCII.GetString(buffer, 0, 8); if (signature != "NTLMSSP\0") { return(false); } // Is it negotiation message? uint messageType = BitConverter.ToUInt32(buffer, 8); if (messageType != (uint)expectedMessageType) { return(false); } if (expectedMessageType == NtlmMessageType.NegotiatieMessage) { // Domain name. bool hasDomainName = (buffer[14] & 0x10) == 1; uint domainNameLength = BitConverter.ToUInt16(buffer, 16); uint domainNameMaxLength = BitConverter.ToUInt16(buffer, 18); uint domainNameOffset = BitConverter.ToUInt32(buffer, 20); } return(true); }
private static void ProcessDigestAuthorization(HeyHttpRequest request, HeyLogger logger) { string headerValue = request.Authorization.Substring("Digest ".Length); string[] pairs = headerValue.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string pair in pairs) { string[] keyAndValue = pair.Split(new char[] { '=' }, 2); if (keyAndValue.Length == 2) { string key = keyAndValue[0].Trim(); string value = keyAndValue[1].Trim('"'); logger.WriteHeadersLine( String.Format("{0}: {1}", key, value)); } } logger.WriteHeadersLine("\r\n"); // TODO: If the password is not the expected one, clear Authorization header, // so a 401 Unauthorized response is sent. }
public static bool IsAuthorizationValid(HeyHttpRequest request) { string user = String.Empty; string password = String.Empty; // 1. Decode headers. if (!String.IsNullOrEmpty(request.Authorization)) { switch (GetScheme(request.Authorization)) { case AuthorizationScheme.Basic: ProcessBasicAuthorization(request.Authorization, out user, out password); break; default: // We cannot decode this header, assume header is valid. return(true); } } // 2. Look for expected values and compare. string expectedUser; string expectedPassword; if (request.QueryStringHas("user", out expectedUser) && request.QueryStringHas("password", out expectedPassword)) { if (expectedUser == user && expectedPassword == password) { return(true); } } return(false); }
private static void OnAccept(IAsyncResult asyncResult) { HeyLogger logger = new HeyLogger(); Socket socketListener = asyncResult.AsyncState as Socket; Socket client = socketListener.EndAccept(asyncResult); socketListener.BeginAccept(OnAccept, asyncResult.AsyncState); try { HeyHttpRequest request = new HeyHttpRequest(logger); // Client got connected. logger.WriteLine(String.Format("Connected: {0}", client.RemoteEndPoint)); // Read HTTP headers. NetworkStream clientStream = new NetworkStream(client); MemoryStream tempStream = new MemoryStream(); request.ReadHeaders(clientStream, tempStream); // Authentication. if (settings.AuthenticationRequired && !IsAuthenticated(request)) { Reply407AndClose(logger, clientStream); return; } // Find server host name. logger.WriteLine(String.Format("Trying to connect to {0}", request.Host)); // Get IP address for the given server hostname. IPHostEntry hostEntry = Dns.GetHostEntry(request.Host); if (hostEntry.AddressList.Length == 0) { throw new Exception("Unknow server hostname."); } IPAddress address = hostEntry.AddressList[0]; // Connect to server. Socket server = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); server.Connect(new IPEndPoint(address, request.Port)); logger.WriteLine(String.Format("Connected to {0}", request.Host)); // Send cached data to server. NetworkStream serverStream = new NetworkStream(server); // When using the CONNECT method, proxy must send a HTTP response to client. // See "Tunneling TCP based protocols through Web proxy servers" internet-draft. if (request.Method == "CONNECT") { HeyHttpResponse response = new HeyHttpResponse(logger); response.Status = "200 Connection established"; response.Headers.Add("Proxy-agent: Happy-Sockets-Proxy/1.0"); response.CopyHeadersTo(clientStream); } else { // Only forward headers when it is not a CONNECT request. tempStream.Seek(0, SeekOrigin.Begin); tempStream.CopyTo(serverStream); } // Forward data. ParameterizedThreadStart serverToClientStart = new ParameterizedThreadStart(ForwardData); Thread serverToClientThread = new Thread(serverToClientStart); serverToClientThread.Start( new StreamsPair { StreamA = serverStream, StreamB = clientStream, Label = "server to client", Logger = logger }); ParameterizedThreadStart clientToServerStart = new ParameterizedThreadStart(ForwardData); Thread clientToServerThread = new Thread(clientToServerStart); clientToServerThread.Start( new StreamsPair { StreamA = clientStream, StreamB = serverStream, Label = "client to server", Logger = logger }); //serverToClientThread.Join(); //clientToServerThread.Join(); // TODO: make sure streams do not go out of scope. // TODO: wait until threads end and ensure connections are close. } catch (SocketException ex) { WriteLine(ConsoleColor.Red, ex.Message); logger.WriteLine(ex.ToString()); // We couldn't connect to the server, terminate connection with the client. client.Close(); } catch (IOException ex) { WriteLine(ConsoleColor.Red, ex.Message); logger.WriteLine(ex.ToString()); // The client closed the connection, terminate the connection with the server. client.Close(); } catch (Exception ex) { WriteLine(ConsoleColor.Red, ex.Message); logger.WriteLine(ex.ToString()); } }
public static void Start(HeyHttpClientSettings settings) { try { Uri uri = new Uri(settings.UriString); //using (TcpClient client = new TcpClient(AddressFamily.InterNetworkV6)) using (TcpClient client = new TcpClient()) { client.Connect(uri.Host, uri.Port); //client.Connect(IPAddress.Parse("2001:4898:1b:4:71e6:90b3:efa0:aa9b"), 80); Stream stream = client.GetStream(); if (uri.Port == 443) { SslStream sslStream = new SslStream(stream, true); sslStream.AuthenticateAsClient(uri.Host); stream = sslStream; } HeyHttpRequest request = new HeyHttpRequest(null); if (!String.IsNullOrEmpty(settings.Method)) { request.Method = settings.Method; } else { request.Method = "GET"; } request.PathAndQuery = uri.PathAndQuery; request.Version = "HTTP/1.1"; request.SetHeader("Host", uri.Host); request.SetHeader("Accept-Encoding", "gzip"); request.SetHeader("Connection", "Keep-Alive"); foreach (var header in settings.Headers) { if (!String.IsNullOrEmpty(header)) { request.SetHeader(header); } } byte[] requestBytes = Encoding.ASCII.GetBytes(request.ConcatenateHeaders()); // This is a sample on how to overwrite the command line request: //StringBuilder builder = new StringBuilder(); //builder.Append("POST /v5.0/folder.a4fb14adbccd1917.A4FB14ADBCCD1917!32089/files HTTP/1.1\r\n"); //builder.Append("Accept-Encoding: \r\n"); //builder.Append("Authorization: Bearer EwCIAq1DBAAUGCCXc8wU/zFu9QnLdZXy%2bYnElFkAAdYrLSFwx5TYQJSLo7JvCeKfAO384WRQiHYnTK8qTQDUiiVU2H5/sLAM1/j5gfRCbPSCdZ4LP6%2bAEBtA%2boOQ9bEdr0LwbQknqjd8ZkdutBdn9EfnS7KP0mjYldAI%2beekBQOHijrFSlmloMONrdbsYj0gkM8JxRezYG%2bOZCHbRTDLRIwMbPjjZg%2bwfZyWMNVT5vDlI9jb7L1q2hDWbpGk3oVprXKll6%2b3dfTwuVsKRJmpDfQz65oaKObxotc4i5dUVpyfGwIe79JAVMT5mYyb50Wv9zSxzOdLRxkOP8PXODIYc27JZQbUNqyhjgbaIXK9TN%2b8Lp4sm35Sy19d3QKo%2bAADZgAACHgZT5b/yvk0WAEbqZFBuQO%2bZgkYIhhbykgbQiB4h%2bbeIuQIFd%2bl4bzD62I9mBppLGjyeni/j4rDbgkkGvyrt/sNrbWkFwtc0DxzFf4ITE8tLY5o1eJ69m9D1vJ/P8xwuO2y/tSK3zuQdKJXagg7w/zx3qGZJ0OMNt%2bES9xkN1MWcS1ErFadoCAd/O0feLxR3V9HxgsEoX/KPV50yOJFEPjCBVhXzoCiZKpQO8uYE0ttOfzAauVkdhcsjD4RoRBfRO1WfoFkidc1wBntxA6lPnFSYX4xbxYyIMo2WAFdHLTa1AGjLcpNksFYR6NJU8cTenlsx6baLJ6%2bAm9VHoWWiTOF4Q18Stj7yeIPzl1k8hDwAKR0VrYx00TjVABuQOWD6VgsMA0vuER4bI1Wo2siPopQz3UdAgsq/frw3kiZB4PPl89kRfvTuaXjwoljSN3I6GeSiVePvFYjCGyFEQBZr8HE2XMB\r\n"); ////builder.Append("Content-Length: 197\r\n"); //builder.Append("Content-Length: 217\r\n"); //builder.Append("Content-Type: multipart/form-data; boundary=8381f8b9-b470-43ce-b23b-f13cf5840014\r\n"); //builder.Append("Host: apis.live.net\r\n"); //builder.Append("Connection: Keep-Alive\r\n"); //builder.Append("Cache-Control: no-cache\r\n"); //builder.Append("\r\n"); //builder.Append("--8381f8b9-b470-43ce-b23b-f13cf5840014\r\n"); ////builder.Append("Content-Length: 9\r\n"); //builder.Append("Content-Type: application/octet-stream; charset=UTF-8\r\n"); //builder.Append("Content-Disposition: form-data; name=\"file\"; filename=\"hello.txt\"\r\n"); ////builder.Append("Content-Type: application/octet-stream\r\n"); //builder.Append("\r\n"); //builder.Append("xxxxxxxxx\r\n"); //builder.Append("--8381f8b9-b470-43ce-b23b-f13cf5840014--\r\n"); //requestBytes = Encoding.UTF8.GetBytes(builder.ToString()); stream.Write(requestBytes, 0, requestBytes.Length); Console.WriteLine(Encoding.UTF8.GetString(requestBytes)); byte[] responseBytes = new byte[1024]; int bytesRead; do { // How to prevent multi-byte chars to be splitted into two buffers? bytesRead = stream.Read(responseBytes, 0, responseBytes.Length); string response = Encoding.UTF8.GetString(responseBytes, 0, bytesRead); Console.Write(response); } while (bytesRead > 0); } } catch (WebException ex) { Console.WriteLine(ex); } catch (IOException ex) { Console.WriteLine(ex); } }
public static void AddAuthenticateHeaderIfNeeded(HeyHttpRequest request, HeyHttpResponse response) { // Basic Server: // GET ---------> // // <--------- 401 Unauthorized // WWW-Authenticate: Basic realm="xyz" // // GET ---------> // Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== // // <--------- 200 OK // Basic Proxy: // // GET ---------> // <-------- 407 Proxy Authentication Required // Proxy-Authenticate: Basic realm="xyz" // // GET ---------> // Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== // // <--------- 200 OK // NTLM: // // GET ---------> // <--------- 401 Unauthorized // negotiate message ---------> // <--------- challenge message // authenticate message ---------> // <--------- 200 OK if (IsNtlmMessage(request, NtlmMessageType.NegotiatieMessage)) { response.Status = "401 Unauthorized"; response.Headers.Add("WWW-Authenticate: NTLM TlRMTVNTUAACAAAADgAOADgAAAAFgomiBTEwAGt4s6QAAAAAAAAAAPwA/ABGAAAABgLwIwAAAA9SAEUARABNAE8ATgBEAAIADgBSAEUARABNAE8ATgBEAAEAHgBXAEkATgAtAEQARgBHADEAMABFADIAOABLADEANgAEADQAcgBlAGQAbQBvAG4AZAAuAGMAbwByAHAALgBtAGkAYwByAG8AcwBvAGYAdAAuAGMAbwBtAAMAVABXAEkATgAtAEQARgBHADEAMABFADIAOABLADEANgAuAHIAZQBkAG0AbwBuAGQALgBjAG8AcgBwAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAFACQAYwBvAHIAcAAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ABwAIADJX/d1Cjc0BAAAAAA=="); } // Require basic access authentication. if (request.QueryStringHasTrueValue("basic") && !IsAuthorizationValid(request)) { response.Status = "401 Unauthorized"; response.Headers.Add("WWW-Authenticate: Basic realm=\"Secure Area\""); request.Path = ""; } // Require digest access authentication. if (request.QueryStringHasTrueValue("digest") && !IsAuthorizationValid(request)) { response.Status = "401 Unauthorized"; response.Headers.Add(String.Format( "WWW-Authenticate: Digest realm=\"{0}\", qop=\"{1}\", nonce=\"{2}\", opaque=\"{3}\"", digestRealm, digestQop, digestNonce, digestOpaque)); request.Path = ""; } // Require NTLM credentials. if (request.QueryStringHasTrueValue("negotiate") && !IsAuthorizationValid(request)) { response.Status = "401 Unauthorized"; response.Headers.Add("WWW-Authenticate: Negotiate"); request.Path = ""; } // NTLM authentication. if (request.QueryStringHasTrueValue("ntlm") && !IsAuthorizationValid(request)) { response.Status = "401 Unauthorized"; response.Headers.Add("WWW-Authenticate: NTLM"); request.Path = ""; } }