//-----------------------------------------------------------------------
//
// Copyright (c) Microsoft. All rights reserved.
// Copyright (c) Andrew Arnott. All rights reserved.
//
//-----------------------------------------------------------------------
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;
///
/// Provides temporary credential storage by persisting them in a protected cookie on the
/// user agent (i.e. browser).
///
public class CookieTemporaryCredentialStorage : ITemporaryCredentialStorage {
///
/// Key used for token cookie
///
protected const string TokenCookieKey = "DNOAOAuth1TempCredential";
///
/// Primary request context.
///
private readonly HttpContextBase httpContext;
///
/// Initializes a new instance of the class
/// using as the source for the context to read and write cookies to.
///
public CookieTemporaryCredentialStorage()
: this(new HttpContextWrapper(HttpContext.Current)) {
}
///
/// Initializes a new instance of the class.
///
/// The HTTP context from and to which to access cookies.
public CookieTemporaryCredentialStorage(HttpContextBase httpContext) {
Requires.NotNull(httpContext, "httpContext");
this.httpContext = httpContext;
}
#region ITemporaryCredentialsStorage Members
///
/// Saves the temporary credential.
///
/// The identifier.
/// The secret.
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);
var escapedIdentifier = Uri.EscapeDataString(identifier);
cookie.Values[escapedIdentifier] = encryptedToken;
this.httpContext.Response.Cookies.Set(cookie);
}
///
/// Obtains the temporary credential identifier and secret, if available.
///
///
/// An initialized key value pair if credentials are available; otherwise both key and value are null.
///
public KeyValuePair RetrieveTemporaryCredential() {
HttpCookie cookie = this.httpContext.Request.Cookies[TokenCookieKey];
if (cookie == null || cookie.Values.Count == 0) {
return new KeyValuePair();
}
string escapedIdentifier = cookie.Values.GetKey(0);
string identifier = Uri.UnescapeDataString(escapedIdentifier);
string secret = DecodeAndUnprotectToken(identifier, cookie.Values[escapedIdentifier]);
return new KeyValuePair(identifier, secret);
}
///
/// Clears the temporary credentials from storage.
///
///
/// DotNetOpenAuth calls this when the credentials are no longer needed.
///
public void ClearTemporaryCredential() {
var cookie = new HttpCookie(TokenCookieKey) {
Value = string.Empty,
Expires = DateTime.UtcNow.AddDays(-5),
};
this.httpContext.Response.Cookies.Set(cookie);
}
#endregion
///
/// Protect and url-encode the specified token secret.
///
/// The token to be used as a key.
/// The token secret to be protected
/// The encrypted and protected string.
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);
}
///
/// Url-decode and unprotect the specified encrypted token string.
///
/// The token to be used as a key.
/// The encrypted token to be decrypted
/// The original token secret
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);
}
}
}