-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #462 from octokit/haacked/oauth
OAuth Web Flow methods
- Loading branch information
Showing
30 changed files
with
533 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
using System; | ||
|
||
namespace Octokit.Reactive | ||
{ | ||
public interface IObservableOauthClient | ||
{ | ||
/// <summary> | ||
/// Gets the URL used in the first step of the web flow. The Web application should redirect to this URL. | ||
/// </summary> | ||
/// <param name="request">Parameters to the Oauth web flow login url</param> | ||
/// <returns></returns> | ||
Uri GetGitHubLoginUrl(OauthLoginRequest request); | ||
|
||
/// <summary> | ||
/// Makes a request to get an access token using the code returned when GitHub.com redirects back from the URL | ||
/// <see cref="GetGitHubLoginUrl">GitHub login url</see> to the application. | ||
/// </summary> | ||
/// <remarks> | ||
/// If the user accepts your request, GitHub redirects back to your site with a temporary code in a code | ||
/// parameter as well as the state you provided in the previous step in a state parameter. If the states don’t | ||
/// match, the request has been created by a third party and the process should be aborted. Exchange this for | ||
/// an access token using this method. | ||
/// </remarks> | ||
/// <param name="request"></param> | ||
/// <returns></returns> | ||
IObservable<OauthToken> CreateAccessToken(OauthTokenRequest request); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
using System; | ||
using System.Reactive.Linq; | ||
using System.Reactive.Threading.Tasks; | ||
|
||
namespace Octokit.Reactive | ||
{ | ||
public class ObservableOauthClient : IObservableOauthClient | ||
{ | ||
readonly IGitHubClient _client; | ||
|
||
public ObservableOauthClient(IGitHubClient client) | ||
{ | ||
Ensure.ArgumentNotNull(client, "client"); | ||
|
||
_client = client; | ||
} | ||
|
||
/// <summary> | ||
/// Gets the URL used in the first step of the web flow. The Web application should redirect to this URL. | ||
/// </summary> | ||
/// <param name="request">Parameters to the Oauth web flow login url</param> | ||
/// <returns></returns> | ||
public Uri GetGitHubLoginUrl(OauthLoginRequest request) | ||
{ | ||
return _client.Oauth.GetGitHubLoginUrl(request); | ||
} | ||
|
||
/// <summary> | ||
/// Makes a request to get an access token using the code returned when GitHub.com redirects back from the URL | ||
/// <see cref="GetGitHubLoginUrl">GitHub login url</see> to the application. | ||
/// </summary> | ||
/// <remarks> | ||
/// If the user accepts your request, GitHub redirects back to your site with a temporary code in a code | ||
/// parameter as well as the state you provided in the previous step in a state parameter. If the states don’t | ||
/// match, the request has been created by a third party and the process should be aborted. Exchange this for | ||
/// an access token using this method. | ||
/// </remarks> | ||
/// <param name="request"></param> | ||
/// <returns></returns> | ||
public IObservable<OauthToken> CreateAccessToken(OauthTokenRequest request) | ||
{ | ||
return _client.Oauth.CreateAccessToken(request).ToObservable(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
using System; | ||
using System.Net.Http; | ||
using System.Threading.Tasks; | ||
using NSubstitute; | ||
using Octokit; | ||
using Octokit.Tests; | ||
using Xunit; | ||
using Xunit.Extensions; | ||
|
||
public class OauthClientTests | ||
{ | ||
public class TheGetGitHubLoginUrlMethod | ||
{ | ||
[Theory] | ||
[InlineData("https://api.github.com", "https://github.com/login/oauth/authorize?client_id=secret")] | ||
[InlineData("https://github.com", "https://github.com/login/oauth/authorize?client_id=secret")] | ||
[InlineData("https://example.com", "https://example.com/login/oauth/authorize?client_id=secret")] | ||
[InlineData("https://api.example.com", "https://api.example.com/login/oauth/authorize?client_id=secret")] | ||
public void ReturnsProperAuthorizeUrl(string baseAddress, string expectedUrl) | ||
{ | ||
var connection = Substitute.For<IConnection>(); | ||
connection.BaseAddress.Returns(new Uri(baseAddress)); | ||
var client = new OauthClient(connection); | ||
|
||
var result = client.GetGitHubLoginUrl(new OauthLoginRequest("secret")); | ||
|
||
Assert.Equal(new Uri(expectedUrl), result); | ||
} | ||
|
||
[Fact] | ||
public void ReturnsUrlWithAllParameters() | ||
{ | ||
var request = new OauthLoginRequest("secret") | ||
{ | ||
RedirectUri = new Uri("https://example.com/foo?foo=bar"), | ||
Scopes = { "foo", "bar" }, | ||
State = "canARY" | ||
}; | ||
var connection = Substitute.For<IConnection>(); | ||
connection.BaseAddress.Returns(new Uri("https://api.github.com")); | ||
var client = new OauthClient(connection); | ||
|
||
var result = client.GetGitHubLoginUrl(request); | ||
|
||
const string expected = "https://github.com/login/oauth/authorize?client_id=secret&redirect_uri=https://example.com/foo?foo=bar&scope=foo,bar&state=canARY"; | ||
Assert.Equal(expected, result.ToString()); | ||
Assert.Equal("?client_id=secret&redirect_uri=https%3A%2F%2Fexample.com%2Ffoo%3Ffoo%3Dbar&scope=foo%2Cbar&state=canARY", result.Query); | ||
} | ||
} | ||
|
||
public class TheCreateAccessTokenMethod | ||
{ | ||
[Fact] | ||
public async Task PostsWithCorrectBodyAndContentType() | ||
{ | ||
var responseToken = new OauthToken(); | ||
var response = Substitute.For<IResponse<OauthToken>>(); | ||
response.BodyAsObject.Returns(responseToken); | ||
var connection = Substitute.For<IConnection>(); | ||
connection.BaseAddress.Returns(new Uri("https://api.github.com/")); | ||
Uri calledUri = null; | ||
FormUrlEncodedContent calledBody = null; | ||
Uri calledHostAddress = null; | ||
connection.PostAsync<OauthToken>( | ||
Arg.Do<Uri>(uri => calledUri = uri), | ||
Arg.Do<object>(body => calledBody = body as FormUrlEncodedContent), | ||
"application/json", | ||
null, | ||
Arg.Do<Uri>(uri => calledHostAddress = uri)) | ||
.Returns(_ => Task.FromResult(response)); | ||
var client = new OauthClient(connection); | ||
|
||
var token = await client.CreateAccessToken(new OauthTokenRequest("secretid", "secretsecret", "code") | ||
{ | ||
RedirectUri = new Uri("https://example.com/foo") | ||
}); | ||
|
||
Assert.Same(responseToken, token); | ||
Assert.Equal("login/oauth/access_token", calledUri.ToString()); | ||
Assert.NotNull(calledBody); | ||
Assert.Equal("https://github.com/", calledHostAddress.ToString()); | ||
Assert.Equal( | ||
"client_id=secretid&client_secret=secretsecret&code=code&redirect_uri=https%3A%2F%2Fexample.com%2Ffoo", | ||
await calledBody.ReadAsStringAsync()); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
|
||
namespace Octokit | ||
{ | ||
/// <summary> | ||
/// Provides methods used in the OAuth web flow. | ||
/// </summary> | ||
public interface IOauthClient | ||
{ | ||
/// <summary> | ||
/// Gets the URL used in the first step of the web flow. The Web application should redirect to this URL. | ||
/// </summary> | ||
/// <param name="request">Parameters to the Oauth web flow login url</param> | ||
/// <returns></returns> | ||
Uri GetGitHubLoginUrl(OauthLoginRequest request); | ||
|
||
/// <summary> | ||
/// Makes a request to get an access token using the code returned when GitHub.com redirects back from the URL | ||
/// <see cref="GetGitHubLoginUrl">GitHub login url</see> to the application. | ||
/// </summary> | ||
/// <remarks> | ||
/// If the user accepts your request, GitHub redirects back to your site with a temporary code in a code | ||
/// parameter as well as the state you provided in the previous step in a state parameter. If the states don’t | ||
/// match, the request has been created by a third party and the process should be aborted. Exchange this for | ||
/// an access token using this method. | ||
/// </remarks> | ||
/// <param name="request"></param> | ||
/// <returns></returns> | ||
Task<OauthToken> CreateAccessToken(OauthTokenRequest request); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
using System; | ||
using System.Net.Http; | ||
using System.Threading.Tasks; | ||
|
||
namespace Octokit | ||
{ | ||
/// <summary> | ||
/// Provides methods used in the OAuth web flow. | ||
/// </summary> | ||
public class OauthClient : IOauthClient | ||
{ | ||
readonly IConnection connection; | ||
readonly Uri hostAddress; | ||
|
||
public OauthClient(IConnection connection) | ||
{ | ||
Ensure.ArgumentNotNull(connection, "connection"); | ||
|
||
this.connection = connection; | ||
var baseAddress = connection.BaseAddress ?? GitHubClient.GitHubDotComUrl; | ||
|
||
// The Oauth login stuff uses https://github.com and not the https://api.github.com URLs. | ||
hostAddress = baseAddress.Host.Equals("api.github.com") | ||
? new Uri("https://github.com") | ||
: baseAddress; | ||
} | ||
|
||
/// <summary> | ||
/// Gets the URL used in the first step of the web flow. The Web application should redirect to this URL. | ||
/// </summary> | ||
/// <param name="request">Parameters to the Oauth web flow login url</param> | ||
/// <returns></returns> | ||
public Uri GetGitHubLoginUrl(OauthLoginRequest request) | ||
{ | ||
Ensure.ArgumentNotNull(request, "request"); | ||
|
||
return new Uri(hostAddress, ApiUrls.OauthAuthorize()) | ||
.ApplyParameters(request.ToParametersDictionary()); | ||
} | ||
|
||
/// <summary> | ||
/// Makes a request to get an access token using the code returned when GitHub.com redirects back from the URL | ||
/// <see cref="GetGitHubLoginUrl">GitHub login url</see> to the application. | ||
/// </summary> | ||
/// <remarks> | ||
/// If the user accepts your request, GitHub redirects back to your site with a temporary code in a code | ||
/// parameter as well as the state you provided in the previous step in a state parameter. If the states don’t | ||
/// match, the request has been created by a third party and the process should be aborted. Exchange this for | ||
/// an access token using this method. | ||
/// </remarks> | ||
/// <param name="request"></param> | ||
/// <returns></returns> | ||
public async Task<OauthToken> CreateAccessToken(OauthTokenRequest request) | ||
{ | ||
Ensure.ArgumentNotNull(request, "request"); | ||
|
||
var endPoint = ApiUrls.OauthAccessToken(); | ||
|
||
var body = new FormUrlEncodedContent(request.ToParametersDictionary()); | ||
|
||
var response = await connection.PostAsync<OauthToken>(endPoint, body, "application/json", null, hostAddress); | ||
return response.BodyAsObject; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.