NUC-5: TelemetryPublisherFirestore now always checks for auth.

This commit is contained in:
Denis-Cosmin Nutiu 2020-10-31 16:55:16 +02:00
parent 44ee9c2071
commit 0f373783df
2 changed files with 42 additions and 30 deletions

View file

@ -32,6 +32,7 @@ namespace NucuCar.Telemetry.Publishers
protected HttpClient HttpClient;
private string _idToken;
private DateTime _nextExpiresTime;
// Variables used for authentication
private readonly string _webEmail;
@ -73,7 +74,13 @@ namespace NucuCar.Telemetry.Publishers
private async Task SetupAuthorization()
{
// Make request
// Check if the token is about to expire in the next 5 minutes.
if (DateTime.UtcNow.AddMinutes(5) < _nextExpiresTime)
{
return;
}
// https://cloud.google.com/identity-platform/docs/use-rest-api#section-sign-in-email-password
var requestUrl = $"https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key={_webApiKey}";
var data = new Dictionary<string, object>()
{
@ -88,6 +95,9 @@ namespace NucuCar.Telemetry.Publishers
{
var jsonContent = await response.GetJson();
_idToken = jsonContent.GetProperty("idToken").ToString();
// Setup next expire.
var expiresIn = double.Parse(jsonContent.GetProperty("expiresIn").ToString());
_nextExpiresTime = DateTime.UtcNow.AddSeconds(expiresIn);
HttpClient.Authorization(_idToken);
}
else
@ -109,6 +119,7 @@ namespace NucuCar.Telemetry.Publishers
HttpResponseMessage responseMessage = null;
try
{
await SetupAuthorization();
responseMessage = await HttpClient.PostAsync("", data);
}
// ArgumentException occurs during json serialization errors.

View file

@ -79,6 +79,9 @@ namespace NucuCar.UnitTests.NucuCar.Domain.Telemetry.Tests
};
var publisher = new MockTelemetryPublisherFirestore(opts);
var mockHttpClient = new MockHttpClient("http://testing.com");
var authResponse = new HttpResponseMessage(HttpStatusCode.OK)
{Content = new StringContent("{\"idToken\": \"1\",\"expiresIn\": \"3600\"}")};
mockHttpClient.SendAsyncResponses.Add(authResponse);
mockHttpClient.SendAsyncResponses.Add(new HttpResponseMessage(HttpStatusCode.OK));
publisher.SetHttpClient(mockHttpClient);
publisher.SetMockData(new Dictionary<string, object> {["testData"] = 1});
@ -87,7 +90,7 @@ namespace NucuCar.UnitTests.NucuCar.Domain.Telemetry.Tests
await publisher.PublishAsync(CancellationToken.None);
// Assert
var request = mockHttpClient.SendAsyncArgCalls[0];
var request = mockHttpClient.SendAsyncArgCalls[1];
Assert.Equal(HttpMethod.Post, request.Method);
Assert.Equal(new Uri("http://testing.com"), request.RequestUri);
Assert.Equal("{\"fields\":{\"testData\":{\"integerValue\":1}}}",
@ -104,6 +107,9 @@ namespace NucuCar.UnitTests.NucuCar.Domain.Telemetry.Tests
};
var publisher = new MockTelemetryPublisherFirestore(opts);
var mockHttpClient = new MockHttpClient("http://testing.com");
var authResponse = new HttpResponseMessage(HttpStatusCode.OK)
{Content = new StringContent("{\"idToken\": \"1\",\"expiresIn\": \"3600\"}")};
mockHttpClient.SendAsyncResponses.Add(authResponse);
mockHttpClient.SendAsyncResponses.Add(new HttpResponseMessage(HttpStatusCode.OK));
publisher.SetHttpClient(mockHttpClient);
publisher.SetMockData(new Dictionary<string, object> {["testData"] = double.PositiveInfinity});
@ -111,8 +117,8 @@ namespace NucuCar.UnitTests.NucuCar.Domain.Telemetry.Tests
// Run
await publisher.PublishAsync(CancellationToken.None);
// Assert no request made.
Assert.Empty(mockHttpClient.SendAsyncArgCalls);
// Assert only auth request made.
Assert.Single(mockHttpClient.SendAsyncArgCalls);
}
[Fact]
@ -140,7 +146,7 @@ namespace NucuCar.UnitTests.NucuCar.Domain.Telemetry.Tests
}
[Fact]
private async Task Test_PublishAsync_Authorization_OK()
private async Task Test_PublishAsync_Authorization_Refresh()
{
// Setup
var opts = new TelemetryPublisherOptions()
@ -150,44 +156,39 @@ namespace NucuCar.UnitTests.NucuCar.Domain.Telemetry.Tests
};
var publisher = new MockTelemetryPublisherFirestore(opts);
var mockHttpClient = new MockHttpClient("http://testing.com");
mockHttpClient.SendAsyncResponses.Add(new HttpResponseMessage(HttpStatusCode.Forbidden));
mockHttpClient.SendAsyncResponses.Add(new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("{\"idToken\":\"testauthtoken\"}")
});
mockHttpClient.SendAsyncResponses.Add(new HttpResponseMessage(HttpStatusCode.OK));
mockHttpClient.SendAsyncResponses.Add(new HttpResponseMessage(HttpStatusCode.OK)
{Content = new StringContent("{\"idToken\": \"1\",\"expiresIn\": \"0\"}")});
mockHttpClient.SendAsyncResponses.Add(new HttpResponseMessage(HttpStatusCode.OK));
mockHttpClient.SendAsyncResponses.Add(new HttpResponseMessage(HttpStatusCode.OK)
{Content = new StringContent("{\"idToken\": \"1\",\"expiresIn\": \"3600\"}")});
mockHttpClient.SendAsyncResponses.Add(new HttpResponseMessage(HttpStatusCode.OK));
publisher.SetHttpClient(mockHttpClient);
publisher.SetMockData(new Dictionary<string, object> {["testData"] = 1});
// Run
await publisher.PublishAsync(CancellationToken.None);
await publisher.PublishAsync(CancellationToken.None);
// Assert
Assert.Equal(3, mockHttpClient.SendAsyncArgCalls.Count);
Assert.Equal(4, mockHttpClient.SendAsyncArgCalls.Count);
// 1st request - auth denied
// 1st request auth
Assert.Equal(HttpMethod.Post, mockHttpClient.SendAsyncArgCalls[0].Method);
Assert.Equal(new Uri("http://testing.com"), mockHttpClient.SendAsyncArgCalls[0].RequestUri);
Assert.Equal("{\"fields\":{\"testData\":{\"integerValue\":1}}}",
mockHttpClient.SendAsyncArgCalls[0].Content.ReadAsStringAsync().GetAwaiter().GetResult());
Assert.Equal("https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=TAPIKEY",
mockHttpClient.SendAsyncArgCalls[0].RequestUri.ToString());
// 2st request - authorizing
// 2st request payload
Assert.Equal(HttpMethod.Post, mockHttpClient.SendAsyncArgCalls[1].Method);
Assert.Equal(new Uri("https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=TAPIKEY"),
mockHttpClient.SendAsyncArgCalls[1].RequestUri);
Assert.Equal("{\"email\":\"t@emai.com\",\"password\":\"tpass\",\"returnSecureToken\":true}",
mockHttpClient.SendAsyncArgCalls[1].Content.ReadAsStringAsync().GetAwaiter().GetResult());
// 3st request with authorization
// 3rd request auth
Assert.Equal(HttpMethod.Post, mockHttpClient.SendAsyncArgCalls[2].Method);
Assert.Equal(new Uri("http://testing.com"), mockHttpClient.SendAsyncArgCalls[2].RequestUri);
Assert.Equal("{\"fields\":{\"testData\":{\"integerValue\":1}}}",
mockHttpClient.SendAsyncArgCalls[2].Content.ReadAsStringAsync().GetAwaiter().GetResult());
Assert.Equal(new AuthenticationHeaderValue("Bearer", "testauthtoken"),
mockHttpClient.SendAsyncArgCalls[2].Headers.Authorization);
Assert.Equal("https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=TAPIKEY",
mockHttpClient.SendAsyncArgCalls[2].RequestUri.ToString());
// 4th request payload
Assert.Equal(HttpMethod.Post, mockHttpClient.SendAsyncArgCalls[1].Method);
}
}
}