summaryrefslogtreecommitdiffstats
path: root/projecttemplates/WebFormsRelyingParty/Code
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2009-11-10 21:00:37 -0800
committerAndrew Arnott <andrewarnott@gmail.com>2009-11-10 21:00:37 -0800
commit6df46c9875f82f5a5f94a082a0b699fde2978d6f (patch)
tree56df88c1a4fe02a363e5a0d7d087c1947322ab09 /projecttemplates/WebFormsRelyingParty/Code
parent5d4d80b4a83bb9d6af62cc5f6d78f6f7e541e67d (diff)
downloadDotNetOpenAuth-6df46c9875f82f5a5f94a082a0b699fde2978d6f.zip
DotNetOpenAuth-6df46c9875f82f5a5f94a082a0b699fde2978d6f.tar.gz
DotNetOpenAuth-6df46c9875f82f5a5f94a082a0b699fde2978d6f.tar.bz2
Added a bunch more OAuth SP supporting code, but it's not done yet.
Diffstat (limited to 'projecttemplates/WebFormsRelyingParty/Code')
-rw-r--r--projecttemplates/WebFormsRelyingParty/Code/OAuthServiceProvider.cs117
-rw-r--r--projecttemplates/WebFormsRelyingParty/Code/OAuthTokenManager.cs26
-rw-r--r--projecttemplates/WebFormsRelyingParty/Code/Utilities.cs66
3 files changed, 208 insertions, 1 deletions
diff --git a/projecttemplates/WebFormsRelyingParty/Code/OAuthServiceProvider.cs b/projecttemplates/WebFormsRelyingParty/Code/OAuthServiceProvider.cs
new file mode 100644
index 0000000..473b6d2
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Code/OAuthServiceProvider.cs
@@ -0,0 +1,117 @@
+//-----------------------------------------------------------------------
+// <copyright file="OAuthServiceProvider.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace WebFormsRelyingParty.Code {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Web;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth;
+ using DotNetOpenAuth.OAuth.ChannelElements;
+ using DotNetOpenAuth.OAuth.Messages;
+
+ public class OAuthServiceProvider {
+ private const string PendingAuthorizationRequestSessionKey = "PendingAuthorizationRequest";
+
+ /// <summary>
+ /// The shared service description for this web site.
+ /// </summary>
+ private static ServiceProviderDescription serviceDescription;
+
+ private static OAuthServiceProviderTokenManager tokenManager;
+
+ /// <summary>
+ /// The shared service provider object.
+ /// </summary>
+ private static ServiceProvider serviceProvider;
+
+ /// <summary>
+ /// The lock to synchronize initialization of the <see cref="serviceProvider"/> field.
+ /// </summary>
+ private static object initializerLock = new object();
+
+ /// <summary>
+ /// Gets the service provider.
+ /// </summary>
+ /// <value>The service provider.</value>
+ public static ServiceProvider ServiceProvider {
+ get {
+ EnsureInitialized();
+ return serviceProvider;
+ }
+ }
+
+ /// <summary>
+ /// Gets the service description.
+ /// </summary>
+ /// <value>The service description.</value>
+ public static ServiceProviderDescription ServiceDescription {
+ get {
+ EnsureInitialized();
+ return serviceDescription;
+ }
+ }
+
+ public static UserAuthorizationRequest PendingAuthorizationRequest {
+ get { return HttpContext.Current.Session[PendingAuthorizationRequestSessionKey] as UserAuthorizationRequest; }
+ set { HttpContext.Current.Session[PendingAuthorizationRequestSessionKey] = value; }
+ }
+
+ public static WebFormsRelyingParty.Consumer PendingAuthorizationConsumer {
+ get {
+ ITokenContainingMessage message = PendingAuthorizationRequest;
+ if (message == null) {
+ throw new InvalidOperationException();
+ }
+
+ return Global.DataContext.IssuedToken.OfType<IssuedRequestToken>().First(t => t.Token == message.Token).Consumer;
+ }
+ }
+
+ public static void AuthorizePendingRequestToken() {
+ var pendingRequest = PendingAuthorizationRequest;
+ if (pendingRequest == null) {
+ throw new InvalidOperationException("No pending authorization request to authorize.");
+ }
+
+ ITokenContainingMessage msg = pendingRequest;
+ var token = Global.DataContext.IssuedToken.OfType<IssuedRequestToken>().First(t => t.Token == msg.Token);
+ token.Authorize();
+
+ var response = serviceProvider.PrepareAuthorizationResponse(pendingRequest);
+ serviceProvider.Channel.Send(response);
+ PendingAuthorizationRequest = null;
+ }
+
+ /// <summary>
+ /// Initializes the <see cref="serviceProvider"/> field if it has not yet been initialized.
+ /// </summary>
+ private static void EnsureInitialized() {
+ if (serviceProvider == null) {
+ lock (initializerLock) {
+ if (serviceDescription == null) {
+ var endpoint = new MessageReceivingEndpoint(Utilities.ApplicationRoot + "OAuth.ashx", HttpDeliveryMethods.PostRequest);
+ serviceDescription = new ServiceProviderDescription {
+ TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
+ RequestTokenEndpoint = endpoint,
+ AccessTokenEndpoint = endpoint,
+ UserAuthorizationEndpoint = endpoint,
+ };
+ }
+
+ if (tokenManager == null) {
+ tokenManager = new OAuthServiceProviderTokenManager();
+ }
+
+ if (serviceProvider == null) {
+ serviceProvider = new ServiceProvider(serviceDescription, tokenManager);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/projecttemplates/WebFormsRelyingParty/Code/OAuthTokenManager.cs b/projecttemplates/WebFormsRelyingParty/Code/OAuthTokenManager.cs
index 653d791..d9c04bd 100644
--- a/projecttemplates/WebFormsRelyingParty/Code/OAuthTokenManager.cs
+++ b/projecttemplates/WebFormsRelyingParty/Code/OAuthTokenManager.cs
@@ -75,18 +75,42 @@ namespace WebFormsRelyingParty.Code {
Global.DataContext.SaveChanges();
}
+ /// <summary>
+ /// Deletes a request token and its associated secret and stores a new access token and secret.
+ /// </summary>
+ /// <param name="consumerKey">The Consumer that is exchanging its request token for an access token.</param>
+ /// <param name="requestToken">The Consumer's request token that should be deleted/expired.</param>
+ /// <param name="accessToken">The new access token that is being issued to the Consumer.</param>
+ /// <param name="accessTokenSecret">The secret associated with the newly issued access token.</param>
+ /// <remarks>
+ /// <para>
+ /// Any scope of granted privileges associated with the request token from the
+ /// original call to <see cref="StoreNewRequestToken"/> should be carried over
+ /// to the new Access Token.
+ /// </para>
+ /// <para>
+ /// To associate a user account with the new access token,
+ /// <see cref="System.Web.HttpContext.User">HttpContext.Current.User</see> may be
+ /// useful in an ASP.NET web application within the implementation of this method.
+ /// Alternatively you may store the access token here without associating with a user account,
+ /// and wait until <see cref="WebConsumer.ProcessUserAuthorization()"/> or
+ /// <see cref="DesktopConsumer.ProcessUserAuthorization(string, string)"/> return the access
+ /// token to associate the access token with a user account at that point.
+ /// </para>
+ /// </remarks>
public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret) {
var requestTokenEntity = Global.DataContext.IssuedToken.OfType<IssuedRequestToken>().First(
t => t.Consumer.ConsumerKey == consumerKey && t.Token == requestToken);
- Global.DataContext.DeleteObject(requestTokenEntity);
var accessTokenEntity = new IssuedAccessToken {
Token = accessToken,
TokenSecret = accessTokenSecret,
ExpirationDate = null, // currently, our access tokens don't expire
CreatedOn = DateTime.Now,
+ User = requestTokenEntity.User,
};
+ Global.DataContext.DeleteObject(requestTokenEntity);
Global.DataContext.AddToIssuedToken(accessTokenEntity);
Global.DataContext.SaveChanges();
}
diff --git a/projecttemplates/WebFormsRelyingParty/Code/Utilities.cs b/projecttemplates/WebFormsRelyingParty/Code/Utilities.cs
new file mode 100644
index 0000000..b9c9f43
--- /dev/null
+++ b/projecttemplates/WebFormsRelyingParty/Code/Utilities.cs
@@ -0,0 +1,66 @@
+//-----------------------------------------------------------------------
+// <copyright file="Utilities.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace WebFormsRelyingParty.Code {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Security.Cryptography;
+ using System.Web;
+
+ public static class Utilities {
+ private static readonly RandomNumberGenerator CryptoRandomDataGenerator = new RNGCryptoServiceProvider();
+
+ public static string ApplicationRoot {
+ get {
+ string appRoot = HttpContext.Current.Request.ApplicationPath;
+ if (!appRoot.EndsWith("/", StringComparison.Ordinal)) {
+ appRoot += "/";
+ }
+
+ return appRoot;
+ }
+ }
+
+ public static string SetCsrfCookie() {
+ // Generate an unpredictable secret that goes to the user agent and must come back
+ // with authorization to guarantee the user interacted with this page rather than
+ // being scripted by an evil Consumer.
+ byte[] randomData = new byte[8];
+ CryptoRandomDataGenerator.GetBytes(randomData);
+ string secret = Convert.ToBase64String(randomData);
+
+ // Send the secret down as a cookie...
+ var cookie = new HttpCookie("CsrfCookie", secret) {
+ Path = HttpContext.Current.Request.Path,
+ HttpOnly = true,
+ Expires = DateTime.Now.AddMinutes(30),
+ };
+ HttpContext.Current.Response.SetCookie(cookie);
+
+ // ...and also return the secret so the caller can save it as a hidden form field.
+ return secret;
+ }
+
+ public static void VerifyCsrfCookie(string secret) {
+ var cookie = HttpContext.Current.Request.Cookies["CsrfCookie"];
+ if (cookie != null) {
+ if (cookie.Value == secret) {
+ // Valid CSRF check. Clear the cookie and return.
+ cookie.Expires = DateTime.Now.Subtract(TimeSpan.FromDays(1));
+ cookie.Value = string.Empty;
+ if (HttpContext.Current.Request.Browser["supportsEmptyStringInCookieValue"] == "false") {
+ cookie.Value = "NoCookie";
+ }
+ HttpContext.Current.Response.SetCookie(cookie);
+ return;
+ }
+ }
+
+ throw new InvalidOperationException("Invalid CSRF check.");
+ }
+ }
+}