From 2152ba4d14effbec67a07d4e09f0d5b0e245002e Mon Sep 17 00:00:00 2001 From: Henrik Andersson Date: Fri, 11 Dec 2015 00:16:36 +1000 Subject: [PATCH] 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 a61641d1..11886069 100644 --- a/Octokit.Reactive/Clients/IObservableAuthorizationsClient.cs +++ b/Octokit.Reactive/Clients/IObservableAuthorizationsClient.cs @@ -31,6 +31,43 @@ namespace Octokit.Reactive 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 bbe991c1..a16762b1 100644 --- a/Octokit.Reactive/Clients/ObservableAuthorizationsClient.cs +++ b/Octokit.Reactive/Clients/ObservableAuthorizationsClient.cs @@ -45,6 +45,57 @@ namespace Octokit.Reactive 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 5a3b741d..5eb0655e 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 ea86d9dd..17815e34 100644 --- a/Octokit.Tests.Integration/Helper.cs +++ b/Octokit.Tests.Integration/Helper.cs @@ -36,6 +36,20 @@ namespace Octokit.Tests.Integration 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 @@ namespace Octokit.Tests.Integration 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 @@ namespace Octokit.Tests.Integration }; } + 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 12858653..e18e32a0 100644 --- a/Octokit/Clients/AuthorizationsClient.cs +++ b/Octokit/Clients/AuthorizationsClient.cs @@ -56,6 +56,77 @@ namespace Octokit 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 198d3802..17e9baf2 100644 --- a/Octokit/Clients/IAuthorizationsClient.cs +++ b/Octokit/Clients/IAuthorizationsClient.cs @@ -47,6 +47,43 @@ namespace Octokit 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.