mirror of
https://github.com/zoriya/octokit.net.git
synced 2025-12-06 07:16:09 +00:00
* Support refreshtokens in OAuth flow Fixes #2731 * Added summary to OauthToken.cs constructors * Mark deprecation of non-refreshToken constructor for OauthToken * Remove unnecessary comment --------- Co-authored-by: Keegan Campbell <me@kfcampbell.com>
282 lines
12 KiB
C#
282 lines
12 KiB
C#
using System;
|
|
using System.Net.Http;
|
|
using System.Threading.Tasks;
|
|
using NSubstitute;
|
|
using Octokit;
|
|
using Octokit.Internal;
|
|
using Xunit;
|
|
|
|
public class OauthClientTests
|
|
{
|
|
public class TheCtor
|
|
{
|
|
[Fact]
|
|
public void EnsuresNonNullArguments()
|
|
{
|
|
Assert.Throws<ArgumentNullException>(() =>
|
|
new OauthClient(null));
|
|
}
|
|
}
|
|
|
|
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/api/v3", "https://example.com/login/oauth/authorize?client_id=secret")]
|
|
[InlineData("https://api.example.com/any/path/really", "https://api.example.com/login/oauth/authorize?client_id=secret")]
|
|
[InlineData(null, "https://github.com/login/oauth/authorize?client_id=secret")]
|
|
public void ReturnsProperAuthorizeUrl(string baseAddress, string expectedUrl)
|
|
{
|
|
var connection = Substitute.For<IConnection>();
|
|
connection.BaseAddress.Returns(baseAddress == null ? null : 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"),
|
|
Login = "johnDOE",
|
|
Scopes = { "foo", "bar" },
|
|
State = "canARY",
|
|
AllowSignup = false
|
|
};
|
|
var connection = Substitute.For<IConnection>();
|
|
connection.BaseAddress.Returns(new Uri("https://api.github.com"));
|
|
var client = new OauthClient(connection);
|
|
|
|
var result = client.GetGitHubLoginUrl(request);
|
|
|
|
Assert.Equal("/login/oauth/authorize", result.AbsolutePath);
|
|
Assert.Equal("?client_id=secret&redirect_uri=https%3A%2F%2Fexample.com%2Ffoo%3Ffoo%3Dbar&login=johnDOE&scope=foo%2Cbar&state=canARY&allow_signup=false", result.Query);
|
|
}
|
|
}
|
|
|
|
public class TheCreateAccessTokenMethod
|
|
{
|
|
[Fact]
|
|
public async Task PostsWithCorrectBodyAndContentType()
|
|
{
|
|
var responseToken = new OauthToken(null, null, null, null, null, null);
|
|
var response = Substitute.For<IApiResponse<OauthToken>>();
|
|
response.Body.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.Post<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());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PostsWithCorrectBodyAndContentTypeForGHE()
|
|
{
|
|
var responseToken = new OauthToken(null, null, null, null, null, null);
|
|
var response = Substitute.For<IApiResponse<OauthToken>>();
|
|
response.Body.Returns(responseToken);
|
|
var connection = Substitute.For<IConnection>();
|
|
connection.BaseAddress.Returns(new Uri("https://example.com/api/v3"));
|
|
Uri calledUri = null;
|
|
FormUrlEncodedContent calledBody = null;
|
|
Uri calledHostAddress = null;
|
|
connection.Post<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://example.com/", calledHostAddress.ToString());
|
|
Assert.Equal(
|
|
"client_id=secretid&client_secret=secretsecret&code=code&redirect_uri=https%3A%2F%2Fexample.com%2Ffoo",
|
|
await calledBody.ReadAsStringAsync());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task InitiateDeviceFlowPostsWithCorrectBodyAndContentType()
|
|
{
|
|
var responseToken = new OauthDeviceFlowResponse("devicecode", "usercode", "uri", 10, 5);
|
|
var response = Substitute.For<IApiResponse<OauthDeviceFlowResponse>>();
|
|
response.Body.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.Post<OauthDeviceFlowResponse>(
|
|
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.InitiateDeviceFlow(new OauthDeviceFlowRequest("clientid"));
|
|
|
|
Assert.Same(responseToken, token);
|
|
Assert.Equal("login/device/code", calledUri.ToString());
|
|
Assert.NotNull(calledBody);
|
|
Assert.Equal("https://github.com/", calledHostAddress.ToString());
|
|
Assert.Equal(
|
|
"client_id=clientid",
|
|
await calledBody.ReadAsStringAsync());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CreateAccessTokenForDeviceFlowPostsWithCorrectBodyAndContentType()
|
|
{
|
|
var responseToken = new OauthToken(null, null, null, null, null, null);
|
|
var response = Substitute.For<IApiResponse<OauthToken>>();
|
|
response.Body.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.Post<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.CreateAccessTokenForDeviceFlow("clientid", new OauthDeviceFlowResponse("devicecode", "usercode", "uri", 10, 5));
|
|
|
|
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=clientid&device_code=devicecode&grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code",
|
|
await calledBody.ReadAsStringAsync());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DeserializesOAuthScopeFormat()
|
|
{
|
|
var responseText =
|
|
"{\"access_token\":\"token-goes-here\",\"token_type\":\"bearer\",\"scope\":\"notifications,user,user:email\"}";
|
|
|
|
var strategy = new SimpleJsonSerializer();
|
|
|
|
var token = strategy.Deserialize<OauthToken>(responseText);
|
|
|
|
Assert.Equal("token-goes-here", token.AccessToken);
|
|
Assert.Equal("bearer", token.TokenType);
|
|
Assert.Contains("notifications", token.Scope);
|
|
Assert.Contains("user:email", token.Scope);
|
|
}
|
|
}
|
|
|
|
public class TheCreateAccessTokenFromRenewalTokenMethod
|
|
{
|
|
[Fact]
|
|
public async Task PostsWithCorrectBodyAndContentType()
|
|
{
|
|
var responseToken = new OauthToken("bearer", "someaccesstoken", 3000, "refreshtoken", 10000, Array.Empty<string>(), null, null, null);
|
|
var response = Substitute.For<IApiResponse<OauthToken>>();
|
|
response.Body.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.Post<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.CreateAccessTokenFromRenewalToken(
|
|
new OauthTokenRenewalRequest("secretid", "secretsecret", "refreshToken"));
|
|
|
|
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&grant_type=refresh_token&refresh_token=refreshToken",
|
|
await calledBody.ReadAsStringAsync());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PostsWithCorrectBodyAndContentTypeForGHE()
|
|
{
|
|
var responseToken = new OauthToken("bearer", "someaccesstoken", 3000, "refreshtoken", 10000, Array.Empty<string>(), null, null, null);
|
|
var response = Substitute.For<IApiResponse<OauthToken>>();
|
|
response.Body.Returns(responseToken);
|
|
|
|
var connection = Substitute.For<IConnection>();
|
|
connection.BaseAddress.Returns(new Uri("https://example.com/api/v3"));
|
|
|
|
Uri calledUri = null;
|
|
FormUrlEncodedContent calledBody = null;
|
|
Uri calledHostAddress = null;
|
|
connection.Post<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.CreateAccessTokenFromRenewalToken(
|
|
new OauthTokenRenewalRequest("secretid", "secretsecret", "refreshToken"));
|
|
|
|
Assert.Same(responseToken, token);
|
|
Assert.Equal("login/oauth/access_token", calledUri.ToString());
|
|
Assert.NotNull(calledBody);
|
|
Assert.Equal("https://example.com/", calledHostAddress.ToString());
|
|
Assert.Equal(
|
|
"client_id=secretid&client_secret=secretsecret&grant_type=refresh_token&refresh_token=refreshToken",
|
|
await calledBody.ReadAsStringAsync());
|
|
}
|
|
}
|
|
}
|