Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incremental auth support #624

Merged
merged 11 commits into from Nov 30, 2015
Expand Up @@ -56,7 +56,7 @@ public class GoogleWebAuthorizationBroker
{
ClientSecrets = clientSecrets,
};
return await AuthorizeAsyncCore(initializer, scopes, user, taskCancellationToken, dataStore)
return await AuthorizeAsync(initializer, scopes, user, taskCancellationToken, dataStore)
.ConfigureAwait(false);
}

Expand All @@ -83,7 +83,7 @@ public class GoogleWebAuthorizationBroker
{
ClientSecretsStream = clientSecretsStream,
};
return await AuthorizeAsyncCore(initializer, scopes, user, taskCancellationToken, dataStore)
return await AuthorizeAsync(initializer, scopes, user, taskCancellationToken, dataStore)
.ConfigureAwait(false);
}

Expand Down Expand Up @@ -113,7 +113,7 @@ public class GoogleWebAuthorizationBroker
/// <param name="taskCancellationToken">Cancellation token to cancel an operation.</param>
/// <param name="dataStore">The data store, if not specified a file data store will be used.</param>
/// <returns>User credential.</returns>
private static async Task<UserCredential> AuthorizeAsyncCore(
public static async Task<UserCredential> AuthorizeAsync(
GoogleAuthorizationCodeFlow.Initializer initializer, IEnumerable<string> scopes, string user,
CancellationToken taskCancellationToken, IDataStore dataStore = null)
{
Expand Down
18 changes: 14 additions & 4 deletions Src/GoogleApis.Auth/OAuth2/AuthorizationCodeInstalledApp.cs
Expand Up @@ -62,9 +62,8 @@ public async Task<UserCredential> AuthorizeAsync(string userId, CancellationToke
// Try to load a token from the data store.
var token = await Flow.LoadTokenAsync(userId, taskCancellationToken).ConfigureAwait(false);

// If the stored token is null or it doesn't have a refresh token and the access token is expired we need
// to retrieve a new authorization code.
if (token == null || (token.RefreshToken == null && token.IsExpired(flow.Clock)))
//Check if a new authorization code is needed.

This comment was marked as spam.

if (ShouldRequestAuthorizationCode(token))
{
// Create an authorization code request.
var redirectUri = CodeReceiver.RedirectUri;
Expand All @@ -88,7 +87,18 @@ public async Task<UserCredential> AuthorizeAsync(string userId, CancellationToke
taskCancellationToken).ConfigureAwait(false);
}

return new UserCredential(flow, userId, token);
return new UserCredential(Flow, userId, token);

This comment was marked as spam.

This comment was marked as spam.

}

/// <summary>
/// Determines the need for retrieval of a new authorization code, based on the given token and the
/// authorization code flow.
/// </summary>
public bool ShouldRequestAuthorizationCode(TokenResponse token)
{
// If the flow includes a parameter that requires a new token, if the stored token is null or it doesn't
// have a refresh token and the access token is expired we need to retrieve a new authorization code.
return Flow.ShouldForceTokenRetrieval() || token == null || (token.RefreshToken == null && token.IsExpired(flow.Clock));

This comment was marked as spam.

This comment was marked as spam.

}

#endregion
Expand Down
2 changes: 2 additions & 0 deletions Src/GoogleApis.Auth/OAuth2/Flows/AuthorizationCodeFlow.cs
Expand Up @@ -270,6 +270,8 @@ public virtual Task RevokeTokenAsync(string userId, string token, CancellationTo
throw new NotImplementedException("The OAuth 2.0 protocol does not support token revocation.");
}

public virtual bool ShouldForceTokenRetrieval() { return false; }

This comment was marked as spam.

This comment was marked as spam.


#endregion

/// <summary>Stores the token in the <see cref="DataStore"/>.</summary>
Expand Down
16 changes: 15 additions & 1 deletion Src/GoogleApis.Auth/OAuth2/Flows/GoogleAuthorizationCodeFlow.cs
Expand Up @@ -35,11 +35,15 @@ public class GoogleAuthorizationCodeFlow : AuthorizationCodeFlow
/// <summary>Gets the token revocation URL.</summary>
public string RevokeTokenUrl { get { return revokeTokenUrl; } }

/// <summary>Gets or sets the include granted scopes indicator.</summary>
private bool? includeGrantedScopes { get; set; }

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.


/// <summary>Constructs a new Google authorization code flow.</summary>
public GoogleAuthorizationCodeFlow(Initializer initializer)
: base(initializer)
{
revokeTokenUrl = initializer.RevokeTokenUrl;
includeGrantedScopes = initializer.IncludeGrantedScopes;
}

public override AuthorizationCodeRequestUrl CreateAuthorizationCodeRequest(string redirectUri)

This comment was marked as spam.

Expand All @@ -48,7 +52,9 @@ public override AuthorizationCodeRequestUrl CreateAuthorizationCodeRequest(strin
{
ClientId = ClientSecrets.ClientId,
Scope = string.Join(" ", Scopes),
RedirectUri = redirectUri
RedirectUri = redirectUri,
IncludeGrantedScopes = includeGrantedScopes.HasValue
? includeGrantedScopes.Value.ToString().ToLower() : null
};
}

Expand All @@ -72,12 +78,20 @@ public override AuthorizationCodeRequestUrl CreateAuthorizationCodeRequest(strin
await DeleteTokenAsync(userId, taskCancellationToken);
}

public override bool ShouldForceTokenRetrieval()
{
return includeGrantedScopes.HasValue && includeGrantedScopes.Value;
}

/// <summary>An initializer class for Google authorization code flow. </summary>
public new class Initializer : AuthorizationCodeFlow.Initializer
{
/// <summary>Gets or sets the token revocation URL.</summary>
public string RevokeTokenUrl { get; set; }

/// <summary>Gets or sets the optional indicator for including granted scopes for incremental authorization.</summary>
public bool? IncludeGrantedScopes { get; set; }

/// <summary>
/// Constructs a new initializer. Sets Authorization server URL to
/// <see cref="Google.Apis.Auth.OAuth2.GoogleAuthConsts.AuthorizationUrl"/>, and Token server URL to
Expand Down
5 changes: 5 additions & 0 deletions Src/GoogleApis.Auth/OAuth2/Flows/IAuthorizationCodeFlow.cs
Expand Up @@ -86,5 +86,10 @@ public interface IAuthorizationCodeFlow : IDisposable
/// <param name="taskCancellationToken">Cancellation token to cancel operation.</param>
/// <returns><c>true</c> if the token was revoked successfully.</returns>
Task RevokeTokenAsync(string userId, string token, CancellationToken taskCancellationToken);

/// <summary>
/// Indicates if a new token needs to be retrieved and stored regardless of normal circumstances.
/// </summary>
bool ShouldForceTokenRetrieval();
}
}
Expand Up @@ -33,7 +33,7 @@ public class GoogleAuthorizationCodeRequestUrl : AuthorizationCodeRequestUrl
public string AccessType { get; set; }

/// <summary>
/// Gets pr sets prompt for consent behavior <c>auto</c> to request auto-approval or<c>force</c> to force the
/// Gets or sets prompt for consent behavior <c>auto</c> to request auto-approval or<c>force</c> to force the

This comment was marked as spam.

/// approval UI to show, or <c>null</c> for the default behavior.
/// </summary>
[Google.Apis.Util.RequestParameterAttribute("approval_prompt", Google.Apis.Util.RequestParameterType.Query)]
Expand All @@ -48,6 +48,16 @@ public class GoogleAuthorizationCodeRequestUrl : AuthorizationCodeRequestUrl
[Google.Apis.Util.RequestParameterAttribute("login_hint", Google.Apis.Util.RequestParameterType.Query)]
public string LoginHint { get; set; }

/// <summary>
/// Gets or sets the include granted scopes to determine if this authorization request should use
/// incremental authorization (https://developers.google.com/+/web/api/rest/oauth#incremental-auth).
/// If true and the authorization request is granted, the authorization will include any previous
/// authorizations granted to this user/application combination for other scopes. Default value is

This comment was marked as spam.

This comment was marked as spam.

/// false and will be omitted unless explicitly indicated.
/// </summary>
[Google.Apis.Util.RequestParameterAttribute("include_granted_scopes", Google.Apis.Util.RequestParameterType.Query)]
public string IncludeGrantedScopes { get; set; }

/// <summary>
/// Constructs a new authorization code request with the given authorization server URL. This constructor sets
/// the <see cref="AccessType"/> to <c>offline</c>.
Expand Down
2 changes: 1 addition & 1 deletion Src/GoogleApis.Core/Apis/Http/HttpClientFactory.cs
Expand Up @@ -54,7 +54,7 @@ protected virtual HttpMessageHandler CreateHandler(CreateHttpClientArgs args)
{
var handler = new HttpClientHandler();

// If the framework supports redirect configuration, set it to false, because ConfigurableMessageHnalder
// If the framework supports redirect configuration, set it to false, because ConfigurableMessageHandler

This comment was marked as spam.

// handles redirect.
if (handler.SupportsRedirectConfiguration)
{
Expand Down