Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(59)

Unified Diff: Src/GoogleApis.Auth.Tests/OAuth2/AuthorizationCodeFlowTests.cs

Issue 13972043: Issue 351: Reimplement OAuth2 (Step 3 - Tests, Flows and Credential) (Closed) Base URL: https://google-api-dotnet-client.googlecode.com/hg/
Patch Set: minor Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Src/GoogleApis.Auth.Tests/OAuth2/AuthorizationCodeFlowTests.cs
===================================================================
new file mode 100644
--- /dev/null
b/Src/GoogleApis.Auth.Tests/OAuth2/AuthorizationCodeFlowTests.cs
@@ -0,0 1,425 @@
/*
Copyright 2013 Google Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Moq;
using NUnit.Framework;
using Google.Apis.Auth.OAuth2.Requests;
using Google.Apis.Auth.OAuth2.Responses;
using Google.Apis.Http;
using Google.Apis.Json;
using Google.Apis.Testing;
using Google.Apis.Tests;
using Google.Apis.Util;
using Google.Apis.Util.Store;
namespace Google.Apis.Auth.OAuth2
{
/// <summary>Tests for <see cref="Google.Apis.Auth.OAuth2.AuthorizationCodeFlow"/>.</summary>
[TestFixture]
public class AuthorizationCodeFlowTests
{
private const string TokenUrl = "https://token.com";
private const string AuthorizationCodeUrl = "https://authorization.com";
#region Constructor
[Test]
public void TestConstructor_ArgumentException()
{
// ClientSecrets are missing.
try
{
new AuthorizationCodeFlow(new AuthorizationCodeFlow.Initializer(
"https://authorization_code.com", "https://token.com"));
Assert.Fail();
}
catch (ArgumentException ex)
{
Assert.True(ex.Message.Contains("You MUST set ClientSecret or ClientSecretStream"));
}
}
[Test]
public void TestConstructor_DefaultValues()
{
var flow = CreateFlow();
Assert.NotNull(flow.AccessMethod);
Assert.That(flow.AccessMethod, Is.InstanceOf<BearerToken.AuthorizationHeaderAccessMethod>());
Assert.That(flow.AuthorizationServerUrl, Is.EqualTo("https://authorization.com"));
Assert.NotNull(flow.ClientSecrets);
Assert.That(flow.ClientSecrets.ClientId, Is.EqualTo("id"));
Assert.That(flow.ClientSecrets.ClientSecret, Is.EqualTo("secret"));
Assert.That(flow.Clock, Is.InstanceOf<SystemClock>());
Assert.Null(flow.DataStore);
Assert.NotNull(flow.HttpClient);
Assert.NotNull(flow.Scopes);
Assert.That(flow.TokenServerUrl, Is.EqualTo("https://token.com"));
Assert.That(flow.HttpClient.MessageHandler.UnsuccessfulResponseHandlers.Count(), Is.EqualTo(1));
Assert.That(flow.HttpClient.MessageHandler.UnsuccessfulResponseHandlers.First(),
Is.InstanceOf<BackOffHandler>());
}
#endregion
#region LoadToken
[Test]
public void LoadTokenAsync_NoDataStore()
{
var flow = CreateFlow();
Assert.Null(flow.LoadTokenAsync("user", CancellationToken.None).Result);
}
[Test]
public void LoadTokenAsync_NullResponse()
{
TaskCompletionSource<TokenResponse> tcs = new TaskCompletionSource<TokenResponse>();
tcs.SetResult(null);
Assert.Null(SubtestLoadTokenAsync(tcs));
}
[Test]
public void LoadTokenAsync_TokenResponse()
{
TokenResponse response = new TokenResponse
{
AccessToken = "access"
};
TaskCompletionSource<TokenResponse> tcs = new TaskCompletionSource<TokenResponse>();
tcs.SetResult(response);
var result = SubtestLoadTokenAsync(tcs);
Assert.That(result, Is.EqualTo(response));
}
private TokenResponse SubtestLoadTokenAsync(TaskCompletionSource<TokenResponse> tcs)
{
var mock = new Mock<IDataStore>();
mock.Setup(ds => ds.GetAsync<TokenResponse>("user")).Returns(tcs.Task);
var flow = CreateFlow(dataStore: mock.Object);
var result = flow.LoadTokenAsync("user", CancellationToken.None).Result;
mock.Verify(ds => ds.GetAsync<TokenResponse>("user"));
return result;
}
#endregion
#region CreateAuthorizationCodeRequest
[Test]
public void TestCreateAuthorizationCodeRequest()
{
var request = CreateFlow(scopes: new[] { "a", "b" }).CreateAuthorizationCodeRequest("redirect");
Assert.That(request.AuthorizationServerUrl, Is.EqualTo(new Uri(AuthorizationCodeUrl)));
Assert.That(request.ClientId, Is.EqualTo("id"));
Assert.That(request.RedirectUri, Is.EqualTo("redirect"));
Assert.That(request.ResponseType, Is.EqualTo("code"));
Assert.That(request.Scope, Is.EqualTo("a b"));
Assert.Null(request.State);
}
#endregion
[Test]
public void TestExchangeCodeForTokenAsync()
{
var mock = new Mock<IDataStore>();
var handler = new FetchTokenMessageHandler();
handler.AuthorizationCodeTokenRequest = new AuthorizationCodeTokenRequest()
{
Code = "c0de",
RedirectUri = "redIrect",
Scope = "a"
};
MockHttpClientFactory mockFactory = new MockHttpClientFactory(handler);
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
tcs.SetResult(null);
mock.Setup(ds => ds.StoreAsync("uSer", It.IsAny<TokenResponse>())).Returns(tcs.Task);
var flow = CreateFlow(httpClientFactory: mockFactory, scopes: new[] { "a" }, dataStore: mock.Object);
var response = flow.ExchangeCodeForTokenAsync("uSer", "c0de", "redIrect", CancellationToken.None).Result;
SubtestTokenResponse(response);
mock.Verify(ds => ds.StoreAsync("uSer", It.IsAny<TokenResponse>()));
}
[Test]
public void TestRefreshTokenAsync()
{
var mock = new Mock<IDataStore>();
var handler = new FetchTokenMessageHandler();
handler.RefreshTokenRequest = new RefreshTokenRequest()
{
RefreshToken = "REFRESH",
Scope = "a"
};
MockHttpClientFactory mockFactory = new MockHttpClientFactory(handler);
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
tcs.SetResult(null);
mock.Setup(ds => ds.StoreAsync("uSer", It.IsAny<TokenResponse>())).Returns(tcs.Task);
var flow = CreateFlow(httpClientFactory: mockFactory, scopes: new[] { "a" }, dataStore: mock.Object);
var response = flow.RefreshTokenAsync("uSer", "REFRESH", CancellationToken.None).Result;
SubtestTokenResponse(response);
mock.Verify(ds => ds.StoreAsync("uSer", It.IsAny<TokenResponse>()));
}
#region FetchToken
/// <summary>
/// Fetch token message handler, which expects an authorization code token request or a refresh token request.
/// It verifies all the query parameters are valid and return an error response in case <see cref="Error"/>
/// is <c>true</c>.
/// </summary>
public class FetchTokenMessageHandler : CountableMessageHandler
{
internal AuthorizationCodeTokenRequest AuthorizationCodeTokenRequest { get; set; }
internal RefreshTokenRequest RefreshTokenRequest { get; set; }
internal bool Error { get; set; }
protected override async Task<HttpResponseMessage> SendAsyncCore(HttpRequestMessage request,
CancellationToken taskCancellationToken)
{
Assert.That(request.RequestUri, Is.EqualTo(new Uri(TokenUrl)));
if (AuthorizationCodeTokenRequest != null)
{
// Verify right parameters.
var content = await request.Content.ReadAsStringAsync();
foreach (var parameter in content.Split('&'))
{
var keyValue = parameter.Split('=');
switch (keyValue[0])
{
case "code":
Assert.That(keyValue[1], Is.EqualTo("c0de"));
break;
case "redirect_uri":
Assert.That(keyValue[1], Is.EqualTo("redIrect"));
break;
case "scope":
Assert.That(keyValue[1], Is.EqualTo("a"));
break;
case "grant_type":
Assert.That(keyValue[1], Is.EqualTo("authorization_code"));
break;
case "client_id":
Assert.That(keyValue[1], Is.EqualTo("id"));
break;
case "client_secret":
Assert.That(keyValue[1], Is.EqualTo("secret"));
break;
default:
throw new ArgumentOutOfRangeException("Invalid parameter!");
}
}
}
else
{
// Verify right parameters.
var content = await request.Content.ReadAsStringAsync();
foreach (var parameter in content.Split('&'))
{
var keyValue = parameter.Split('=');
switch (keyValue[0])
{
case "refresh_token":
Assert.That(keyValue[1], Is.EqualTo("REFRESH"));
break;
case "scope":
Assert.That(keyValue[1], Is.EqualTo("a"));
break;
case "grant_type":
Assert.That(keyValue[1], Is.EqualTo("refresh_token"));
break;
case "client_id":
Assert.That(keyValue[1], Is.EqualTo("id"));
break;
case "client_secret":
Assert.That(keyValue[1], Is.EqualTo("secret"));
break;
default:
throw new ArgumentOutOfRangeException("Invalid parameter!");
}
}
}
var response = new HttpResponseMessage();
if (Error)
{
response.StatusCode = System.Net.HttpStatusCode.BadRequest;
var serializedObject = NewtonsoftJsonSerializer.Instance.Serialize(new TokenErrorResponse
{
Error = "error",
ErrorDescription = "desc",
ErrorUri = "uri"
});
response.Content = new StringContent(serializedObject, Encoding.UTF8);
}
else
{
var serializedObject = NewtonsoftJsonSerializer.Instance.Serialize(new TokenResponse
{
AccessToken = "a",
RefreshToken = "r",
ExpiresInSeconds = 100,
Scope = "b",
});
response.Content = new StringContent(serializedObject, Encoding.UTF8);
}
return response;
}
}
[Test]
public void TestFetchTokenAsync_AuthorizationCodeRequest()
{
var handler = new FetchTokenMessageHandler();
handler.AuthorizationCodeTokenRequest = new AuthorizationCodeTokenRequest()
{
Code = "c0de",
RedirectUri = "redIrect",
Scope = "a"
};
MockHttpClientFactory mockFactory = new MockHttpClientFactory(handler);
var flow = CreateFlow(httpClientFactory: mockFactory);
var response = flow.FetchTokenAsync("user", handler.AuthorizationCodeTokenRequest,
CancellationToken.None).Result;
SubtestTokenResponse(response);
}
[Test]
public void TestFetchTokenAsync_RefreshTokenRequest()
{
var handler = new FetchTokenMessageHandler();
handler.RefreshTokenRequest = new RefreshTokenRequest()
{
RefreshToken = "REFRESH",
Scope = "a"
};
MockHttpClientFactory mockFactory = new MockHttpClientFactory(handler);
var flow = CreateFlow(httpClientFactory: mockFactory);
var response = flow.FetchTokenAsync("user", handler.RefreshTokenRequest, CancellationToken.None).Result;
SubtestTokenResponse(response);
}
[Test]
public void TestFetchTokenAsync_AuthorizationCodeRequest_Error()
{
var handler = new FetchTokenMessageHandler();
handler.AuthorizationCodeTokenRequest = new AuthorizationCodeTokenRequest()
{
Code = "c0de",
RedirectUri = "redIrect",
Scope = "a"
};
handler.Error = true;
SubtestFetchTokenAsync_Error(handler);
}
[Test]
public void TestFetchTokenAsync_RefreshTokenRequest_Error()
{
var handler = new FetchTokenMessageHandler();
handler.RefreshTokenRequest = new RefreshTokenRequest()
{
RefreshToken = "REFRESH",
Scope = "a"
};
handler.Error = true;
SubtestFetchTokenAsync_Error(handler);
}
/// <summary>Subtest for receiving an error token response.</summary>
/// <param name="handler">The message handler.</param>
private void SubtestFetchTokenAsync_Error(FetchTokenMessageHandler handler)
{
MockHttpClientFactory mockFactory = new MockHttpClientFactory(handler);
var flow = CreateFlow(httpClientFactory: mockFactory);
try
{
var request =
(TokenRequest)handler.AuthorizationCodeTokenRequest ?? (TokenRequest)handler.RefreshTokenRequest;
var result = flow.FetchTokenAsync("user", request, CancellationToken.None).Result;
Assert.Fail();
}
catch (AggregateException aex)
{
var ex = aex.InnerException as TokenResponseException;
Assert.IsNotNull(ex);
var result = ex.Error;
Assert.That(result.Error, Is.EqualTo("error"));
Assert.That(result.ErrorDescription, Is.EqualTo("desc"));
Assert.That(result.ErrorUri, Is.EqualTo("uri"));
}
}
#endregion
/// <summary>Creates an authorization code flow with the given parameters.</summary>
/// <param name="dataStore">The data store.</param>
/// <param name="scopes">The Scopes.</param>
/// <param name="httpClientFactory">The HTTP client factory. If not set the default will be used.</param>
/// <returns>Authorization code flow</returns>
private AuthorizationCodeFlow CreateFlow(IDataStore dataStore = null, IEnumerable<string> scopes = null,
IHttpClientFactory httpClientFactory = null)
{
var secrets = new ClientSecrets() { ClientId = "id", ClientSecret = "secret" };
var initializer = new AuthorizationCodeFlow.Initializer(AuthorizationCodeUrl, TokenUrl)
{
ClientSecrets = secrets,
HttpClientFactory = httpClientFactory
};
if (dataStore != null)
{
initializer.DataStore = dataStore;
}
if (scopes != null)
{
initializer.Scopes = scopes;
}
return new AuthorizationCodeFlow(initializer);
}
/// <summary>Verifies that the token response contains the expected data.</summary>
/// <param name="response">The token response</param>
private void SubtestTokenResponse(TokenResponse response)
{
Assert.That(response.RefreshToken, Is.EqualTo("r"));
Assert.That(response.ExpiresInSeconds, Is.EqualTo(100));
Assert.That(response.Scope, Is.EqualTo("b"));
}
}
}
« no previous file with comments | « Src/GoogleApis.Auth.Tests/GoogleApis.Auth.Tests.csproj ('k') | Src/GoogleApis.Auth.Tests/OAuth2/BearerTokenTests.cs » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b