diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2013-02-26 22:55:18 -0800 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2013-02-26 22:55:18 -0800 |
commit | 6204dcf07f31b78478bc1ddb55a6ca9027617b67 (patch) | |
tree | 2b92fff13f9e253c9504e73b677ec61b352d9f38 | |
parent | 38a1162c5cbaea035e655dc9accd92f9de5019ed (diff) | |
download | DotNetOpenAuth-6204dcf07f31b78478bc1ddb55a6ca9027617b67.zip DotNetOpenAuth-6204dcf07f31b78478bc1ddb55a6ca9027617b67.tar.gz DotNetOpenAuth-6204dcf07f31b78478bc1ddb55a6ca9027617b67.tar.bz2 |
Fixes some OAuth 1 build breaks.
19 files changed, 311 insertions, 258 deletions
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs b/samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs index 2302837..def378f 100644 --- a/samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs +++ b/samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs @@ -7,6 +7,7 @@ namespace DotNetOpenAuth.ApplicationBlock { using System; using System.Collections.Generic; + using System.Configuration; using System.Diagnostics; using System.Globalization; using System.IO; @@ -19,6 +20,7 @@ namespace DotNetOpenAuth.ApplicationBlock { using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; + using System.Web; using System.Xml; using System.Xml.Linq; using DotNetOpenAuth.Messaging; @@ -66,6 +68,18 @@ namespace DotNetOpenAuth.ApplicationBlock { private static readonly Uri GetContactsEndpoint = new Uri("http://www.google.com/m8/feeds/contacts/default/full/"); /// <summary> + /// Initializes a new instance of the <see cref="GoogleConsumer"/> class. + /// </summary> + public GoogleConsumer() { + this.ServiceProvider = ServiceDescription; + this.ConsumerKey = ConfigurationManager.AppSettings["googleConsumerKey"]; + this.ConsumerSecret = ConfigurationManager.AppSettings["googleConsumerSecret"]; + this.TemporaryCredentialStorage = HttpContext.Current != null + ? (ITemporaryCredentialStorage)new CookieTemporaryCredentialStorage() + : new MemoryTemporaryCredentialStorage(); + } + + /// <summary> /// The many specific authorization scopes Google offers. /// </summary> [Flags] @@ -151,19 +165,23 @@ namespace DotNetOpenAuth.ApplicationBlock { Maps = 0x8000, } - public GoogleConsumer() { + /// <summary> + /// Gets the scope URI in Google's format. + /// </summary> + /// <param name="scope">The scope, which may include one or several Google applications.</param> + /// <returns>A space-delimited list of URIs for the requested Google applications.</returns> + public static string GetScopeUri(Applications scope) { + return string.Join(" ", Util.GetIndividualFlags(scope).Select(app => DataScopeUris[(Applications)app]).ToArray()); } /// <summary> /// Requests authorization from Google to access data from a set of Google applications. /// </summary> - /// <param name="consumer">The Google consumer previously constructed using <see cref="CreateWebConsumer" /> or <see cref="CreateDesktopConsumer" />.</param> /// <param name="requestedAccessScope">The requested access scope.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns> /// A task that completes with the asynchronous operation. /// </returns> - /// <exception cref="System.ArgumentNullException">consumer</exception> public Task<Uri> RequestUserAuthorizationAsync(Applications requestedAccessScope, CancellationToken cancellationToken = default(CancellationToken)) { var extraParameters = new Dictionary<string, string> { { "scope", GetScopeUri(requestedAccessScope) }, @@ -175,7 +193,6 @@ namespace DotNetOpenAuth.ApplicationBlock { /// <summary> /// Gets the Gmail address book's contents. /// </summary> - /// <param name="consumer">The Google consumer.</param> /// <param name="accessToken">The access token previously retrieved.</param> /// <param name="maxResults">The maximum number of entries to return. If you want to receive all of the contacts, rather than only the default maximum, you can specify a very large number here.</param> /// <param name="startIndex">The 1-based index of the first result to be retrieved (for paging).</param> @@ -183,7 +200,6 @@ namespace DotNetOpenAuth.ApplicationBlock { /// <returns> /// An XML document returned by Google. /// </returns> - /// <exception cref="System.ArgumentNullException">consumer</exception> public async Task<XDocument> GetContactsAsync(AccessToken accessToken, int maxResults = 25, int startIndex = 1, CancellationToken cancellationToken = default(CancellationToken)) { // Enable gzip compression. Google only compresses the response for recognized user agent headers. - Mike Lim var handler = new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip }; @@ -244,14 +260,5 @@ namespace DotNetOpenAuth.ApplicationBlock { } } } - - /// <summary> - /// Gets the scope URI in Google's format. - /// </summary> - /// <param name="scope">The scope, which may include one or several Google applications.</param> - /// <returns>A space-delimited list of URIs for the requested Google applications.</returns> - public static string GetScopeUri(Applications scope) { - return string.Join(" ", Util.GetIndividualFlags(scope).Select(app => DataScopeUris[(Applications)app]).ToArray()); - } } } diff --git a/samples/DotNetOpenAuth.ApplicationBlock/TwitterConsumer.cs b/samples/DotNetOpenAuth.ApplicationBlock/TwitterConsumer.cs index 7bbfaa1..bb6f9d3 100644 --- a/samples/DotNetOpenAuth.ApplicationBlock/TwitterConsumer.cs +++ b/samples/DotNetOpenAuth.ApplicationBlock/TwitterConsumer.cs @@ -30,7 +30,7 @@ namespace DotNetOpenAuth.ApplicationBlock { /// <summary> /// A consumer capable of communicating with Twitter. /// </summary> - public static class TwitterConsumer { + public class TwitterConsumer : Consumer { /// <summary> /// The description of Twitter's OAuth protocol URIs for use with actually reading/writing /// a user's private Twitter data. @@ -64,19 +64,36 @@ namespace DotNetOpenAuth.ApplicationBlock { private static readonly Uri VerifyCredentialsEndpoint = new Uri("http://api.twitter.com/1/account/verify_credentials.xml"); - private class HostFactories : IHostFactories { - private static readonly IHostFactories underlyingFactories = new DefaultOAuthHostFactories(); - - public HttpMessageHandler CreateHttpMessageHandler() { - return new WebRequestHandler(); - } + /// <summary> + /// Initializes a new instance of the <see cref="TwitterConsumer"/> class. + /// </summary> + public TwitterConsumer() { + this.ServiceProvider = ServiceDescription; + this.ConsumerKey = ConfigurationManager.AppSettings["twitterConsumerKey"]; + this.ConsumerSecret = ConfigurationManager.AppSettings["twitterConsumerSecret"]; + this.TemporaryCredentialStorage = HttpContext.Current != null + ? (ITemporaryCredentialStorage)new CookieTemporaryCredentialStorage() + : new MemoryTemporaryCredentialStorage(); + } - public HttpClient CreateHttpClient(HttpMessageHandler handler = null) { - var client = underlyingFactories.CreateHttpClient(handler); + /// <summary> + /// Initializes a new instance of the <see cref="TwitterConsumer"/> class. + /// </summary> + /// <param name="consumerKey">The consumer key.</param> + /// <param name="consumerSecret">The consumer secret.</param> + public TwitterConsumer(string consumerKey, string consumerSecret) + : this() { + this.ConsumerKey = consumerKey; + this.ConsumerSecret = consumerSecret; + } - // Twitter can't handle the Expect 100 Continue HTTP header. - client.DefaultRequestHeaders.ExpectContinue = false; - return client; + /// <summary> + /// Gets a value indicating whether the Twitter consumer key and secret are set in the web.config file. + /// </summary> + public static bool IsTwitterConsumerConfigured { + get { + return !string.IsNullOrEmpty(ConfigurationManager.AppSettings["twitterConsumerKey"]) && + !string.IsNullOrEmpty(ConfigurationManager.AppSettings["twitterConsumerSecret"]); } } @@ -86,7 +103,7 @@ namespace DotNetOpenAuth.ApplicationBlock { if (IsTwitterConsumerConfigured) { ITemporaryCredentialStorage storage = forWeb ? (ITemporaryCredentialStorage)new CookieTemporaryCredentialStorage() : new MemoryTemporaryCredentialStorage(); return new Consumer(consumerKey, consumerSecret, ServiceDescription, storage) { - HostFactories = new HostFactories(), + HostFactories = new TwitterHostFactories(), }; } else { throw new InvalidOperationException("No Twitter OAuth consumer key and secret could be found in web.config AppSettings."); @@ -94,17 +111,55 @@ namespace DotNetOpenAuth.ApplicationBlock { } /// <summary> - /// Gets a value indicating whether the Twitter consumer key and secret are set in the web.config file. + /// Prepares a redirect that will send the user to Twitter to sign in. /// </summary> - public static bool IsTwitterConsumerConfigured { - get { - return !string.IsNullOrEmpty(ConfigurationManager.AppSettings["twitterConsumerKey"]) && - !string.IsNullOrEmpty(ConfigurationManager.AppSettings["twitterConsumerSecret"]); + /// <param name="forceNewLogin">if set to <c>true</c> the user will be required to re-enter their Twitter credentials even if already logged in to Twitter.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns> + /// The redirect message. + /// </returns> + /// <remarks> + /// Call <see cref="OutgoingWebResponse.Send" /> or + /// <c>return StartSignInWithTwitter().<see cref="MessagingUtilities.AsActionResult">AsActionResult()</see></c> + /// to actually perform the redirect. + /// </remarks> + public static async Task<Uri> StartSignInWithTwitterAsync(bool forceNewLogin = false, CancellationToken cancellationToken = default(CancellationToken)) { + var redirectParameters = new Dictionary<string, string>(); + if (forceNewLogin) { + redirectParameters["force_login"] = "true"; + } + Uri callback = MessagingUtilities.GetRequestUrlFromContext().StripQueryArgumentsWithPrefix("oauth_"); + + var consumer = CreateConsumer(); + consumer.ServiceProvider = SignInWithTwitterServiceDescription; + Uri redirectUrl = await consumer.RequestUserAuthorizationAsync(callback, cancellationToken: cancellationToken); + return redirectUrl; + } + + /// <summary> + /// Checks the incoming web request to see if it carries a Twitter authentication response, + /// and provides the user's Twitter screen name and unique id if available. + /// </summary> + /// <param name="completeUrl">The URL that came back from the service provider to complete the authorization.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns> + /// A tuple with the screen name and Twitter unique user ID if successful; otherwise <c>null</c>. + /// </returns> + public static async Task<Tuple<string, int>> TryFinishSignInWithTwitterAsync(Uri completeUrl = null, CancellationToken cancellationToken = default(CancellationToken)) { + var consumer = CreateConsumer(); + consumer.ServiceProvider = SignInWithTwitterServiceDescription; + var response = await consumer.ProcessUserAuthorizationAsync(completeUrl ?? HttpContext.Current.Request.Url, cancellationToken: cancellationToken); + if (response == null) { + return null; } + + string screenName = response.ExtraData["screen_name"]; + int userId = int.Parse(response.ExtraData["user_id"]); + return Tuple.Create(screenName, userId); } - public static async Task<JArray> GetUpdatesAsync(Consumer twitter, AccessToken accessToken, CancellationToken cancellationToken = default(CancellationToken)) { - using (var httpClient = twitter.CreateHttpClient(accessToken)) { + public async Task<JArray> GetUpdatesAsync(AccessToken accessToken, CancellationToken cancellationToken = default(CancellationToken)) { + using (var httpClient = this.CreateHttpClient(accessToken)) { using (var response = await httpClient.GetAsync(GetFriendTimelineStatusEndpoint, cancellationToken)) { response.EnsureSuccessStatusCode(); string jsonString = await response.Content.ReadAsStringAsync(); @@ -114,8 +169,8 @@ namespace DotNetOpenAuth.ApplicationBlock { } } - public static async Task<XDocument> GetFavorites(Consumer twitter, AccessToken accessToken, CancellationToken cancellationToken = default(CancellationToken)) { - using (var httpClient = twitter.CreateHttpClient(accessToken)) { + public async Task<XDocument> GetFavorites(AccessToken accessToken, CancellationToken cancellationToken = default(CancellationToken)) { + using (var httpClient = this.CreateHttpClient(accessToken)) { using (HttpResponseMessage response = await httpClient.GetAsync(GetFavoritesEndpoint, cancellationToken)) { response.EnsureSuccessStatusCode(); return XDocument.Parse(await response.Content.ReadAsStringAsync()); @@ -123,7 +178,7 @@ namespace DotNetOpenAuth.ApplicationBlock { } } - public static async Task<XDocument> UpdateProfileBackgroundImageAsync(Consumer twitter, AccessToken accessToken, string image, bool tile, CancellationToken cancellationToken) { + public async Task<XDocument> UpdateProfileBackgroundImageAsync(AccessToken accessToken, string image, bool tile, CancellationToken cancellationToken) { var imageAttachment = new StreamContent(File.OpenRead(image)); imageAttachment.Headers.ContentType = new MediaTypeHeaderValue("image/" + Path.GetExtension(image).Substring(1).ToLowerInvariant()); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, UpdateProfileBackgroundImageEndpoint); @@ -132,7 +187,7 @@ namespace DotNetOpenAuth.ApplicationBlock { content.Add(new StringContent(tile.ToString().ToLowerInvariant()), "tile"); request.Content = content; request.Headers.ExpectContinue = false; - using (var httpClient = twitter.CreateHttpClient(accessToken)) { + using (var httpClient = this.CreateHttpClient(accessToken)) { using (HttpResponseMessage response = await httpClient.SendAsync(request, cancellationToken)) { response.EnsureSuccessStatusCode(); string responseString = await response.Content.ReadAsStringAsync(); @@ -141,19 +196,19 @@ namespace DotNetOpenAuth.ApplicationBlock { } } - public static Task<XDocument> UpdateProfileImageAsync(Consumer twitter, AccessToken accessToken, string pathToImage, CancellationToken cancellationToken = default(CancellationToken)) { + public Task<XDocument> UpdateProfileImageAsync(AccessToken accessToken, string pathToImage, CancellationToken cancellationToken = default(CancellationToken)) { string contentType = "image/" + Path.GetExtension(pathToImage).Substring(1).ToLowerInvariant(); - return UpdateProfileImageAsync(twitter, accessToken, File.OpenRead(pathToImage), contentType, cancellationToken); + return this.UpdateProfileImageAsync(accessToken, File.OpenRead(pathToImage), contentType, cancellationToken); } - public static async Task<XDocument> UpdateProfileImageAsync(Consumer twitter, AccessToken accessToken, Stream image, string contentType, CancellationToken cancellationToken = default(CancellationToken)) { + public async Task<XDocument> UpdateProfileImageAsync(AccessToken accessToken, Stream image, string contentType, CancellationToken cancellationToken = default(CancellationToken)) { var imageAttachment = new StreamContent(image); imageAttachment.Headers.ContentType = new MediaTypeHeaderValue(contentType); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, UpdateProfileImageEndpoint); var content = new MultipartFormDataContent(); content.Add(imageAttachment, "image", "twitterPhoto"); request.Content = content; - using (var httpClient = twitter.CreateHttpClient(accessToken)) { + using (var httpClient = this.CreateHttpClient(accessToken)) { using (HttpResponseMessage response = await httpClient.SendAsync(request, cancellationToken)) { response.EnsureSuccessStatusCode(); string responseString = await response.Content.ReadAsStringAsync(); @@ -162,8 +217,8 @@ namespace DotNetOpenAuth.ApplicationBlock { } } - public static async Task<XDocument> VerifyCredentialsAsync(Consumer twitter, AccessToken accessToken, CancellationToken cancellationToken = default(CancellationToken)) { - using (var httpClient = twitter.CreateHttpClient(accessToken)) { + public async Task<XDocument> VerifyCredentialsAsync(AccessToken accessToken, CancellationToken cancellationToken = default(CancellationToken)) { + using (var httpClient = this.CreateHttpClient(accessToken)) { using (var response = await httpClient.GetAsync(VerifyCredentialsEndpoint, cancellationToken)) { response.EnsureSuccessStatusCode(); using (var stream = await response.Content.ReadAsStreamAsync()) { @@ -173,57 +228,26 @@ namespace DotNetOpenAuth.ApplicationBlock { } } - public static async Task<string> GetUsername(Consumer twitter, AccessToken accessToken, CancellationToken cancellationToken = default(CancellationToken)) { - XDocument xml = await VerifyCredentialsAsync(twitter, accessToken, cancellationToken); + public async Task<string> GetUsername(AccessToken accessToken, CancellationToken cancellationToken = default(CancellationToken)) { + XDocument xml = await this.VerifyCredentialsAsync(accessToken, cancellationToken); XPathNavigator nav = xml.CreateNavigator(); return nav.SelectSingleNode("/user/screen_name").Value; } - /// <summary> - /// Prepares a redirect that will send the user to Twitter to sign in. - /// </summary> - /// <param name="forceNewLogin">if set to <c>true</c> the user will be required to re-enter their Twitter credentials even if already logged in to Twitter.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns> - /// The redirect message. - /// </returns> - /// <remarks> - /// Call <see cref="OutgoingWebResponse.Send" /> or - /// <c>return StartSignInWithTwitter().<see cref="MessagingUtilities.AsActionResult">AsActionResult()</see></c> - /// to actually perform the redirect. - /// </remarks> - public static async Task<Uri> StartSignInWithTwitterAsync(bool forceNewLogin = false, CancellationToken cancellationToken = default(CancellationToken)) { - var redirectParameters = new Dictionary<string, string>(); - if (forceNewLogin) { - redirectParameters["force_login"] = "true"; + private class TwitterHostFactories : IHostFactories { + private static readonly IHostFactories underlyingFactories = new DefaultOAuthHostFactories(); + + public HttpMessageHandler CreateHttpMessageHandler() { + return new WebRequestHandler(); } - Uri callback = MessagingUtilities.GetRequestUrlFromContext().StripQueryArgumentsWithPrefix("oauth_"); - var consumer = CreateConsumer(); - consumer.ServiceProvider = SignInWithTwitterServiceDescription; - Uri redirectUrl = await consumer.RequestUserAuthorizationAsync(callback, cancellationToken: cancellationToken); - return redirectUrl; - } + public HttpClient CreateHttpClient(HttpMessageHandler handler = null) { + var client = underlyingFactories.CreateHttpClient(handler); - /// <summary> - /// Checks the incoming web request to see if it carries a Twitter authentication response, - /// and provides the user's Twitter screen name and unique id if available. - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns> - /// A tuple with the screen name and Twitter unique user ID if successful; otherwise <c>null</c>. - /// </returns> - public static async Task<Tuple<string, int>> TryFinishSignInWithTwitterAsync(Uri completeUrl, CancellationToken cancellationToken = default(CancellationToken)) { - var consumer = CreateConsumer(); - consumer.ServiceProvider = SignInWithTwitterServiceDescription; - var response = await consumer.ProcessUserAuthorizationAsync(completeUrl, cancellationToken: cancellationToken); - if (response == null) { - return null; + // Twitter can't handle the Expect 100 Continue HTTP header. + client.DefaultRequestHeaders.ExpectContinue = false; + return client; } - - string screenName = response.ExtraData["screen_name"]; - int userId = int.Parse(response.ExtraData["user_id"]); - return Tuple.Create(screenName, userId); } } } diff --git a/samples/DotNetOpenAuth.ApplicationBlock/YammerConsumer.cs b/samples/DotNetOpenAuth.ApplicationBlock/YammerConsumer.cs index 4bcb112..1dff5b6 100644 --- a/samples/DotNetOpenAuth.ApplicationBlock/YammerConsumer.cs +++ b/samples/DotNetOpenAuth.ApplicationBlock/YammerConsumer.cs @@ -13,12 +13,13 @@ namespace DotNetOpenAuth.ApplicationBlock { using System.Text; using System.Threading; using System.Threading.Tasks; + using System.Web; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OAuth; using DotNetOpenAuth.OAuth.ChannelElements; using DotNetOpenAuth.OAuth.Messages; - public static class YammerConsumer { + public class YammerConsumer : Consumer { /// <summary> /// The Consumer to use for accessing Google data APIs. /// </summary> @@ -28,6 +29,15 @@ namespace DotNetOpenAuth.ApplicationBlock { "https://www.yammer.com/oauth/authorize", "https://www.yammer.com/oauth/access_token"); + public YammerConsumer() { + this.ServiceProvider = ServiceDescription; + this.ConsumerKey = ConfigurationManager.AppSettings["YammerConsumerKey"]; + this.ConsumerSecret = ConfigurationManager.AppSettings["YammerConsumerSecret"]; + this.TemporaryCredentialStorage = HttpContext.Current != null + ? (ITemporaryCredentialStorage)new CookieTemporaryCredentialStorage() + : new MemoryTemporaryCredentialStorage(); + } + /// <summary> /// Gets a value indicating whether the Twitter consumer key and secret are set in the web.config file. /// </summary> @@ -37,16 +47,5 @@ namespace DotNetOpenAuth.ApplicationBlock { !string.IsNullOrEmpty(ConfigurationManager.AppSettings["yammerConsumerSecret"]); } } - - public static Consumer CreateConsumer(bool forWeb = true) { - string consumerKey = ConfigurationManager.AppSettings["yammerConsumerKey"]; - string consumerSecret = ConfigurationManager.AppSettings["yammerConsumerSecret"]; - if (IsConsumerConfigured) { - ITemporaryCredentialStorage storage = forWeb ? (ITemporaryCredentialStorage)new CookieTemporaryCredentialStorage() : new MemoryTemporaryCredentialStorage(); - return new Consumer(consumerKey, consumerSecret, ServiceDescription, storage); - } else { - throw new InvalidOperationException("No Yammer OAuth consumer key and secret could be found in web.config AppSettings."); - } - } } } diff --git a/samples/OAuthConsumer/GoogleAddressBook.aspx.cs b/samples/OAuthConsumer/GoogleAddressBook.aspx.cs index 8a2a816..4eb4101 100644 --- a/samples/OAuthConsumer/GoogleAddressBook.aspx.cs +++ b/samples/OAuthConsumer/GoogleAddressBook.aspx.cs @@ -14,50 +14,34 @@ /// A page to demonstrate downloading a Gmail address book using OAuth. /// </summary> public partial class GoogleAddressBook : System.Web.UI.Page { - private string AccessToken { - get { return (string)Session["GoogleAccessToken"]; } + private AccessToken AccessToken { + get { return (AccessToken)Session["GoogleAccessToken"]; } set { Session["GoogleAccessToken"] = value; } } - private InMemoryTokenManager TokenManager { - get { - var tokenManager = (InMemoryTokenManager)Application["GoogleTokenManager"]; - if (tokenManager == null) { - string consumerKey = ConfigurationManager.AppSettings["googleConsumerKey"]; - string consumerSecret = ConfigurationManager.AppSettings["googleConsumerSecret"]; - if (!string.IsNullOrEmpty(consumerKey)) { - tokenManager = new InMemoryTokenManager(consumerKey, consumerSecret); - Application["GoogleTokenManager"] = tokenManager; - } - } - - return tokenManager; - } - } - protected async void Page_Load(object sender, EventArgs e) { - if (this.TokenManager != null) { + var google = new GoogleConsumer(); + if (google.ConsumerKey != null) { this.MultiView1.ActiveViewIndex = 1; if (!IsPostBack) { - var google = new WebConsumer(GoogleConsumer.ServiceDescription, this.TokenManager); - // Is Google calling back with authorization? - var accessTokenResponse = await google.ProcessUserAuthorizationAsync(new HttpRequestWrapper(Request), Response.ClientDisconnectedToken); + var accessTokenResponse = await google.ProcessUserAuthorizationAsync(this.Request.Url); if (accessTokenResponse != null) { this.AccessToken = accessTokenResponse.AccessToken; - } else if (this.AccessToken == null) { + } else if (this.AccessToken.Token == null) { // If we don't yet have access, immediately request it. - await GoogleConsumer.RequestAuthorizationAsync(google, GoogleConsumer.Applications.Contacts); + Uri redirectUri = await google.RequestUserAuthorizationAsync(GoogleConsumer.Applications.Contacts); + this.Response.RedirectLocation = redirectUri.AbsoluteUri; } } } } protected async void getAddressBookButton_Click(object sender, EventArgs e) { - var google = new WebConsumer(GoogleConsumer.ServiceDescription, this.TokenManager); + var google = new GoogleConsumer(); - XDocument contactsDocument = await GoogleConsumer.GetContactsAsync(google, this.AccessToken, 5, 1, Response.ClientDisconnectedToken); + XDocument contactsDocument = await google.GetContactsAsync(this.AccessToken, 5, 1, Response.ClientDisconnectedToken); var contacts = from entry in contactsDocument.Root.Elements(XName.Get("entry", "http://www.w3.org/2005/Atom")) select new { Name = entry.Element(XName.Get("title", "http://www.w3.org/2005/Atom")).Value, Email = entry.Element(XName.Get("email", "http://schemas.google.com/g/2005")).Attribute("address").Value }; StringBuilder tableBuilder = new StringBuilder(); diff --git a/samples/OAuthConsumer/GoogleApps2Legged.aspx.cs b/samples/OAuthConsumer/GoogleApps2Legged.aspx.cs index af490cf..cff24ea 100644 --- a/samples/OAuthConsumer/GoogleApps2Legged.aspx.cs +++ b/samples/OAuthConsumer/GoogleApps2Legged.aspx.cs @@ -12,26 +12,10 @@ using DotNetOpenAuth.OAuth.Messages; public partial class GoogleApps2Legged : System.Web.UI.Page { - private InMemoryTokenManager TokenManager { - get { - var tokenManager = (InMemoryTokenManager)Application["GoogleTokenManager"]; - if (tokenManager == null) { - string consumerKey = ConfigurationManager.AppSettings["googleConsumerKey"]; - string consumerSecret = ConfigurationManager.AppSettings["googleConsumerSecret"]; - if (!string.IsNullOrEmpty(consumerKey)) { - tokenManager = new InMemoryTokenManager(consumerKey, consumerSecret); - Application["GoogleTokenManager"] = tokenManager; - } - } - - return tokenManager; - } - } - protected async void Page_Load(object sender, EventArgs e) { - var google = new WebConsumer(GoogleConsumer.ServiceDescription, this.TokenManager); - string accessToken = await google.RequestNewClientAccountAsync(cancellationToken: Response.ClientDisconnectedToken); - using (var httpClient = google.CreateHttpClient(accessToken)) { + var google = new GoogleConsumer(); + var accessToken = await google.RequestNewClientAccountAsync(); + using (var httpClient = google.CreateHttpClient(accessToken.AccessToken)) { await httpClient.GetAsync("http://someUri", Response.ClientDisconnectedToken); } } diff --git a/samples/OAuthConsumer/OAuthConsumer.csproj b/samples/OAuthConsumer/OAuthConsumer.csproj index 12553c3..94bed9c 100644 --- a/samples/OAuthConsumer/OAuthConsumer.csproj +++ b/samples/OAuthConsumer/OAuthConsumer.csproj @@ -107,9 +107,6 @@ </None> </ItemGroup> <ItemGroup> - <Compile Include="..\DotNetOpenAuth.ApplicationBlock\InMemoryTokenManager.cs"> - <Link>Code\InMemoryTokenManager.cs</Link> - </Compile> <Compile Include="Global.asax.cs"> <DependentUpon>Global.asax</DependentUpon> </Compile> diff --git a/samples/OAuthConsumer/SampleWcf.aspx.cs b/samples/OAuthConsumer/SampleWcf.aspx.cs index 9c32f59..7ea5f62 100644 --- a/samples/OAuthConsumer/SampleWcf.aspx.cs +++ b/samples/OAuthConsumer/SampleWcf.aspx.cs @@ -24,9 +24,9 @@ public partial class SampleWcf : System.Web.UI.Page { protected async void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { - if (Session["WcfTokenManager"] != null) { - WebConsumer consumer = this.CreateConsumer(); - var accessTokenMessage = await consumer.ProcessUserAuthorizationAsync(new HttpRequestWrapper(Request), Response.ClientDisconnectedToken); + var consumer = this.CreateConsumer(); + if (consumer.ConsumerKey != null) { + var accessTokenMessage = await consumer.ProcessUserAuthorizationAsync(this.Request.Url); if (accessTokenMessage != null) { Session["WcfAccessToken"] = accessTokenMessage.AccessToken; this.authorizationLabel.Text = "Authorized! Access token: " + accessTokenMessage.AccessToken; @@ -36,7 +36,7 @@ } protected async void getAuthorizationButton_Click(object sender, EventArgs e) { - WebConsumer consumer = this.CreateConsumer(); + var consumer = this.CreateConsumer(); UriBuilder callback = new UriBuilder(Request.Url); callback.Query = null; string[] scopes = (from item in this.scopeList.Items.OfType<ListItem>() @@ -44,11 +44,10 @@ select item.Value).ToArray(); string scope = string.Join("|", scopes); var requestParams = new Dictionary<string, string> { - { "scope", scope }, - }; - var response = await consumer.PrepareRequestUserAuthorizationAsync(callback.Uri, requestParams, null, Response.ClientDisconnectedToken); - var responseMessage = await consumer.Channel.PrepareResponseAsync(response, Response.ClientDisconnectedToken); - await responseMessage.SendAsync(new HttpResponseWrapper(Response), Response.ClientDisconnectedToken); + { "scope", scope }, + }; + Uri redirectUri = await consumer.RequestUserAuthorizationAsync(callback.Uri, requestParams); + this.Response.RedirectLocation = redirectUri.AbsoluteUri; } protected async void getNameButton_Click(object sender, EventArgs e) { @@ -80,16 +79,15 @@ private async Task<T> CallServiceAsync<T>(Func<DataApiClient, T> predicate) { DataApiClient client = new DataApiClient(); var serviceEndpoint = new MessageReceivingEndpoint(client.Endpoint.Address.Uri, HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.PostRequest); - var accessToken = Session["WcfAccessToken"] as string; - if (accessToken == null) { + var accessToken = (AccessToken)(Session["WcfAccessToken"] ?? default(AccessToken)); + if (accessToken.Token == null) { throw new InvalidOperationException("No access token!"); } var httpRequest = new HttpRequestMessage(HttpMethod.Post, client.Endpoint.Address.Uri); - using (WebConsumer consumer = this.CreateConsumer()) { - using (var handler = consumer.CreateMessageHandler(accessToken)) { - handler.ApplyAuthorization(httpRequest); - } + var consumer = this.CreateConsumer(); + using (var handler = consumer.CreateMessageHandler(accessToken)) { + handler.ApplyAuthorization(httpRequest); } HttpRequestMessageProperty httpDetails = new HttpRequestMessageProperty(); @@ -100,27 +98,17 @@ } } - private WebConsumer CreateConsumer() { + private Consumer CreateConsumer() { string consumerKey = "sampleconsumer"; string consumerSecret = "samplesecret"; - var tokenManager = Session["WcfTokenManager"] as InMemoryTokenManager; - if (tokenManager == null) { - tokenManager = new InMemoryTokenManager(consumerKey, consumerSecret); - Session["WcfTokenManager"] = tokenManager; - } MessageReceivingEndpoint oauthEndpoint = new MessageReceivingEndpoint( new Uri("http://localhost:65169/OAuth.ashx"), HttpDeliveryMethods.PostRequest); - WebConsumer consumer = new WebConsumer( - new ServiceProviderDescription { - RequestTokenEndpoint = oauthEndpoint, - UserAuthorizationEndpoint = oauthEndpoint, - AccessTokenEndpoint = oauthEndpoint, - TamperProtectionElements = new DotNetOpenAuth.Messaging.ITamperProtectionChannelBindingElement[] { - new HmacSha1SigningBindingElement(), - }, - }, - tokenManager); + var consumer = new Consumer( + consumerKey, + consumerSecret, + new ServiceProviderDescription(oauthEndpoint.Location.AbsoluteUri, oauthEndpoint.Location.AbsoluteUri, oauthEndpoint.Location.AbsoluteUri), + new CookieTemporaryCredentialStorage()); return consumer; } diff --git a/samples/OAuthConsumer/SignInWithTwitter.aspx.cs b/samples/OAuthConsumer/SignInWithTwitter.aspx.cs index f90d557..d34c0a5 100644 --- a/samples/OAuthConsumer/SignInWithTwitter.aspx.cs +++ b/samples/OAuthConsumer/SignInWithTwitter.aspx.cs @@ -19,7 +19,7 @@ this.MultiView1.ActiveViewIndex = 1; if (!IsPostBack) { - var tuple = await TwitterConsumer.TryFinishSignInWithTwitterAsync(Response.ClientDisconnectedToken); + var tuple = await TwitterConsumer.TryFinishSignInWithTwitterAsync(); if (tuple != null) { string screenName = tuple.Item1; int userId = tuple.Item2; @@ -35,8 +35,8 @@ } protected async void signInButton_Click(object sender, ImageClickEventArgs e) { - var response = await TwitterConsumer.StartSignInWithTwitterAsync(this.forceLoginCheckbox.Checked, Response.ClientDisconnectedToken); - await response.SendAsync(); + Uri redirectUrl = await TwitterConsumer.StartSignInWithTwitterAsync(this.forceLoginCheckbox.Checked, Response.ClientDisconnectedToken); + this.Response.RedirectLocation = redirectUrl.AbsoluteUri; } } }
\ No newline at end of file diff --git a/samples/OAuthConsumer/Twitter.aspx.cs b/samples/OAuthConsumer/Twitter.aspx.cs index 6ff6993..e107928 100644 --- a/samples/OAuthConsumer/Twitter.aspx.cs +++ b/samples/OAuthConsumer/Twitter.aspx.cs @@ -14,51 +14,33 @@ using DotNetOpenAuth.OAuth; public partial class Twitter : System.Web.UI.Page { - private string AccessToken { - get { return (string)Session["TwitterAccessToken"]; } + private AccessToken AccessToken { + get { return (AccessToken)Session["TwitterAccessToken"]; } set { Session["TwitterAccessToken"] = value; } } - private InMemoryTokenManager TokenManager { - get { - var tokenManager = (InMemoryTokenManager)Application["TwitterTokenManager"]; - if (tokenManager == null) { - string consumerKey = ConfigurationManager.AppSettings["twitterConsumerKey"]; - string consumerSecret = ConfigurationManager.AppSettings["twitterConsumerSecret"]; - if (!string.IsNullOrEmpty(consumerKey)) { - tokenManager = new InMemoryTokenManager(consumerKey, consumerSecret); - Application["TwitterTokenManager"] = tokenManager; - } - } - - return tokenManager; - } - } - protected async void Page_Load(object sender, EventArgs e) { - if (this.TokenManager != null) { + var twitter = new TwitterConsumer(); + if (twitter.ConsumerKey != null) { this.MultiView1.ActiveViewIndex = 1; if (!IsPostBack) { - var twitter = new WebConsumer(TwitterConsumer.ServiceDescription, this.TokenManager); - // Is Twitter calling back with authorization? - var accessTokenResponse = await twitter.ProcessUserAuthorizationAsync(new HttpRequestWrapper(Request), Response.ClientDisconnectedToken); + var accessTokenResponse = await twitter.ProcessUserAuthorizationAsync(this.Request.Url); if (accessTokenResponse != null) { this.AccessToken = accessTokenResponse.AccessToken; - } else if (this.AccessToken == null) { + } else { // If we don't yet have access, immediately request it. - var message = await twitter.PrepareRequestUserAuthorizationAsync(Response.ClientDisconnectedToken); - var response = await twitter.Channel.PrepareResponseAsync(message, Response.ClientDisconnectedToken); - await response.SendAsync(); + Uri redirectUrl = await twitter.RequestUserAuthorizationAsync(MessagingUtilities.GetPublicFacingUrl()); + this.Response.RedirectLocation = redirectUrl.AbsoluteUri; } } } } protected async void downloadUpdates_Click(object sender, EventArgs e) { - var twitter = new WebConsumer(TwitterConsumer.ServiceDescription, this.TokenManager); - var statusesJson = await TwitterConsumer.GetUpdatesAsync(twitter, this.AccessToken, Response.ClientDisconnectedToken); + var twitter = new TwitterConsumer(); + var statusesJson = await twitter.GetUpdatesAsync(this.AccessToken); StringBuilder tableBuilder = new StringBuilder(); tableBuilder.Append("<table><tr><td>Name</td><td>Update</td></tr>"); @@ -83,13 +65,11 @@ return; } - var twitter = new WebConsumer(TwitterConsumer.ServiceDescription, this.TokenManager); - XDocument imageResult = await TwitterConsumer.UpdateProfileImageAsync( - twitter, + var twitter = new TwitterConsumer(); + XDocument imageResult = await twitter.UpdateProfileImageAsync( this.AccessToken, this.profilePhoto.PostedFile.InputStream, - this.profilePhoto.PostedFile.ContentType, - Response.ClientDisconnectedToken); + this.profilePhoto.PostedFile.ContentType); this.photoUploadedLabel.Visible = true; } } diff --git a/samples/OAuthConsumer/Yammer.aspx.cs b/samples/OAuthConsumer/Yammer.aspx.cs index 57169fc..b1031ae 100644 --- a/samples/OAuthConsumer/Yammer.aspx.cs +++ b/samples/OAuthConsumer/Yammer.aspx.cs @@ -11,48 +11,27 @@ using DotNetOpenAuth.OAuth; public partial class Yammer : System.Web.UI.Page { - private string RequestToken { - get { return (string)ViewState["YammerRequestToken"]; } - set { ViewState["YammerRequestToken"] = value; } - } - - private string AccessToken { - get { return (string)Session["YammerAccessToken"]; } + private AccessToken AccessToken { + get { return (AccessToken)Session["YammerAccessToken"]; } set { Session["YammerAccessToken"] = value; } } - private InMemoryTokenManager TokenManager { - get { - var tokenManager = (InMemoryTokenManager)Application["YammerTokenManager"]; - if (tokenManager == null) { - string consumerKey = ConfigurationManager.AppSettings["YammerConsumerKey"]; - string consumerSecret = ConfigurationManager.AppSettings["YammerConsumerSecret"]; - if (!string.IsNullOrEmpty(consumerKey)) { - tokenManager = new InMemoryTokenManager(consumerKey, consumerSecret); - Application["YammerTokenManager"] = tokenManager; - } - } - - return tokenManager; - } - } - protected void Page_Load(object sender, EventArgs e) { - if (this.TokenManager != null) { + var yammer = new YammerConsumer(); + if (yammer.ConsumerKey != null) { this.MultiView1.SetActiveView(this.BeginAuthorizationView); } } protected void getYammerMessages_Click(object sender, EventArgs e) { - var yammer = new WebConsumer(YammerConsumer.ServiceDescription, this.TokenManager); + var yammer = new YammerConsumer(); + + // TODO: code here } protected async void obtainAuthorizationButton_Click(object sender, EventArgs e) { - var yammer = YammerConsumer.CreateConsumer(this.TokenManager); - var tuple = await YammerConsumer.PrepareRequestAuthorizationAsync(yammer, Response.ClientDisconnectedToken); - Uri popupWindowLocation = tuple.Item1; - string requestToken = tuple.Item2; - this.RequestToken = requestToken; + var yammer = new YammerConsumer(); + Uri popupWindowLocation = await yammer.RequestUserAuthorizationAsync(MessagingUtilities.GetPublicFacingUrl()); string javascript = "window.open('" + popupWindowLocation.AbsoluteUri + "');"; this.Page.ClientScript.RegisterStartupScript(GetType(), "YammerPopup", javascript, true); this.MultiView1.SetActiveView(this.CompleteAuthorizationView); @@ -63,8 +42,8 @@ return; } - var yammer = YammerConsumer.CreateConsumer(this.TokenManager); - var authorizationResponse = await YammerConsumer.CompleteAuthorizationAsync(yammer, this.RequestToken, this.yammerUserCode.Text, Response.ClientDisconnectedToken); + var yammer = new YammerConsumer(); + var authorizationResponse = await yammer.ProcessUserAuthorizationAsync(this.yammerUserCode.Text); if (authorizationResponse != null) { this.accessTokenLabel.Text = HttpUtility.HtmlEncode(authorizationResponse.AccessToken); this.MultiView1.SetActiveView(this.AuthorizationCompleteView); diff --git a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs index 501b5b2..38abe4a 100644 --- a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs +++ b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs @@ -393,6 +393,15 @@ namespace DotNetOpenAuth.Messaging { } /// <summary> + /// Gets the public facing URL for the given incoming HTTP request. + /// </summary> + /// <returns>The URI that the outside world used to create this request.</returns> + public static Uri GetPublicFacingUrl() { + ErrorUtilities.VerifyHttpContext(); + return GetPublicFacingUrl(new HttpRequestWrapper(HttpContext.Current.Request)); + } + + /// <summary> /// Wraps a response message as an MVC <see cref="ActionResult"/> so it can be conveniently returned from an MVC controller's action method. /// </summary> /// <param name="response">The response message.</param> diff --git a/src/DotNetOpenAuth.OAuth.Consumer/DotNetOpenAuth.OAuth.Consumer.csproj b/src/DotNetOpenAuth.OAuth.Consumer/DotNetOpenAuth.OAuth.Consumer.csproj index fe14abc..173bb3e 100644 --- a/src/DotNetOpenAuth.OAuth.Consumer/DotNetOpenAuth.OAuth.Consumer.csproj +++ b/src/DotNetOpenAuth.OAuth.Consumer/DotNetOpenAuth.OAuth.Consumer.csproj @@ -29,6 +29,7 @@ <Compile Include="OAuth\OAuth1HttpMessageHandlerBase.cs" /> <Compile Include="OAuth\OAuth1PlainTextMessageHandler.cs" /> <Compile Include="OAuth\OAuth1RsaSha1HttpMessageHandler.cs" /> + <Compile Include="OAuth\ServiceProviderDescription.cs" /> <Compile Include="Properties\AssemblyInfo.cs"> <SubType> </SubType> diff --git a/src/DotNetOpenAuth.OAuth/OAuth/ServiceProviderDescription.cs b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ServiceProviderDescription.cs index e6a2b32..e6a2b32 100644 --- a/src/DotNetOpenAuth.OAuth/OAuth/ServiceProviderDescription.cs +++ b/src/DotNetOpenAuth.OAuth.Consumer/OAuth/ServiceProviderDescription.cs diff --git a/src/DotNetOpenAuth.OAuth.ServiceProvider/DotNetOpenAuth.OAuth.ServiceProvider.csproj b/src/DotNetOpenAuth.OAuth.ServiceProvider/DotNetOpenAuth.OAuth.ServiceProvider.csproj index 059f025..fd2aa9e 100644 --- a/src/DotNetOpenAuth.OAuth.ServiceProvider/DotNetOpenAuth.OAuth.ServiceProvider.csproj +++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/DotNetOpenAuth.OAuth.ServiceProvider.csproj @@ -32,6 +32,7 @@ <Compile Include="OAuth\ChannelElements\StandardTokenGenerator.cs" /> <Compile Include="OAuth\ChannelElements\TokenHandlingBindingElement.cs" /> <Compile Include="OAuth\ServiceProvider.cs" /> + <Compile Include="OAuth\ServiceProviderHostDescription.cs" /> <Compile Include="OAuth\VerificationCodeFormat.cs" /> <Compile Include="Properties\AssemblyInfo.cs"> <SubType> diff --git a/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ServiceProvider.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ServiceProvider.cs index de7ff7c..936bdaa 100644 --- a/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ServiceProvider.cs +++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ServiceProvider.cs @@ -55,7 +55,7 @@ namespace DotNetOpenAuth.OAuth { /// </summary> /// <param name="serviceDescription">The endpoints and behavior on the Service Provider.</param> /// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param> - public ServiceProvider(ServiceProviderDescription serviceDescription, IServiceProviderTokenManager tokenManager) + public ServiceProvider(ServiceProviderHostDescription serviceDescription, IServiceProviderTokenManager tokenManager) : this(serviceDescription, tokenManager, new OAuthServiceProviderMessageFactory(tokenManager)) { } @@ -65,7 +65,7 @@ namespace DotNetOpenAuth.OAuth { /// <param name="serviceDescription">The endpoints and behavior on the Service Provider.</param> /// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param> /// <param name="messageTypeProvider">An object that can figure out what type of message is being received for deserialization.</param> - public ServiceProvider(ServiceProviderDescription serviceDescription, IServiceProviderTokenManager tokenManager, OAuthServiceProviderMessageFactory messageTypeProvider) + public ServiceProvider(ServiceProviderHostDescription serviceDescription, IServiceProviderTokenManager tokenManager, OAuthServiceProviderMessageFactory messageTypeProvider) : this(serviceDescription, tokenManager, OAuthElement.Configuration.ServiceProvider.ApplicationStore.CreateInstance(GetHttpApplicationStore(), null), messageTypeProvider) { Requires.NotNull(serviceDescription, "serviceDescription"); Requires.NotNull(tokenManager, "tokenManager"); @@ -78,7 +78,7 @@ namespace DotNetOpenAuth.OAuth { /// <param name="serviceDescription">The endpoints and behavior on the Service Provider.</param> /// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param> /// <param name="nonceStore">The nonce store.</param> - public ServiceProvider(ServiceProviderDescription serviceDescription, IServiceProviderTokenManager tokenManager, INonceStore nonceStore) + public ServiceProvider(ServiceProviderHostDescription serviceDescription, IServiceProviderTokenManager tokenManager, INonceStore nonceStore) : this(serviceDescription, tokenManager, nonceStore, new OAuthServiceProviderMessageFactory(tokenManager)) { } @@ -89,7 +89,7 @@ namespace DotNetOpenAuth.OAuth { /// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param> /// <param name="nonceStore">The nonce store.</param> /// <param name="messageTypeProvider">An object that can figure out what type of message is being received for deserialization.</param> - public ServiceProvider(ServiceProviderDescription serviceDescription, IServiceProviderTokenManager tokenManager, INonceStore nonceStore, OAuthServiceProviderMessageFactory messageTypeProvider) { + public ServiceProvider(ServiceProviderHostDescription serviceDescription, IServiceProviderTokenManager tokenManager, INonceStore nonceStore, OAuthServiceProviderMessageFactory messageTypeProvider) { Requires.NotNull(serviceDescription, "serviceDescription"); Requires.NotNull(tokenManager, "tokenManager"); Requires.NotNull(nonceStore, "nonceStore"); @@ -107,7 +107,7 @@ namespace DotNetOpenAuth.OAuth { /// <summary> /// Gets the description of this Service Provider. /// </summary> - public ServiceProviderDescription ServiceDescription { get; private set; } + public ServiceProviderHostDescription ServiceDescription { get; private set; } /// <summary> /// Gets or sets the generator responsible for generating new tokens and secrets. diff --git a/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ServiceProviderHostDescription.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ServiceProviderHostDescription.cs new file mode 100644 index 0000000..33834eb --- /dev/null +++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuth/ServiceProviderHostDescription.cs @@ -0,0 +1,101 @@ +//----------------------------------------------------------------------- +// <copyright file="ServiceProviderHostDescription.cs" company="Outercurve Foundation"> +// Copyright (c) Outercurve Foundation. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth { + using System; + using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; + using System.Linq; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuth.ChannelElements; + + /// <summary> + /// A description of the endpoints on a Service Provider. + /// </summary> + public class ServiceProviderHostDescription { + /// <summary> + /// The field used to store the value of the <see cref="RequestTokenEndpoint"/> property. + /// </summary> + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private MessageReceivingEndpoint requestTokenEndpoint; + + /// <summary> + /// Initializes a new instance of the <see cref="ServiceProviderHostDescription"/> class. + /// </summary> + public ServiceProviderHostDescription() { + this.ProtocolVersion = Protocol.Default.ProtocolVersion; + } + + /// <summary> + /// Gets or sets the OAuth version supported by the Service Provider. + /// </summary> + public ProtocolVersion ProtocolVersion { get; set; } + + /// <summary> + /// Gets or sets the URL used to obtain an unauthorized Request Token, + /// described in Section 6.1 (Obtaining an Unauthorized Request Token). + /// </summary> + /// <remarks> + /// The request URL query MUST NOT contain any OAuth Protocol Parameters. + /// This is the URL that <see cref="OAuth.Messages.UnauthorizedTokenRequest"/> messages are directed to. + /// </remarks> + /// <exception cref="ArgumentException">Thrown if this property is set to a URI with OAuth protocol parameters.</exception> + public MessageReceivingEndpoint RequestTokenEndpoint { + get { + return this.requestTokenEndpoint; + } + + set { + if (value != null && UriUtil.QueryStringContainPrefixedParameters(value.Location, OAuth.Protocol.ParameterPrefix)) { + throw new ArgumentException(OAuthStrings.RequestUrlMustNotHaveOAuthParameters); + } + + this.requestTokenEndpoint = value; + } + } + + /// <summary> + /// Gets or sets the URL used to obtain User authorization for Consumer access, + /// described in Section 6.2 (Obtaining User Authorization). + /// </summary> + /// <remarks> + /// This is the URL that <see cref="OAuth.Messages.UserAuthorizationRequest"/> messages are + /// indirectly (via the user agent) sent to. + /// </remarks> + public MessageReceivingEndpoint UserAuthorizationEndpoint { get; set; } + + /// <summary> + /// Gets or sets the URL used to exchange the User-authorized Request Token + /// for an Access Token, described in Section 6.3 (Obtaining an Access Token). + /// </summary> + /// <remarks> + /// This is the URL that <see cref="OAuth.Messages.AuthorizedTokenRequest"/> messages are directed to. + /// </remarks> + public MessageReceivingEndpoint AccessTokenEndpoint { get; set; } + + /// <summary> + /// Gets or sets the signing policies that apply to this Service Provider. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "Type initializers require this format.")] + public ITamperProtectionChannelBindingElement[] TamperProtectionElements { get; set; } + + /// <summary> + /// Gets the OAuth version supported by the Service Provider. + /// </summary> + internal Version Version { + get { return Protocol.Lookup(this.ProtocolVersion).Version; } + } + + /// <summary> + /// Creates a signing element that includes all the signing elements this service provider supports. + /// </summary> + /// <returns>The created signing element.</returns> + internal ITamperProtectionChannelBindingElement CreateTamperProtectionElement() { + RequiresEx.ValidState(this.TamperProtectionElements != null); + return new SigningBindingElementChain(this.TamperProtectionElements.Select(el => (ITamperProtectionChannelBindingElement)el.Clone()).ToArray()); + } + } +} diff --git a/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuthReporting.cs b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuthReporting.cs index aa3f934..8171e1a 100644 --- a/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuthReporting.cs +++ b/src/DotNetOpenAuth.OAuth.ServiceProvider/OAuthReporting.cs @@ -25,7 +25,7 @@ namespace DotNetOpenAuth { /// <param name="service">The service.</param> /// <param name="tokenManager">The token manager.</param> /// <param name="nonceStore">The nonce store.</param> - internal static void RecordFeatureAndDependencyUse(object value, ServiceProviderDescription service, ITokenManager tokenManager, INonceStore nonceStore) { + internal static void RecordFeatureAndDependencyUse(object value, ServiceProviderHostDescription service, ITokenManager tokenManager, INonceStore nonceStore) { Requires.NotNull(value, "value"); Requires.NotNull(service, "service"); Requires.NotNull(tokenManager, "tokenManager"); @@ -45,7 +45,7 @@ namespace DotNetOpenAuth { builder.Append(nonceStore.GetType().Name); } builder.Append(" "); - builder.Append(service.ResourceOwnerAuthorizationEndpoint); + builder.Append(service.UserAuthorizationEndpoint.Location); Reporting.ObservedFeatures.Add(builder.ToString()); Reporting.Touch(); } diff --git a/src/DotNetOpenAuth.OAuth/DotNetOpenAuth.OAuth.csproj b/src/DotNetOpenAuth.OAuth/DotNetOpenAuth.OAuth.csproj index 8524a78..af9aea9 100644 --- a/src/DotNetOpenAuth.OAuth/DotNetOpenAuth.OAuth.csproj +++ b/src/DotNetOpenAuth.OAuth/DotNetOpenAuth.OAuth.csproj @@ -44,7 +44,6 @@ <Compile Include="OAuth\Messages\ITokenContainingMessage.cs" /> <Compile Include="OAuth\Messages\SignedMessageBase.cs" /> <Compile Include="OAuth\ChannelElements\SigningBindingElementBase.cs" /> - <Compile Include="OAuth\ServiceProviderDescription.cs" /> <Compile Include="OAuth\ServiceProviderSecuritySettings.cs" /> <Compile Include="OAuth\ChannelElements\ITamperResistantOAuthMessage.cs" /> <Compile Include="OAuth\Messages\MessageBase.cs" /> diff --git a/src/DotNetOpenAuth.OpenIdOAuth/OAuth/ServiceProviderOpenIdProvider.cs b/src/DotNetOpenAuth.OpenIdOAuth/OAuth/ServiceProviderOpenIdProvider.cs index f827857..1c0c5fb 100644 --- a/src/DotNetOpenAuth.OpenIdOAuth/OAuth/ServiceProviderOpenIdProvider.cs +++ b/src/DotNetOpenAuth.OpenIdOAuth/OAuth/ServiceProviderOpenIdProvider.cs @@ -41,7 +41,7 @@ namespace DotNetOpenAuth.OAuth { /// </summary> /// <param name="serviceDescription">The endpoints and behavior on the Service Provider.</param> /// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param> - public ServiceProviderOpenIdProvider(ServiceProviderDescription serviceDescription, IServiceProviderTokenManager tokenManager) + public ServiceProviderOpenIdProvider(ServiceProviderHostDescription serviceDescription, IServiceProviderTokenManager tokenManager) : base(serviceDescription, tokenManager) { } @@ -51,7 +51,7 @@ namespace DotNetOpenAuth.OAuth { /// <param name="serviceDescription">The service description.</param> /// <param name="tokenManager">The token manager.</param> /// <param name="messageTypeProvider">The message type provider.</param> - public ServiceProviderOpenIdProvider(ServiceProviderDescription serviceDescription, IServiceProviderTokenManager tokenManager, OAuthServiceProviderMessageFactory messageTypeProvider) + public ServiceProviderOpenIdProvider(ServiceProviderHostDescription serviceDescription, IServiceProviderTokenManager tokenManager, OAuthServiceProviderMessageFactory messageTypeProvider) : base(serviceDescription, tokenManager, messageTypeProvider) { } @@ -61,7 +61,7 @@ namespace DotNetOpenAuth.OAuth { /// <param name="serviceDescription">The service description.</param> /// <param name="tokenManager">The token manager.</param> /// <param name="nonceStore">The nonce store.</param> - public ServiceProviderOpenIdProvider(ServiceProviderDescription serviceDescription, IServiceProviderTokenManager tokenManager, INonceStore nonceStore) + public ServiceProviderOpenIdProvider(ServiceProviderHostDescription serviceDescription, IServiceProviderTokenManager tokenManager, INonceStore nonceStore) : base(serviceDescription, tokenManager, nonceStore) { } @@ -72,7 +72,7 @@ namespace DotNetOpenAuth.OAuth { /// <param name="tokenManager">The token manager.</param> /// <param name="nonceStore">The nonce store.</param> /// <param name="messageTypeProvider">The message type provider.</param> - public ServiceProviderOpenIdProvider(ServiceProviderDescription serviceDescription, IServiceProviderTokenManager tokenManager, INonceStore nonceStore, OAuthServiceProviderMessageFactory messageTypeProvider) + public ServiceProviderOpenIdProvider(ServiceProviderHostDescription serviceDescription, IServiceProviderTokenManager tokenManager, INonceStore nonceStore, OAuthServiceProviderMessageFactory messageTypeProvider) : base(serviceDescription, tokenManager, nonceStore, messageTypeProvider) { } |