Skip to content

Commit d013b6d

Browse files
committedNov 19, 2020
merge conflict resolved
2 parents 6c2c96f + 3bbfc54 commit d013b6d

11 files changed

+200
-32
lines changed
 

‎.github/workflows/dotnet-core.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
name: Build .NET Library
22

33
on:
4-
push:
5-
branches: [ develop ]
64
pull_request:
75
branches: [ develop, main ]
86
release:

‎.github/workflows/sonarqube-analysis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
sonarOrganization: qatoolkit
2929
dotnetBuildArguments: ./src/QAToolKit.Source.Swagger/QAToolKit.Source.Swagger.csproj
3030
dotnetTestArguments: ./src/QAToolKit.Source.Swagger.Test/QAToolKit.Source.Swagger.Test.csproj /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
31-
sonarBeginArguments: /d:sonar.verbose="true" /d:sonar.language="cs" /d:sonar.cs.opencover.reportsPaths="**/coverage.opencover.xml" /d:sonar.coverage.exclusions="**Tests.cs"
31+
sonarBeginArguments: /d:sonar.verbose="true" /d:sonar.language="cs" /d:sonar.cs.opencover.reportsPaths="**/*.opencover.xml"
3232
sonarHostname: "https://sonarcloud.io"
3333
env:
3434
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

‎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.3.0</Version>
3+
<Version>0.3.5</Version>
44
</PropertyGroup>
55
</Project>

‎README.md

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

77
## Description
88
`QAToolKit.Source.Swagger` is a .NET library, which generates `IEnumerable<HttpRequest>` object that is the input for other components.
@@ -50,10 +50,29 @@ The above code is quite simple, but it needs some explanation.
5050
#### 1. AddBasicAuthentication
5151
If your Swagger.json files are protected by basic authentication, you can set those with `AddBasicAuthentication`.
5252

53-
#### 2. AddRequestFilters
53+
#### 2. AddNTLMAuthentication
54+
If your Swagger.json files are protected by Windows (NTLM) authentication, you can add it with `AddNTLMAuthentication`. There are two overrides which you can use.
55+
56+
```csharp
57+
SwaggerUrlSource swaggerSource = new SwaggerUrlSource(
58+
options =>
59+
{
60+
options.AddNTLMAuthentication("myuser", "mypassword");
61+
....
62+
63+
//or use default security context (logged in user)
64+
65+
SwaggerUrlSource swaggerSource = new SwaggerUrlSource(
66+
options =>
67+
{
68+
options.AddNTLMAuthentication();
69+
...
70+
```
71+
72+
#### 3. AddRequestFilters
5473
Filters comprise of different types. Those are `AuthenticationTypes`, `TestTypes` and `EndpointNameWhitelist`. All are optional.
5574

56-
##### 2.1. AuthenticationTypes
75+
##### 3.1. AuthenticationTypes
5776
Here we specify a list of Authentication types, that will be filtered out from the whole swagger file. This is where QA Tool Kit presents a convention.
5877
The built-in types are:
5978
- `AuthenticationType.Customer` which specifies a string `"@customer"`,
@@ -81,7 +100,7 @@ This is an example from swagger.json excerpt:
81100

82101
Parser then finds those string in the description field and populates the `RequestFilter` property.
83102

84-
##### 2.2 TestTypes
103+
##### 3.2 TestTypes
85104
Similarly as in the `AuthenticationTypes` you can filter out certain endpoints to be used in different test scenarios. Currently library supports:
86105

87106
- TestType.LoadTest which specifies a string `"@loadtest"`,
@@ -103,13 +122,13 @@ The same swagger.json excerpt which support test type tags might look like this:
103122

104123
If you feed the list of `HttpRequest` objects with load type tags to the library like `QAToolKit.Engine.Bombardier`, only those requests will be tested.
105124

106-
##### 2.3 EndpointNameWhitelist
125+
##### 3.3 EndpointNameWhitelist
107126
Final `RequestFilter` option is `EndpointNameWhitelist`. You can specify a list of endpoints that will be included in the results.
108127

109128
Every other endpoint will be excluded from the results. In the sample above we have set the result to include only `GetCategories` endpoint.
110129
That corresponds to the `operationId` in the swagger file above.
111130

112-
#### 3. AddBaseUrl
131+
#### 4. AddBaseUrl
113132
Your swagger file has a `Server section`, where you can specify an server URI and can be absolute or relative. An example of relative server section is:
114133
```json
115134
"servers": [
@@ -120,7 +139,7 @@ Your swagger file has a `Server section`, where you can specify an server URI an
120139
```
121140
In case of relative paths you need to add an absolute base URL to `Swagger Processor` with `AddBaseUrl`, otherwise the one from the `Servers section` will be used.
122141

123-
#### 4. UseSwaggerExampleValues
142+
#### 5. UseSwaggerExampleValues
124143
You can set `UseSwaggerExampleValues = true` in the SwaggerOptions when creating new Swagger source object. This will
125144
check Swagger for example files and populate those.
126145

‎qatoolkit-64x64.png

-813 Bytes
Loading

‎src/QAToolKit.Source.Swagger.Test/QAToolKit.Source.Swagger.Test.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<TargetFramework>net5.0</TargetFramework>
5-
5+
<LangVersion>latest</LangVersion>
66
<IsPackable>false</IsPackable>
77
</PropertyGroup>
88

‎src/QAToolKit.Source.Swagger.Test/SwaggerOptionsTest.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,43 @@ public void SwaggerBasicAuthTest_Successful()
2828
Assert.Equal("user", options.UserName);
2929
Assert.Equal("password", options.Password);
3030
Assert.True(options.UseBasicAuth);
31+
Assert.False(options.UseNTLMAuth);
3132
}
3233

34+
[Fact]
35+
public void SwaggerNTLMAuthTest_Successful()
36+
{
37+
var options = new SwaggerOptions();
38+
options.AddNTLMAuthentication("user", "password");
39+
40+
Assert.Equal("user", options.UserName);
41+
Assert.Equal("password", options.Password);
42+
Assert.False(options.UseBasicAuth);
43+
Assert.True(options.UseNTLMAuth);
44+
}
45+
46+
[Theory]
47+
[InlineData("","")]
48+
[InlineData(null, null)]
49+
[InlineData(null, "test")]
50+
[InlineData("test", null)]
51+
public void SwaggerNTLMAuthTest_Fails(string userName, string password)
52+
{
53+
var options = new SwaggerOptions();
54+
Assert.Throws<ArgumentNullException>(() => options.AddNTLMAuthentication(userName, password));
55+
}
56+
57+
[Fact]
58+
public void SwaggerNTLMAuthWithDefaultUserTest_Successful()
59+
{
60+
var options = new SwaggerOptions();
61+
options.AddNTLMAuthentication();
62+
63+
Assert.Null(options.UserName);
64+
Assert.Null( options.Password);
65+
Assert.False(options.UseBasicAuth);
66+
Assert.True(options.UseNTLMAuth);
67+
}
3368

3469
[Fact]
3570
public void SwaggerAuthenticationTypeRequestFiltersTest_Successful()

‎src/QAToolKit.Source.Swagger.Test/SwaggerUrlSourceIntegrationTests.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,5 +86,49 @@ await Assert.ThrowsAsync<ArgumentNullException>(async () => await urlSource.Load
8686
new Uri("https://github.com")
8787
}));
8888
}
89+
90+
[Fact]
91+
public async Task SwaggerUrlSourceWithBasicAuthTest_Successfull()
92+
{
93+
var swaggerSource = new SwaggerUrlSource(
94+
options =>
95+
{
96+
options.AddRequestFilters(new RequestFilter()
97+
{
98+
EndpointNameWhitelist = new string[] { "getPetById", "addPet" }
99+
});
100+
options.AddBasicAuthentication("test", "test");
101+
});
102+
103+
var requests = await swaggerSource.Load(new Uri[] {
104+
new Uri("https://petstore3.swagger.io/api/v3/openapi.json")
105+
});
106+
107+
_logger.LogInformation(JsonConvert.SerializeObject(requests, Formatting.Indented));
108+
109+
Assert.NotNull(requests);
110+
}
111+
112+
[Fact]
113+
public async Task SwaggerUrlSourceWithNTLMAuthTest_Successfull()
114+
{
115+
var swaggerSource = new SwaggerUrlSource(
116+
options =>
117+
{
118+
options.AddRequestFilters(new RequestFilter()
119+
{
120+
EndpointNameWhitelist = new string[] { "getPetById", "addPet" }
121+
});
122+
options.AddNTLMAuthentication("test", "test");
123+
});
124+
125+
var requests = await swaggerSource.Load(new Uri[] {
126+
new Uri("https://petstore3.swagger.io/api/v3/openapi.json")
127+
});
128+
129+
_logger.LogInformation(JsonConvert.SerializeObject(requests, Formatting.Indented));
130+
131+
Assert.NotNull(requests);
132+
}
89133
}
90134
}

‎src/QAToolKit.Source.Swagger/QAToolKit.Source.Swagger.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
<PackageProjectUrl>https://github.com/qatoolkit/qatoolkit-source-swagger-net</PackageProjectUrl>
2020
<PackageIcon>qatoolkit-64x64.png</PackageIcon>
2121
<RepositoryUrl>https://github.com/qatoolkit/qatoolkit-source-swagger-net</RepositoryUrl>
22-
<PackageTags>qatoolkit-source-swagger-net;.net;c#;f#;swagger;dotnet;netstandard</PackageTags>
23-
<Configurations>Debug;Release;Debug With Project References</Configurations>
22+
<PackageTags>qatoolkit-source-swagger-net;.net;c#;f#;swagger;dotnet;netstandard;net5</PackageTags>
23+
<Configurations>Debug;Release</Configurations>
2424
</PropertyGroup>
2525

2626
<PropertyGroup>

‎src/QAToolKit.Source.Swagger/SwaggerOptions.cs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ public class SwaggerOptions
1919
/// </summary>
2020
internal bool UseBasicAuth { get; private set; } = false;
2121
/// <summary>
22+
/// Is Swagger protected with NTLM authentication?
23+
/// </summary>
24+
internal bool UseNTLMAuth { get; private set; } = false;
25+
/// <summary>
2226
/// Use request filters?
2327
/// </summary>
2428
internal bool UseRequestFilter { get; private set; } = false;
@@ -38,6 +42,10 @@ public class SwaggerOptions
3842
/// Use Swagger example values that come with Swagger file
3943
/// </summary>
4044
public bool UseSwaggerExampleValues { get; set; } = false;
45+
/// <summary>
46+
/// Disable SSL validation when accessing swagger.json file
47+
/// </summary>
48+
public bool DisableSSLValidation { get; set; } = false;
4149

4250
/// <summary>
4351
/// Add basic authentication
@@ -48,16 +56,50 @@ public class SwaggerOptions
4856
public SwaggerOptions AddBasicAuthentication(string userName, string password)
4957
{
5058
if (string.IsNullOrEmpty(userName))
51-
throw new ArgumentException(nameof(userName));
59+
throw new ArgumentNullException($"{nameof(userName)} is null.");
5260
if (string.IsNullOrEmpty(password))
53-
throw new ArgumentException(nameof(password));
61+
throw new ArgumentNullException($"{nameof(password)} is null.");
5462

5563
UseBasicAuth = true;
64+
UseNTLMAuth = false;
5665
UserName = userName;
5766
Password = password;
5867
return this;
5968
}
6069

70+
/// <summary>
71+
/// Add NTLM authentication
72+
/// </summary>
73+
/// <param name="userName"></param>
74+
/// <param name="password"></param>
75+
/// <returns></returns>
76+
public SwaggerOptions AddNTLMAuthentication(string userName, string password)
77+
{
78+
if (string.IsNullOrEmpty(userName))
79+
throw new ArgumentNullException($"{nameof(userName)} is null.");
80+
if (string.IsNullOrEmpty(password))
81+
throw new ArgumentNullException($"{nameof(password)} is null.");
82+
83+
UseBasicAuth = false;
84+
UseNTLMAuth = true;
85+
UserName = userName;
86+
Password = password;
87+
return this;
88+
}
89+
90+
/// <summary>
91+
/// Add Default NTLM authentication which represents the authentication credentials for the current security context in which the application is running.
92+
/// </summary>
93+
/// <returns></returns>
94+
public SwaggerOptions AddNTLMAuthentication()
95+
{
96+
UseBasicAuth = false;
97+
UseNTLMAuth = true;
98+
UserName = null;
99+
Password = null;
100+
return this;
101+
}
102+
61103
/// <summary>
62104
/// Use request filters
63105
/// </summary>
@@ -66,7 +108,7 @@ public SwaggerOptions AddBasicAuthentication(string userName, string password)
66108
public SwaggerOptions AddRequestFilters(RequestFilter requestFilter)
67109
{
68110
UseRequestFilter = true;
69-
RequestFilter = requestFilter ?? throw new ArgumentException(nameof(requestFilter));
111+
RequestFilter = requestFilter ?? throw new ArgumentNullException($"{nameof(requestFilter)} is null.");
70112
return this;
71113
}
72114

@@ -77,7 +119,7 @@ public SwaggerOptions AddRequestFilters(RequestFilter requestFilter)
77119
/// <returns></returns>
78120
public SwaggerOptions AddBaseUrl(Uri baseUrl)
79121
{
80-
BaseUrl = baseUrl ?? throw new ArgumentException(nameof(baseUrl));
122+
BaseUrl = baseUrl ?? throw new ArgumentNullException($"{nameof(baseUrl)} is null.");
81123
return this;
82124
}
83125
}

‎src/QAToolKit.Source.Swagger/SwaggerUrlSource.cs

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System;
66
using System.Collections.Generic;
77
using System.IO;
8+
using System.Net;
89
using System.Net.Http;
910
using System.Net.Http.Headers;
1011
using System.Text;
@@ -48,24 +49,53 @@ private async Task<IEnumerable<HttpRequest>> LoadInternal(Uri[] source)
4849

4950
foreach (var uri in source)
5051
{
51-
using (var httpClient = new HttpClient())
52+
using (var handler = new HttpClientHandler())
5253
{
53-
if (_swaggerOptions.UseBasicAuth)
54+
if (_swaggerOptions.UseNTLMAuth)
5455
{
55-
var authenticationString = $"{_swaggerOptions.UserName}:{_swaggerOptions.Password}";
56-
var base64EncodedAuthenticationString = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(authenticationString));
57-
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64EncodedAuthenticationString);
56+
var credentials = new NetworkCredential();
57+
if (string.IsNullOrEmpty(_swaggerOptions.UserName) || string.IsNullOrEmpty(_swaggerOptions.Password))
58+
{
59+
credentials = CredentialCache.DefaultNetworkCredentials;
60+
}
61+
else
62+
{
63+
credentials = new NetworkCredential(_swaggerOptions.UserName, _swaggerOptions.Password);
64+
}
65+
66+
var credentialsCache = new CredentialCache { { uri, "NTLM", credentials } };
67+
handler.Credentials = credentialsCache;
5868
}
5969

60-
var stream = await httpClient.GetStreamAsync(uri);
70+
if (_swaggerOptions.DisableSSLValidation && (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps))
71+
{
72+
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
73+
handler.ServerCertificateCustomValidationCallback =
74+
(httpRequestMessage, cert, cetChain, policyErrors) =>
75+
{
76+
return true;
77+
};
78+
}
6179

62-
var openApiDocument = new OpenApiStreamReader().Read(stream, out var diagnostic);
63-
var textWritter = new OpenApiJsonWriter(new StringWriter());
64-
openApiDocument.SerializeAsV3(textWritter);
80+
using (var httpClient = new HttpClient(handler))
81+
{
82+
if (_swaggerOptions.UseBasicAuth)
83+
{
84+
var authenticationString = $"{_swaggerOptions.UserName}:{_swaggerOptions.Password}";
85+
var base64EncodedAuthenticationString = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(authenticationString));
86+
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64EncodedAuthenticationString);
87+
}
6588

66-
var requests = processor.MapFromOpenApiDocument(new Uri($"{uri.Scheme}://{uri.Host}"), openApiDocument);
89+
var stream = await httpClient.GetStreamAsync(uri);
6790

68-
restRequests.AddRange(requests);
91+
var openApiDocument = new OpenApiStreamReader().Read(stream, out var diagnostic);
92+
var textWritter = new OpenApiJsonWriter(new StringWriter());
93+
openApiDocument.SerializeAsV3(textWritter);
94+
95+
var requests = processor.MapFromOpenApiDocument(new Uri($"{uri.Scheme}://{uri.Host}"), openApiDocument);
96+
97+
restRequests.AddRange(requests);
98+
}
6999
}
70100
}
71101

0 commit comments

Comments
 (0)