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

Unified Diff: Src/GoogleApis.Auth/OAuth2/Credential.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/OAuth2/Credential.cs
===================================================================
--- a/Src/GoogleApis.Auth/OAuth2/Credential.cs
b/Src/GoogleApis.Auth/OAuth2/Credential.cs
@@ -15,13 15,125 @@
*/
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Google.Apis.Auth.OAuth2.Responses;
using Google.Apis.Http;
using Google.Apis.Logging;
namespace Google.Apis.Auth.OAuth2
{
- public class Credential
/// <summary>
/// OAuth 2.0 credential for accessing protected resources using an access token, as well as optionally refreshing
/// the access token when it expires using a refresh token.
/// </summary>
public class Credential : IHttpExecuteInterceptor, IHttpUnsuccessfulResponseHandler,
IConfigurableHttpClientInitializer
{
private static readonly ILogger Logger = ApplicationContext.Logger.ForType<Credential>();
private TokenResponse token;
private object lockObject = new object();
public TokenResponse Token
{
get
{
lock (lockObject)
{
return token;
}
}
private set
{
lock (lockObject)
{
token = value;
}
}
}
private readonly IAuthorizationCodeFlow flow;
private readonly string userId;
/// <summary>Constructs a new credential instance.</summary>
/// <param name="flow">Authorization code flow</param>
/// <param name="userId">User identifier</param>
/// <param name="token">An initial token for the user</param>
public Credential(IAuthorizationCodeFlow flow, string userId, TokenResponse token)
{
this.flow = flow;
this.userId = userId;
this.token = token;
}
/// <summary>
/// Default implementation is to try to refresh the access token if there is no access token or if we are 1
/// minute away from expiration. If token server is unavailable, it will try to use the access token even if
/// has expired. If successful, it will call <seealso cref="IAccessMethod.Intercept"/>.
/// </summary>
public async Task InterceptAsync(HttpRequestMessage request, CancellationToken taskCancellationToken)
{
if (Token.IsExpired(flow.Clock))
{
if (!await RefreshTokenAsync(taskCancellationToken).ConfigureAwait(false))
{
throw new InvalidOperationException("The access token is expired but we can't refresh it");
}
}
flow.AccessMethod.Intercept(request, Token.AccessToken);
}
/// <summary>
/// Refreshes the token by calling to <seealso cref="IAuthorizationCodeFlow.RefreshTokenAsync"/>. Then it
/// updates the <see cref="TokenResponse"/> with the new token instance.
/// </summary>
/// <param name="taskCancellationToken">Cancellation token to cancel an operation</param>
/// <returns><c>true</c> if the token was refreshed</returns>
private async Task<bool> RefreshTokenAsync(CancellationToken taskCancellationToken)
{
if (Token.RefreshToken == null)
{
Logger.Warning("Refresh token is null, can't refresh the token!");
return false;
}
// It's possible that two concurrent calls will be made to refresh the token, in that case the last one
// will win.
var newToken = await flow.RefreshTokenAsync(userId, Token.RefreshToken, taskCancellationToken)
.ConfigureAwait(false);
Logger.Info("Access token was refreshed");
if (newToken.RefreshToken == null)
{
newToken.RefreshToken = Token.RefreshToken;
}
Token = newToken;
return true;
}
public async Task<bool> HandleResponseAsync(HandleUnsuccessfulResponseArgs args)
{
// TODO(peleyal): check WWW-Authenticate header
if (args.Response.StatusCode == HttpStatusCode.Unauthorized)
{
return !Object.Equals(Token.AccessToken, flow.AccessMethod.GetAccessToken(args.Request))
|| await RefreshTokenAsync(args.CancellationToken).ConfigureAwait(false);
}
return false;
}
public void Initialize(ConfigurableHttpClient httpClient)
{
httpClient.MessageHandler.ExecuteInterceptors.Add(this);
httpClient.MessageHandler.UnsuccessfulResponseHandlers.Add(this);
}
}
}
« no previous file with comments | « Src/GoogleApis.Auth/OAuth2/BearerToken.cs ('k') | Src/GoogleApis.Auth/OAuth2/GoogleAuthorizationCodeFlow.cs » ('j') | no next file with comments »

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