Files
octokit.net/Octokit.Tests/Clients/OauthClientTests.cs
Ken Christensen bbcd33d96e Support refreshtokens in OAuth flow (#2749)
* 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>
2023-07-27 15:46:03 -07:00

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());
}
}
}