| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | using Google.Apis.Auth.OAuth2.Flows; |
| | using Google.Apis.Auth.OAuth2.Responses; |
| | using Google.Apis.Http; |
| | using Google.Apis.Logging; |
| | using System; |
| | using System.Collections.Generic; |
| | using System.Net; |
| | using System.Net.Http; |
| | using System.Threading; |
| | using System.Threading.Tasks; |
| |
|
| | namespace Google.Apis.Auth.OAuth2 |
| | { |
| | |
| | |
| | |
| | |
| | public class UserCredential : IGoogleCredential, IHttpExecuteInterceptor, IHttpUnsuccessfulResponseHandler |
| | { |
| | |
| | protected static readonly ILogger Logger = ApplicationContext.Logger.ForType<UserCredential>(); |
| |
|
| | |
| | public TokenResponse Token |
| | { |
| | get => _refreshManager.Token; |
| | set => _refreshManager.Token = value; |
| | } |
| |
|
| | |
| | public IAuthorizationCodeFlow Flow { get; } |
| |
|
| | |
| | public string UserId { get; } |
| |
|
| | |
| | public string QuotaProject { get; } |
| |
|
| | |
| | bool IGoogleCredential.HasExplicitScopes => false; |
| |
|
| | |
| | bool IGoogleCredential.SupportsExplicitScopes => false; |
| |
|
| | private readonly TokenRefreshManager _refreshManager; |
| |
|
| | |
| | |
| | |
| | |
| | public UserCredential(IAuthorizationCodeFlow flow, string userId, TokenResponse token) |
| | : this(flow, userId, token, null) |
| | { } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | public UserCredential(IAuthorizationCodeFlow flow, string userId, TokenResponse token, string quotaProjectId) |
| | { |
| | Flow = flow; |
| | UserId = userId; |
| | _refreshManager = new TokenRefreshManager(RefreshTokenAsync, flow.Clock, Logger); |
| | Token = token; |
| | QuotaProject = quotaProjectId; |
| | } |
| |
|
| | |
| | public GoogleCredential ToGoogleCredential() => new GoogleCredential(this); |
| |
|
| | |
| | Task<string> IGoogleCredential.GetUniverseDomainAsync(CancellationToken _) => Task.FromResult(GoogleAuthConsts.DefaultUniverseDomain); |
| |
|
| | |
| | string IGoogleCredential.GetUniverseDomain() => GoogleAuthConsts.DefaultUniverseDomain; |
| |
|
| | |
| | IGoogleCredential IGoogleCredential.WithQuotaProject(string quotaProject) => |
| | new UserCredential(Flow, UserId, Token, quotaProject); |
| |
|
| | |
| | IGoogleCredential IGoogleCredential.MaybeWithScopes(IEnumerable<string> scopes) => this; |
| |
|
| | |
| | IGoogleCredential IGoogleCredential.WithUserForDomainWideDelegation(string user) => |
| | throw new InvalidOperationException($"{nameof(UserCredential)} does not support Domain-Wide Delegation"); |
| |
|
| | |
| | IGoogleCredential IGoogleCredential.WithHttpClientFactory(IHttpClientFactory httpClientFactory) => |
| | Flow is IHttpAuthorizationFlow httpFlow |
| | ? new UserCredential(httpFlow.WithHttpClientFactory(httpClientFactory), UserId, Token, QuotaProject) |
| | : throw new InvalidOperationException($"{Flow.GetType().FullName} does not support an HTTP client factory to be set"); |
| |
|
| | |
| | IGoogleCredential IGoogleCredential.WithUniverseDomain(string universeDomain) => universeDomain switch |
| | { |
| | null => this, |
| | GoogleAuthConsts.DefaultUniverseDomain => this, |
| | _ => throw new InvalidOperationException($"{nameof(UserCredential)} is not supported in universes other than {GoogleAuthConsts.DefaultUniverseDomain}.") |
| | }; |
| |
|
| | #region IHttpExecuteInterceptor |
| |
|
| | |
| | |
| | |
| | |
| | |
| | public async Task InterceptAsync(HttpRequestMessage request, CancellationToken taskCancellationToken) |
| | { |
| | var accessToken = await GetAccessTokenWithHeadersForRequestAsync(request.RequestUri.AbsoluteUri, taskCancellationToken).ConfigureAwait(false); |
| | Flow.AccessMethod.Intercept(request, accessToken.AccessToken); |
| | accessToken.AddHeaders(request); |
| | } |
| |
|
| | #endregion |
| |
|
| | #region IHttpUnsuccessfulResponseHandler |
| |
|
| | |
| | public async Task<bool> HandleResponseAsync(HandleUnsuccessfulResponseArgs args) |
| | { |
| | |
| | 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.Credential = this; |
| |
|
| | #endregion |
| |
|
| | #region ITokenAccess implementation |
| | |
| | public virtual Task<string> GetAccessTokenForRequestAsync(string authUri = null, |
| | CancellationToken cancellationToken = default(CancellationToken)) => |
| | _refreshManager.GetAccessTokenForRequestAsync(cancellationToken); |
| | #endregion |
| |
|
| | #region ITokenAccessWithHeaders implementation |
| | |
| | public async Task<AccessTokenWithHeaders> GetAccessTokenWithHeadersForRequestAsync(string authUri = null, CancellationToken cancellationToken = default) |
| | { |
| | string token = await GetAccessTokenForRequestAsync(authUri, cancellationToken).ConfigureAwait(false); |
| | return new AccessTokenWithHeaders.Builder { QuotaProject = QuotaProject }.Build(token); |
| | } |
| | #endregion |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public async Task<bool> RefreshTokenAsync(CancellationToken taskCancellationToken) |
| | { |
| | if (Token.RefreshToken == null) |
| | { |
| | Logger.Warning("Refresh token is null, can't refresh the token!"); |
| | return false; |
| | } |
| |
|
| | |
| | |
| | var newToken = await Flow.RefreshTokenAsync(UserId, Token.RefreshToken, taskCancellationToken) |
| | .ConfigureAwait(false); |
| |
|
| | Logger.Info("Access token was refreshed successfully"); |
| |
|
| | if (newToken.RefreshToken == null) |
| | { |
| | newToken.RefreshToken = Token.RefreshToken; |
| | } |
| |
|
| | Token = newToken; |
| | return true; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | public async Task<bool> RevokeTokenAsync(CancellationToken taskCancellationToken) |
| | { |
| | if (Token == null) |
| | { |
| | Logger.Warning("Token is already null, no need to revoke it."); |
| | return false; |
| | } |
| |
|
| | await Flow.RevokeTokenAsync(UserId, Token.AccessToken, taskCancellationToken).ConfigureAwait(false); |
| | Logger.Info("Access token was revoked successfully"); |
| | |
| | return true; |
| | } |
| | } |
| | } |
| |
|