diff --git a/RestSharp.IntegrationTests/Helpers/SimpleServer.cs b/RestSharp.IntegrationTests/Helpers/SimpleServer.cs index 34e679b61..0087b9b0a 100644 --- a/RestSharp.IntegrationTests/Helpers/SimpleServer.cs +++ b/RestSharp.IntegrationTests/Helpers/SimpleServer.cs @@ -10,9 +10,14 @@ public class SimpleServer : IDisposable readonly Action _handler; Thread _processor; - public static SimpleServer Create(string url, Action handler) + public static SimpleServer Create(string url, Action handler, AuthenticationSchemes authenticationSchemes = AuthenticationSchemes.Anonymous) { - var server = new SimpleServer(new HttpListener { Prefixes = { url } }, handler); + var listener = new HttpListener + { + Prefixes = { url }, + AuthenticationSchemes = authenticationSchemes + }; + var server = new SimpleServer(listener, handler); server.Start(); return server; } diff --git a/RestSharp.IntegrationTests/RequestHeadTests.cs b/RestSharp.IntegrationTests/RequestHeadTests.cs new file mode 100644 index 000000000..ce6593152 --- /dev/null +++ b/RestSharp.IntegrationTests/RequestHeadTests.cs @@ -0,0 +1,98 @@ +using System.Collections.Specialized; +using System.Linq; +using System.Net; +using RestSharp.IntegrationTests.Helpers; +using Xunit; + +namespace RestSharp.IntegrationTests +{ + public class RequestHeadTests + { + private const string BASE_URL = "http://localhost:8080/"; + + public RequestHeadTests() + { + RequestHeadCapturer.Initialize(); + } + + [Fact] + public void Does_Not_Pass_Default_Credentials_When_Server_Does_Not_Negotiate() + { + const Method httpMethod = Method.GET; + using (SimpleServer.Create(BASE_URL, Handlers.Generic())) + { + var client = new RestClient(BASE_URL); + var request = new RestRequest(RequestHeadCapturer.RESOURCE, httpMethod) + { + UseDefaultCredentials = true + }; + + client.Execute(request); + + Assert.NotNull(RequestHeadCapturer.CapturedHeaders); + var keys = RequestHeadCapturer.CapturedHeaders.Keys.Cast().ToArray(); + Assert.False(keys.Contains("Authorization"), "Authorization header was present in HTTP request from client, even though server does not use the Negotiate scheme"); + } + } + + [Fact] + public void Passes_Default_Credentials_When_UseDefaultCredentials_Is_True() + { + const Method httpMethod = Method.GET; + using (SimpleServer.Create(BASE_URL, Handlers.Generic(), AuthenticationSchemes.Negotiate)) + { + var client = new RestClient(BASE_URL); + var request = new RestRequest(RequestHeadCapturer.RESOURCE, httpMethod) + { + UseDefaultCredentials = true + }; + + var response = client.Execute(request); + + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(RequestHeadCapturer.CapturedHeaders); + var keys = RequestHeadCapturer.CapturedHeaders.Keys.Cast().ToArray(); + Assert.True(keys.Contains("Authorization"), "Authorization header not present in HTTP request from client, even though UseDefaultCredentials = true"); + } + } + + [Fact] + public void Does_Not_Pass_Default_Credentials_When_UseDefaultCredentials_Is_False() + { + const Method httpMethod = Method.GET; + using (SimpleServer.Create(BASE_URL, Handlers.Generic(), AuthenticationSchemes.Negotiate)) + { + var client = new RestClient(BASE_URL); + var request = new RestRequest(RequestHeadCapturer.RESOURCE, httpMethod) + { + // UseDefaultCredentials is currently false by default, but to make the test more robust in case that ever + // changes, it's better to explicitly set it here. + UseDefaultCredentials = false + }; + + var response = client.Execute(request); + + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Null(RequestHeadCapturer.CapturedHeaders); + } + } + + private class RequestHeadCapturer + { + public const string RESOURCE = "Capture"; + + public static NameValueCollection CapturedHeaders { get; set; } + + public static void Initialize() + { + CapturedHeaders = null; + } + + public static void Capture(HttpListenerContext context) + { + var request = context.Request; + CapturedHeaders = request.Headers; + } + } + } +} \ No newline at end of file diff --git a/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj b/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj index 3872ba5bb..5be3f9c41 100644 --- a/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj +++ b/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj @@ -76,6 +76,7 @@ + diff --git a/RestSharp/Http.Async.cs b/RestSharp/Http.Async.cs index 69f4a6a33..afa9108b8 100644 --- a/RestSharp/Http.Async.cs +++ b/RestSharp/Http.Async.cs @@ -350,6 +350,8 @@ partial void AddAsyncHeaderActions() #endif } + // TODO: Try to merge the shared parts between ConfigureWebRequest and ConfigureAsyncWebRequest (quite a bit of code + // TODO: duplication at the moment). private HttpWebRequest ConfigureAsyncWebRequest(string method, Uri url) { #if SILVERLIGHT @@ -357,7 +359,7 @@ private HttpWebRequest ConfigureAsyncWebRequest(string method, Uri url) WebRequest.RegisterPrefix("https://", WebRequestCreator.ClientHttp); #endif var webRequest = (HttpWebRequest)WebRequest.Create(url); - webRequest.UseDefaultCredentials = false; + webRequest.UseDefaultCredentials = UseDefaultCredentials; AppendHeaders(webRequest); AppendCookies(webRequest); diff --git a/RestSharp/Http.Sync.cs b/RestSharp/Http.Sync.cs index 3adc1e317..4efd86a79 100644 --- a/RestSharp/Http.Sync.cs +++ b/RestSharp/Http.Sync.cs @@ -212,10 +212,12 @@ private void WriteRequestBody(HttpWebRequest webRequest) } } + // TODO: Try to merge the shared parts between ConfigureWebRequest and ConfigureAsyncWebRequest (quite a bit of code + // TODO: duplication at the moment). private HttpWebRequest ConfigureWebRequest(string method, Uri url) { var webRequest = (HttpWebRequest)WebRequest.Create(url); - webRequest.UseDefaultCredentials = false; + webRequest.UseDefaultCredentials = UseDefaultCredentials; ServicePointManager.Expect100Continue = false; AppendHeaders(webRequest); diff --git a/RestSharp/Http.cs b/RestSharp/Http.cs index a1ef10059..5dfe0f5e6 100644 --- a/RestSharp/Http.cs +++ b/RestSharp/Http.cs @@ -135,6 +135,12 @@ protected bool HasFiles /// public int? MaxRedirects { get; set; } #endif + /// + /// Determine whether or not the "default credentials" (e.g. the user account under which the current process is running) + /// will be sent along to the server. + /// + public bool UseDefaultCredentials { get; set; } + /// /// HTTP headers to be sent with request /// diff --git a/RestSharp/IHttp.cs b/RestSharp/IHttp.cs index c12e9f55e..0538b250f 100644 --- a/RestSharp/IHttp.cs +++ b/RestSharp/IHttp.cs @@ -42,6 +42,7 @@ public interface IHttp X509CertificateCollection ClientCertificates { get; set; } int? MaxRedirects { get; set; } #endif + bool UseDefaultCredentials { get; set; } IList Headers { get; } IList Parameters { get; } diff --git a/RestSharp/IRestRequest.cs b/RestSharp/IRestRequest.cs index 97033dc3a..4de8a85af 100644 --- a/RestSharp/IRestRequest.cs +++ b/RestSharp/IRestRequest.cs @@ -118,6 +118,12 @@ public interface IRestRequest /// int Attempts { get; } + /// + /// Determine whether or not the "default credentials" (e.g. the user account under which the current process is running) + /// will be sent along to the server. The default is false. + /// + bool UseDefaultCredentials { get; set; } + #if FRAMEWORK /// /// Adds a file to the Files collection to be included with a POST or PUT request diff --git a/RestSharp/RestClient.cs b/RestSharp/RestClient.cs index 5e00ebb10..08309a08f 100644 --- a/RestSharp/RestClient.cs +++ b/RestSharp/RestClient.cs @@ -158,7 +158,7 @@ IDeserializer GetHandler(string contentType) /// /// Proxy to use for requests made by this client instance. - /// Passed on to underying WebRequest if set. + /// Passed on to underlying WebRequest if set. /// public IWebProxy Proxy { get; set; } #endif @@ -295,11 +295,11 @@ private string EncodeParameters(IRestRequest request, IEnumerable par private void ConfigureHttp(IRestRequest request, IHttp http) { http.AlwaysMultipartFormData = request.AlwaysMultipartFormData; + http.UseDefaultCredentials = request.UseDefaultCredentials; + http.ResponseWriter = request.ResponseWriter; http.CookieContainer = CookieContainer; - http.ResponseWriter = request.ResponseWriter; - // move RestClient.DefaultParameters into Request.Parameters foreach (var p in DefaultParameters) { diff --git a/RestSharp/RestRequest.cs b/RestSharp/RestRequest.cs index d039f8711..758fb98ff 100644 --- a/RestSharp/RestRequest.cs +++ b/RestSharp/RestRequest.cs @@ -51,6 +51,12 @@ public class RestRequest : IRestRequest /// public Action ResponseWriter { get; set; } + /// + /// Determine whether or not the "default credentials" (e.g. the user account under which the current process is running) + /// will be sent along to the server. The default is false. + /// + public bool UseDefaultCredentials { get; set; } + /// /// Default constructor ///