diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2012-11-26 17:06:00 -0800 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2012-11-26 17:06:00 -0800 |
commit | f4589005375571770d5b47eed18adf2a73d0afa6 (patch) | |
tree | 8ed0bbb79bc0511e330e469ae9e5516a4b066198 /src | |
parent | d8aa2dbf93d3d48de8f5fe5fdf51e524a14b76fd (diff) | |
parent | e0772aec6a14265af869a8e4db2a2330cc2feb1f (diff) | |
download | DotNetOpenAuth-f4589005375571770d5b47eed18adf2a73d0afa6.zip DotNetOpenAuth-f4589005375571770d5b47eed18adf2a73d0afa6.tar.gz DotNetOpenAuth-f4589005375571770d5b47eed18adf2a73d0afa6.tar.bz2 |
Merge pull request #235 from dotnetjunky/v4.1
Fix bug in the LinkedInClient not working
Fixes #232
Diffstat (limited to 'src')
4 files changed, 112 insertions, 13 deletions
diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/AuthenticationOnlyCookieOAuthTokenManager.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/AuthenticationOnlyCookieOAuthTokenManager.cs index 2ec988b..efc382f 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/AuthenticationOnlyCookieOAuthTokenManager.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth/AuthenticationOnlyCookieOAuthTokenManager.cs @@ -17,7 +17,7 @@ namespace DotNetOpenAuth.AspNet.Clients { /// <summary> /// Key used for token cookie /// </summary> - private const string TokenCookieKey = "OAuthTokenSecret"; + protected const string TokenCookieKey = "OAuthTokenSecret"; /// <summary> /// Primary request context. @@ -41,7 +41,7 @@ namespace DotNetOpenAuth.AspNet.Clients { /// <summary> /// Gets the effective HttpContext object to use. /// </summary> - private HttpContextBase Context { + protected HttpContextBase Context { get { return this.primaryContext ?? new HttpContextWrapper(HttpContext.Current); } @@ -54,15 +54,13 @@ namespace DotNetOpenAuth.AspNet.Clients { /// <returns> /// The token's secret /// </returns> - public string GetTokenSecret(string token) { + public virtual string GetTokenSecret(string token) { HttpCookie cookie = this.Context.Request.Cookies[TokenCookieKey]; if (cookie == null || string.IsNullOrEmpty(cookie.Values[token])) { return null; } - byte[] cookieBytes = HttpServerUtility.UrlTokenDecode(cookie.Values[token]); - byte[] clearBytes = MachineKeyUtil.Unprotect(cookieBytes, TokenCookieKey, "Token:" + token); - string secret = Encoding.UTF8.GetString(clearBytes); + string secret = DecodeAndUnprotectToken(token, cookie.Values[token]); return secret; } @@ -72,7 +70,7 @@ namespace DotNetOpenAuth.AspNet.Clients { /// <param name="requestToken">The request token.</param> /// <param name="accessToken">The access token.</param> /// <param name="accessTokenSecret">The access token secret.</param> - public void ReplaceRequestTokenWithAccessToken(string requestToken, string accessToken, string accessTokenSecret) { + public virtual void ReplaceRequestTokenWithAccessToken(string requestToken, string accessToken, string accessTokenSecret) { var cookie = new HttpCookie(TokenCookieKey) { Value = string.Empty, Expires = DateTime.UtcNow.AddDays(-5) @@ -85,7 +83,7 @@ namespace DotNetOpenAuth.AspNet.Clients { /// </summary> /// <param name="requestToken">The request token.</param> /// <param name="requestTokenSecret">The request token secret.</param> - public void StoreRequestToken(string requestToken, string requestTokenSecret) { + public virtual void StoreRequestToken(string requestToken, string requestTokenSecret) { var cookie = new HttpCookie(TokenCookieKey) { HttpOnly = true }; @@ -94,10 +92,36 @@ namespace DotNetOpenAuth.AspNet.Clients { cookie.Secure = true; } - byte[] cookieBytes = Encoding.UTF8.GetBytes(requestTokenSecret); - var secretBytes = MachineKeyUtil.Protect(cookieBytes, TokenCookieKey, "Token:" + requestToken); - cookie.Values[requestToken] = HttpServerUtility.UrlTokenEncode(secretBytes); + var encryptedToken = ProtectAndEncodeToken(requestToken, requestTokenSecret); + cookie.Values[requestToken] = encryptedToken; + this.Context.Response.Cookies.Set(cookie); } + + /// <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); + } } }
\ No newline at end of file diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/CookieOAuthTokenManager.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/CookieOAuthTokenManager.cs new file mode 100644 index 0000000..835b6f1 --- /dev/null +++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth/CookieOAuthTokenManager.cs @@ -0,0 +1,74 @@ +using System.Web; +using System.Web.Security; + +namespace DotNetOpenAuth.AspNet.Clients { + + /// <summary> + /// Stores OAuth tokens in the current request's cookie. + /// </summary> + /// <remarks> + /// This class is different from the <see cref="AuthenticationOnlyCookieOAuthTokenManager"/> in that + /// it also stores the access token after the authentication has succeeded. + /// </remarks> + public class CookieOAuthTokenManager : AuthenticationOnlyCookieOAuthTokenManager { + /// <summary> + /// Initializes a new instance of the <see cref="CookieOAuthTokenManager"/> class. + /// </summary> + public CookieOAuthTokenManager() { + } + + /// <summary> + /// Initializes a new instance of the <see cref="CookieOAuthTokenManager"/> class. + /// </summary> + /// <param name="context">The current request context.</param> + public CookieOAuthTokenManager(HttpContextBase context) + : base(context) { + } + + /// <summary> + /// Gets the token secret from the specified token. + /// </summary> + /// <param name="token">The token.</param> + /// <returns> + /// The token's secret + /// </returns> + public override string GetTokenSecret(string token) { + string secret = base.GetTokenSecret(token); + if (secret != null) { + return secret; + } + + // The base class checks for cookies in the Request object. + // Here we check in the Response object as well because we + // may have set it earlier in the request life cycle. + HttpCookie cookie = this.Context.Response.Cookies[TokenCookieKey]; + if (cookie == null || string.IsNullOrEmpty(cookie.Values[token])) { + return null; + } + + secret = DecodeAndUnprotectToken(token, cookie.Values[token]); + return secret; + } + + /// <summary> + /// Replaces the request token with access token. + /// </summary> + /// <param name="requestToken">The request token.</param> + /// <param name="accessToken">The access token.</param> + /// <param name="accessTokenSecret">The access token secret.</param> + public override void ReplaceRequestTokenWithAccessToken(string requestToken, string accessToken, string accessTokenSecret) { + var cookie = new HttpCookie(TokenCookieKey) { + HttpOnly = true + }; + + if (FormsAuthentication.RequireSSL) { + cookie.Secure = true; + } + + var encryptedToken = ProtectAndEncodeToken(accessToken, accessTokenSecret); + cookie.Values[accessToken] = encryptedToken; + + this.Context.Response.Cookies.Set(cookie); + } + } +}
\ No newline at end of file diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/LinkedInClient.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/LinkedInClient.cs index 26bc88d..3c157f3 100644 --- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/LinkedInClient.cs +++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth/LinkedInClient.cs @@ -60,7 +60,7 @@ namespace DotNetOpenAuth.AspNet.Clients { [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "We can't dispose the object because we still need it through the app lifetime.")] public LinkedInClient(string consumerKey, string consumerSecret) - : this(consumerKey, consumerSecret, new AuthenticationOnlyCookieOAuthTokenManager()) { } + : this(consumerKey, consumerSecret, new CookieOAuthTokenManager()) { } /// <summary> /// Initializes a new instance of the <see cref="LinkedInClient"/> class. diff --git a/src/DotNetOpenAuth.AspNet/DotNetOpenAuth.AspNet.csproj b/src/DotNetOpenAuth.AspNet/DotNetOpenAuth.AspNet.csproj index 2f03ec7..405ac3c 100644 --- a/src/DotNetOpenAuth.AspNet/DotNetOpenAuth.AspNet.csproj +++ b/src/DotNetOpenAuth.AspNet/DotNetOpenAuth.AspNet.csproj @@ -28,7 +28,7 @@ <Import Project="$(ProjectRoot)tools\DotNetOpenAuth.props" /> <Import Project="$(ProjectRoot)tools\DotNetOpenAuth.Product.props" /> <PropertyGroup> - <RootNamespace>DotNetOpenAuth.AspNet</RootNamespace> + <RootNamespace>DotNetOpenAuth.AspNet</RootNamespace> </PropertyGroup> <ItemGroup> <Reference Include="System" /> @@ -48,6 +48,7 @@ <Compile Include="Clients\OAuth\AuthenticationOnlyCookieOAuthTokenManager.cs"> <SubType>Code</SubType> </Compile> + <Compile Include="Clients\OAuth\CookieOAuthTokenManager.cs" /> <Compile Include="Clients\OAuth\IOAuthTokenManager.cs" /> <Compile Include="Clients\OAuth\SimpleConsumerTokenManager.cs" /> <Compile Include="IAuthenticationClient.cs" /> |