Skip to content

Commit a47f36b

Browse files
Update authenticators
1 parent e5f1e46 commit a47f36b

File tree

6 files changed

+93
-176
lines changed

6 files changed

+93
-176
lines changed
Lines changed: 17 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,29 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Net.Http;
4-
using System.Threading;
5-
using System.Threading.Tasks;
64

75
namespace Vaas.Authentication;
86

9-
public class ClientCredentialsGrantAuthenticator : IAuthenticator
7+
public class ClientCredentialsGrantAuthenticator(
8+
string clientId,
9+
string clientSecret,
10+
Uri? tokenEndpoint = null,
11+
HttpClient? httpClient = null,
12+
ISystemClock? systemClock = null
13+
) : TokenReceiver(tokenEndpoint, httpClient, systemClock), IAuthenticator
1014
{
11-
private readonly TokenReceiver _tokenReceiver;
15+
private string ClientId { get; } = clientId;
16+
private string ClientSecret { get; } = clientSecret;
1217

13-
private string ClientId { get; }
14-
private string ClientSecret { get; }
15-
16-
public ClientCredentialsGrantAuthenticator(
17-
string clientId,
18-
string clientSecret,
19-
Uri? tokenUrl = null,
20-
HttpClient? httpClient = null,
21-
ISystemClock? systemClock = null
22-
)
18+
protected override FormUrlEncodedContent TokenRequestToForm()
2319
{
24-
_tokenReceiver = new ClientCredentialsTokenReceiver(
25-
this,
26-
tokenUrl,
27-
httpClient,
28-
systemClock
20+
return new FormUrlEncodedContent(
21+
new List<KeyValuePair<string, string>>
22+
{
23+
new("client_id", ClientId),
24+
new("client_secret", ClientSecret ?? throw new InvalidOperationException()),
25+
new("grant_type", "client_credentials"),
26+
}
2927
);
30-
ClientId = clientId;
31-
ClientSecret = clientSecret;
32-
}
33-
34-
public async Task<string> GetTokenAsync(CancellationToken cancellationToken)
35-
{
36-
return await _tokenReceiver.GetTokenAsync(cancellationToken);
37-
}
38-
39-
private class ClientCredentialsTokenReceiver(
40-
IAuthenticator authenticator,
41-
Uri? tokenUrl = null,
42-
HttpClient? httpClient = null,
43-
ISystemClock? systemClock = null
44-
) : TokenReceiver(authenticator, tokenUrl, httpClient, systemClock)
45-
{
46-
protected override FormUrlEncodedContent TokenRequestToForm()
47-
{
48-
var authenticator = (ClientCredentialsGrantAuthenticator)Authenticator;
49-
return new FormUrlEncodedContent(
50-
new List<KeyValuePair<string, string>>
51-
{
52-
new("client_id", authenticator.ClientId),
53-
new(
54-
"client_secret",
55-
authenticator.ClientSecret ?? throw new InvalidOperationException()
56-
),
57-
new("grant_type", "client_credentials"),
58-
}
59-
);
60-
}
6128
}
6229
}
Lines changed: 20 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,32 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Net.Http;
4-
using System.Threading;
5-
using System.Threading.Tasks;
64

75
namespace Vaas.Authentication;
86

9-
public class ResourceOwnerPasswordGrantAuthenticator : IAuthenticator
7+
public class ResourceOwnerPasswordGrantAuthenticator(
8+
string clientId,
9+
string userName,
10+
string password,
11+
Uri? tokenEndpoint = null,
12+
HttpClient? httpClient = null,
13+
ISystemClock? systemClock = null
14+
) : TokenReceiver(tokenEndpoint, httpClient, systemClock), IAuthenticator
1015
{
11-
private readonly TokenReceiver _tokenReceiver;
16+
private string ClientId { get; } = clientId;
17+
private string UserName { get; } = userName;
18+
private string Password { get; } = password;
1219

13-
private string ClientId { get; }
14-
private string UserName { get; }
15-
private string Password { get; }
16-
17-
public ResourceOwnerPasswordGrantAuthenticator(
18-
string clientId,
19-
string userName,
20-
string password,
21-
Uri? tokenUrl = null,
22-
HttpClient? httpClient = null,
23-
ISystemClock? systemClock = null
24-
)
20+
protected override FormUrlEncodedContent TokenRequestToForm()
2521
{
26-
_tokenReceiver = new ResourceOwnerPasswordTokenReceiver(
27-
this,
28-
tokenUrl,
29-
httpClient,
30-
systemClock
22+
return new FormUrlEncodedContent(
23+
new List<KeyValuePair<string, string>>
24+
{
25+
new("client_id", ClientId),
26+
new("username", UserName ?? throw new InvalidOperationException()),
27+
new("password", Password ?? throw new InvalidOperationException()),
28+
new("grant_type", "password"),
29+
}
3130
);
32-
ClientId = clientId;
33-
UserName = userName;
34-
Password = password;
35-
}
36-
37-
public async Task<string> GetTokenAsync(CancellationToken cancellationToken)
38-
{
39-
return await _tokenReceiver.GetTokenAsync(cancellationToken);
40-
}
41-
42-
private class ResourceOwnerPasswordTokenReceiver(
43-
IAuthenticator authenticator,
44-
Uri? tokenUrl = null,
45-
HttpClient? httpClient = null,
46-
ISystemClock? systemClock = null
47-
) : TokenReceiver(authenticator, tokenUrl, httpClient, systemClock)
48-
{
49-
protected override FormUrlEncodedContent TokenRequestToForm()
50-
{
51-
var authenticator = (ResourceOwnerPasswordGrantAuthenticator)Authenticator;
52-
return new FormUrlEncodedContent(
53-
new List<KeyValuePair<string, string>>
54-
{
55-
new("client_id", authenticator.ClientId),
56-
new(
57-
"username",
58-
authenticator.UserName ?? throw new InvalidOperationException()
59-
),
60-
new(
61-
"password",
62-
authenticator.Password ?? throw new InvalidOperationException()
63-
),
64-
new("grant_type", "password"),
65-
}
66-
);
67-
}
6831
}
6932
}

dotnet/Vaas/src/Vaas/Authentication/TokenReceiver.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,12 @@
77

88
namespace Vaas.Authentication;
99

10-
internal abstract class TokenReceiver(
11-
IAuthenticator authenticator,
10+
public abstract class TokenReceiver(
1211
Uri? tokenUrl = null,
1312
HttpClient? httpClient = null,
1413
ISystemClock? systemClock = null
15-
) : IAuthenticator, IDisposable
14+
) : IDisposable
1615
{
17-
protected readonly IAuthenticator Authenticator = authenticator;
1816
private readonly Uri _tokenUrl =
1917
tokenUrl
2018
?? new Uri("https://account.gdata.de/realms/vaas-production/protocol/openid-connect/token");

dotnet/Vaas/src/Vaas/Vaas.cs

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -143,30 +143,41 @@ public async Task<VaasVerdict> ForFileAsync(
143143
ForFileOptions? options = null
144144
)
145145
{
146-
options ??= ForFileOptions.From(_options);
146+
if (!File.Exists(path))
147+
throw new VaasClientException("File does not exist: " + path);
147148

148-
var sha256 = ChecksumSha256.Sha256CheckSum(path);
149+
options ??= ForFileOptions.From(_options);
149150

150-
var forSha256Options = new ForSha256Options
151+
if (options.UseCache || options.UseHashLookup)
151152
{
152-
VaasRequestId = options.VaasRequestId,
153-
UseHashLookup = options.UseHashLookup,
154-
UseCache = options.UseCache,
155-
};
153+
var forSha256Options = new ForSha256Options
154+
{
155+
VaasRequestId = options.VaasRequestId,
156+
UseHashLookup = options.UseHashLookup,
157+
UseCache = options.UseCache,
158+
};
156159

157-
var response = await ForSha256Async(sha256, cancellationToken, forSha256Options);
158-
159-
var verdictWithoutDetection =
160-
response.Verdict is Verdict.Malicious or Verdict.Pup
161-
&& string.IsNullOrEmpty(response.Detection);
162-
if (
163-
response.Verdict != Verdict.Unknown
164-
&& !verdictWithoutDetection
165-
&& !string.IsNullOrWhiteSpace(response.FileType)
166-
&& !string.IsNullOrEmpty(response.MimeType)
167-
)
168-
{
169-
return response;
160+
try
161+
{
162+
var sha256 = ChecksumSha256.Sha256CheckSum(path);
163+
var response = await ForSha256Async(sha256, cancellationToken, forSha256Options);
164+
var verdictWithoutDetection =
165+
response.Verdict is Verdict.Malicious or Verdict.Pup
166+
&& string.IsNullOrEmpty(response.Detection);
167+
if (
168+
response.Verdict != Verdict.Unknown
169+
&& !verdictWithoutDetection
170+
&& !string.IsNullOrWhiteSpace(response.FileType)
171+
&& !string.IsNullOrEmpty(response.MimeType)
172+
)
173+
{
174+
return response;
175+
}
176+
}
177+
catch (Exception)
178+
{
179+
// ignore
180+
}
170181
}
171182

172183
await using var stream = File.OpenRead(path);
@@ -188,7 +199,7 @@ public async Task<VaasVerdict> ForStreamAsync(
188199

189200
var url = new Uri(
190201
_options.VaasUrl,
191-
$"/files?useHashLookup={JsonSerializer.Serialize(options.UseHashLookup)}"
202+
$"/files?useHashLookup={JsonSerializer.Serialize(options.UseHashLookup)}&useCache={JsonSerializer.Serialize(true)}"
192203
);
193204

194205
var request = new HttpRequestMessage

dotnet/Vaas/src/Vaas/Vaas.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.1" />
3030
<PackageReference Include="Microsoft.Extensions.Options.DataAnnotations" Version="9.0.1" />
3131
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.4.0" />
32-
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.4.0" />
3332
<PackageReference Include="Websocket.Client" Version="5.1.2" />
3433
</ItemGroup>
3534

dotnet/Vaas/test/Vaas.Test/VaasTest.cs

Lines changed: 22 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ private static ServiceCollection GetServices()
6464
return GetServices(
6565
new Dictionary<string, string>
6666
{
67-
{ "VerdictAsAService:Options:UseHashLookup", "false" },
67+
{ "VerdictAsAService:Options:UseHashLookup", "true" },
6868
{ "VerdictAsAService:Options:UseCache", "false" },
6969
{ "VerdictAsAService:Options:VaasUrl", VaasUrl.ToString() },
7070
{ "VerdictAsAService:Options:Timeout", "10" },
@@ -360,29 +360,32 @@ public async Task ForFileOptions_SendsOptions(bool useCache, bool useHashLookup)
360360
const string content =
361361
"X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*";
362362
const string sha256 = "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f";
363-
var fileName = Guid.NewGuid().ToString() + ".txt";
363+
var fileName = Guid.NewGuid() + ".txt";
364364

365365
await File.WriteAllBytesAsync(fileName, Encoding.UTF8.GetBytes(content));
366366

367367
var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);
368368

369-
handlerMock
370-
.SetupRequest(request =>
371-
request.RequestUri != null
372-
&& request.Method == HttpMethod.Get
373-
&& request.RequestUri.ToString().Contains(sha256)
374-
&& request
375-
.RequestUri.ToString()
376-
.Contains("useCache=" + JsonSerializer.Serialize(useCache))
377-
&& request
378-
.RequestUri.ToString()
379-
.Contains("useHashLookup=" + JsonSerializer.Serialize(useHashLookup))
380-
)
381-
.ReturnsResponse(
382-
JsonSerializer.Serialize(
383-
new FileReport { Sha256 = EicarSha256, Verdict = Verdict.Unknown }
369+
if (useCache || useHashLookup)
370+
{
371+
handlerMock
372+
.SetupRequest(request =>
373+
request.RequestUri != null
374+
&& request.Method == HttpMethod.Get
375+
&& request.RequestUri.ToString().Contains(sha256)
376+
&& request
377+
.RequestUri.ToString()
378+
.Contains("useCache=" + JsonSerializer.Serialize(useCache))
379+
&& request
380+
.RequestUri.ToString()
381+
.Contains("useHashLookup=" + JsonSerializer.Serialize(useHashLookup))
384382
)
385-
);
383+
.ReturnsResponse(
384+
JsonSerializer.Serialize(
385+
new FileReport { Sha256 = EicarSha256, Verdict = Verdict.Unknown }
386+
)
387+
);
388+
}
386389

387390
if (!useCache)
388391
{
@@ -422,7 +425,7 @@ public async Task ForFileOptions_SendsOptions(bool useCache, bool useHashLookup)
422425
var vaas = provider.GetRequiredService<IVaas>();
423426

424427
await vaas.ForFileAsync(
425-
"file.txt",
428+
fileName,
426429
CancellationToken.None,
427430
new ForFileOptions { UseCache = useCache, UseHashLookup = useHashLookup }
428431
);
@@ -632,30 +635,6 @@ await _vaas
632635
.ThrowAsync<OperationCanceledException>();
633636
}
634637

635-
[Fact]
636-
public async Task ForFileAsync_IfForSha256DoesNotReturnDetectionEtc_UploadsFile()
637-
{
638-
var buffer = new byte[1024];
639-
Random.Shared.NextBytes(buffer);
640-
await File.WriteAllBytesAsync("file.txt", buffer);
641-
var sha256 = new ChecksumSha256(SHA256.HashData(buffer));
642-
// TODO: Mock response
643-
644-
var actual = await _vaas.ForFileAsync("file.txt", CancellationToken.None);
645-
646-
actual
647-
.Should()
648-
.BeEquivalentTo(
649-
new VaasVerdict
650-
{
651-
Sha256 = sha256,
652-
Detection = null,
653-
FileType = "data",
654-
MimeType = "application/octet-stream",
655-
}
656-
);
657-
}
658-
659638
[Fact]
660639
public async Task ForStreamAsync_ReturnsVerdict()
661640
{

0 commit comments

Comments
 (0)