Skip to content

Commit 709c410

Browse files
authored
Added NTLM authentication and small updates
* nullable check * readme update * Added NTLM authentication * small asserter refactoring and readme file updates * version bump
1 parent 8555cdd commit 709c410

File tree

6 files changed

+142
-37
lines changed

6 files changed

+142
-37
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<Project>
22
<PropertyGroup>
3-
<Version>0.2.0</Version>
3+
<Version>0.2.5</Version>
44
</PropertyGroup>
55
</Project>

README.md

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# QAToolKit Engine HttpTester library
2-
![https://github.com/qatoolkit/qatoolkit-engine-httptester-net/actions](![Build .NET Library](https://github.com/qatoolkit/qatoolkit-engine-httptester-net/workflows/Build%20.NET%20Library/badge.svg))
3-
![https://github.com/qatoolkit/qatoolkit-engine-httptester-net/security/code-scanning](https://github.com/qatoolkit/qatoolkit-engine-httptester-net/workflows/CodeQL%20Analyze/badge.svg)
4-
![https://sonarcloud.io/dashboard?id=qatoolkit_qatoolkit-engine-httptester-net](https://github.com/qatoolkit/qatoolkit-engine-httptester-net/workflows/Sonarqube%20Analyze/badge.svg)
5-
![https://www.nuget.org/packages/QAToolKit.Engine.HttpTester/](https://img.shields.io/nuget/v/QAToolKit.Engine.HttpTester?label=QAToolKit.Engine.HttpTester)
2+
[![Build .NET Library](https://github.com/qatoolkit/qatoolkit-engine-httptester-net/workflows/Build%20.NET%20Library/badge.svg)](https://github.com/qatoolkit/qatoolkit-engine-httptester-net/actions)
3+
[![CodeQL](https://github.com/qatoolkit/qatoolkit-engine-httptester-net/workflows/CodeQL%20Analyze/badge.svg)](https://github.com/qatoolkit/qatoolkit-engine-httptester-net/security/code-scanning)
4+
[![Sonarcloud Quality gate](https://github.com/qatoolkit/qatoolkit-engine-httptester-net/workflows/Sonarqube%20Analyze/badge.svg)](https://sonarcloud.io/dashboard?id=qatoolkit_qatoolkit-engine-httptester-net)
5+
[![NuGet package](https://img.shields.io/nuget/v/QAToolKit.Engine.HttpTester?label=QAToolKit.Engine.HttpTester)](https://www.nuget.org/packages/QAToolKit.Engine.HttpTester/)
66

77
## Description
88
`QAToolKit.Engine.HttpTester` is a .NET Standard 2.1 library, that that contains an implementation of `IHttpTesterClient` that is a thin wrapper around .NET `HttpClient` to allow to write easy Http Request calls.
@@ -69,6 +69,40 @@ using (var client = new HttpTesterClient())
6969
}
7070
```
7171

72+
#### HttpTesterClient Authentication
73+
74+
Currently `HttpTesterClient` supports:
75+
76+
**Basic authentication**
77+
78+
```csharp
79+
var response = await client
80+
.CreateHttpRequest(new Uri("https://qatoolkitapi.azurewebsites.net"))
81+
....
82+
.WithBasicAuthentication("user", "pass")
83+
.Start();
84+
```
85+
86+
**Bearer token authentication**
87+
88+
```csharp
89+
var response = await client
90+
.CreateHttpRequest(new Uri("https://qatoolkitapi.azurewebsites.net"))
91+
....
92+
.WithBearerAuthentication("eXy....")
93+
.Start();
94+
```
95+
96+
**NTLM authentication**
97+
98+
```csharp
99+
var response = await client
100+
.CreateHttpRequest(new Uri("https://qatoolkitapi.azurewebsites.net"))
101+
....
102+
.WithNTKMAuthentication("user", "pass") // or default security context .WithNTKMAuthentication()
103+
.Start();
104+
```
105+
72106
### HttpTestAsserter
73107

74108
This is an implementation of the HTTP response message asserter, which can be used to assert different paramters.

src/QAToolKit.Engine.HttpTester.Test/HttpTesterClientTests.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,5 +401,45 @@ public async Task HttpTesterClientPostObjectBodyWithFulUrlWithBearerAuthorizatio
401401
Assert.Equal("Giant", msg.brand.ToString());
402402
}
403403
}
404+
405+
[Fact]
406+
public async Task HttpTesterClientPostObjectBodyWithFulUrlWithNTLMDefaultAuthorization_Success()
407+
{
408+
using (var client = new HttpTesterClient())
409+
{
410+
var response = await client
411+
.CreateHttpRequest(new Uri("https://qatoolkitapi.azurewebsites.net/api/bicycles?api-version=1"))
412+
.WithJsonBody(BicycleFixture.GetCfr())
413+
.WithMethod(HttpMethod.Post)
414+
.WithNTLMAuthentication()
415+
.Start();
416+
417+
var msg = await response.GetResponseBody<dynamic>();
418+
419+
Assert.True(client.Duration < 2000);
420+
Assert.True(response.IsSuccessStatusCode);
421+
Assert.Equal("Giant", msg.brand.ToString());
422+
}
423+
}
424+
425+
[Fact]
426+
public async Task HttpTesterClientPostObjectBodyWithFulUrlWithNTLMAuthorization_Success()
427+
{
428+
using (var client = new HttpTesterClient())
429+
{
430+
var response = await client
431+
.CreateHttpRequest(new Uri("https://qatoolkitapi.azurewebsites.net/api/bicycles?api-version=1"))
432+
.WithJsonBody(BicycleFixture.GetCfr())
433+
.WithMethod(HttpMethod.Post)
434+
.WithNTLMAuthentication("user","pass")
435+
.Start();
436+
437+
var msg = await response.GetResponseBody<dynamic>();
438+
439+
Assert.True(client.Duration < 2000);
440+
Assert.True(response.IsSuccessStatusCode);
441+
Assert.Equal("Giant", msg.brand.ToString());
442+
}
443+
}
404444
}
405445
}

src/QAToolKit.Engine.HttpTester/HttpTestAsserter.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public class HttpTestAsserter : IHttpTestAsserter
2222
/// <param name="httpResponseMessage"></param>
2323
public HttpTestAsserter(HttpResponseMessage httpResponseMessage)
2424
{
25-
_httpResponseMessage = httpResponseMessage;
25+
_httpResponseMessage = httpResponseMessage ?? throw new ArgumentNullException($"{nameof(httpResponseMessage)} is null.");
2626
_assertResults = new List<AssertResult>();
2727
}
2828

@@ -45,7 +45,7 @@ public IHttpTestAsserter ResponseContentContains(string keyword, bool caseInsens
4545
{
4646
if (string.IsNullOrEmpty(keyword))
4747
{
48-
throw new ArgumentNullException($"Keyword is null.");
48+
throw new ArgumentNullException($"{nameof(keyword)} is null.");
4949
}
5050

5151
var bodyString = _httpResponseMessage.Content.ReadAsStringAsync().GetAwaiter().GetResult();
@@ -54,7 +54,7 @@ public IHttpTestAsserter ResponseContentContains(string keyword, bool caseInsens
5454
{
5555
Name = nameof(ResponseContentContains),
5656
Message = $"Body contains '{keyword}'.",
57-
IsTrue = caseInsensitive == true ? StringHelper.ContainsCaseInsensitive(bodyString, keyword) : bodyString.Contains(keyword)
57+
IsTrue = caseInsensitive ? StringHelper.ContainsCaseInsensitive(bodyString, keyword) : bodyString.Contains(keyword)
5858
});
5959

6060
return this;
@@ -88,7 +88,7 @@ public IHttpTestAsserter ResponseHasHttpHeader(string headerName)
8888
{
8989
if (string.IsNullOrEmpty(headerName))
9090
{
91-
throw new ArgumentNullException($"Header name is null.");
91+
throw new ArgumentNullException($"{nameof(headerName)} is null.");
9292
}
9393

9494
_assertResults.Add(new AssertResult()
@@ -111,7 +111,7 @@ public IHttpTestAsserter ResponseStatusCodeEquals(HttpStatusCode httpStatusCode)
111111
_assertResults.Add(new AssertResult()
112112
{
113113
Name = nameof(ResponseStatusCodeEquals),
114-
Message = $"Expected status code is {httpStatusCode} returne code is {_httpResponseMessage.StatusCode}.",
114+
Message = $"Expected status code is '{httpStatusCode}' return code is '{_httpResponseMessage.StatusCode}'.",
115115
IsTrue = _httpResponseMessage.StatusCode == httpStatusCode
116116
});
117117

src/QAToolKit.Engine.HttpTester/HttpTesterClient.cs

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Collections.Generic;
66
using System.Diagnostics;
7+
using System.Net;
78
using System.Net.Http;
89
using System.Net.Http.Headers;
910
using System.Text;
@@ -20,6 +21,7 @@ public class HttpTesterClient : IHttpTesterClient, IDisposable
2021
/// HttpClient object
2122
/// </summary>
2223
public HttpClient HttpClient { get; private set; }
24+
private HttpClientHandler HttpHandler { get; set; }
2325
private string _path = null;
2426
private Dictionary<string, string> _headers = null;
2527
private string _body = null;
@@ -40,43 +42,25 @@ public class HttpTesterClient : IHttpTesterClient, IDisposable
4042
/// <returns></returns>
4143
public IHttpTesterClient CreateHttpRequest(Uri baseAddress, bool validateCertificate = true)
4244
{
45+
HttpHandler = new HttpClientHandler();
46+
4347
if (!validateCertificate &&
4448
(baseAddress.Scheme == Uri.UriSchemeHttp || baseAddress.Scheme == Uri.UriSchemeHttps))
4549
{
46-
NonValidatingClient(baseAddress);
47-
}
48-
else
49-
{
50-
ValidatingClient(baseAddress);
51-
}
52-
53-
return this;
54-
}
55-
56-
private void ValidatingClient(Uri baseAddress)
57-
{
58-
HttpClient = new HttpClient()
59-
{
60-
BaseAddress = baseAddress
61-
};
62-
}
63-
64-
private void NonValidatingClient(Uri baseAddress)
65-
{
66-
var handler = new HttpClientHandler
67-
{
68-
ClientCertificateOptions = ClientCertificateOption.Manual,
69-
ServerCertificateCustomValidationCallback =
50+
HttpHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
51+
HttpHandler.ServerCertificateCustomValidationCallback =
7052
(httpRequestMessage, cert, cetChain, policyErrors) =>
7153
{
7254
return true;
73-
}
74-
};
55+
};
56+
}
7557

76-
HttpClient = new HttpClient(handler)
58+
HttpClient = new HttpClient(HttpHandler)
7759
{
7860
BaseAddress = baseAddress
7961
};
62+
63+
return this;
8064
}
8165

8266
/// <summary>
@@ -179,6 +163,40 @@ public IHttpTesterClient WithBearerAuthentication(string accessToken)
179163
return this;
180164
}
181165

166+
/// <summary>
167+
/// Use NTLM authentication
168+
/// </summary>
169+
/// <param name="userName"></param>
170+
/// <param name="password"></param>
171+
/// <returns></returns>
172+
public IHttpTesterClient WithNTLMAuthentication(string userName, string password)
173+
{
174+
if (string.IsNullOrEmpty(userName))
175+
throw new ArgumentNullException($"{nameof(userName)} is null.");
176+
if (string.IsNullOrEmpty(password))
177+
throw new ArgumentNullException($"{nameof(password)} is null.");
178+
179+
var credentials = new NetworkCredential(userName, password);
180+
181+
var credentialsCache = new CredentialCache { { HttpClient.BaseAddress, "NTLM", credentials } };
182+
HttpHandler.Credentials = credentialsCache;
183+
184+
return this;
185+
}
186+
187+
/// <summary>
188+
/// Use NTLM authentication which represents the authentication credentials for the current security context in which the application is running.
189+
/// </summary>
190+
/// <returns></returns>
191+
public IHttpTesterClient WithNTLMAuthentication()
192+
{
193+
var credentials = CredentialCache.DefaultNetworkCredentials;
194+
var credentialsCache = new CredentialCache { { HttpClient.BaseAddress, "NTLM", credentials } };
195+
HttpHandler.Credentials = credentialsCache;
196+
197+
return this;
198+
}
199+
182200
/// <summary>
183201
/// Start the HTTP request
184202
/// </summary>
@@ -253,6 +271,7 @@ public void Dispose()
253271
protected virtual void Dispose(bool disposing)
254272
{
255273
HttpClient?.Dispose();
274+
HttpHandler?.Dispose();
256275
}
257276
}
258277
}

src/QAToolKit.Engine.HttpTester/Interfaces/IHttpTesterClient.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,18 @@ public interface IHttpTesterClient
6262
/// <returns></returns>
6363
IHttpTesterClient WithBearerAuthentication(string accessToken);
6464
/// <summary>
65+
/// Use NTLM authentication
66+
/// </summary>
67+
/// <param name="userName"></param>
68+
/// <param name="password"></param>
69+
/// <returns></returns>
70+
IHttpTesterClient WithNTLMAuthentication(string userName, string password);
71+
/// <summary>
72+
/// Use NTLM authentication which represents the authentication credentials for the current security context in which the application is running.
73+
/// </summary>
74+
/// <returns></returns>
75+
IHttpTesterClient WithNTLMAuthentication();
76+
/// <summary>
6577
/// Start the HTTP request
6678
/// </summary>
6779
/// <returns></returns>

0 commit comments

Comments
 (0)