Index: GoogleApisClient.sln
===================================================================
--- a/GoogleApisClient.sln
+++ b/GoogleApisClient.sln
@@ -24,6 +24,8 @@
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GoogleApis.Auth.Tests", "Src\GoogleApis.Auth.Tests\GoogleApis.Auth.Tests.csproj", "{548D6C9B-A97B-4316-91AC-9AAD35202884}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GoogleApis.Auth.Mvc4", "Src\GoogleApis.Auth.Mvc4\GoogleApis.Auth.Mvc4.csproj", "{B700243A-2FAC-454B-8858-47635BFA71C6}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -114,6 +116,16 @@
{548D6C9B-A97B-4316-91AC-9AAD35202884}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{548D6C9B-A97B-4316-91AC-9AAD35202884}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{548D6C9B-A97B-4316-91AC-9AAD35202884}.Release|Win32.ActiveCfg = Release|Any CPU
+ {B700243A-2FAC-454B-8858-47635BFA71C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B700243A-2FAC-454B-8858-47635BFA71C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B700243A-2FAC-454B-8858-47635BFA71C6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {B700243A-2FAC-454B-8858-47635BFA71C6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {B700243A-2FAC-454B-8858-47635BFA71C6}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {B700243A-2FAC-454B-8858-47635BFA71C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B700243A-2FAC-454B-8858-47635BFA71C6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B700243A-2FAC-454B-8858-47635BFA71C6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {B700243A-2FAC-454B-8858-47635BFA71C6}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {B700243A-2FAC-454B-8858-47635BFA71C6}.Release|Win32.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Index: Src/GoogleApis.Auth.DotNet4/GoogleApis.Auth.DotNet4.csproj
===================================================================
--- a/Src/GoogleApis.Auth.DotNet4/GoogleApis.Auth.DotNet4.csproj
+++ b/Src/GoogleApis.Auth.DotNet4/GoogleApis.Auth.DotNet4.csproj
@@ -78,6 +78,7 @@
+
Index: Src/GoogleApis.Auth.DotNet4/OAuth2/GoogleWebAuthenticationBroker.cs
===================================================================
--- a/Src/GoogleApis.Auth.DotNet4/OAuth2/GoogleWebAuthenticationBroker.cs
+++ b/Src/GoogleApis.Auth.DotNet4/OAuth2/GoogleWebAuthenticationBroker.cs
@@ -19,6 +19,7 @@
using System.Threading;
using System.Threading.Tasks;
+using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Util.Store;
namespace Google.Apis.Auth.OAuth2
@@ -97,7 +98,7 @@
var flow = new GoogleAuthorizationCodeFlow(initializer);
// Create authorization code installed app instance and authorize the user.
- return await new AuthorizationCodeInstalledApp(flow, new LocalServerCodeReceiver()).Authorize
+ return await new AuthorizationCodeInstalledApp(flow, new LocalServerCodeReceiver()).AuthorizeAsync
(user, taskCancellationToken);
}
}
Index: Src/GoogleApis.Auth.DotNet4/OAuth2/ServiceAccountCredential.cs
===================================================================
new file mode 100644
--- /dev/null
+++ b/Src/GoogleApis.Auth.DotNet4/OAuth2/ServiceAccountCredential.cs
@@ -0,0 +1,338 @@
+/*
+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.Net;
+using System.Net.Http;
+using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Google.Apis.Auth.OAuth2.Requests;
+using Google.Apis.Auth.OAuth2.Responses;
+using Google.Apis.Http;
+using Google.Apis.Json;
+using Google.Apis.Logging;
+using Google.Apis.Util;
+
+namespace Google.Apis.Auth.OAuth2
+{
+ ///
+ /// Google OAuth 2.0 credential for accessing protected resources using an access token. The Google OAuth 2.0
+ /// Authorization Server supports server-to-server interactions such as those between a web application and Google
+ /// Cloud Storage. The requesting application has to prove its own identity to gain access to an API, and an
+ /// end-user doesn't have to be involved.
+ ///
+ /// Take a look in https://developers.google.com/accounts/docs/OAuth2ServiceAccount for more details.
+ ///
+ ///
+ public class ServiceAccountCredential : IHttpExecuteInterceptor, IHttpUnsuccessfulResponseHandler,
+ IConfigurableHttpClientInitializer
+ {
+ private static readonly ILogger Logger = ApplicationContext.Logger.ForType();
+
+ /// An initializer class for the service account credential.
+ public class Initializer
+ {
+ /// Gets the service account ID (typically an e-mail address).
+ public string Id { get; private set; }
+
+ /// Gets the token server URL.
+ public string TokenServerUrl { get; private set; }
+
+ ///
+ /// Gets or sets the email address of the user the application is trying to impersonate in the service
+ /// account flow or null.
+ ///
+ public string User { get; set; }
+
+ /// Gets the scopes which indicate API access your application is requesting.
+ public IEnumerable Scopes { get; set; }
+
+ ///
+ /// Gets or sets the clock. The clock is used to determine if the token has expired, if so we will try to
+ /// refresh it. The default value is .
+ ///
+ public IClock Clock { get; set; }
+
+ ///
+ /// Gets or sets the key which is used to sign the request, as specified in
+ /// https://developers.google.com/accounts/docs/OAuth2ServiceAccount#computingsignature.
+ ///
+ public RSACryptoServiceProvider Key { get; set; }
+
+ ///
+ /// Gets or sets the method for presenting the access token to the resource server.
+ /// The default value is .
+ ///
+ public IAccessMethod AccessMethod { get; set; }
+
+ ///
+ /// Gets or sets the factory for creating a instance.
+ ///
+ public IHttpClientFactory HttpClientFactory { get; set; }
+
+ ///
+ /// Get or sets the exponential back-off policy. Default value is UnsuccessfulResponse503, which
+ /// means that exponential back-off is used on 503 abnormal HTTP responses.
+ /// If the value is set to None, no exponential back-off policy is used, and it's up to the user to
+ /// configure the in an
+ /// to set a specific back-off
+ /// implementation (using ).
+ ///
+ public ExponentialBackOffPolicy DefaultExponentialBackOffPolicy { get; set; }
+
+ /// Constructs a new initializer using the given id.
+ public Initializer(string id)
+ : this(id, GoogleAuthConsts.TokenUrl) { }
+
+ /// Constructs a new initializer using the given id and the token server URL.
+ public Initializer(string id, string tokenServerUrl)
+ {
+ Id = id;
+ TokenServerUrl = tokenServerUrl;
+
+ AccessMethod = new BearerToken.AuthorizationHeaderAccessMethod();
+ Clock = SystemClock.Default;
+ DefaultExponentialBackOffPolicy = ExponentialBackOffPolicy.UnsuccessfulResponse503;
+ Scopes = new List();
+ }
+
+ /// Extracts a from the given certificate.
+ public Initializer FromCertificate(X509Certificate2 certificate)
+ {
+ // Workaround to correctly cast the private key as a RSACryptoServiceProvider type 24.
+ RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)certificate.PrivateKey;
+ byte[] privateKeyBlob = rsa.ExportCspBlob(true);
+ Key = new RSACryptoServiceProvider();
+ Key.ImportCspBlob(privateKeyBlob);
+ return this;
+ }
+ }
+
+ #region Readonly fields
+
+ private readonly string id;
+ private readonly string tokenServerUrl;
+ private readonly string user;
+ private readonly IEnumerable scopes;
+ private readonly IClock clock;
+ private readonly IAccessMethod accessMethod;
+ private readonly ConfigurableHttpClient httpClient;
+ private readonly RSACryptoServiceProvider key;
+
+ #endregion
+
+ /// Gets the service account ID (typically an e-mail address).
+ public string Id { get { return id; } }
+
+ /// Gets the token server URL.
+ public string TokenServerUrl { get { return tokenServerUrl; } }
+
+ ///
+ /// Gets the email address of the user the application is trying to impersonate in the service account flow
+ /// or null.
+ ///
+ public string User { get { return user; } }
+
+ /// Gets the service account scopes.
+ public IEnumerable Scopes { get { return scopes; } }
+
+ ///
+ /// Gets the clock. The clock is used to determine if the token has expired, if so we will try to refresh it.
+ ///
+ public IClock Clock { get { return clock; } }
+
+ /// Gets the method for presenting the access token to the resource server.
+ public IAccessMethod AccessMethod { get { return accessMethod; } }
+
+ /// Gets the HTTP client used to make authentication requests to the server.
+ public ConfigurableHttpClient HttpClient { get { return httpClient; } }
+
+ ///
+ /// Gets the key which is used to sign the request, as specified in
+ /// https://developers.google.com/accounts/docs/OAuth2ServiceAccount#computingsignature.
+ ///
+ public RSACryptoServiceProvider Key { get { return key; } }
+
+ private TokenResponse token;
+ private object lockObject = new object();
+
+ /// Gets the token response which contains the access token.
+ public TokenResponse Token
+ {
+ get
+ {
+ lock (lockObject)
+ {
+ return token;
+ }
+ }
+ private set
+ {
+ lock (lockObject)
+ {
+ token = value;
+ }
+ }
+ }
+
+ /// Constructs a new service account credential using the given initializer.
+ ///
+ public ServiceAccountCredential(Initializer initializer)
+ {
+ id = initializer.Id.ThrowIfNullOrEmpty("initializer.Id");
+ user = initializer.User;
+ scopes = initializer.Scopes;
+ tokenServerUrl = initializer.TokenServerUrl;
+ accessMethod = initializer.AccessMethod.ThrowIfNull("initializer.AccessMethod");
+ clock = initializer.Clock.ThrowIfNull("initializer.Clock");
+
+ // Set the HTTP client.
+ var httpArgs = new CreateHttpClientArgs();
+
+ // Add exponential back-off initializer if necessary.
+ if (initializer.DefaultExponentialBackOffPolicy != ExponentialBackOffPolicy.None)
+ {
+ httpArgs.Initializers.Add(
+ new ExponentialBackOffInitializer(initializer.DefaultExponentialBackOffPolicy,
+ () => new BackOffHandler(new ExponentialBackOff())));
+ }
+ httpClient = (initializer.HttpClientFactory ?? new HttpClientFactory()).CreateHttpClient(httpArgs);
+ key = initializer.Key.ThrowIfNull("initializer.Key");
+ }
+
+ public void Initialize(ConfigurableHttpClient httpClient)
+ {
+ httpClient.MessageHandler.ExecuteInterceptors.Add(this);
+ httpClient.MessageHandler.UnsuccessfulResponseHandlers.Add(this);
+ }
+
+ public async Task InterceptAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ if (Token == null || Token.IsExpired(Clock))
+ {
+ Logger.Debug("Token has expired, trying to get a new one.");
+ if (!await RequestAccessToken(cancellationToken))
+ {
+ throw new InvalidOperationException("The access token has expired but we can't refresh it");
+ }
+ Logger.Info("New access token was received successfully");
+ }
+
+ AccessMethod.Intercept(request, Token.AccessToken);
+ }
+
+ public async Task HandleResponseAsync(HandleUnsuccessfulResponseArgs args)
+ {
+ // TODO(peleyal): check WWW-Authenticate header
+ if (args.Response.StatusCode == HttpStatusCode.Unauthorized)
+ {
+ return !Object.Equals(Token.AccessToken, AccessMethod.GetAccessToken(args.Request))
+ || await RequestAccessToken(args.CancellationToken).ConfigureAwait(false);
+ }
+
+ return false;
+ }
+
+ ///
+ /// Requests a new token as specified in
+ /// https://developers.google.com/accounts/docs/OAuth2ServiceAccount#makingrequest.
+ ///
+ /// Cancellation token to cancel operation
+ /// true if a new token was received successfully
+ private async Task RequestAccessToken(CancellationToken taskCancellationToken)
+ {
+ string serializedHeader = CreateSerializedHeader();
+ string serializedPayload = GetSerializedPayload();
+
+ StringBuilder assertion = new StringBuilder();
+ assertion.Append(UrlSafeBase64Encode(serializedHeader))
+ .Append(".")
+ .Append(UrlSafeBase64Encode(serializedPayload));
+
+ // Sign the header and the payload.
+ var signature = UrlSafeBase64Encode(key.SignData(Encoding.ASCII.GetBytes(assertion.ToString()), "SHA256"));
+ assertion.Append(".").Append(signature);
+
+ // Create the request.
+ var request = new GoogleAssertionTokenRequest()
+ {
+ Assertion = assertion.ToString()
+ };
+
+ Logger.Debug("Request a new access token. Assertion data is: " + request.Assertion);
+
+ var newToken = await request.ExecuteAsync(httpClient, tokenServerUrl, taskCancellationToken, Clock);
+ Token = newToken;
+ return true;
+ }
+
+ ///
+ /// Creates a serialized header as specified in
+ /// https://developers.google.com/accounts/docs/OAuth2ServiceAccount#formingheader.
+ ///
+ private static string CreateSerializedHeader()
+ {
+ var header = new GoogleJsonWebSignature.Header()
+ {
+ Algorithm = "RS256",
+ Type = "JWT"
+ };
+
+ return NewtonsoftJsonSerializer.Instance.Serialize(header);
+ }
+
+ ///
+ /// Creates a serialized claim set as specified in
+ /// https://developers.google.com/accounts/docs/OAuth2ServiceAccount#formingclaimset
+ ///
+ private string GetSerializedPayload()
+ {
+ var issued = (int)(Clock.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
+ var payload = new GoogleJsonWebSignature.Payload()
+ {
+ Issuer = Id,
+ Audience = TokenServerUrl,
+ IssuedAtTimeSeconds = issued,
+ ExpirationTimeSeconds = issued + 3600,
+ Subject = User,
+ Scope = String.Join(" ", Scopes)
+ };
+
+ return NewtonsoftJsonSerializer.Instance.Serialize(payload);
+ }
+
+ /// Encodes the provided UTF8 string into an URL safe base64 string.
+ /// Value to encode
+ /// The URL safe base64 string
+ private string UrlSafeBase64Encode(string value)
+ {
+ return UrlSafeBase64Encode(Encoding.UTF8.GetBytes(value));
+ }
+
+ /// Encodes the byte array into an URL safe base64 string.
+ /// Byte array to encode
+ /// The URL safe base64 string
+ private string UrlSafeBase64Encode(byte[] bytes)
+ {
+ return Convert.ToBase64String(bytes).Replace("=", String.Empty).Replace('+', '-').Replace('/', '_');
+ }
+ }
+}
Index: Src/GoogleApis.Auth.DotNet4/Properties/AssemblyInfo.cs
===================================================================
--- a/Src/GoogleApis.Auth.DotNet4/Properties/AssemblyInfo.cs
+++ b/Src/GoogleApis.Auth.DotNet4/Properties/AssemblyInfo.cs
@@ -1,4 +1,4 @@
-/*
+/*
Copyright 2013 Google Inc
Licensed under the Apache License, Version 2.0 (the "License");
Index: Src/GoogleApis.Auth.Mvc4/GoogleApis.Auth.Mvc4.csproj
===================================================================
new file mode 100644
--- /dev/null
+++ b/Src/GoogleApis.Auth.Mvc4/GoogleApis.Auth.Mvc4.csproj
@@ -0,0 +1,144 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {B700243A-2FAC-454B-8858-47635BFA71C6}
+ Library
+ Properties
+ Google.Apis.Auth
+ Google.Apis.Auth.Mvc4
+ v4.0
+ 512
+ ..\..\
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ Google.Apis.Auth.Mvc4.xml
+
+
+
+ ..\..\packages\Microsoft.Bcl.Async.1.0.16\lib\net40\Microsoft.Threading.Tasks.dll
+
+
+ ..\..\packages\Microsoft.Bcl.Async.1.0.16\lib\net40\Microsoft.Threading.Tasks.Extensions.dll
+
+
+ ..\..\packages\Microsoft.Bcl.Async.1.0.16\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll
+
+
+ True
+ ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll
+
+
+ False
+ ..\..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll
+
+
+
+
+
+ False
+ ..\..\packages\Microsoft.Net.Http.2.1.10\lib\net40\System.Net.Http.dll
+
+
+ ..\..\packages\Microsoft.Net.Http.2.1.10\lib\net40\System.Net.Http.Extensions.dll
+
+
+ ..\..\packages\Microsoft.AspNet.WebApi.Client.4.0.30506.0\lib\net40\System.Net.Http.Formatting.dll
+
+
+ ..\..\packages\Microsoft.Net.Http.2.1.10\lib\net40\System.Net.Http.Primitives.dll
+
+
+ False
+ ..\..\packages\Microsoft.Net.Http.2.1.10\lib\net40\System.Net.Http.WebRequest.dll
+
+
+ ..\..\packages\Microsoft.Bcl.1.0.19\lib\net40\System.Runtime.dll
+
+
+ ..\..\packages\Microsoft.Bcl.1.0.19\lib\net40\System.Threading.Tasks.dll
+
+
+
+ True
+ ..\..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.Helpers.dll
+
+
+ True
+ ..\..\packages\Microsoft.AspNet.Mvc.4.0.30506.0\lib\net40\System.Web.Mvc.dll
+
+
+ True
+ ..\..\packages\Microsoft.AspNet.Razor.2.0.30506.0\lib\net40\System.Web.Razor.dll
+
+
+ True
+ ..\..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.dll
+
+
+ True
+ ..\..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Deployment.dll
+
+
+ True
+ ..\..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Razor.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {0aaaf32e-2bf0-49c5-bc2d-90874cfb5510}
+ GoogleApis.Auth
+
+
+ {826cf988-eee8-4b75-8f53-b7e851a17baa}
+ GoogleApis
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
Index: Src/GoogleApis.Auth.Mvc4/OAuth2/Mvc/AuthorizationCodeMvcApp.cs
===================================================================
new file mode 100644
--- /dev/null
+++ b/Src/GoogleApis.Auth.Mvc4/OAuth2/Mvc/AuthorizationCodeMvcApp.cs
@@ -0,0 +1,67 @@
+/*
+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.Threading;
+using System.Threading.Tasks;
+using System.Web.Mvc;
+
+using Google.Apis.Auth.OAuth2.Web;
+
+namespace Google.Apis.Auth.OAuth2.Mvc
+{
+ ///
+ /// Thread-safe OAuth 2.0 authorization code flow for a MVC web application that persists end-user credentials.
+ ///
+ public class AuthorizationCodeMvcApp : AuthorizationCodeWebApp
+ {
+ // TODO(peleyal): we should also follow the MVC framework Authorize attribute
+
+ private readonly Controller controller;
+ private readonly FlowMetadata flowData;
+
+ /// Gets the controller which is the owner of this authorization code MVC app instance.
+ public Controller Controller { get { return controller; } }
+
+ /// Gets the object.
+ public FlowMetadata FlowData { get { return flowData; } }
+
+ /// Constructs a new authorization code MVC app using the given controller and flow data.
+ public AuthorizationCodeMvcApp(Controller controller, FlowMetadata flowData)
+ : base(
+ flowData.Flow,
+ new Uri(controller.Request.Url.GetLeftPart(UriPartial.Authority) + flowData.AuthCallback).ToString(),
+ controller.Request.Url.ToString())
+ {
+ this.controller = controller;
+ this.flowData = flowData;
+ }
+
+ ///
+ /// Asynchronously authorizes the installed application to access user's protected data. It gets the user
+ /// identifier by calling to and then calls to
+ /// .
+ ///
+ /// Cancellation token to cancel an operation
+ ///
+ /// Auth result object which contains the user's credential or redirect URI for the authorization server
+ ///
+ public Task AuthorizeAsync(CancellationToken taskCancellationToken)
+ {
+ return base.AuthorizeAsync(FlowData.GetUserId(Controller), taskCancellationToken);
+ }
+ }
+}
Index: Src/GoogleApis.Auth.Mvc4/OAuth2/Mvc/Controllers/AuthCallbackController.cs
===================================================================
new file mode 100644
--- /dev/null
+++ b/Src/GoogleApis.Auth.Mvc4/OAuth2/Mvc/Controllers/AuthCallbackController.cs
@@ -0,0 +1,103 @@
+/*
+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.Threading;
+using System.Threading.Tasks;
+using System.Web.Mvc;
+
+using Google.Apis.Auth.OAuth2;
+using Google.Apis.Auth.OAuth2.Flows;
+using Google.Apis.Auth.OAuth2.Mvc.Filters;
+using Google.Apis.Auth.OAuth2.Responses;
+using Google.Apis.Auth.OAuth2.Web;
+using Google.Apis.Logging;
+
+namespace Google.Apis.Auth.OAuth2.Mvc.Controllers
+{
+ ///
+ /// Auth callback to process the authorization code or error response from the authorization redirect page.
+ ///
+ [AuthorizationCodeActionFilter]
+ public abstract class AuthCallbackController : Controller
+ {
+ protected static readonly ILogger Logger = ApplicationContext.Logger.ForType();
+
+ /// Gets the authorization code flow.
+ protected IAuthorizationCodeFlow Flow { get { return FlowData.Flow; } }
+
+ ///
+ /// Gets the user identifier. Potential logic is to use session variables to retrieve that information.
+ ///
+ protected string UserId { get { return FlowData.GetUserId(this); } }
+
+ #region Abstract and Virtual Members
+
+ /// Gets the flow data which contains
+ protected abstract FlowMetadata FlowData { get; }
+
+ ///
+ /// A callback which gets the error when this controller didn't receive an authorization code. The default
+ /// implementation throws a .
+ ///
+ protected virtual ActionResult OnTokenError(TokenErrorResponse errorResponse)
+ {
+ throw new TokenResponseException(errorResponse);
+ }
+
+ ///
+ /// The authorization callback which receives an authorization code which contains an error or a code.
+ /// If a code is available the method exchange the coed with an access token and redirect back to the original
+ /// page which initialized the auth process (using the state parameter).
+ ///
+ /// The current timeout is set to 10 seconds. You can change the default behavior by setting
+ /// with a different value on your controller.
+ ///
+ ///
+ /// Authorization code response which contains the code or an error.
+ /// Cancellation token to cancel operation.
+ ///
+ /// Redirect action to the state parameter or in case of an error.
+ ///
+ [AsyncTimeout(10000)]
+ public async virtual Task IndexAsync(AuthorizationCodeResponseUrl authorizationCode,
+ CancellationToken taskCancellationToken)
+ {
+ if (string.IsNullOrEmpty(authorizationCode.Code))
+ {
+ var errorResponse = new TokenErrorResponse(authorizationCode);
+ Logger.Info("Received an error. The response is: {0}", errorResponse);
+
+ return OnTokenError(errorResponse);
+ }
+
+ Logger.Debug("Received \"{0}\" code", authorizationCode.Code);
+
+ var returnUrl = Request.Url.ToString();
+ returnUrl = returnUrl.Substring(0, returnUrl.IndexOf("?"));
+
+ var token = await Flow.ExchangeCodeForTokenAsync(UserId, authorizationCode.Code, returnUrl,
+ taskCancellationToken);
+
+ // Extract the right state.
+ var oauthState = await AuthWebUtility.ExtracRedirectFromState(Flow.DataStore, UserId, authorizationCode.State);
+
+ return new RedirectResult(oauthState);
+ }
+
+ #endregion
+ }
+}
Index: Src/GoogleApis.Auth.Mvc4/OAuth2/Mvc/Filters/AuthActionFilter.cs
===================================================================
new file mode 100644
--- /dev/null
+++ b/Src/GoogleApis.Auth.Mvc4/OAuth2/Mvc/Filters/AuthActionFilter.cs
@@ -0,0 +1,55 @@
+/*
+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.Web;
+using System.Web.Mvc;
+
+using Google.Apis.Auth.OAuth2.Responses;
+
+namespace Google.Apis.Auth.OAuth2.Mvc.Filters
+{
+ ///
+ /// An action filter which parses the query parameters into .
+ ///
+ public class AuthorizationCodeActionFilter : ActionFilterAttribute, IActionFilter
+ {
+ ///
+ /// Parses the request into
+ ///
+ public override void OnActionExecuting(ActionExecutingContext actionContext)
+ {
+ (actionContext.ActionParameters["authorizationCode"] as AuthorizationCodeResponseUrl)
+ .ParseRequest(actionContext.RequestContext.HttpContext.Request);
+
+ base.OnActionExecuting(actionContext);
+ }
+ }
+
+ /// Auth extensions methods.
+ public static class AuthExtensions
+ {
+ /// Parses the HTTP request query parameters into the Authorization code response.
+ internal static void ParseRequest(this AuthorizationCodeResponseUrl authorizationCode, HttpRequestBase request)
+ {
+ var queryDic = HttpUtility.ParseQueryString(request.Url.Query);
+ authorizationCode.Code = queryDic["code"];
+ authorizationCode.Error = queryDic["error"];
+ authorizationCode.ErrorDescription = queryDic["error_description"];
+ authorizationCode.ErrorUri = queryDic["error_uri"];
+ authorizationCode.State = queryDic["state"];
+ }
+ }
+}
\ No newline at end of file
Index: Src/GoogleApis.Auth.Mvc4/OAuth2/Mvc/FlowMetadata.cs
===================================================================
new file mode 100644
--- /dev/null
+++ b/Src/GoogleApis.Auth.Mvc4/OAuth2/Mvc/FlowMetadata.cs
@@ -0,0 +1,52 @@
+/*
+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.Web.Mvc;
+
+using Google.Apis.Auth.OAuth2.Flows;
+
+namespace Google.Apis.Auth.OAuth2.Mvc
+{
+ ///
+ /// Flow metadata abstract class which contains the reference to the and
+ /// method to get the user identifier.
+ ///
+ public abstract class FlowMetadata
+ {
+ ///
+ /// Gets the user identifier.
+ ///
+ /// An example implementation may get the user identifier by retrieving the
+ /// (from ).
+ ///
+ ///
+ /// The controller
+ /// User identifier
+ public abstract string GetUserId(Controller controller);
+
+ /// Gets the authorization code flow.
+ public abstract IAuthorizationCodeFlow Flow { get; }
+
+ ///
+ /// Gets the authorization application's call back. That relative URL will handle the authorization code
+ /// response.
+ ///
+ public virtual string AuthCallback
+ {
+ get { return @"/AuthCallback/IndexAsync"; }
+ }
+ }
+}
Index: Src/GoogleApis.Auth.Mvc4/Properties/AssemblyInfo.cs
===================================================================
new file mode 100644
--- /dev/null
+++ b/Src/GoogleApis.Auth.Mvc4/Properties/AssemblyInfo.cs
@@ -0,0 +1,40 @@
+/*
+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.Reflection;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Google.Apis.Auth.Mvc4")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Google Inc")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Copyright © Google Inc 2013")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+[assembly: AssemblyVersion("1.5.0.*")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
Index: Src/GoogleApis.Auth.Mvc4/packages.config
===================================================================
new file mode 100644
--- /dev/null
+++ b/Src/GoogleApis.Auth.Mvc4/packages.config
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
Index: Src/GoogleApis.Auth.Tests/GoogleApis.Auth.Tests.csproj
===================================================================
--- a/Src/GoogleApis.Auth.Tests/GoogleApis.Auth.Tests.csproj
+++ b/Src/GoogleApis.Auth.Tests/GoogleApis.Auth.Tests.csproj
@@ -80,7 +80,7 @@
-
+
Index: Src/GoogleApis.Auth.Tests/OAuth2/Flows/AuthorizationCodeFlowTests.cs
===================================================================
rename from Src/GoogleApis.Auth.Tests/OAuth2/AuthorizationCodeFlowTests.cs
rename to Src/GoogleApis.Auth.Tests/OAuth2/Flows/AuthorizationCodeFlowTests.cs
--- a/Src/GoogleApis.Auth.Tests/OAuth2/AuthorizationCodeFlowTests.cs
+++ b/Src/GoogleApis.Auth.Tests/OAuth2/Flows/AuthorizationCodeFlowTests.cs
@@ -34,7 +34,7 @@
using Google.Apis.Util;
using Google.Apis.Util.Store;
-namespace Google.Apis.Auth.OAuth2
+namespace Google.Apis.Auth.OAuth2.Flows
{
/// Tests for .
[TestFixture]
Index: Src/GoogleApis.Auth/GoogleApis.Auth.csproj
===================================================================
--- a/Src/GoogleApis.Auth/GoogleApis.Auth.csproj
+++ b/Src/GoogleApis.Auth/GoogleApis.Auth.csproj
@@ -38,16 +38,17 @@
-
+
-
+
+
-
+
-
+
-
+
Index: Src/GoogleApis.Auth/OAuth2/AuthorizationCodeInstalledApp.cs
===================================================================
--- a/Src/GoogleApis.Auth/OAuth2/AuthorizationCodeInstalledApp.cs
+++ b/Src/GoogleApis.Auth/OAuth2/AuthorizationCodeInstalledApp.cs
@@ -17,6 +17,7 @@
using System.Threading;
using System.Threading.Tasks;
+using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Responses;
using Google.Apis.Auth.OAuth2.Requests;
using Google.Apis.Logging;
@@ -56,7 +57,7 @@
get { return codeReceiver; }
}
- public async Task Authorize(string userId, CancellationToken taskCancellationToken)
+ public async Task AuthorizeAsync(string userId, CancellationToken taskCancellationToken)
{
// Try to load a token from the data store.
var token = await Flow.LoadTokenAsync(userId, taskCancellationToken).ConfigureAwait(false);
Index: Src/GoogleApis.Auth/OAuth2/Credential.cs
===================================================================
deleted file mode 100644
--- a/Src/GoogleApis.Auth/OAuth2/Credential.cs
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
-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.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
-{
- ///
- /// 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.
- ///
- public class Credential : IHttpExecuteInterceptor, IHttpUnsuccessfulResponseHandler,
- IConfigurableHttpClientInitializer
- {
- private static readonly ILogger Logger = ApplicationContext.Logger.ForType();
-
- 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;
-
- /// Constructs a new credential instance.
- /// Authorization code flow
- /// User identifier
- /// An initial token for the user
- public Credential(IAuthorizationCodeFlow flow, string userId, TokenResponse token)
- {
- this.flow = flow;
- this.userId = userId;
- this.token = token;
- }
-
- ///
- /// 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 .
- ///
- 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);
- }
-
- ///
- /// Refreshes the token by calling to . Then it
- /// updates the with the new token instance.
- ///
- /// Cancellation token to cancel an operation
- /// true if the token was refreshed
- private async Task 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 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);
- }
- }
-}
Index: Src/GoogleApis.Auth/OAuth2/Flows/AuthorizationCodeFlow.cs
===================================================================
rename from Src/GoogleApis.Auth/OAuth2/AuthorizationCodeFlow.cs
rename to Src/GoogleApis.Auth/OAuth2/Flows/AuthorizationCodeFlow.cs
--- a/Src/GoogleApis.Auth/OAuth2/AuthorizationCodeFlow.cs
+++ b/Src/GoogleApis.Auth/OAuth2/Flows/AuthorizationCodeFlow.cs
@@ -29,7 +29,7 @@
using Google.Apis.Util.Store;
using Google.Apis.Testing;
-namespace Google.Apis.Auth.OAuth2
+namespace Google.Apis.Auth.OAuth2.Flows
{
///
/// Thread-safe OAuth 2.0 authorization code flow that manages and persists end-user credentials.
@@ -290,7 +290,8 @@
TokenResponseException tokenException = null;
try
{
- var tokenResponse = await request.Execute(httpClient, TokenServerUrl, taskCancellationToken, Clock);
+ var tokenResponse = await request.ExecuteAsync
+ (httpClient, TokenServerUrl, taskCancellationToken, Clock).ConfigureAwait(false);
return tokenResponse;
}
catch (TokenResponseException ex)
@@ -299,7 +300,7 @@
// the data store.
tokenException = ex;
}
- await DeleteTokenAsync(userId, taskCancellationToken);
+ await DeleteTokenAsync(userId, taskCancellationToken).ConfigureAwait(false);
throw tokenException;
}
Index: Src/GoogleApis.Auth/OAuth2/Flows/GoogleAuthorizationCodeFlow.cs
===================================================================
rename from Src/GoogleApis.Auth/OAuth2/GoogleAuthorizationCodeFlow.cs
rename to Src/GoogleApis.Auth/OAuth2/Flows/GoogleAuthorizationCodeFlow.cs
--- a/Src/GoogleApis.Auth/OAuth2/GoogleAuthorizationCodeFlow.cs
+++ b/Src/GoogleApis.Auth/OAuth2/Flows/GoogleAuthorizationCodeFlow.cs
@@ -18,7 +18,7 @@
using Google.Apis.Auth.OAuth2.Requests;
-namespace Google.Apis.Auth.OAuth2
+namespace Google.Apis.Auth.OAuth2.Flows
{
///
/// Google specific authorization code flow which inherits from .
Index: Src/GoogleApis.Auth/OAuth2/Flows/IAuthorizationCodeFlow.cs
===================================================================
rename from Src/GoogleApis.Auth/OAuth2/IAuthorizationCodeFlow.cs
rename to Src/GoogleApis.Auth/OAuth2/Flows/IAuthorizationCodeFlow.cs
--- a/Src/GoogleApis.Auth/OAuth2/IAuthorizationCodeFlow.cs
+++ b/Src/GoogleApis.Auth/OAuth2/Flows/IAuthorizationCodeFlow.cs
@@ -23,7 +23,7 @@
using Google.Apis.Util;
using Google.Apis.Util.Store;
-namespace Google.Apis.Auth.OAuth2
+namespace Google.Apis.Auth.OAuth2.Flows
{
/// OAuth 2.0 authorization code flow that manages and persists end-user credentials.
public interface IAuthorizationCodeFlow : IDisposable
Index: Src/GoogleApis.Auth/OAuth2/IAuthorizationCodeInstalledApp.cs
===================================================================
--- a/Src/GoogleApis.Auth/OAuth2/IAuthorizationCodeInstalledApp.cs
+++ b/Src/GoogleApis.Auth/OAuth2/IAuthorizationCodeInstalledApp.cs
@@ -17,6 +17,8 @@
using System.Threading;
using System.Threading.Tasks;
+using Google.Apis.Auth.OAuth2.Flows;
+
namespace Google.Apis.Auth.OAuth2
{
///
@@ -34,6 +36,6 @@
/// User identifier
/// Cancellation token to cancel an operation
/// The user's credential
- Task Authorize(string userId, CancellationToken taskCancellationToken);
+ Task AuthorizeAsync(string userId, CancellationToken taskCancellationToken);
}
}
Index: Src/GoogleApis.Auth/OAuth2/Requests/TokenRequestExtenstions.cs
===================================================================
rename from Src/GoogleApis.Auth/OAuth2/TokenRequestExtenstions.cs
rename to Src/GoogleApis.Auth/OAuth2/Requests/TokenRequestExtenstions.cs
--- a/Src/GoogleApis.Auth/OAuth2/TokenRequestExtenstions.cs
+++ b/Src/GoogleApis.Auth/OAuth2/Requests/TokenRequestExtenstions.cs
@@ -18,13 +18,12 @@
using System.Threading;
using System.Threading.Tasks;
-using Google.Apis.Auth.OAuth2.Requests;
using Google.Apis.Auth.OAuth2.Responses;
using Google.Apis.Json;
using Google.Apis.Requests.Parameters;
using Google.Apis.Util;
-namespace Google.Apis.Auth.OAuth2
+namespace Google.Apis.Auth.OAuth2.Requests
{
///
/// Extension methods to .
@@ -42,7 +41,7 @@
/// Cancellation token to cancel operation.
/// The clock which is used to set the property.
/// Token response with the new access token.
- public static async Task Execute(this TokenRequest request, HttpClient httpClient,
+ public static async Task ExecuteAsync(this TokenRequest request, HttpClient httpClient,
string tokenServerUrl, CancellationToken taskCancellationToken, IClock clock)
{
var httpRequest = new HttpRequestMessage(HttpMethod.Post, tokenServerUrl);
Index: Src/GoogleApis.Auth/OAuth2/UserCredential.cs
===================================================================
--- a/Src/GoogleApis.Auth/OAuth2/UserCredential.cs
+++ b/Src/GoogleApis.Auth/OAuth2/UserCredential.cs
@@ -20,6 +20,7 @@
using System.Threading;
using System.Threading.Tasks;
+using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Responses;
using Google.Apis.Http;
using Google.Apis.Logging;
Index: Src/GoogleApis.Auth/OAuth2/Web/AuthWebUtility.cs
===================================================================
new file mode 100644
--- /dev/null
+++ b/Src/GoogleApis.Auth/OAuth2/Web/AuthWebUtility.cs
@@ -0,0 +1,62 @@
+/*
+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.Threading.Tasks;
+
+using Google.Apis.Auth.OAuth2.Responses;
+using Google.Apis.Util.Store;
+
+namespace Google.Apis.Auth.OAuth2.Web
+{
+ /// Auth Utility methods for web development.
+ public class AuthWebUtility
+ {
+ /// Extracts the redirect URI from the state OAuth2 parameter.
+ ///
+ /// If the data store is not null, this method verifies that the state parameter which was returned
+ /// from the authorization server is the same as the one we set before redirecting to the authorization server.
+ ///
+ /// The data store which contains the original state parameter.
+ /// User identifier.
+ ///
+ /// The authorization state parameter which we got back from the authorization server.
+ ///
+ /// Redirect URI to the address which initializes the authorization code flow.
+ public static async Task ExtracRedirectFromState(IDataStore dataStore, string userId, string state)
+ {
+ var oauthState = state;
+ if (dataStore != null)
+ {
+ var userKey = AuthorizationCodeWebApp.StateKey + userId;
+ var expectedState = await dataStore.GetAsync(userKey);
+
+ // Verify that the stored state is equal to the one we got back from the authorization server.
+ if (!Object.Equals(oauthState, expectedState))
+ {
+ throw new TokenResponseException(new TokenErrorResponse
+ {
+ Error = "State is invalid"
+ });
+ }
+ await dataStore.DeleteAsync(userKey);
+ oauthState = oauthState.Substring(0, oauthState.Length - AuthorizationCodeWebApp.StateRandomLength);
+ }
+
+ return oauthState;
+ }
+ }
+}
Index: Src/GoogleApis.Auth/OAuth2/Web/AuthorizationCodeWebApp.cs
===================================================================
rename from Src/GoogleApis.Auth/OAuth2/AuthorizationCodeWebApp.cs
rename to Src/GoogleApis.Auth/OAuth2/Web/AuthorizationCodeWebApp.cs
--- a/Src/GoogleApis.Auth/OAuth2/AuthorizationCodeWebApp.cs
+++ b/Src/GoogleApis.Auth/OAuth2/Web/AuthorizationCodeWebApp.cs
@@ -18,9 +18,10 @@
using System.Threading;
using System.Threading.Tasks;
+using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Requests;
-namespace Google.Apis.Auth.OAuth2
+namespace Google.Apis.Auth.OAuth2.Web
{
///
/// Thread safe OAuth 2.0 authorization code flow for a web application that persists end-user credentials.
@@ -82,19 +83,19 @@
///
public AuthorizationCodeWebApp(IAuthorizationCodeFlow flow, string redirectUri, string state)
{
- // TODO(peleyal): should we provide a way to disable to random number in the end of the state parameter?
+ // TODO(peleyal): Provide a way to disable to random number in the end of the state parameter.
this.flow = flow;
this.redirectUri = redirectUri;
this.state = state;
}
- /// Authorizes the web application to access user's protected data.
+ /// Asynchronously authorizes the web application to access user's protected data.
/// User identifier
/// Cancellation token to cancel an operation
///
/// Auth result object which contains the user's credential or redirect URI for the authorization server
///
- public async Task Authorize(string userId, CancellationToken taskCancellationToken)
+ public async Task AuthorizeAsync(string userId, CancellationToken taskCancellationToken)
{
// Try to load a token from the data store.
var token = await Flow.LoadTokenAsync(userId, taskCancellationToken).ConfigureAwait(false);
Index: Src/GoogleApis.DotNet4/Apis/Util/Store/FileDataStore.cs
===================================================================
--- a/Src/GoogleApis.DotNet4/Apis/Util/Store/FileDataStore.cs
+++ b/Src/GoogleApis.DotNet4/Apis/Util/Store/FileDataStore.cs
@@ -48,7 +48,7 @@
}
///
- /// Stores the given value for the given key. It creates a new file (named ) in
+ /// Stores the given value for the given key. It creates a new file (named ) in
/// .
///
/// The type to store in the data store
@@ -62,13 +62,13 @@
}
var serialized = NewtonsoftJsonSerializer.Instance.Serialize(value);
- var filePath = Path.Combine(folderPath, GetStoredKey(key, typeof(T)));
+ var filePath = Path.Combine(folderPath, GenerateStoredKey(key, typeof(T)));
File.WriteAllText(filePath, serialized);
return TaskEx.Delay(0);
}
///
- /// Deletes the given key. It deletes the named file in .
+ /// Deletes the given key. It deletes the named file in .
///
/// The key to delete from the data store
public Task DeleteAsync(string key)
@@ -78,7 +78,7 @@
throw new ArgumentException("Key MUST have a value");
}
- var filePath = Path.Combine(folderPath, GetStoredKey(key, typeof(T)));
+ var filePath = Path.Combine(folderPath, GenerateStoredKey(key, typeof(T)));
if (File.Exists(filePath))
{
File.Delete(filePath);
@@ -87,7 +87,7 @@
}
///
- /// Returns the stored value for the given key or null if the matching file (
+ /// Returns the stored value for the given key or null if the matching file (
/// in doesn't exist.
///
/// The type to retrieve
@@ -101,7 +101,7 @@
}
TaskCompletionSource tcs = new TaskCompletionSource();
- var filePath = Path.Combine(folderPath, GetStoredKey(key, typeof(T)));
+ var filePath = Path.Combine(folderPath, GenerateStoredKey(key, typeof(T)));
if (File.Exists(filePath))
{
try
@@ -138,7 +138,7 @@
/// Creates a unique stored key based on the key and the class type.
/// The object key
/// The type to store or retrieve
- public static string GetStoredKey(string key, Type t)
+ public static string GenerateStoredKey(string key, Type t)
{
return string.Format("{0}-{1}", t.FullName, key);
}
Index: Src/GoogleApis/Apis/Services/BaseClientService.cs
===================================================================
--- a/Src/GoogleApis/Apis/Services/BaseClientService.cs
+++ b/Src/GoogleApis/Apis/Services/BaseClientService.cs
@@ -78,7 +78,7 @@
/// Get or sets the exponential back-off policy used by the service. Default value is
/// UnsuccessfulResponse503, which means that exponential back-off is used on 503 abnormal HTTP
/// response.
- /// If the value is set to None, no exponential back-off policy is used, and it's up to user to
+ /// If the value is set to None, no exponential back-off policy is used, and it's up to the user to
/// configure the in an
/// to set a specific back-off
/// implementation (using ).
@@ -177,8 +177,8 @@
// Add authenticator initializer to intercept a request and add the "Authorization" header and also handle
// abnormal 401 responses in case the authenticator is an instance of unsuccessful response handler.
args.Initializers.Add(new AuthenticatorMessageHandlerInitializer(Authenticator));
-
- var httpClient = factory.CreateHttpClient(args);
+
+ var httpClient = factory.CreateHttpClient(args);
if (initializer.MaxUrlLength > 0)
{
httpClient.MessageHandler.ExecuteInterceptors.Add(