public void AuthenticateMessage() { NtlmChallengeMessageGenerator type2Message = new NtlmChallengeMessageGenerator(type2Challenge); NtlmAuthenticateMessageGenerator generator = new NtlmAuthenticateMessageGenerator(randomNumberGenerator, testTime, null, null, userName, password, type2Message.Challenge, type2Message.Flags, type2Message.Target, type2Message.TargetInfo); byte[] actualAuthBytes = generator.GetAuthorizationBytes(); string actualAuthValue = generator.GetAuthorizationValue(); string calculatedValue = Convert.ToBase64String(actualAuthBytes); Assert.That(calculatedValue, Is.EqualTo(expectedType3)); Assert.That(actualAuthValue, Is.EqualTo(expectedType3)); }
public async Task TestNtlm() { string authType = NtlmGenerator.AuthorizationHeaderMarker; string userName = "******"; string password = "******"; string relativeUri = "/api/auth/ntlm"; Uri fullUri = new Uri(baseUri, relativeUri); string initialRequest = CreateInitialRequest(fullUri); using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { socket.Connect("localhost", port); HttpResponse initialResponse = await SendRequestAndGetResponse(socket, initialRequest); Assert.That(initialResponse.StatusCode, Is.EqualTo(401)); Assert.That(initialResponse.Headers.ContainsKey("WWW-Authenticate")); string authHeader = GetDesiredAuthHeader(authType, initialResponse); Assert.That(authHeader, Is.Not.Null); NtlmNegotiateMessageGenerator type1Generator = new NtlmNegotiateMessageGenerator(); string negotioateRequest = CreateRequest(fullUri, type1Generator.GenerateAuthorizationHeader()); HttpResponse challengeResponse = await SendRequestAndGetResponse(socket, negotioateRequest); Assert.That(challengeResponse.StatusCode, Is.EqualTo(401)); Assert.That(challengeResponse.Headers.ContainsKey("WWW-Authenticate")); string challengeAuthHeader = GetDesiredAuthHeader(authType, challengeResponse); Assert.That(challengeAuthHeader, Is.Not.Null); NtlmChallengeMessageGenerator type2Generator = new NtlmChallengeMessageGenerator(challengeAuthHeader); NtlmAuthenticateMessageGenerator type3Generator = new NtlmAuthenticateMessageGenerator(null, null, userName, password, type2Generator); string authorizeRequest = CreateRequest(fullUri, type3Generator.GenerateAuthorizationHeader()); HttpResponse authorizedResponse = await SendRequestAndGetResponse(socket, authorizeRequest); Assert.That(authorizedResponse.StatusCode, Is.EqualTo(200)); socket.Close(); } }
private void ProcessResponse(ProcessingContext context) { // Only do any processing on the response if the response is 401, // or "Unauthorized". if (context.ResponseHeader != null && context.ResponseHeader.StatusCode == 401) { //context.ServerStream.ReadTimeout = 5000; //context.ServerStream.WriteTimeout = 5000; var reader = new StreamReader(context.ServerStream); if (context.ResponseHeader.EntityHeaders.ContentLength != 0) { ReadFromStream(reader); } // We do not want the proxy to do any further processing after // handling this message. context.StopProcessing(); if (context.ResponseHeader.WWWAuthenticate.Contains(BasicGenerator.AuthorizationHeaderMarker)) { // This is the generation of the HTTP Basic authorization header value. var basicAuthHeaderValue = $"user:pass"; var encodedHeaderValue = Convert.ToBase64String(Encoding.ASCII.GetBytes(basicAuthHeaderValue)); context.RequestHeader.Authorization = "Basic " + encodedHeaderValue; // Resend the request (with the Authorization header) to the server // using BenderProxy's HttpMessageWriter. var writer = new HttpMessageWriter(context.ServerStream); writer.Write(context.RequestHeader); // Get the authorized response, and forward it on to the browser, using // BenderProxy's HttpHeaderReader and support classes. var headerReader = new HttpHeaderReader(reader); var header = new HttpResponseHeader(headerReader.ReadHttpMessageHeader()); var body = ReadFromStream(reader); Stream bodyStream = new MemoryStream(Encoding.UTF8.GetBytes(body)); new HttpResponseWriter(context.ClientStream).Write(header, bodyStream, bodyStream.Length); } else if (context.ResponseHeader.WWWAuthenticate.Contains(NtlmGenerator.AuthorizationHeaderMarker)) { // Read the WWW-Authenticate header. Because of the way the test // web app is configured, it returns multiple headers, with // different schemes. We need to select the correct one. var authHeader = GetAuthenticationHeader(context.ResponseHeader.WWWAuthenticate, NtlmGenerator.AuthorizationHeaderMarker); var type1 = new NtlmNegotiateMessageGenerator(); var type1HeaderValue = type1.GenerateAuthorizationHeader(); context.RequestHeader.Authorization = type1HeaderValue; var writer = new HttpMessageWriter(context.ServerStream); writer.Write(context.RequestHeader); var headerReader = new HttpHeaderReader(reader); var challengeHeader = new HttpResponseHeader(headerReader.ReadHttpMessageHeader()); var challengeAuthHeader = challengeHeader.WWWAuthenticate; var challengeBody = ReadFromStream(reader); if (!string.IsNullOrEmpty(challengeAuthHeader) && challengeAuthHeader.StartsWith(NtlmGenerator.AuthorizationHeaderMarker)) { // If a proper message was received (the "type 2" or "Challenge" message), // parse it, and generate the proper authentication header (the "type 3" // or "Authorization" message). var type2 = new NtlmChallengeMessageGenerator(challengeAuthHeader); var type3 = new NtlmAuthenticateMessageGenerator(null, null, "user", "pass", type2); var type3HeaderValue = type3.GenerateAuthorizationHeader(); context.RequestHeader.Authorization = type3HeaderValue; writer.Write(context.RequestHeader); // Get the authorized response from the server, and forward it on to // the browser. var header = new HttpResponseHeader(headerReader.ReadHttpMessageHeader()); var body = ReadFromStream(reader); Stream bodyStream = new MemoryStream(Encoding.UTF8.GetBytes(body)); new HttpResponseWriter(context.ClientStream).Write(header, bodyStream, bodyStream.Length); context.ClientStream.Flush(); } } } }
/// <summary> /// Handles the OnResponseReceived for the proxy, which occurs after the response is /// received from the web server, but before it is forwarded on to the browser. /// </summary> /// <param name="context">A <see cref="BenderProxy.ProcessingContext"/> object.</param> public override void OnResponseReceived(ProcessingContext context) { string userName = "******"; string password = "******"; if (context.ResponseHeader != null && context.ResponseHeader.StatusCode == 401) { // Only process requests for localhost or the redirected- // via-hosts-file-entry host, and where NTLM auth is requested. List <string> candidateUrls = new List <string>() { string.Format("localhost:{0}", TestWebAppPort), string.Format("{0}:{1}", TestWebAppHostName, TestWebAppPort) }; if (candidateUrls.Contains(context.RequestHeader.Host) && context.ResponseHeader.WWWAuthenticate != null && context.ResponseHeader.WWWAuthenticate.Contains(NtlmGenerator.AuthorizationHeaderMarker)) { // Read the headers from the response and finish reading the response // body, if any. Console.WriteLine("Received 401 - Unauthorized response"); context.ServerStream.ReadTimeout = 5000; context.ServerStream.WriteTimeout = 5000; StreamReader reader = new StreamReader(context.ServerStream); if (context.ResponseHeader.EntityHeaders.ContentLength != 0) { string drainBody = ReadFromStream(reader); } // We do not want the proxy to do any further processing after // handling this message. context.StopProcessing(); // Read the WWW-Authenticate header. Because of the way the test // web app is configured, it returns multiple headers, with // different schemes. We need to select the correct one. string authHeader = GetAuthenticationHeader(context.ResponseHeader.WWWAuthenticate, NtlmGenerator.AuthorizationHeaderMarker); Console.WriteLine("Processing WWW-Authenticate header: {0}", authHeader); // Generate the initial message (the "type 1" or "Negotiation" message") // and get the response, using BenderProxy's HttpMessageWriter and // HttpHeaderReader and support classes. Console.WriteLine("Generating authorization header value for Negotiate ('Type 1') message"); NtlmNegotiateMessageGenerator type1 = new NtlmNegotiateMessageGenerator(); string type1HeaderValue = type1.GenerateAuthorizationHeader(); context.RequestHeader.Authorization = type1HeaderValue; Console.WriteLine("Resending request with Authorization header: {0}", type1HeaderValue); HttpMessageWriter writer = new HttpMessageWriter(context.ServerStream); writer.Write(context.RequestHeader); HttpHeaderReader headerReader = new HttpHeaderReader(reader); HttpResponseHeader challengeHeader = new HttpResponseHeader(headerReader.ReadHttpMessageHeader()); string challengeAuthHeader = challengeHeader.WWWAuthenticate; string challengeBody = ReadFromStream(reader); if (!string.IsNullOrEmpty(challengeAuthHeader) && challengeAuthHeader.StartsWith(NtlmGenerator.AuthorizationHeaderMarker)) { // If a proper message was received (the "type 2" or "Challenge" message), // parse it, and generate the proper authentication header (the "type 3" // or "Authorization" message). Console.WriteLine("Received 401 response with Challenge ('Type 2') message: {0}", challengeAuthHeader); NtlmChallengeMessageGenerator type2 = new NtlmChallengeMessageGenerator(challengeAuthHeader); Console.WriteLine("Generating Authorization ('Type 3') message for user name '{0}' and password '{1}'", userName, password); NtlmAuthenticateMessageGenerator type3 = new NtlmAuthenticateMessageGenerator(null, null, userName, password, type2); string type3HeaderValue = type3.GenerateAuthorizationHeader(); Console.WriteLine("Resending request with Authorization header: {0}", type3HeaderValue); context.RequestHeader.Authorization = type3HeaderValue; writer.Write(context.RequestHeader); // Get the authorized response from the server, and forward it on to // the browser. HttpResponseHeader header = new HttpResponseHeader(headerReader.ReadHttpMessageHeader()); string body = ReadFromStream(reader); Stream bodyStream = new MemoryStream(Encoding.UTF8.GetBytes(body)); new HttpResponseWriter(context.ClientStream).Write(header, bodyStream, bodyStream.Length); context.ClientStream.Flush(); } } } }