Skip to content

Commit

Permalink
fix: evaluate client creds token expiry period in seconds instead of ms
Browse files Browse the repository at this point in the history
  • Loading branch information
rhamzeh committed May 1, 2023
1 parent 163630f commit 7f72628
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 19 deletions.
1 change: 0 additions & 1 deletion .github/PULL_REQUEST_TEMPLATE.md

This file was deleted.

8 changes: 0 additions & 8 deletions .github/SECURITY.md

This file was deleted.

2 changes: 0 additions & 2 deletions .openapi-generator/FILES
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
.github/CODEOWNERS
.github/ISSUE_TEMPLATES/bug_report.md
.github/ISSUE_TEMPLATES/feature_request.md
.github/PULL_REQUEST_TEMPLATE.md
.github/SECURITY.md
.github/workflows/main.yaml
.github/workflows/semgrep.yaml
.gitignore
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## v0.2.4

### [0.2.4](https://github.com/openfga/dotnet-sdk/compare/v0.2.3...v0.2.4) (2023-05-01)
- fix: client credentials token expiry period was being evaluated as ms instead of seconds, leading to token refreshes on every call

## v0.2.3

### [0.2.3](https://github.com/openfga/dotnet-sdk/compare/v0.2.2...v0.2.3) (2023-04-13)
Expand Down
120 changes: 116 additions & 4 deletions src/OpenFga.Sdk.Test/Api/OpenFgaApiTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ public async Task ExchangeCredentialsTest() {

var mockHandler = new Mock<HttpMessageHandler>(MockBehavior.Strict);
mockHandler.Protected()
.Setup<Task<HttpResponseMessage>>(
.SetupSequence<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.Is<HttpRequestMessage>(req =>
req.RequestUri == new Uri($"https://{config.Credentials.Config.ApiTokenIssuer}/oauth/token") &&
Expand All @@ -314,7 +314,15 @@ public async Task ExchangeCredentialsTest() {
StatusCode = HttpStatusCode.OK,
Content = Utils.CreateJsonStringContent(new OAuth2Client.AccessTokenResponse() {
AccessToken = "some-token",
ExpiresIn = 20000,
ExpiresIn = 86400,
TokenType = "Bearer"
}),
})
.ReturnsAsync(new HttpResponseMessage() {
StatusCode = HttpStatusCode.OK,
Content = Utils.CreateJsonStringContent(new OAuth2Client.AccessTokenResponse() {
AccessToken = "some-token",
ExpiresIn = 86400,
TokenType = "Bearer"
}),
});
Expand All @@ -326,11 +334,16 @@ public async Task ExchangeCredentialsTest() {
req.Headers.Contains("Authorization") &&
req.Headers.Authorization.Equals(new AuthenticationHeaderValue("Bearer", "some-token")));
mockHandler.Protected()
.Setup<Task<HttpResponseMessage>>(
.SetupSequence<Task<HttpResponseMessage>>(
"SendAsync",
readAuthorizationModelsMockExpression,
ItExpr.IsAny<CancellationToken>()
)
.ReturnsAsync(new HttpResponseMessage() {
StatusCode = HttpStatusCode.OK,
Content = Utils.CreateJsonStringContent(
new ReadAuthorizationModelsResponse() { AuthorizationModels = { } }),
})
.ReturnsAsync(new HttpResponseMessage() {
StatusCode = HttpStatusCode.OK,
Content = Utils.CreateJsonStringContent(
Expand All @@ -341,6 +354,7 @@ public async Task ExchangeCredentialsTest() {
var openFgaApi = new OpenFgaApi(config, httpClient);

var response = await openFgaApi.ReadAuthorizationModels(null, null);
var response2 = await openFgaApi.ReadAuthorizationModels(null, null);

mockHandler.Protected().Verify(
"SendAsync",
Expand All @@ -352,7 +366,105 @@ public async Task ExchangeCredentialsTest() {
);
mockHandler.Protected().Verify(
"SendAsync",
Times.Exactly(1),
Times.Exactly(2),
readAuthorizationModelsMockExpression,
ItExpr.IsAny<CancellationToken>()
);
mockHandler.Protected().Verify(
"SendAsync",
Times.Exactly(0),
ItExpr.Is<HttpRequestMessage>(req =>
req.RequestUri == new Uri($"{config.BasePath}/stores/{config.StoreId}/check") &&
req.Method == HttpMethod.Post),
ItExpr.IsAny<CancellationToken>()
);
}

/// <summary>
/// Test that a network call is issued to get the token at the first request if client id is provided, and then again before the next call if expired
/// </summary>
[Fact]
public async Task ExchangeCredentialsAfterExpiryTest() {
var config = new Configuration.Configuration() {
StoreId = _storeId,
ApiHost = _host,
Credentials = new Credentials() {
Method = CredentialsMethod.ClientCredentials,
Config = new CredentialsConfig() {
ClientId = "some-id",
ClientSecret = "some-secret",
ApiTokenIssuer = "tokenissuer.fga.example",
ApiAudience = "some-audience",
}
}
};

var mockHandler = new Mock<HttpMessageHandler>(MockBehavior.Strict);
mockHandler.Protected()
.SetupSequence<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.Is<HttpRequestMessage>(req =>
req.RequestUri == new Uri($"https://{config.Credentials.Config.ApiTokenIssuer}/oauth/token") &&
req.Method == HttpMethod.Post),
ItExpr.IsAny<CancellationToken>()
)
.ReturnsAsync(new HttpResponseMessage() {
StatusCode = HttpStatusCode.OK,
Content = Utils.CreateJsonStringContent(new OAuth2Client.AccessTokenResponse() {
AccessToken = "some-token",
ExpiresIn = 1,
TokenType = "Bearer"
}),
})
.ReturnsAsync(new HttpResponseMessage() {
StatusCode = HttpStatusCode.OK,
Content = Utils.CreateJsonStringContent(new OAuth2Client.AccessTokenResponse() {
AccessToken = "some-token",
ExpiresIn = 86400,
TokenType = "Bearer"
}),
});

var readAuthorizationModelsMockExpression = ItExpr.Is<HttpRequestMessage>(req =>
req.RequestUri.ToString()
.StartsWith($"{config.BasePath}/stores/{config.StoreId}/authorization-models") &&
req.Method == HttpMethod.Get &&
req.Headers.Contains("Authorization") &&
req.Headers.Authorization.Equals(new AuthenticationHeaderValue("Bearer", "some-token")));
mockHandler.Protected()
.SetupSequence<Task<HttpResponseMessage>>(
"SendAsync",
readAuthorizationModelsMockExpression,
ItExpr.IsAny<CancellationToken>()
)
.ReturnsAsync(new HttpResponseMessage() {
StatusCode = HttpStatusCode.OK,
Content = Utils.CreateJsonStringContent(
new ReadAuthorizationModelsResponse() { AuthorizationModels = { } }),
})
.ReturnsAsync(new HttpResponseMessage() {
StatusCode = HttpStatusCode.OK,
Content = Utils.CreateJsonStringContent(
new ReadAuthorizationModelsResponse() { AuthorizationModels = { } }),
});

var httpClient = new HttpClient(mockHandler.Object);
var openFgaApi = new OpenFgaApi(config, httpClient);

var response = await openFgaApi.ReadAuthorizationModels(null, null);
var response2 = await openFgaApi.ReadAuthorizationModels(null, null);

mockHandler.Protected().Verify(
"SendAsync",
Times.Exactly(2),
ItExpr.Is<HttpRequestMessage>(req =>
req.RequestUri == new Uri($"https://{config.Credentials.Config.ApiTokenIssuer}/oauth/token") &&
req.Method == HttpMethod.Post),
ItExpr.IsAny<CancellationToken>()
);
mockHandler.Protected().Verify(
"SendAsync",
Times.Exactly(2),
readAuthorizationModelsMockExpression,
ItExpr.IsAny<CancellationToken>()
);
Expand Down
2 changes: 1 addition & 1 deletion src/OpenFga.Sdk/ApiClient/OAuth2Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ private async Task ExchangeTokenAsync(CancellationToken cancellationToken = defa

_authToken = new AuthToken() {
AccessToken = accessTokenResponse.AccessToken,
ExpiresAt = DateTime.Now + TimeSpan.FromMilliseconds(accessTokenResponse.ExpiresIn)
ExpiresAt = DateTime.Now + TimeSpan.FromSeconds(accessTokenResponse.ExpiresIn)
};
}

Expand Down
1 change: 0 additions & 1 deletion src/OpenFga.Sdk/Client/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ public class OpenFgaClient : IDisposable {
private string CLIENT_METHOD_HEADER = "X-OpenFGA-Client-Method";

private readonly int DEFAULT_MAX_METHOD_PARALLEL_REQS = 10;
private readonly int DEFAULT_WAIT_TIME_BETWEEN_CHUNKS_IN_MS = 100;

public OpenFgaClient(
ClientConfiguration configuration,
Expand Down
2 changes: 1 addition & 1 deletion src/OpenFga.Sdk/Configuration/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public void IsValid() {
/// Version of the package.
/// </summary>
/// <value>Version of the package.</value>
public const string Version = "0.2.3";
public const string Version = "0.2.4";

#endregion Constants

Expand Down
2 changes: 1 addition & 1 deletion src/OpenFga.Sdk/OpenFga.Sdk.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<Description>.NET SDK for OpenFGA</Description>
<Copyright>OpenFGA</Copyright>
<RootNamespace>OpenFga.Sdk</RootNamespace>
<Version>0.2.3</Version>
<Version>0.2.4</Version>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\OpenFga.Sdk.xml</DocumentationFile>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
Expand Down

0 comments on commit 7f72628

Please sign in to comment.