From c471516cc115aca64747a679480d70883de87e95 Mon Sep 17 00:00:00 2001 From: Michael Gendotti Date: Wed, 18 Oct 2017 12:28:29 -0700 Subject: [PATCH 1/7] Add support for Bearer tokens. --- PlanGrid.Api/PlanGridHttpHandler.cs | 26 +++++++++++++++++--------- PlanGrid.Api/TokenType.cs | 13 +++++++++++++ 2 files changed, 30 insertions(+), 9 deletions(-) create mode 100644 PlanGrid.Api/TokenType.cs diff --git a/PlanGrid.Api/PlanGridHttpHandler.cs b/PlanGrid.Api/PlanGridHttpHandler.cs index 6df5840..b5cd9a2 100644 --- a/PlanGrid.Api/PlanGridHttpHandler.cs +++ b/PlanGrid.Api/PlanGridHttpHandler.cs @@ -19,13 +19,15 @@ public class PlanGridHttpHandler : HttpClientHandler public const HttpStatusCode RateLimitExceeded = (HttpStatusCode)429; private string authenticationToken; + private TokenType tokenType; private RefitSettings settings; private string version; private int? maxRetries; - public PlanGridHttpHandler(string accessToken, RefitSettings settings, string version, int? maxRetries) + public PlanGridHttpHandler(string accessToken, RefitSettings settings, string version, int? maxRetries, TokenType tokenType = TokenType.Basic) { - authenticationToken = BuildAuthenticationToken(accessToken); + authenticationToken = BuildAuthenticationToken(accessToken, tokenType); + this.tokenType = tokenType; this.settings = settings; this.version = version; this.maxRetries = maxRetries; @@ -42,7 +44,7 @@ protected override async Task SendAsync(HttpRequestMessage request.Content = new StringContent("", Encoding.UTF8, "application/json"); } - request.Headers.Authorization = new AuthenticationHeaderValue("Basic", authenticationToken); + request.Headers.Authorization = new AuthenticationHeaderValue(this.tokenType, authenticationToken); request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse($"application/vnd.plangrid+json; version={version}")); HttpResponseMessage response = await base.SendAsync(request, cancellationToken); @@ -79,12 +81,18 @@ protected override async Task SendAsync(HttpRequestMessage throw new FailedRequestException(HttpStatusCode.ServiceUnavailable, $"Service unavailable after retrying {maxRetries} times."); } - private string BuildAuthenticationToken(string accessToken) + private string BuildAuthenticationToken(string accessToken, TokenType tokenType) { - string unencoded = $"{accessToken}:"; - byte[] authParamBytes = Encoding.ASCII.GetBytes(unencoded); - string encodedAuthParams = Convert.ToBase64String(authParamBytes); - return encodedAuthParams; + if (tokenType == TokenType.Basic) + { + string unencoded = $"{accessToken}:"; + byte[] authParamBytes = Encoding.ASCII.GetBytes(unencoded); + string encodedAuthParams = Convert.ToBase64String(authParamBytes); + return encodedAuthParams; + } else if (tokenType == TokenType.Bearer) + { + return accessToken; + } } } -} \ No newline at end of file +} diff --git a/PlanGrid.Api/TokenType.cs b/PlanGrid.Api/TokenType.cs new file mode 100644 index 0000000..ce0563e --- /dev/null +++ b/PlanGrid.Api/TokenType.cs @@ -0,0 +1,13 @@ +using System.Runtime.Serialization; + +namespace PlanGrid.Api +{ + public enum TokenType + { + [EnumMember(Value = "Basic")] + Basic, + + [EnumMember(Value = "Bearer")] + Bearer + } +} From a800bd5797447384489778193c523492cd6d70b4 Mon Sep 17 00:00:00 2001 From: Michael Gendotti Date: Fri, 20 Oct 2017 12:26:19 -0700 Subject: [PATCH 2/7] Updates from comments --- PlanGrid.Api.Tests/ProjectsTests.cs | 2 +- PlanGrid.Api/AutoGeneratedIPlanGridApi.cs | 4 +++- PlanGrid.Api/PlanGridClient.cs | 10 ++++++---- PlanGrid.Api/PlanGridHttpHandler.cs | 18 +++++++++--------- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/PlanGrid.Api.Tests/ProjectsTests.cs b/PlanGrid.Api.Tests/ProjectsTests.cs index 58e0513..06b93e5 100644 --- a/PlanGrid.Api.Tests/ProjectsTests.cs +++ b/PlanGrid.Api.Tests/ProjectsTests.cs @@ -73,4 +73,4 @@ public async Task CreateProject() } */ } -} \ No newline at end of file +} diff --git a/PlanGrid.Api/AutoGeneratedIPlanGridApi.cs b/PlanGrid.Api/AutoGeneratedIPlanGridApi.cs index 461873f..60b9886 100644 --- a/PlanGrid.Api/AutoGeneratedIPlanGridApi.cs +++ b/PlanGrid.Api/AutoGeneratedIPlanGridApi.cs @@ -16,13 +16,15 @@ public partial class AutoGeneratedIPlanGridApi public RefitSettings Settings { get; private set; } public string Version { get; private set; } public int? MaxRetries { get; private set; } + public TokenType KeyType { get; private set; } - public void Initialize(string apiKey, RefitSettings settings, string version, int? maxRetries) + public void Initialize(string apiKey, RefitSettings settings, string version, int? maxRetries, TokenType keyType) { ApiKey = apiKey; Settings = settings; Version = version; MaxRetries = maxRetries; + KeyType = keyType; foreach (KeyValuePair> methodImpl in methodImpls.ToArray()) { diff --git a/PlanGrid.Api/PlanGridClient.cs b/PlanGrid.Api/PlanGridClient.cs index 7134d61..3a89944 100644 --- a/PlanGrid.Api/PlanGridClient.cs +++ b/PlanGrid.Api/PlanGridClient.cs @@ -22,8 +22,9 @@ public class PlanGridClient /// The version of the API you want to use. /// The maximum time that may elapse when making a call before timing out. /// The maximum number of attempts to make contacting the server in the event of a 503 service unavailable repsonse. This defaults to unlimited retries, with a delay between each attempt that multiplies by two. + /// The type of API key provided by PlanGrid. /// An interface upon which you can invoke the various methods exposed via the Public PlanGrid API. - public static IPlanGridApi Create(string apiKey = null, string baseUrl = null, string version = "1", int timeout = 60, int? maxRetries = null) + public static IPlanGridApi Create(string apiKey = null, string baseUrl = null, string version = "1", int timeout = 60, int? maxRetries = null, TokenType keyType = TokenType.Basic) { apiKey = apiKey ?? Settings.ApiKey ?? Environment.GetEnvironmentVariable("PLANGRIDAPIKEY"); if (apiKey == null) @@ -31,6 +32,7 @@ public static IPlanGridApi Create(string apiKey = null, string baseUrl = null, s throw new ArgumentException("An ApiKey is required. Either pass it in to this method, add it to your App.config file, or set the environment variable \"PLANGRIDAPIKEY\".", nameof(apiKey)); } baseUrl = baseUrl ?? Settings.ApiBaseUrl ?? Environment.GetEnvironmentVariable("PLANGRIDAPIURL") ?? "https://io.plangrid.com"; + keyType = keyType ?? Settings.ApiKeyType ?? Environment.GetEnvironmentVariable("PLANGRIDAPIKEYTYPE"); string url = baseUrl; var settings = new RefitSettings @@ -48,13 +50,13 @@ public static IPlanGridApi Create(string apiKey = null, string baseUrl = null, s } }; var api = (AutoGeneratedIPlanGridApi)RestService.For( - new HttpClient(new PlanGridHttpHandler(apiKey, settings, version, maxRetries)) + new HttpClient(new PlanGridHttpHandler(apiKey, settings, version, maxRetries, keyType)) { BaseAddress = new Uri(url), Timeout = TimeSpan.FromSeconds(timeout) }, settings); - api.Initialize(apiKey, settings, version, maxRetries); + api.Initialize(apiKey, settings, version, maxRetries, keyType); return api; } } -} \ No newline at end of file +} diff --git a/PlanGrid.Api/PlanGridHttpHandler.cs b/PlanGrid.Api/PlanGridHttpHandler.cs index b5cd9a2..e675cb2 100644 --- a/PlanGrid.Api/PlanGridHttpHandler.cs +++ b/PlanGrid.Api/PlanGridHttpHandler.cs @@ -44,7 +44,7 @@ protected override async Task SendAsync(HttpRequestMessage request.Content = new StringContent("", Encoding.UTF8, "application/json"); } - request.Headers.Authorization = new AuthenticationHeaderValue(this.tokenType, authenticationToken); + request.Headers.Authorization = new AuthenticationHeaderValue(this.tokenType.ToString(), authenticationToken); request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse($"application/vnd.plangrid+json; version={version}")); HttpResponseMessage response = await base.SendAsync(request, cancellationToken); @@ -83,15 +83,15 @@ protected override async Task SendAsync(HttpRequestMessage private string BuildAuthenticationToken(string accessToken, TokenType tokenType) { - if (tokenType == TokenType.Basic) + switch (TokenType) { - string unencoded = $"{accessToken}:"; - byte[] authParamBytes = Encoding.ASCII.GetBytes(unencoded); - string encodedAuthParams = Convert.ToBase64String(authParamBytes); - return encodedAuthParams; - } else if (tokenType == TokenType.Bearer) - { - return accessToken; + case TokenType.Basic: + string unencoded = $"{accessToken}:"; + byte[] authParamBytes = Encoding.ASCII.GetBytes(unencoded); + string encodedAuthParams = Convert.ToBase64String(authParamBytes); + return encodedAuthParams; + case TokenType.Bearer: + return accessToken; } } } From 3fef68f9da47f6cf3a85e168a6df04acc2341b90 Mon Sep 17 00:00:00 2001 From: Michael Gendotti Date: Fri, 20 Oct 2017 12:49:43 -0700 Subject: [PATCH 3/7] Let's make it public --- PlanGrid.Api/PlanGridClient.cs | 2 +- PlanGrid.Api/TokenType.cs | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/PlanGrid.Api/PlanGridClient.cs b/PlanGrid.Api/PlanGridClient.cs index 3a89944..1aacbb4 100644 --- a/PlanGrid.Api/PlanGridClient.cs +++ b/PlanGrid.Api/PlanGridClient.cs @@ -24,7 +24,7 @@ public class PlanGridClient /// The maximum number of attempts to make contacting the server in the event of a 503 service unavailable repsonse. This defaults to unlimited retries, with a delay between each attempt that multiplies by two. /// The type of API key provided by PlanGrid. /// An interface upon which you can invoke the various methods exposed via the Public PlanGrid API. - public static IPlanGridApi Create(string apiKey = null, string baseUrl = null, string version = "1", int timeout = 60, int? maxRetries = null, TokenType keyType = TokenType.Basic) + public static IPlanGridApi Create(string apiKey = null, string baseUrl = null, string version = "1", int timeout = 60, int? maxRetries = null, TokenType keyType = null) { apiKey = apiKey ?? Settings.ApiKey ?? Environment.GetEnvironmentVariable("PLANGRIDAPIKEY"); if (apiKey == null) diff --git a/PlanGrid.Api/TokenType.cs b/PlanGrid.Api/TokenType.cs index ce0563e..773ea47 100644 --- a/PlanGrid.Api/TokenType.cs +++ b/PlanGrid.Api/TokenType.cs @@ -1,13 +1,10 @@ using System.Runtime.Serialization; -namespace PlanGrid.Api +public enum TokenType { - public enum TokenType - { - [EnumMember(Value = "Basic")] - Basic, + [EnumMember(Value = "Basic")] + Basic, - [EnumMember(Value = "Bearer")] - Bearer - } + [EnumMember(Value = "Bearer")] + Bearer } From f9fd7f131bbdd626c2adb0169a82e80689dee911 Mon Sep 17 00:00:00 2001 From: Michael Gendotti Date: Fri, 20 Oct 2017 13:16:36 -0700 Subject: [PATCH 4/7] Put it in a file --- PlanGrid.Api/PlanGrid.Api.projitems | 3 ++- PlanGrid.Api/TokenType.cs | 13 ++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/PlanGrid.Api/PlanGrid.Api.projitems b/PlanGrid.Api/PlanGrid.Api.projitems index 0cd3314..eb1f8f2 100644 --- a/PlanGrid.Api/PlanGrid.Api.projitems +++ b/PlanGrid.Api/PlanGrid.Api.projitems @@ -76,5 +76,6 @@ + - \ No newline at end of file + diff --git a/PlanGrid.Api/TokenType.cs b/PlanGrid.Api/TokenType.cs index 773ea47..ce0563e 100644 --- a/PlanGrid.Api/TokenType.cs +++ b/PlanGrid.Api/TokenType.cs @@ -1,10 +1,13 @@ using System.Runtime.Serialization; -public enum TokenType +namespace PlanGrid.Api { - [EnumMember(Value = "Basic")] - Basic, + public enum TokenType + { + [EnumMember(Value = "Basic")] + Basic, - [EnumMember(Value = "Bearer")] - Bearer + [EnumMember(Value = "Bearer")] + Bearer + } } From 0876f1c23e2334b86f3631a8b074fed02d848e95 Mon Sep 17 00:00:00 2001 From: Michael Gendotti Date: Fri, 20 Oct 2017 13:22:51 -0700 Subject: [PATCH 5/7] oops --- PlanGrid.Api/PlanGridClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PlanGrid.Api/PlanGridClient.cs b/PlanGrid.Api/PlanGridClient.cs index 1aacbb4..c05c69c 100644 --- a/PlanGrid.Api/PlanGridClient.cs +++ b/PlanGrid.Api/PlanGridClient.cs @@ -24,7 +24,7 @@ public class PlanGridClient /// The maximum number of attempts to make contacting the server in the event of a 503 service unavailable repsonse. This defaults to unlimited retries, with a delay between each attempt that multiplies by two. /// The type of API key provided by PlanGrid. /// An interface upon which you can invoke the various methods exposed via the Public PlanGrid API. - public static IPlanGridApi Create(string apiKey = null, string baseUrl = null, string version = "1", int timeout = 60, int? maxRetries = null, TokenType keyType = null) + public static IPlanGridApi Create(string apiKey = null, string baseUrl = null, string version = "1", int timeout = 60, int? maxRetries = null, TokenType keyType = TokenType) { apiKey = apiKey ?? Settings.ApiKey ?? Environment.GetEnvironmentVariable("PLANGRIDAPIKEY"); if (apiKey == null) From 86f5e73c2ef5417cf7e9ff81d09c32981eb99403 Mon Sep 17 00:00:00 2001 From: Michael Gendotti Date: Fri, 20 Oct 2017 13:24:35 -0700 Subject: [PATCH 6/7] double oops --- PlanGrid.Api/PlanGridClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PlanGrid.Api/PlanGridClient.cs b/PlanGrid.Api/PlanGridClient.cs index c05c69c..3a89944 100644 --- a/PlanGrid.Api/PlanGridClient.cs +++ b/PlanGrid.Api/PlanGridClient.cs @@ -24,7 +24,7 @@ public class PlanGridClient /// The maximum number of attempts to make contacting the server in the event of a 503 service unavailable repsonse. This defaults to unlimited retries, with a delay between each attempt that multiplies by two. /// The type of API key provided by PlanGrid. /// An interface upon which you can invoke the various methods exposed via the Public PlanGrid API. - public static IPlanGridApi Create(string apiKey = null, string baseUrl = null, string version = "1", int timeout = 60, int? maxRetries = null, TokenType keyType = TokenType) + public static IPlanGridApi Create(string apiKey = null, string baseUrl = null, string version = "1", int timeout = 60, int? maxRetries = null, TokenType keyType = TokenType.Basic) { apiKey = apiKey ?? Settings.ApiKey ?? Environment.GetEnvironmentVariable("PLANGRIDAPIKEY"); if (apiKey == null) From 16f352826bda3d4f080933323acba260dd67fd3e Mon Sep 17 00:00:00 2001 From: Michael Gendotti Date: Fri, 20 Oct 2017 13:59:13 -0700 Subject: [PATCH 7/7] thanks david --- PlanGrid.Api/PlanGridClient.cs | 7 +++++-- PlanGrid.Api/PlanGridHttpHandler.cs | 4 +++- PlanGrid.Api/TokenType.cs | 2 ++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/PlanGrid.Api/PlanGridClient.cs b/PlanGrid.Api/PlanGridClient.cs index 3a89944..01d183c 100644 --- a/PlanGrid.Api/PlanGridClient.cs +++ b/PlanGrid.Api/PlanGridClient.cs @@ -24,7 +24,7 @@ public class PlanGridClient /// The maximum number of attempts to make contacting the server in the event of a 503 service unavailable repsonse. This defaults to unlimited retries, with a delay between each attempt that multiplies by two. /// The type of API key provided by PlanGrid. /// An interface upon which you can invoke the various methods exposed via the Public PlanGrid API. - public static IPlanGridApi Create(string apiKey = null, string baseUrl = null, string version = "1", int timeout = 60, int? maxRetries = null, TokenType keyType = TokenType.Basic) + public static IPlanGridApi Create(string apiKey = null, string baseUrl = null, string version = "1", int timeout = 60, int? maxRetries = null, TokenType keyType = TokenType.Unknown) { apiKey = apiKey ?? Settings.ApiKey ?? Environment.GetEnvironmentVariable("PLANGRIDAPIKEY"); if (apiKey == null) @@ -32,7 +32,10 @@ public static IPlanGridApi Create(string apiKey = null, string baseUrl = null, s throw new ArgumentException("An ApiKey is required. Either pass it in to this method, add it to your App.config file, or set the environment variable \"PLANGRIDAPIKEY\".", nameof(apiKey)); } baseUrl = baseUrl ?? Settings.ApiBaseUrl ?? Environment.GetEnvironmentVariable("PLANGRIDAPIURL") ?? "https://io.plangrid.com"; - keyType = keyType ?? Settings.ApiKeyType ?? Environment.GetEnvironmentVariable("PLANGRIDAPIKEYTYPE"); + if (keyType == TokenType.Unknown) + { + keyType = Settings.ApiKeyType ?? Environment.GetEnvironmentVariable("PLANGRIDAPIKEYTYPE") ?? TokenType.Basic; + } string url = baseUrl; var settings = new RefitSettings diff --git a/PlanGrid.Api/PlanGridHttpHandler.cs b/PlanGrid.Api/PlanGridHttpHandler.cs index e675cb2..4b37cd7 100644 --- a/PlanGrid.Api/PlanGridHttpHandler.cs +++ b/PlanGrid.Api/PlanGridHttpHandler.cs @@ -83,7 +83,7 @@ protected override async Task SendAsync(HttpRequestMessage private string BuildAuthenticationToken(string accessToken, TokenType tokenType) { - switch (TokenType) + switch (tokenType) { case TokenType.Basic: string unencoded = $"{accessToken}:"; @@ -92,6 +92,8 @@ private string BuildAuthenticationToken(string accessToken, TokenType tokenType) return encodedAuthParams; case TokenType.Bearer: return accessToken; + default: + throw new InvalidEnumArgumentException(); } } } diff --git a/PlanGrid.Api/TokenType.cs b/PlanGrid.Api/TokenType.cs index ce0563e..6fd68cf 100644 --- a/PlanGrid.Api/TokenType.cs +++ b/PlanGrid.Api/TokenType.cs @@ -4,6 +4,8 @@ namespace PlanGrid.Api { public enum TokenType { + Unknown, + [EnumMember(Value = "Basic")] Basic,