Index: Src/GoogleApis.Auth/OAuth2/UserCredential.cs |
=================================================================== |
--- a/Src/GoogleApis.Auth/OAuth2/UserCredential.cs |
b/Src/GoogleApis.Auth/OAuth2/UserCredential.cs |
@@ -34,12 34,12 @@ |
public class UserCredential : IHttpExecuteInterceptor, IHttpUnsuccessfulResponseHandler, |
IConfigurableHttpClientInitializer |
{ |
- private static readonly ILogger Logger = ApplicationContext.Logger.ForType<UserCredential>(); |
protected static readonly ILogger Logger = ApplicationContext.Logger.ForType<UserCredential>(); |
private TokenResponse token; |
private object lockObject = new object(); |
- /// <summary>Gets the token response which contains the access token.</summary> |
/// <summary>Gets or sets the token response which contains the access token.</summary> |
public TokenResponse Token |
{ |
get |
@@ -49,7 49,7 @@ |
return token; |
} |
} |
- private set |
set |
{ |
lock (lockObject) |
{ |
@@ -58,6 58,18 @@ |
} |
} |
/// <summary>Gets the authorization code flow.</summary> |
public IAuthorizationCodeFlow Flow |
{ |
get { return flow; } |
} |
/// <summary>Gets the user identity.</summary> |
public string UderId |
{ |
get { return userId; } |
} |
private readonly IAuthorizationCodeFlow flow; |
private readonly string userId; |
@@ -72,6 84,8 @@ |
this.token = token; |
} |
#region IHttpExecuteInterceptor |
/// <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 |
@@ -91,6 105,34 @@ |
flow.AccessMethod.Intercept(request, Token.AccessToken); |
} |
#endregion |
#region IHttpUnsuccessfulResponseHandler |
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; |
} |
#endregion |
#region IConfigurableHttpClientInitializer |
public void Initialize(ConfigurableHttpClient httpClient) |
{ |
httpClient.MessageHandler.ExecuteInterceptors.Add(this); |
httpClient.MessageHandler.UnsuccessfulResponseHandlers.Add(this); |
} |
#endregion |
/// <summary> |
/// Refreshes the token by calling to <seealso cref="IAuthorizationCodeFlow.RefreshTokenAsync"/>. Then it |
/// updates the <see cref="TokenResponse"/> with the new token instance. |
@@ -121,22 163,24 @@ |
return true; |
} |
- public async Task<bool> HandleResponseAsync(HandleUnsuccessfulResponseArgs args) |
/// <summary> |
/// Asynchronously revokes the token by calling |
/// <see cref="Google.Apis.Auth.OAuth2.Flows.IAuthorizationCodeFlow.RevokeTokenAsync"/>. |
/// </summary> |
/// <param name="taskCancellationToken">Cancellation token to cancel an operation.</param> |
/// <returns><c>true</c> if the token was revoked successfully.</returns> |
public async Task<bool> RevokeTokenAsync(CancellationToken taskCancellationToken) |
{ |
- // TODO(peleyal): check WWW-Authenticate header. |
- if (args.Response.StatusCode == HttpStatusCode.Unauthorized) |
if (Token == null) |
{ |
- return !Object.Equals(Token.AccessToken, flow.AccessMethod.GetAccessToken(args.Request)) |
- || await RefreshTokenAsync(args.CancellationToken).ConfigureAwait(false); |
Logger.Warning("Token is already null, no need to revoke it."); |
return false; |
} |
- return false; |
- } |
- |
- public void Initialize(ConfigurableHttpClient httpClient) |
- { |
- httpClient.MessageHandler.ExecuteInterceptors.Add(this); |
- httpClient.MessageHandler.UnsuccessfulResponseHandlers.Add(this); |
await flow.RevokeTokenAsync(userId, Token.AccessToken, taskCancellationToken).ConfigureAwait(false); |
Logger.Info("Access token was revoked successfully"); |
// We don't set the token to null, cause we want that the next request (without reauthorizing) will fail). |
return true; |
} |
} |
} |