Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

style: use file-scope namespace and primary constructor #730

Merged
merged 1 commit into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 83 additions & 85 deletions Client/Impl/Builder/CamundaCloudClientBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,115 +1,113 @@
using System;
using Microsoft.Extensions.Logging;
using Zeebe.Client.Api.Builder;
using Zeebe.Client.Impl.Builder;

namespace Zeebe.Client.Impl.Builder
namespace Zeebe.Client.Impl.Builder;

public class CamundaCloudClientBuilder : ICamundaCloudClientBuilder, ICamundaCloudClientBuilderStep1, ICamundaCloudClientBuilderStep2, ICamundaCloudClientBuilderFinalStep
{
public class CamundaCloudClientBuilder : ICamundaCloudClientBuilder, ICamundaCloudClientBuilderStep1, ICamundaCloudClientBuilderStep2, ICamundaCloudClientBuilderFinalStep
private const string ZeebeAddressEnvVar = "ZEEBE_ADDRESS";
private const string ZeebeClientIdEnvVar = "ZEEBE_CLIENT_ID";
private const string ZeebeClientSecretEnvVar = "ZEEBE_CLIENT_SECRET";
private const string ZeebeAuthServerEnvVar = "ZEEBE_AUTHORIZATION_SERVER_URL";

private readonly CamundaCloudTokenProviderBuilder camundaCloudTokenProviderBuilder;
private string gatewayAddress;
private ILoggerFactory loggerFactory;

private CamundaCloudClientBuilder()
{
private const string ZeebeAddressEnvVar = "ZEEBE_ADDRESS";
private const string ZeebeClientIdEnvVar = "ZEEBE_CLIENT_ID";
private const string ZeebeClientSecretEnvVar = "ZEEBE_CLIENT_SECRET";
private const string ZeebeAuthServerEnvVar = "ZEEBE_AUTHORIZATION_SERVER_URL";
camundaCloudTokenProviderBuilder = CamundaCloudTokenProvider.Builder();
}

private readonly CamundaCloudTokenProviderBuilder camundaCloudTokenProviderBuilder;
private string gatewayAddress;
private ILoggerFactory loggerFactory;
public static ICamundaCloudClientBuilder Builder()
{
return new CamundaCloudClientBuilder();
}

private CamundaCloudClientBuilder()
{
camundaCloudTokenProviderBuilder = CamundaCloudTokenProvider.Builder();
}
public ICamundaCloudClientBuilderStep1 UseClientId(string clientId)
{
camundaCloudTokenProviderBuilder.UseClientId(clientId);
return this;
}

public static ICamundaCloudClientBuilder Builder()
{
return new CamundaCloudClientBuilder();
}
public ICamundaCloudClientBuilderStep2 UseClientSecret(string clientSecret)
{
camundaCloudTokenProviderBuilder.UseClientSecret(clientSecret);
return this;
}

public ICamundaCloudClientBuilderFinalStep UseContactPoint(string contactPoint)
{
_ = contactPoint ?? throw new ArgumentNullException(nameof(contactPoint));

public ICamundaCloudClientBuilderStep1 UseClientId(string clientId)
if (!contactPoint.EndsWith(":443"))
{
camundaCloudTokenProviderBuilder.UseClientId(clientId);
return this;
gatewayAddress = contactPoint + ":443";
camundaCloudTokenProviderBuilder.UseAudience(contactPoint);
}

public ICamundaCloudClientBuilderStep2 UseClientSecret(string clientSecret)
else
{
camundaCloudTokenProviderBuilder.UseClientSecret(clientSecret);
return this;
gatewayAddress = contactPoint;
camundaCloudTokenProviderBuilder.UseAudience(contactPoint.Replace(":443", ""));
}

public ICamundaCloudClientBuilderFinalStep UseContactPoint(string contactPoint)
{
_ = contactPoint ?? throw new ArgumentNullException(nameof(contactPoint));

if (!contactPoint.EndsWith(":443"))
{
gatewayAddress = contactPoint + ":443";
camundaCloudTokenProviderBuilder.UseAudience(contactPoint);
}
else
{
gatewayAddress = contactPoint;
camundaCloudTokenProviderBuilder.UseAudience(contactPoint.Replace(":443", ""));
}
return this;
}

return this;
}
public ICamundaCloudClientBuilderFinalStep UseLoggerFactory(ILoggerFactory loggerFactory)
{
this.loggerFactory = loggerFactory;
camundaCloudTokenProviderBuilder.UseLoggerFactory(this.loggerFactory);
return this;
}

public ICamundaCloudClientBuilderFinalStep UseLoggerFactory(ILoggerFactory loggerFactory)
public ICamundaCloudClientBuilderFinalStep UseAuthServer(string url)
{
if (url is null)
{
this.loggerFactory = loggerFactory;
camundaCloudTokenProviderBuilder.UseLoggerFactory(this.loggerFactory);
// use default
return this;
}

public ICamundaCloudClientBuilderFinalStep UseAuthServer(string url)
{
if (url is null)
{
// use default
return this;
}

camundaCloudTokenProviderBuilder.UseAuthServer(url);
return this;
}
camundaCloudTokenProviderBuilder.UseAuthServer(url);
return this;
}

public ICamundaCloudClientBuilderFinalStep UsePersistedStoragePath(string path)
public ICamundaCloudClientBuilderFinalStep UsePersistedStoragePath(string path)
{
if (path is null)
{
if (path is null)
{
// use default
return this;
}

camundaCloudTokenProviderBuilder.UsePath(path);
// use default
return this;
}

private string GetFromEnv(string key)
{
char[] charsToTrim = { ' ', '\'' };
return Environment.GetEnvironmentVariable(key)?.Trim(charsToTrim);
}
camundaCloudTokenProviderBuilder.UsePath(path);
return this;
}

public ICamundaCloudClientBuilderFinalStep FromEnv()
{
this.UseClientId(GetFromEnv(ZeebeClientIdEnvVar))
.UseClientSecret(GetFromEnv(ZeebeClientSecretEnvVar))
.UseContactPoint(GetFromEnv(ZeebeAddressEnvVar))
.UseAuthServer(GetFromEnv(ZeebeAuthServerEnvVar));
return this;
}
private string GetFromEnv(string key)
{
char[] charsToTrim = [' ', '\''];
return Environment.GetEnvironmentVariable(key)?.Trim(charsToTrim);
}

public IZeebeClient Build()
{
return ZeebeClient.Builder()
.UseLoggerFactory(loggerFactory)
.UseGatewayAddress(gatewayAddress)
.UseTransportEncryption()
.UseAccessTokenSupplier(camundaCloudTokenProviderBuilder.Build())
.Build();
}
public ICamundaCloudClientBuilderFinalStep FromEnv()
{
UseClientId(GetFromEnv(ZeebeClientIdEnvVar))
.UseClientSecret(GetFromEnv(ZeebeClientSecretEnvVar))
.UseContactPoint(GetFromEnv(ZeebeAddressEnvVar))
.UseAuthServer(GetFromEnv(ZeebeAuthServerEnvVar));
return this;
}

public IZeebeClient Build()
{
return ZeebeClient.Builder()
.UseLoggerFactory(loggerFactory)
.UseGatewayAddress(gatewayAddress)
.UseTransportEncryption()
.UseAccessTokenSupplier(camundaCloudTokenProviderBuilder.Build())
.Build();
}
}
175 changes: 87 additions & 88 deletions Client/Impl/Builder/CamundaCloudTokenProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,105 +8,104 @@
using Zeebe.Client.Api.Builder;
using Zeebe.Client.Impl.Misc;

namespace Zeebe.Client.Impl.Builder
namespace Zeebe.Client.Impl.Builder;

public class CamundaCloudTokenProvider : IAccessTokenSupplier, IDisposable
{
public class CamundaCloudTokenProvider : IAccessTokenSupplier, IDisposable
{
private static readonly string ZeebeRootPath =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".zeebe");
private static readonly string ZeebeRootPath =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".zeebe");

private readonly ILogger<CamundaCloudTokenProvider> logger;
private readonly string authServer;
private readonly string clientId;
private readonly string clientSecret;
private readonly string audience;
private HttpClient httpClient;
private HttpMessageHandler httpMessageHandler;
private readonly PersistedAccessTokenCache persistedAccessTokenCache;
private readonly ILogger<CamundaCloudTokenProvider> logger;
private readonly string authServer;
private readonly string clientId;
private readonly string clientSecret;
private readonly string audience;
private HttpClient httpClient;
private HttpMessageHandler httpMessageHandler;
private readonly PersistedAccessTokenCache persistedAccessTokenCache;

internal CamundaCloudTokenProvider(
string authServer,
string clientId,
string clientSecret,
string audience,
string path = null,
ILoggerFactory loggerFactory = null)
{
persistedAccessTokenCache = new PersistedAccessTokenCache(path ?? ZeebeRootPath, FetchAccessToken, loggerFactory?.CreateLogger<PersistedAccessTokenCache>());
this.logger = loggerFactory?.CreateLogger<CamundaCloudTokenProvider>();
this.authServer = authServer;
this.clientId = clientId;
this.clientSecret = clientSecret;
this.audience = audience;
httpClient = new HttpClient(new HttpClientHandler(), disposeHandler: false);
}
internal CamundaCloudTokenProvider(
string authServer,
string clientId,
string clientSecret,
string audience,
string path = null,
ILoggerFactory loggerFactory = null)
{
persistedAccessTokenCache = new PersistedAccessTokenCache(path ?? ZeebeRootPath, FetchAccessToken, loggerFactory?.CreateLogger<PersistedAccessTokenCache>());
logger = loggerFactory?.CreateLogger<CamundaCloudTokenProvider>();
this.authServer = authServer;
this.clientId = clientId;
this.clientSecret = clientSecret;
this.audience = audience;
httpClient = new HttpClient(new HttpClientHandler(), disposeHandler: false);
}

public static CamundaCloudTokenProviderBuilder Builder()
{
return new CamundaCloudTokenProviderBuilder();
}
public static CamundaCloudTokenProviderBuilder Builder()
{
return new CamundaCloudTokenProviderBuilder();
}

internal void SetHttpMessageHandler(HttpMessageHandler handler)
{
httpMessageHandler = handler;
httpClient = new HttpClient(handler);
}
internal void SetHttpMessageHandler(HttpMessageHandler handler)
{
httpMessageHandler = handler;
httpClient = new HttpClient(handler);
}

private async Task<AccessToken> FetchAccessToken()
{
// Requesting the token is similar to this:
// curl -X POST https://login.cloud.ultrawombat.com/oauth/token \
// -H "Content-Type: application/x-www-form-urlencoded" \
// -d "client_id=213131&client_secret=12-23~oU.321&audience=zeebe.ultrawombat.com&grant_type=client_credentials"
//
// alternative is json
// curl --request POST \
// --url https://login.cloud.[ultrawombat.com | camunda.io]/oauth/token \
// --header 'content-type: application/json' \
// --data '{"client_id":"${clientId}","client_secret":"${clientSecret}","audience":"${audience}","grant_type":"client_credentials"}'
private async Task<AccessToken> FetchAccessToken()
{
// Requesting the token is similar to this:
// curl -X POST https://login.cloud.ultrawombat.com/oauth/token \
// -H "Content-Type: application/x-www-form-urlencoded" \
// -d "client_id=213131&client_secret=12-23~oU.321&audience=zeebe.ultrawombat.com&grant_type=client_credentials"
//
// alternative is json
// curl --request POST \
// --url https://login.cloud.[ultrawombat.com | camunda.io]/oauth/token \
// --header 'content-type: application/json' \
// --data '{"client_id":"${clientId}","client_secret":"${clientSecret}","audience":"${audience}","grant_type":"client_credentials"}'

var formContent = BuildRequestAccessTokenContent();
var httpResponseMessage = await httpClient.PostAsync(authServer, formContent);
var formContent = BuildRequestAccessTokenContent();
var httpResponseMessage = await httpClient.PostAsync(authServer, formContent);

// Code expects the following result:
//
// {
// "access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
// "token_type":"bearer",
// "expires_in":3600,
// "refresh_token":"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk",
// "scope":"create"
// }
//
// Defined here https://www.oauth.com/oauth2-servers/access-tokens/access-token-response/
var result = await httpResponseMessage.Content.ReadAsStringAsync();
var token = AccessToken.FromJson(result);
logger?.LogDebug("Received access token for {Audience}", audience);
return token;
}
// Code expects the following result:
//
// {
// "access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
// "token_type":"bearer",
// "expires_in":3600,
// "refresh_token":"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk",
// "scope":"create"
// }
//
// Defined here https://www.oauth.com/oauth2-servers/access-tokens/access-token-response/
var result = await httpResponseMessage.Content.ReadAsStringAsync();
var token = AccessToken.FromJson(result);
logger?.LogDebug("Received access token for {Audience}", audience);
return token;
}

private FormUrlEncodedContent BuildRequestAccessTokenContent()
private FormUrlEncodedContent BuildRequestAccessTokenContent()
{
var formContent = new FormUrlEncodedContent(new[]
{
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("client_id", clientId),
new KeyValuePair<string, string>("client_secret", clientSecret),
new KeyValuePair<string, string>("audience", audience),
new KeyValuePair<string, string>("grant_type", "client_credentials")
});
return formContent;
}
new KeyValuePair<string, string>("client_id", clientId),
new KeyValuePair<string, string>("client_secret", clientSecret),
new KeyValuePair<string, string>("audience", audience),
new KeyValuePair<string, string>("grant_type", "client_credentials")
});
return formContent;
}

public void Dispose()
{
httpClient.Dispose();
httpMessageHandler.Dispose();
}
public void Dispose()
{
httpClient.Dispose();
httpMessageHandler.Dispose();
}

public async Task<string> GetAccessTokenForRequestAsync(string authUri = null,
CancellationToken cancellationToken = default(CancellationToken))
{
return await persistedAccessTokenCache.Get(audience);
}
public async Task<string> GetAccessTokenForRequestAsync(string authUri = null,
CancellationToken cancellationToken = default(CancellationToken))
{
return await persistedAccessTokenCache.Get(audience);
}
}
Loading
Loading