From 2152ba4d14effbec67a07d4e09f0d5b0e245002e Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Fri, 11 Dec 2015 00:16:36 +1000 Subject: [PATCH 1/2] Implemented methods for creating an authorization without having to specify an app clientid/clientsecret. These methods will ONLY work with username/password Basic Auth. Added a helper method to return a GitHub client using basic auth credentials as if you have both password and oauth token environment variables, you get credentials based on the oauth token. --- .../IObservableAuthorizationsClient.cs | 37 ++++++++++ .../Clients/ObservableAuthorizationsClient.cs | 51 +++++++++++++ .../Clients/AuthorizationClientTests.cs | 34 +++++++++ Octokit.Tests.Integration/Helper.cs | 24 +++++++ Octokit/Clients/AuthorizationsClient.cs | 71 +++++++++++++++++++ Octokit/Clients/IAuthorizationsClient.cs | 37 ++++++++++ 6 files changed, 254 insertions(+) diff --git a/Octokit.Reactive/Clients/IObservableAuthorizationsClient.cs b/Octokit.Reactive/Clients/IObservableAuthorizationsClient.cs index a61641d11d..1188606901 100644 --- a/Octokit.Reactive/Clients/IObservableAuthorizationsClient.cs +++ b/Octokit.Reactive/Clients/IObservableAuthorizationsClient.cs @@ -31,6 +31,43 @@ public interface IObservableAuthorizationsClient Justification = "It's fiiiine. It's fine. Trust us.")] IObservable Get(int id); + /// + /// Creates a new personal token for the authenticated user. + /// + /// + /// This method requires authentication. + /// See the API documentation for more information. + /// + /// Describes the new authorization to create + /// + /// Thrown when the current user does not have permission to make this request. + /// + /// + /// Thrown when the current account has two-factor authentication enabled and an authentication code is required. + /// + /// Thrown when a general API error occurs. + /// The created . + IObservable Create(NewAuthorization newAuthorization); + + /// + /// Creates a new personal token for the authenticated user. + /// + /// + /// This method requires authentication. + /// See the API documentation for more information. + /// + /// The two-factor authentication code in response to the current user's previous challenge + /// Describes the new authorization to create + /// + /// Thrown when the current user does not have permission to make this request. + /// + /// + /// Thrown when the current account has two-factor authentication enabled and an authentication code is required. + /// + /// Thrown when a general API error occurs. + /// The created . + IObservable Create(NewAuthorization newAuthorization, string twoFactorAuthenticationCode); + /// /// Creates a new authorization for the specified OAuth application if an authorization for that application /// doesn’t already exist for the user; otherwise, it fails. diff --git a/Octokit.Reactive/Clients/ObservableAuthorizationsClient.cs b/Octokit.Reactive/Clients/ObservableAuthorizationsClient.cs index bbe991c1c1..a16762b15c 100644 --- a/Octokit.Reactive/Clients/ObservableAuthorizationsClient.cs +++ b/Octokit.Reactive/Clients/ObservableAuthorizationsClient.cs @@ -45,6 +45,57 @@ public IObservable Get(int id) return _client.Get(id).ToObservable(); } + /// + /// Creates a new personal token for the authenticated user. + /// + /// + /// This method requires authentication. + /// See the API documentation for more information. + /// + /// Describes the new authorization to create + /// + /// Thrown when the current user does not have permission to make this request. + /// + /// + /// Thrown when the current account has two-factor authentication enabled and an authentication code is required. + /// + /// Thrown when a general API error occurs. + /// The created . + public IObservable Create(NewAuthorization newAuthorization) + { + Ensure.ArgumentNotNull(newAuthorization, "authorization"); + + return _client.Create(newAuthorization).ToObservable(); + + } + + /// + /// Creates a new personal token for the authenticated user. + /// + /// + /// This method requires authentication. + /// See the API documentation for more information. + /// + /// The two-factor authentication code in response to the current user's previous challenge + /// Describes the new authorization to create + /// + /// Thrown when the current user does not have permission to make this request. + /// + /// + /// Thrown when the current account has two-factor authentication enabled and an authentication code is required. + /// + /// Thrown when a general API error occurs. + /// The created . + public IObservable Create( + NewAuthorization newAuthorization, + string twoFactorAuthenticationCode) + { + Ensure.ArgumentNotNull(newAuthorization, "authorization"); + Ensure.ArgumentNotNullOrEmptyString(twoFactorAuthenticationCode, "twoFactorAuthenticationCode"); + + return _client.Create(newAuthorization, twoFactorAuthenticationCode).ToObservable(); + } + /// /// Creates a new authorization for the specified OAuth application if an authorization for that application /// doesn’t already exist for the user; otherwise, it fails. diff --git a/Octokit.Tests.Integration/Clients/AuthorizationClientTests.cs b/Octokit.Tests.Integration/Clients/AuthorizationClientTests.cs index 5a3b741d48..5eb0655ede 100644 --- a/Octokit.Tests.Integration/Clients/AuthorizationClientTests.cs +++ b/Octokit.Tests.Integration/Clients/AuthorizationClientTests.cs @@ -7,6 +7,40 @@ namespace Octokit.Tests.Integration.Clients { public class AuthorizationClientTests { + [IntegrationTest] + public async Task CanCreatePersonalToken() + { + var github = Helper.GetBasicAuthClient(); + var note = Helper.MakeNameWithTimestamp("Testing authentication"); + var newAuthorization = new NewAuthorization( + note, + new string[] { "user" }); + + var created = await github.Authorization.Create(newAuthorization); + + Assert.False(String.IsNullOrWhiteSpace(created.Token)); + Assert.False(String.IsNullOrWhiteSpace(created.TokenLastEight)); + Assert.False(String.IsNullOrWhiteSpace(created.HashedToken)); + + var get = await github.Authorization.Get(created.Id); + + Assert.Equal(created.Id, get.Id); + Assert.Equal(created.Note, get.Note); + } + + [IntegrationTest] + public async Task CannotCreatePersonalTokenWhenUsingOauthTokenCredentials() + { + var github = Helper.GetAuthenticatedClient(); + var note = Helper.MakeNameWithTimestamp("Testing authentication"); + var newAuthorization = new NewAuthorization( + note, + new string[] { "user" }); + + var error = Assert.ThrowsAsync(() => github.Authorization.Create(newAuthorization)); + Assert.True(error.Result.Message.Contains("username and password Basic Auth")); + } + [ApplicationTest] public async Task CanCreateAndGetAuthorizationWithoutFingerPrint() { diff --git a/Octokit.Tests.Integration/Helper.cs b/Octokit.Tests.Integration/Helper.cs index ea86d9dd89..17815e3439 100644 --- a/Octokit.Tests.Integration/Helper.cs +++ b/Octokit.Tests.Integration/Helper.cs @@ -36,6 +36,20 @@ public static class Helper return new Credentials(applicationClientId, applicationClientSecret); }); + static readonly Lazy _basicAuthCredentials = new Lazy(() => + { + var githubUsername = Environment.GetEnvironmentVariable("OCTOKIT_GITHUBUSERNAME"); + UserName = githubUsername; + Organization = Environment.GetEnvironmentVariable("OCTOKIT_GITHUBORGANIZATION"); + + var githubPassword = Environment.GetEnvironmentVariable("OCTOKIT_GITHUBPASSWORD"); + + if (githubUsername == null || githubPassword == null) + return null; + + return new Credentials(githubUsername, githubPassword); + }); + static Helper() { // Force reading of environment variables. @@ -51,6 +65,8 @@ static Helper() public static Credentials ApplicationCredentials { get { return _oauthApplicationCredentials.Value; } } + public static Credentials BasicAuthCredentials { get { return _basicAuthCredentials.Value; } } + public static bool IsUsingToken { get @@ -118,6 +134,14 @@ public static IGitHubClient GetAuthenticatedClient() }; } + public static IGitHubClient GetBasicAuthClient() + { + return new GitHubClient(new ProductHeaderValue("OctokitTests")) + { + Credentials = BasicAuthCredentials + }; + } + public static GitHubClient GetAuthenticatedApplicationClient() { return new GitHubClient(new ProductHeaderValue("OctokitTests")) diff --git a/Octokit/Clients/AuthorizationsClient.cs b/Octokit/Clients/AuthorizationsClient.cs index 128586537d..e18e32a0f4 100644 --- a/Octokit/Clients/AuthorizationsClient.cs +++ b/Octokit/Clients/AuthorizationsClient.cs @@ -56,6 +56,77 @@ public Task Get(int id) return ApiConnection.Get(ApiUrls.Authorizations(id), null); } + + /// + /// Creates a new personal token for the authenticated user. + /// + /// + /// This method requires authentication. + /// See the API documentation for more information. + /// + /// Describes the new authorization to create + /// + /// Thrown when the current user does not have permission to make this request. + /// + /// + /// Thrown when the current account has two-factor authentication enabled and an authentication code is required. + /// + /// Thrown when a general API error occurs. + /// The created . + public Task Create(NewAuthorization newAuthorization) + { + Ensure.ArgumentNotNull(newAuthorization, "authorization"); + + var requestData = new + { + scopes = newAuthorization.Scopes, + note = newAuthorization.Note, + note_url = newAuthorization.NoteUrl, + fingerprint = newAuthorization.Fingerprint + }; + + var endpoint = ApiUrls.Authorizations(); + + return ApiConnection.Post(endpoint, requestData); + + } + + /// + /// Creates a new personal token for the authenticated user. + /// + /// + /// This method requires authentication. + /// See the API documentation for more information. + /// + /// The two-factor authentication code in response to the current user's previous challenge + /// Describes the new authorization to create + /// + /// Thrown when the current user does not have permission to make this request. + /// + /// + /// Thrown when the current account has two-factor authentication enabled and an authentication code is required. + /// + /// Thrown when a general API error occurs. + /// The created . + public Task Create( + NewAuthorization newAuthorization, + string twoFactorAuthenticationCode) + { + Ensure.ArgumentNotNull(newAuthorization, "authorization"); + Ensure.ArgumentNotNullOrEmptyString(twoFactorAuthenticationCode, "twoFactorAuthenticationCode"); + + var requestData = new + { + scopes = newAuthorization.Scopes, + note = newAuthorization.Note, + note_url = newAuthorization.NoteUrl, + fingerprint = newAuthorization.Fingerprint + }; + + var endpoint = ApiUrls.Authorizations(); + return ApiConnection.Post(endpoint, requestData, null, null, twoFactorAuthenticationCode); + } + /// /// Creates a new authorization for the specified OAuth application if an authorization for that application /// doesn’t already exist for the user; otherwise, it fails. diff --git a/Octokit/Clients/IAuthorizationsClient.cs b/Octokit/Clients/IAuthorizationsClient.cs index 198d3802d5..17e9baf26d 100644 --- a/Octokit/Clients/IAuthorizationsClient.cs +++ b/Octokit/Clients/IAuthorizationsClient.cs @@ -47,6 +47,43 @@ public interface IAuthorizationsClient Justification = "It's fiiiine. It's fine. Trust us.")] Task Get(int id); + /// + /// Creates a new personal token for the authenticated user. + /// + /// + /// This method requires authentication. + /// See the API documentation for more information. + /// + /// Describes the new authorization to create + /// + /// Thrown when the current user does not have permission to make this request. + /// + /// + /// Thrown when the current account has two-factor authentication enabled and an authentication code is required. + /// + /// Thrown when a general API error occurs. + /// The created . + Task Create(NewAuthorization newAuthorization); + + /// + /// Creates a new personal token for the authenticated user. + /// + /// + /// This method requires authentication. + /// See the API documentation for more information. + /// + /// The two-factor authentication code in response to the current user's previous challenge + /// Describes the new authorization to create + /// + /// Thrown when the current user does not have permission to make this request. + /// + /// + /// Thrown when the current account has two-factor authentication enabled and an authentication code is required. + /// + /// Thrown when a general API error occurs. + /// The created . + Task Create(NewAuthorization newAuthorization, string twoFactorAuthenticationCode); + /// /// Creates a new authorization for the specified OAuth application if an authorization for that application /// doesn’t already exist for the user; otherwise, it fails. From 596a1d3887911c3b924c1e4bdb5a22a19959538f Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Fri, 11 Dec 2015 07:50:11 +1000 Subject: [PATCH 2/2] :fire: white space :fire: --- Octokit.Reactive/Clients/ObservableAuthorizationsClient.cs | 1 - Octokit/Clients/AuthorizationsClient.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/Octokit.Reactive/Clients/ObservableAuthorizationsClient.cs b/Octokit.Reactive/Clients/ObservableAuthorizationsClient.cs index a16762b15c..514c4da9d7 100644 --- a/Octokit.Reactive/Clients/ObservableAuthorizationsClient.cs +++ b/Octokit.Reactive/Clients/ObservableAuthorizationsClient.cs @@ -66,7 +66,6 @@ public IObservable Create(NewAuthorization newAuthoriz Ensure.ArgumentNotNull(newAuthorization, "authorization"); return _client.Create(newAuthorization).ToObservable(); - } /// diff --git a/Octokit/Clients/AuthorizationsClient.cs b/Octokit/Clients/AuthorizationsClient.cs index e18e32a0f4..4860c5ae5d 100644 --- a/Octokit/Clients/AuthorizationsClient.cs +++ b/Octokit/Clients/AuthorizationsClient.cs @@ -88,7 +88,6 @@ public Task Create(NewAuthorization newAuthorization) var endpoint = ApiUrls.Authorizations(); return ApiConnection.Post(endpoint, requestData); - } ///