Skip to content

Commit

Permalink
Build structure for kinde sdk 1.2.0 using OpenAPI custom template
Browse files Browse the repository at this point in the history
  • Loading branch information
quoc-tran-sgt committed May 16, 2023
1 parent 78def94 commit d36143b
Show file tree
Hide file tree
Showing 60 changed files with 3,964 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Kinde.Sdk/
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## .NET SDK generator


Install OpenApi generator.<br />
Please read [OpenAPI generator installation](https://github.com/OpenAPITools/openapi-generator#1---installation) or [OpenAPI generator installation](https://openapi-generator.tech/docs/installation).

---
Clone the repository to your computer:
```
git clone https://github.com/kinde-oss/kinde-dotnet-generator
```
---
To generate SDK please run:
```
openapi-generator-cli generate -i https://kinde.com/api/kinde-mgmt-api-specs.yaml -g csharp-netcore -o Kinde.Sdk --package-name=Kinde.Api -c config.yaml --library=httpclient --additional-properties=targetFramework=net6.0,packageGuid=9A19103F-16F7-4668-BE54-9A1E7A4F7556,packageVersion=1.2.0,sourceFolder= --global-property apiTests=false,modelTests=false
```
---
Folder `Kinde.Sdk` contains our final SDK after build.
In order to copy files generated from Kinde.Sdk folder to the development repository, eg: `../kinde-dotnet-sdk` , please run
```
cp -r Kinde.Sdk/Kinde.Api ../kinde-dotnet-sdk/
```
104 changes: 104 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
generateSourceCodeOnly: true
templateDir: my_custom_templates
files:
LICENSE: {}
Kinde.Api/ApiClient.cs:
destinationFilename: /Kinde.Api/ApiClient.cs
Kinde.Api/Enums/AuthorizationStates.cs:
destinationFilename: /Kinde.Api/Enums/AuthorizationStates.cs
Kinde.Api/Flows/AuthorizationCodeFlow.cs:
destinationFilename: /Kinde.Api/Flows/AuthorizationCodeFlow.cs
Kinde.Api/Flows/BaseAuthorizationFlow.cs:
destinationFilename: /Kinde.Api/Flows/BaseAuthorizationFlow.cs
Kinde.Api/Flows/ClientCredentialsFlow.cs:
destinationFilename: /Kinde.Api/Flows/ClientCredentialsFlow.cs
Kinde.Api/Flows/IAuthorizationFlow.cs:
destinationFilename: /Kinde.Api/Flows/IAuthorizationFlow.cs
Kinde.Api/Flows/ICodeFlow.cs:
destinationFilename: /Kinde.Api/Flows/ICodeFlow.cs
Kinde.Api/Flows/PKCES256Flow.cs:
destinationFilename: /Kinde.Api/Flows/PKCES256Flow.cs
Kinde.Api/Hashing/BaseCodeVerifier.cs:
destinationFilename: /Kinde.Api/Hashing/BaseCodeVerifier.cs
Kinde.Api/Hashing/ICodeVerifier.cs:
destinationFilename: /Kinde.Api/Hashing/ICodeVerifier.cs
Kinde.Api/Hashing/SHA256CodeVerifier.cs:
destinationFilename: /Kinde.Api/Hashing/SHA256CodeVerifier.cs
Kinde.Api/KindeClient.cs:
destinationFilename: /Kinde.Api/KindeClient.cs
Kinde.Api/KindeClientFactory.cs:
destinationFilename: /Kinde.Api/KindeClientFactory.cs
Kinde.Api/KindeHttpClient.cs:
destinationFilename: /Kinde.Api/KindeHttpClient.cs
Kinde.Api/Models/Configuration/ApplicationConfiguration.cs:
destinationFilename: /Kinde.Api/Models/Configuration/ApplicationConfiguration.cs
Kinde.Api/Models/Configuration/AuthorizationCodeConfiguration.cs:
destinationFilename: /Kinde.Api/Models/Configuration/AuthorizationCodeConfiguration.cs
Kinde.Api/Models/Configuration/AuthorizationConfigurationWrapper.cs:
destinationFilename: /Kinde.Api/Models/Configuration/AuthorizationConfigurationWrapper.cs
Kinde.Api/Models/Configuration/BaseAuthorizationConfiguration.cs:
destinationFilename: /Kinde.Api/Models/Configuration/BaseAuthorizationConfiguration.cs
Kinde.Api/Models/Configuration/ClientCredentialsConfiguration.cs:
destinationFilename: /Kinde.Api/Models/Configuration/ClientCredentialsConfiguration.cs
Kinde.Api/Models/Configuration/DefaultApplicationConfigurationProvider.cs:
destinationFilename: /Kinde.Api/Models/Configuration/DefaultApplicationConfigurationProvider.cs
Kinde.Api/Models/Configuration/DefaultAuthorizationConfigurationProvider.cs:
destinationFilename: /Kinde.Api/Models/Configuration/DefaultAuthorizationConfigurationProvider.cs
Kinde.Api/Models/Configuration/DefaultConfigurationProvider.cs:
destinationFilename: /Kinde.Api/Models/Configuration/DefaultConfigurationProvider.cs
Kinde.Api/Models/Configuration/IApplicationConfiguration.cs:
destinationFilename: /Kinde.Api/Models/Configuration/IApplicationConfiguration.cs
Kinde.Api/Models/Configuration/IApplicationConfigurationProvider.cs:
destinationFilename: /Kinde.Api/Models/Configuration/IApplicationConfigurationProvider.cs
Kinde.Api/Models/Configuration/IAuthorizationConfiguration.cs:
destinationFilename: /Kinde.Api/Models/Configuration/IAuthorizationConfiguration.cs
Kinde.Api/Models/Configuration/IAuthorizationConfigurationProvider.cs:
destinationFilename: /Kinde.Api/Models/Configuration/IAuthorizationConfigurationProvider.cs
Kinde.Api/Models/Configuration/IConfigurationProvider.cs:
destinationFilename: /Kinde.Api/Models/Configuration/IConfigurationProvider.cs
Kinde.Api/Models/Configuration/IdentityProviderConfiguration.cs:
destinationFilename: /Kinde.Api/Models/Configuration/IdentityProviderConfiguration.cs
Kinde.Api/Models/Configuration/IIdentityProviderConfiguration.cs:
destinationFilename: /Kinde.Api/Models/Configuration/IIdentityProviderConfiguration.cs
Kinde.Api/Models/Configuration/IRedirectAuthorizationConfiguration.cs:
destinationFilename: /Kinde.Api/Models/Configuration/IRedirectAuthorizationConfiguration.cs
Kinde.Api/Models/Configuration/PKCEConfiguration.cs:
destinationFilename: /Kinde.Api/Models/Configuration/PKCEConfiguration.cs
Kinde.Api/Models/Configuration/PKCES256Configuration.cs:
destinationFilename: /Kinde.Api/Models/Configuration/PKCES256Configuration.cs
Kinde.Api/Models/Tokens/OauthToken.cs:
destinationFilename: /Kinde.Api/Models/Tokens/OauthToken.cs
Kinde.Api/Models/User/AuthorizationCodeUserActionResolver.cs:
destinationFilename: /Kinde.Api/Models/User/AuthorizationCodeUserActionResolver.cs
Kinde.Api/Models/User/DefaultUserActionResolver.cs:
destinationFilename: /Kinde.Api/Models/User/DefaultUserActionResolver.cs
Kinde.Api/Models/User/IUserActionResolver.cs:
destinationFilename: /Kinde.Api/Models/User/IUserActionResolver.cs
Kinde.Api/Models/User/KindeSSOUser.cs:
destinationFilename: /Kinde.Api/Models/User/KindeSSOUser.cs
Kinde.Api/Models/User/PKCEUserActionResolver.cs:
destinationFilename: /Kinde.Api/Models/User/PKCEUserActionResolver.cs
Kinde.Api/Models/User/UserActionsCompletedEventArgs.cs:
destinationFilename: /Kinde.Api/Models/User/UserActionsCompletedEventArgs.cs
Kinde.Api/Models/User/UserActionsNeededEventArgs.cs:
destinationFilename: /Kinde.Api/Models/User/UserActionsNeededEventArgs.cs
Kinde.Api/Models/Utils/AuthorizationCodeStore.cs:
destinationFilename: /Kinde.Api/Models/Utils/AuthorizationCodeStore.cs
Kinde.Api/Models/Utils/ItemAddedEventArgs.cs:
destinationFilename: /Kinde.Api/Models/Utils/ItemAddedEventArgs.cs
Kinde.Api.Test/AuthorizationTests.cs:
destinationFilename: /Kinde.Api.Test/AuthorizationTests.cs
Kinde.Api.Test/CodeTests.cs:
destinationFilename: /Kinde.Api.Test/CodeTests.cs
Kinde.Api.Test/Mocks/Flows/MockAuthCodeConfiguration.cs:
destinationFilename: /Kinde.Api.Test/Mocks/Flows/MockAuthCodeConfiguration.cs
Kinde.Api.Test/Mocks/Flows/MockClientConfiguration.cs:
destinationFilename: /Kinde.Api.Test/Mocks/Flows/MockClientConfiguration.cs
Kinde.Api.Test/Mocks/Flows/MockPKCEConfiguration.cs:
destinationFilename: /Kinde.Api.Test/Mocks/Flows/MockPKCEConfiguration.cs
Kinde.Api.Test/Mocks/MockHttpClient.cs:
destinationFilename: /Kinde.Api.Test/Mocks/MockHttpClient.cs
Kinde.Api.Test/Mocks/MockIdentityProviderConfiguration.cs:
destinationFilename: /Kinde.Api.Test/Mocks/MockIdentityProviderConfiguration.cs
Kinde.Api.Test/UserProfileTests.cs:
destinationFilename: /Kinde.Api.Test/UserProfileTests.cs
197 changes: 197 additions & 0 deletions my_custom_templates/Kinde.Api.Test/AuthorizationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
using Kinde.Api.Client;
using Kinde.Api.Models.Configuration;
using Kinde.Api.Models.Tokens;
using Kinde.Api.Test.Mocks;
using Kinde.Api.Test.Mocks.Flows;
using Newtonsoft.Json;
using System.Diagnostics;
using System.Reflection;
using Xunit;

namespace Kinde.Api.Test
{
[Collection("Sequential")]
public class Authentication
{
protected static string Token { get { return JsonConvert.SerializeObject(new OauthToken() { AccessToken = "access token", ExpiresIn = 3600 }); } }
protected static string ExpiredToken { get { return JsonConvert.SerializeObject(new OauthToken() { AccessToken = "expired token", RefreshToken = "refresh token", ExpiresIn = 0 }); } }

[Theory]
[InlineData(System.Net.HttpStatusCode.Forbidden, null, true)]
[InlineData(System.Net.HttpStatusCode.Redirect, null, true)]
[InlineData(System.Net.HttpStatusCode.OK, null, true)]
[InlineData(System.Net.HttpStatusCode.OK, "Token", false)]
public void ClientCredentialsTest(System.Net.HttpStatusCode result, string content, bool throws)
{
//Arrange
var response = new HttpResponseMessage(result);
if (content == "Token")
{
response.Content = new StringContent(Token);
}
var client = new MockHttpClient(response);
var apiClient = new KindeClient(new MockIdentityProviderConfiguration(), client);

IAuthorizationConfiguration authConfig = (IAuthorizationConfiguration)Activator.CreateInstance(typeof(MockClientConfiguration));

//Act
if (throws)
{
Assert.ThrowsAsync<ApplicationException>(async () => { await apiClient.Authorize(authConfig); });
return;
}
var task = apiClient.Authorize(authConfig);
task.Wait();

//Assert
Assert.Equal(Enums.AuthorizationStates.Authorized, apiClient.AuthorizationState);
Assert.NotNull(apiClient.Token);
}

[Theory]
[InlineData(System.Net.HttpStatusCode.Forbidden, null, true)]
[InlineData(System.Net.HttpStatusCode.Redirect, null, false)]
[InlineData(System.Net.HttpStatusCode.OK, null, true)]
public void AuthorizationCodeTest(System.Net.HttpStatusCode result, string content, bool throws)
{
//Arrange
var response = new HttpResponseMessage(result);
if (result == System.Net.HttpStatusCode.Redirect)
{
response.Headers.Location = new Uri("https://test.com/go/here");
}
var client = new MockHttpClient(response);
var apiClient = new KindeClient(new MockIdentityProviderConfiguration(), client);

IAuthorizationConfiguration authConfig = (IAuthorizationConfiguration)Activator.CreateInstance(typeof(MockAuthCodeConfiguration));

//Act
if (throws)
{
Assert.ThrowsAsync<ApplicationException>(async () => { await apiClient.Authorize(authConfig); });
return;
}
var task = apiClient.Authorize(authConfig);
task.Wait();

//Assert
Assert.Equal(Enums.AuthorizationStates.UserActionsNeeded, apiClient.AuthorizationState);
Assert.Null(apiClient.Token);
}

[Theory]
[InlineData(System.Net.HttpStatusCode.Forbidden, null, true)]
[InlineData(System.Net.HttpStatusCode.Redirect, null, false)]
[InlineData(System.Net.HttpStatusCode.OK, null, true)]
public void PKCETest(System.Net.HttpStatusCode result, string content, bool throws)
{
//Arrange
var response = new HttpResponseMessage(result);
if (result == System.Net.HttpStatusCode.Redirect)
{
response.Headers.Location = new Uri("https://test.com/go/here");
}
var client = new MockHttpClient(response);
var apiClient = new KindeClient(new MockIdentityProviderConfiguration(), client);

MockPKCEConfiguration authConfig = (MockPKCEConfiguration)Activator.CreateInstance(typeof(MockPKCEConfiguration));

//Act
if (throws)
{
Assert.ThrowsAsync<ApplicationException>(async () => { await apiClient.Authorize(authConfig); });
return;
}
var task = apiClient.Authorize(authConfig);
task.Wait();

//Assert
Assert.Equal(Enums.AuthorizationStates.UserActionsNeeded, apiClient.AuthorizationState);
Assert.Null(apiClient.Token);
Assert.Throws<KeyNotFoundException>(() => { KindeClient.CodeStore.Get(authConfig.State); });
}

[Theory]
[InlineData(System.Net.HttpStatusCode.OK, typeof(MockClientConfiguration))]
public async Task FetchToken_AuthorizeSuccess_RequestHeaderShouldContainsSdkVersion(System.Net.HttpStatusCode result, Type type)
{
//Arrange
var response = new HttpResponseMessage(result) { Content = new StringContent(Token) };
var client = new MockHttpClient(response);
var apiClient = new KindeClient(new MockIdentityProviderConfiguration(), client);
var authConfig = Activator.CreateInstance(type) as IAuthorizationConfiguration;

//Act
await apiClient.Authorize(authConfig);
var header = client.Request.Content.Headers.FirstOrDefault(x => x.Key == "Kinde-SDK");
var expectedKindeSdkVersion = $".NET/{FileVersionInfo.GetVersionInfo(Assembly.GetAssembly(typeof(KindeClient)).Location).ProductVersion}";

//Assert
Assert.NotNull(header.Key);
Assert.NotNull(header.Value?.FirstOrDefault());
Assert.Equal(header.Value?.FirstOrDefault(), expectedKindeSdkVersion);
}

[Theory]
[InlineData(System.Net.HttpStatusCode.OK, typeof(MockClientConfiguration))]
public async Task GetToken_UnAuthorizedClient_ThrowException(System.Net.HttpStatusCode result, Type type)
{
//Arrange
var response = new HttpResponseMessage(result) { Content = new StringContent(Token) };
var client = new MockHttpClient(response);
var apiClient = new KindeClient(new MockIdentityProviderConfiguration(), client);
var authConfig = Activator.CreateInstance(type) as IAuthorizationConfiguration;

//Act
await apiClient.Authorize(authConfig);
await apiClient.Logout();
var exception = await Assert.ThrowsAsync<ApplicationException>(async () => { await apiClient.GetToken(); });

//Assert
Assert.Equal("Please authorize first", exception.Message);
Assert.Null(apiClient.Token);
}

[Theory]
[InlineData(System.Net.HttpStatusCode.OK, typeof(MockClientConfiguration))]
public async Task GetToken_UnExpiredToken_ReturnAccessToken(System.Net.HttpStatusCode result, Type type)
{
//Arrange
var response = new HttpResponseMessage(result) { Content = new StringContent(Token) };
var client = new MockHttpClient(response);
var apiClient = new KindeClient(new MockIdentityProviderConfiguration(), client);
var authConfig = Activator.CreateInstance(type) as IAuthorizationConfiguration;

//Act
await apiClient.Authorize(authConfig);
var accessToken = await apiClient.GetToken();

//Assert
Assert.False(apiClient.Token.IsExpired);
Assert.Equal("access token", accessToken);
}

[Theory]
[InlineData(System.Net.HttpStatusCode.OK, typeof(MockClientConfiguration))]
public async Task GetToken_ExpiredToken_ReturnNewToken(System.Net.HttpStatusCode result, Type type)
{
//Arrange
var response = new HttpResponseMessage(result) { Content = new StringContent(ExpiredToken) };
var client = new MockHttpClient(response);
var apiClient = new KindeClient(new MockIdentityProviderConfiguration(), client);
var authConfig = Activator.CreateInstance(type) as IAuthorizationConfiguration;

//Act
await apiClient.Authorize(authConfig);
Assert.True(apiClient.Token.IsExpired);
Assert.Equal("expired token", apiClient.Token.AccessToken);

client.Result = new HttpResponseMessage(result) { Content = new StringContent(Token) };
var accessToken = await apiClient.GetToken();

//Assert
Assert.Equal("access token", accessToken);
Assert.False(apiClient.Token.IsExpired);
}
}
}
51 changes: 51 additions & 0 deletions my_custom_templates/Kinde.Api.Test/CodeTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using Kinde.Api.Client;
using Kinde.Api.Models.Configuration;
using Kinde.Api.Models.Tokens;
using Kinde.Api.Test.Mocks;
using Kinde.Api.Test.Mocks.Flows;
using Newtonsoft.Json;
using Xunit;

namespace Kinde.Api.Test
{
[Collection("Sequential")]
public class CodeTests
{
protected static string Token { get { return JsonConvert.SerializeObject(new OauthToken() { AccessToken = Guid.NewGuid().ToString(), ExpiresIn = 3600 }); } }

public KindeClient client;

public MockHttpClient _mockClient;

[Theory]
[InlineData(typeof(MockAuthCodeConfiguration))]
[InlineData(typeof(MockPKCEConfiguration))]
public async Task CodeReceivedTest(Type authType)
{
//Arrange
IRedirectAuthorizationConfiguration authConfig = (IRedirectAuthorizationConfiguration)Activator.CreateInstance(authType);

var config = new MockIdentityProviderConfiguration();
var response = new HttpResponseMessage(System.Net.HttpStatusCode.Redirect);
response.Headers.Location = new Uri("https://test.tes");
_mockClient = new MockHttpClient(response);
client = KindeClientFactory.Instance.GetOrCreate("123", config, _mockClient);

await client.Authorize((IAuthorizationConfiguration)authConfig);

var resp = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
resp.Content = new StringContent(Token);
_mockClient.Result = resp;

//Act
KindeClient.OnCodeReceived("here_is_code", authConfig.State);

//Assert
Assert.Equal(client, KindeClientFactory.Instance.Get("123"));
Assert.Equal(Enums.AuthorizationStates.Authorized, client.AuthorizationState);
Assert.Throws<KeyNotFoundException>(() => { KindeClient.CodeStore.Get("123"); });

KindeClientFactory.Instance.Remove("123");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Kinde.Api.Models.Configuration;

namespace Kinde.Api.Test.Mocks.Flows
{
internal class MockAuthCodeConfiguration : AuthorizationCodeConfiguration
{
public MockAuthCodeConfiguration() : base("123", "123", "123", "1111111111111111", "https://test.test")
{

}
}
}
Loading

0 comments on commit d36143b

Please sign in to comment.