diff options
Diffstat (limited to 'src/DotNetOpenAuth.OAuth.Consumer/OAuth/CookieTemporaryCredentialStorage.cs')
-rw-r--r-- | src/DotNetOpenAuth.OAuth.Consumer/OAuth/CookieTemporaryCredentialStorage.cs | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/src/DotNetOpenAuth.OAuth.Consumer/OAuth/CookieTemporaryCredentialStorage.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/CookieTemporaryCredentialStorage.cs new file mode 100644 index 0000000..25941e6 --- /dev/null +++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/CookieTemporaryCredentialStorage.cs @@ -0,0 +1,130 @@ +//----------------------------------------------------------------------- +// <copyright file="CookieTemporaryCredentialStorage.cs" company="Microsoft"> +// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + using System.Web; + using System.Web.Security; + using Validation; + + /// <summary> + /// Provides temporary credential storage by persisting them in a protected cookie on the + /// user agent (i.e. browser). + /// </summary> + public class CookieTemporaryCredentialStorage : ITemporaryCredentialStorage { + /// <summary> + /// Key used for token cookie + /// </summary> + protected const string TokenCookieKey = "DNOAOAuth1TempCredential"; + + /// <summary> + /// Primary request context. + /// </summary> + private readonly HttpContextBase httpContext; + + /// <summary> + /// Initializes a new instance of the <see cref="CookieTemporaryCredentialsStorage"/> class + /// using <see cref="HttpContext.Current"/> as the source for the context to read and write cookies to. + /// </summary> + public CookieTemporaryCredentialStorage() + : this(new HttpContextWrapper(HttpContext.Current)) { + } + + /// <summary> + /// Initializes a new instance of the <see cref="CookieTemporaryCredentialsStorage"/> class. + /// </summary> + /// <param name="httpContext">The HTTP context from and to which to access cookies.</param> + public CookieTemporaryCredentialStorage(HttpContextBase httpContext) { + Requires.NotNull(httpContext, "httpContext"); + this.httpContext = httpContext; + } + + #region ITemporaryCredentialsStorage Members + + /// <summary> + /// Saves the temporary credential. + /// </summary> + /// <param name="identifier">The identifier.</param> + /// <param name="secret">The secret.</param> + public void SaveTemporaryCredential(string identifier, string secret) { + var cookie = new HttpCookie(TokenCookieKey) { + HttpOnly = true + }; + + if (FormsAuthentication.RequireSSL) { + cookie.Secure = true; + } + + var encryptedToken = ProtectAndEncodeToken(identifier, secret); + cookie.Values[identifier] = encryptedToken; + + this.httpContext.Response.Cookies.Set(cookie); + } + + /// <summary> + /// Obtains the temporary credential identifier and secret, if available. + /// </summary> + /// <returns> + /// An initialized key value pair if credentials are available; otherwise both key and value are <c>null</c>. + /// </returns> + /// <exception cref="System.NotImplementedException"></exception> + public KeyValuePair<string, string> RetrieveTemporaryCredential() { + HttpCookie cookie = this.httpContext.Request.Cookies[TokenCookieKey]; + if (cookie == null || cookie.Values.Count == 0) { + return new KeyValuePair<string, string>(); + } + + string identifier = cookie.Values.GetKey(0); + string secret = DecodeAndUnprotectToken(identifier, cookie.Values[identifier]); + return new KeyValuePair<string, string>(identifier, secret); + } + + /// <summary> + /// Clears the temporary credentials from storage. + /// </summary> + /// <remarks> + /// DotNetOpenAuth calls this when the credentials are no longer needed. + /// </remarks> + public void ClearTemporaryCredential() { + var cookie = new HttpCookie(TokenCookieKey) { + Value = string.Empty, + Expires = DateTime.UtcNow.AddDays(-5), + }; + this.httpContext.Response.Cookies.Set(cookie); + } + + #endregion + + /// <summary> + /// Protect and url-encode the specified token secret. + /// </summary> + /// <param name="token">The token to be used as a key.</param> + /// <param name="tokenSecret">The token secret to be protected</param> + /// <returns>The encrypted and protected string.</returns> + protected static string ProtectAndEncodeToken(string token, string tokenSecret) { + byte[] cookieBytes = Encoding.UTF8.GetBytes(tokenSecret); + var secretBytes = MachineKeyUtil.Protect(cookieBytes, TokenCookieKey, "Token:" + token); + return HttpServerUtility.UrlTokenEncode(secretBytes); + } + + /// <summary> + /// Url-decode and unprotect the specified encrypted token string. + /// </summary> + /// <param name="token">The token to be used as a key.</param> + /// <param name="encryptedToken">The encrypted token to be decrypted</param> + /// <returns>The original token secret</returns> + protected static string DecodeAndUnprotectToken(string token, string encryptedToken) { + byte[] cookieBytes = HttpServerUtility.UrlTokenDecode(encryptedToken); + byte[] clearBytes = MachineKeyUtil.Unprotect(cookieBytes, TokenCookieKey, "Token:" + token); + return Encoding.UTF8.GetString(clearBytes); + } + } +} |