diff options
Diffstat (limited to 'samples/DotNetOpenAuth.ApplicationBlock/OAuth1')
3 files changed, 573 insertions, 0 deletions
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/OAuth1/GoogleConsumer.cs b/samples/DotNetOpenAuth.ApplicationBlock/OAuth1/GoogleConsumer.cs new file mode 100644 index 0000000..1bdb04d --- /dev/null +++ b/samples/DotNetOpenAuth.ApplicationBlock/OAuth1/GoogleConsumer.cs @@ -0,0 +1,288 @@ +//----------------------------------------------------------------------- +// <copyright file="GoogleConsumer.cs" company="Outercurve Foundation"> +// Copyright (c) Outercurve Foundation. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.ApplicationBlock { + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Globalization; + using System.IO; + using System.Linq; + using System.Net; + using System.Security.Cryptography.X509Certificates; + using System.Text; + using System.Text.RegularExpressions; + using System.Xml; + using System.Xml.Linq; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuth; + using DotNetOpenAuth.OAuth.ChannelElements; + + /// <summary> + /// A consumer capable of communicating with Google Data APIs. + /// </summary> + public static class GoogleConsumer { + /// <summary> + /// The Consumer to use for accessing Google data APIs. + /// </summary> + public static readonly ServiceProviderDescription ServiceDescription = new ServiceProviderDescription { + RequestTokenEndpoint = new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthGetRequestToken", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest), + UserAuthorizationEndpoint = new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthAuthorizeToken", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest), + AccessTokenEndpoint = new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthGetAccessToken", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest), + TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() }, + }; + + /// <summary> + /// A mapping between Google's applications and their URI scope values. + /// </summary> + private static readonly Dictionary<Applications, string> DataScopeUris = new Dictionary<Applications, string> { + { Applications.Analytics, "https://www.google.com/analytics/feeds/" }, + { Applications.GoogleBase, "http://www.google.com/base/feeds/" }, + { Applications.Blogger, "http://www.blogger.com/feeds" }, + { Applications.BookSearch, "http://www.google.com/books/feeds/" }, + { Applications.Calendar, "http://www.google.com/calendar/feeds/" }, + { Applications.Contacts, "http://www.google.com/m8/feeds/" }, + { Applications.DocumentsList, "http://docs.google.com/feeds/" }, + { Applications.Finance, "http://finance.google.com/finance/feeds/" }, + { Applications.Gmail, "https://mail.google.com/mail/feed/atom" }, + { Applications.Health, "https://www.google.com/h9/feeds/" }, + { Applications.Maps, "http://maps.google.com/maps/feeds/" }, + { Applications.OpenSocial, "http://sandbox.gmodules.com/api/" }, + { Applications.PicasaWeb, "http://picasaweb.google.com/data/" }, + { Applications.Spreadsheets, "http://spreadsheets.google.com/feeds/" }, + { Applications.WebmasterTools, "http://www.google.com/webmasters/tools/feeds/" }, + { Applications.YouTube, "http://gdata.youtube.com" }, + }; + + /// <summary> + /// The URI to get contacts once authorization is granted. + /// </summary> + private static readonly MessageReceivingEndpoint GetContactsEndpoint = new MessageReceivingEndpoint("http://www.google.com/m8/feeds/contacts/default/full/", HttpDeliveryMethods.GetRequest); + + /// <summary> + /// The many specific authorization scopes Google offers. + /// </summary> + [Flags] + public enum Applications : long { + /// <summary> + /// The Gmail address book. + /// </summary> + Contacts = 0x1, + + /// <summary> + /// Appointments in Google Calendar. + /// </summary> + Calendar = 0x2, + + /// <summary> + /// Blog post authoring. + /// </summary> + Blogger = 0x4, + + /// <summary> + /// Google Finance + /// </summary> + Finance = 0x8, + + /// <summary> + /// Google Gmail + /// </summary> + Gmail = 0x10, + + /// <summary> + /// Google Health + /// </summary> + Health = 0x20, + + /// <summary> + /// Google OpenSocial + /// </summary> + OpenSocial = 0x40, + + /// <summary> + /// Picasa Web + /// </summary> + PicasaWeb = 0x80, + + /// <summary> + /// Google Spreadsheets + /// </summary> + Spreadsheets = 0x100, + + /// <summary> + /// Webmaster Tools + /// </summary> + WebmasterTools = 0x200, + + /// <summary> + /// YouTube service + /// </summary> + YouTube = 0x400, + + /// <summary> + /// Google Docs + /// </summary> + DocumentsList = 0x800, + + /// <summary> + /// Google Book Search + /// </summary> + BookSearch = 0x1000, + + /// <summary> + /// Google Base + /// </summary> + GoogleBase = 0x2000, + + /// <summary> + /// Google Analytics + /// </summary> + Analytics = 0x4000, + + /// <summary> + /// Google Maps + /// </summary> + Maps = 0x8000, + } + + /// <summary> + /// The service description to use for accessing Google data APIs using an X509 certificate. + /// </summary> + /// <param name="signingCertificate">The signing certificate.</param> + /// <returns>A service description that can be used to create an instance of + /// <see cref="DesktopConsumer"/> or <see cref="WebConsumer"/>. </returns> + public static ServiceProviderDescription CreateRsaSha1ServiceDescription(X509Certificate2 signingCertificate) { + if (signingCertificate == null) { + throw new ArgumentNullException("signingCertificate"); + } + + return new ServiceProviderDescription { + RequestTokenEndpoint = new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthGetRequestToken", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest), + UserAuthorizationEndpoint = new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthAuthorizeToken", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest), + AccessTokenEndpoint = new MessageReceivingEndpoint("https://www.google.com/accounts/OAuthGetAccessToken", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest), + TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new RsaSha1ConsumerSigningBindingElement(signingCertificate) }, + }; + } + + /// <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> + public static void RequestAuthorization(WebConsumer consumer, Applications requestedAccessScope) { + if (consumer == null) { + throw new ArgumentNullException("consumer"); + } + + var extraParameters = new Dictionary<string, string> { + { "scope", GetScopeUri(requestedAccessScope) }, + }; + Uri callback = Util.GetCallbackUrlFromContext(); + var request = consumer.PrepareRequestUserAuthorization(callback, extraParameters, null); + consumer.Channel.Send(request); + } + + /// <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="requestToken">The unauthorized request token assigned by Google.</param> + /// <returns>The request token</returns> + public static Uri RequestAuthorization(DesktopConsumer consumer, Applications requestedAccessScope, out string requestToken) { + if (consumer == null) { + throw new ArgumentNullException("consumer"); + } + + var extraParameters = new Dictionary<string, string> { + { "scope", GetScopeUri(requestedAccessScope) }, + }; + + return consumer.RequestUserAuthorization(extraParameters, null, out requestToken); + } + + /// <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> + /// <returns>An XML document returned by Google.</returns> + public static XDocument GetContacts(ConsumerBase consumer, string accessToken, int maxResults/* = 25*/, int startIndex/* = 1*/) { + if (consumer == null) { + throw new ArgumentNullException("consumer"); + } + + var extraData = new Dictionary<string, string>() { + { "start-index", startIndex.ToString(CultureInfo.InvariantCulture) }, + { "max-results", maxResults.ToString(CultureInfo.InvariantCulture) }, + }; + var request = consumer.PrepareAuthorizedRequest(GetContactsEndpoint, accessToken, extraData); + + // Enable gzip compression. Google only compresses the response for recognized user agent headers. - Mike Lim + request.AutomaticDecompression = DecompressionMethods.GZip; + request.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.151 Safari/534.16"; + + var response = consumer.Channel.WebRequestHandler.GetResponse(request); + string body = response.GetResponseReader().ReadToEnd(); + XDocument result = XDocument.Parse(body); + return result; + } + + public static void PostBlogEntry(ConsumerBase consumer, string accessToken, string blogUrl, string title, XElement body) { + string feedUrl; + var getBlogHome = WebRequest.Create(blogUrl); + using (var blogHomeResponse = getBlogHome.GetResponse()) { + using (StreamReader sr = new StreamReader(blogHomeResponse.GetResponseStream())) { + string homePageHtml = sr.ReadToEnd(); + Match m = Regex.Match(homePageHtml, @"http://www.blogger.com/feeds/\d+/posts/default"); + Debug.Assert(m.Success, "Posting operation failed."); + feedUrl = m.Value; + } + } + const string Atom = "http://www.w3.org/2005/Atom"; + XElement entry = new XElement( + XName.Get("entry", Atom), + new XElement(XName.Get("title", Atom), new XAttribute("type", "text"), title), + new XElement(XName.Get("content", Atom), new XAttribute("type", "xhtml"), body), + new XElement(XName.Get("category", Atom), new XAttribute("scheme", "http://www.blogger.com/atom/ns#"), new XAttribute("term", "oauthdemo"))); + + MemoryStream ms = new MemoryStream(); + XmlWriterSettings xws = new XmlWriterSettings() { + Encoding = Encoding.UTF8, + }; + XmlWriter xw = XmlWriter.Create(ms, xws); + entry.WriteTo(xw); + xw.Flush(); + + WebRequest request = consumer.PrepareAuthorizedRequest(new MessageReceivingEndpoint(feedUrl, HttpDeliveryMethods.PostRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), accessToken); + request.ContentType = "application/atom+xml"; + request.Method = "POST"; + request.ContentLength = ms.Length; + ms.Seek(0, SeekOrigin.Begin); + using (Stream requestStream = request.GetRequestStream()) { + ms.CopyTo(requestStream); + } + using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { + if (response.StatusCode == HttpStatusCode.Created) { + // Success + } else { + // Error! + } + } + } + + /// <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/OAuth1/TwitterConsumer.cs b/samples/DotNetOpenAuth.ApplicationBlock/OAuth1/TwitterConsumer.cs new file mode 100644 index 0000000..013e66b --- /dev/null +++ b/samples/DotNetOpenAuth.ApplicationBlock/OAuth1/TwitterConsumer.cs @@ -0,0 +1,224 @@ +//----------------------------------------------------------------------- +// <copyright file="TwitterConsumer.cs" company="Outercurve Foundation"> +// Copyright (c) Outercurve Foundation. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.ApplicationBlock { + using System; + using System.Collections.Generic; + using System.Configuration; + using System.Globalization; + using System.IO; + using System.Net; + using System.Web; + using System.Xml; + using System.Xml.Linq; + using System.Xml.XPath; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuth; + using DotNetOpenAuth.OAuth.ChannelElements; + + /// <summary> + /// A consumer capable of communicating with Twitter. + /// </summary> + public static class TwitterConsumer { + /// <summary> + /// The description of Twitter's OAuth protocol URIs for use with actually reading/writing + /// a user's private Twitter data. + /// </summary> + public static readonly ServiceProviderDescription ServiceDescription = new ServiceProviderDescription { + RequestTokenEndpoint = new MessageReceivingEndpoint("http://twitter.com/oauth/request_token", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), + UserAuthorizationEndpoint = new MessageReceivingEndpoint("http://twitter.com/oauth/authorize", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), + AccessTokenEndpoint = new MessageReceivingEndpoint("http://twitter.com/oauth/access_token", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), + TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() }, + }; + + /// <summary> + /// The description of Twitter's OAuth protocol URIs for use with their "Sign in with Twitter" feature. + /// </summary> + public static readonly ServiceProviderDescription SignInWithTwitterServiceDescription = new ServiceProviderDescription { + RequestTokenEndpoint = new MessageReceivingEndpoint("http://twitter.com/oauth/request_token", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), + UserAuthorizationEndpoint = new MessageReceivingEndpoint("http://twitter.com/oauth/authenticate", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), + AccessTokenEndpoint = new MessageReceivingEndpoint("http://twitter.com/oauth/access_token", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), + TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() }, + }; + + /// <summary> + /// The URI to get a user's favorites. + /// </summary> + private static readonly MessageReceivingEndpoint GetFavoritesEndpoint = new MessageReceivingEndpoint("http://twitter.com/favorites.xml", HttpDeliveryMethods.GetRequest); + + /// <summary> + /// The URI to get the data on the user's home page. + /// </summary> + private static readonly MessageReceivingEndpoint GetFriendTimelineStatusEndpoint = new MessageReceivingEndpoint("http://twitter.com/statuses/friends_timeline.xml", HttpDeliveryMethods.GetRequest); + + private static readonly MessageReceivingEndpoint UpdateProfileBackgroundImageEndpoint = new MessageReceivingEndpoint("http://twitter.com/account/update_profile_background_image.xml", HttpDeliveryMethods.PostRequest | HttpDeliveryMethods.AuthorizationHeaderRequest); + + private static readonly MessageReceivingEndpoint UpdateProfileImageEndpoint = new MessageReceivingEndpoint("http://twitter.com/account/update_profile_image.xml", HttpDeliveryMethods.PostRequest | HttpDeliveryMethods.AuthorizationHeaderRequest); + + private static readonly MessageReceivingEndpoint VerifyCredentialsEndpoint = new MessageReceivingEndpoint("http://api.twitter.com/1/account/verify_credentials.xml", HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest); + + /// <summary> + /// The consumer used for the Sign in to Twitter feature. + /// </summary> + private static WebConsumer signInConsumer; + + /// <summary> + /// The lock acquired to initialize the <see cref="signInConsumer"/> field. + /// </summary> + private static object signInConsumerInitLock = new object(); + + /// <summary> + /// Initializes static members of the <see cref="TwitterConsumer"/> class. + /// </summary> + static TwitterConsumer() { + // Twitter can't handle the Expect 100 Continue HTTP header. + ServicePointManager.FindServicePoint(GetFavoritesEndpoint.Location).Expect100Continue = false; + } + + /// <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"]); + } + } + + /// <summary> + /// Gets the consumer to use for the Sign in to Twitter feature. + /// </summary> + /// <value>The twitter sign in.</value> + private static WebConsumer TwitterSignIn { + get { + if (signInConsumer == null) { + lock (signInConsumerInitLock) { + if (signInConsumer == null) { + signInConsumer = new WebConsumer(SignInWithTwitterServiceDescription, ShortTermUserSessionTokenManager); + } + } + } + + return signInConsumer; + } + } + + private static InMemoryTokenManager ShortTermUserSessionTokenManager { + get { + var store = HttpContext.Current.Session; + var tokenManager = (InMemoryTokenManager)store["TwitterShortTermUserSessionTokenManager"]; + if (tokenManager == null) { + string consumerKey = ConfigurationManager.AppSettings["twitterConsumerKey"]; + string consumerSecret = ConfigurationManager.AppSettings["twitterConsumerSecret"]; + if (IsTwitterConsumerConfigured) { + tokenManager = new InMemoryTokenManager(consumerKey, consumerSecret); + store["TwitterShortTermUserSessionTokenManager"] = tokenManager; + } else { + throw new InvalidOperationException("No Twitter OAuth consumer key and secret could be found in web.config AppSettings."); + } + } + + return tokenManager; + } + } + + public static XDocument GetUpdates(ConsumerBase twitter, string accessToken) { + IncomingWebResponse response = twitter.PrepareAuthorizedRequestAndSend(GetFriendTimelineStatusEndpoint, accessToken); + return XDocument.Load(XmlReader.Create(response.GetResponseReader())); + } + + public static XDocument GetFavorites(ConsumerBase twitter, string accessToken) { + IncomingWebResponse response = twitter.PrepareAuthorizedRequestAndSend(GetFavoritesEndpoint, accessToken); + return XDocument.Load(XmlReader.Create(response.GetResponseReader())); + } + + public static XDocument UpdateProfileBackgroundImage(ConsumerBase twitter, string accessToken, string image, bool tile) { + var parts = new[] { + MultipartPostPart.CreateFormFilePart("image", image, "image/" + Path.GetExtension(image).Substring(1).ToLowerInvariant()), + MultipartPostPart.CreateFormPart("tile", tile.ToString().ToLowerInvariant()), + }; + HttpWebRequest request = twitter.PrepareAuthorizedRequest(UpdateProfileBackgroundImageEndpoint, accessToken, parts); + request.ServicePoint.Expect100Continue = false; + IncomingWebResponse response = twitter.Channel.WebRequestHandler.GetResponse(request); + string responseString = response.GetResponseReader().ReadToEnd(); + return XDocument.Parse(responseString); + } + + public static XDocument UpdateProfileImage(ConsumerBase twitter, string accessToken, string pathToImage) { + string contentType = "image/" + Path.GetExtension(pathToImage).Substring(1).ToLowerInvariant(); + return UpdateProfileImage(twitter, accessToken, File.OpenRead(pathToImage), contentType); + } + + public static XDocument UpdateProfileImage(ConsumerBase twitter, string accessToken, Stream image, string contentType) { + var parts = new[] { + MultipartPostPart.CreateFormFilePart("image", "twitterPhoto", contentType, image), + }; + HttpWebRequest request = twitter.PrepareAuthorizedRequest(UpdateProfileImageEndpoint, accessToken, parts); + IncomingWebResponse response = twitter.Channel.WebRequestHandler.GetResponse(request); + string responseString = response.GetResponseReader().ReadToEnd(); + return XDocument.Parse(responseString); + } + + public static XDocument VerifyCredentials(ConsumerBase twitter, string accessToken) { + IncomingWebResponse response = twitter.PrepareAuthorizedRequestAndSend(VerifyCredentialsEndpoint, accessToken); + return XDocument.Load(XmlReader.Create(response.GetResponseReader())); + } + + public static string GetUsername(ConsumerBase twitter, string accessToken) { + XDocument xml = VerifyCredentials(twitter, accessToken); + 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> + /// <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 OutgoingWebResponse StartSignInWithTwitter(bool forceNewLogin) { + var redirectParameters = new Dictionary<string, string>(); + if (forceNewLogin) { + redirectParameters["force_login"] = "true"; + } + Uri callback = MessagingUtilities.GetRequestUrlFromContext().StripQueryArgumentsWithPrefix("oauth_"); + var request = TwitterSignIn.PrepareRequestUserAuthorization(callback, null, redirectParameters); + return TwitterSignIn.Channel.PrepareResponse(request); + } + + /// <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="screenName">The user's Twitter screen name.</param> + /// <param name="userId">The user's Twitter unique user ID.</param> + /// <returns> + /// A value indicating whether Twitter authentication was successful; + /// otherwise <c>false</c> to indicate that no Twitter response was present. + /// </returns> + public static bool TryFinishSignInWithTwitter(out string screenName, out int userId) { + screenName = null; + userId = 0; + var response = TwitterSignIn.ProcessUserAuthorization(); + if (response == null) { + return false; + } + + screenName = response.ExtraData["screen_name"]; + userId = int.Parse(response.ExtraData["user_id"]); + + // If we were going to make this LOOK like OpenID even though it isn't, + // this seems like a reasonable, secure claimed id to allow the user to assume. + OpenId.Identifier fake_claimed_id = string.Format(CultureInfo.InvariantCulture, "http://twitter.com/{0}#{1}", screenName, userId); + + return true; + } + } +} diff --git a/samples/DotNetOpenAuth.ApplicationBlock/OAuth1/YammerConsumer.cs b/samples/DotNetOpenAuth.ApplicationBlock/OAuth1/YammerConsumer.cs new file mode 100644 index 0000000..bbeb861 --- /dev/null +++ b/samples/DotNetOpenAuth.ApplicationBlock/OAuth1/YammerConsumer.cs @@ -0,0 +1,61 @@ +//----------------------------------------------------------------------- +// <copyright file="YammerConsumer.cs" company="Outercurve Foundation"> +// Copyright (c) Outercurve Foundation. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.ApplicationBlock { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Net; + using System.Text; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuth; + using DotNetOpenAuth.OAuth.ChannelElements; + using DotNetOpenAuth.OAuth.Messages; + + public static class YammerConsumer { + /// <summary> + /// The Consumer to use for accessing Google data APIs. + /// </summary> + public static readonly ServiceProviderDescription ServiceDescription = new ServiceProviderDescription { + RequestTokenEndpoint = new MessageReceivingEndpoint("https://www.yammer.com/oauth/request_token", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.PostRequest), + UserAuthorizationEndpoint = new MessageReceivingEndpoint("https://www.yammer.com/oauth/authorize", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest), + AccessTokenEndpoint = new MessageReceivingEndpoint("https://www.yammer.com/oauth/access_token", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.PostRequest), + TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new PlaintextSigningBindingElement() }, + ProtocolVersion = ProtocolVersion.V10, + }; + + public static DesktopConsumer CreateConsumer(IConsumerTokenManager tokenManager) { + return new DesktopConsumer(ServiceDescription, tokenManager); + } + + public static Uri PrepareRequestAuthorization(DesktopConsumer consumer, out string requestToken) { + if (consumer == null) { + throw new ArgumentNullException("consumer"); + } + + Uri authorizationUrl = consumer.RequestUserAuthorization(null, null, out requestToken); + return authorizationUrl; + } + + public static AuthorizedTokenResponse CompleteAuthorization(DesktopConsumer consumer, string requestToken, string userCode) { + // Because Yammer has a proprietary callback_token parameter, and it's passed + // with the message that specifically bans extra arguments being passed, we have + // to cheat by adding the data to the URL itself here. + var customServiceDescription = new ServiceProviderDescription { + RequestTokenEndpoint = ServiceDescription.RequestTokenEndpoint, + UserAuthorizationEndpoint = ServiceDescription.UserAuthorizationEndpoint, + AccessTokenEndpoint = new MessageReceivingEndpoint(ServiceDescription.AccessTokenEndpoint.Location.AbsoluteUri + "?oauth_verifier=" + Uri.EscapeDataString(userCode), HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.PostRequest), + TamperProtectionElements = ServiceDescription.TamperProtectionElements, + ProtocolVersion = ProtocolVersion.V10, + }; + + // To use a custom service description we also must create a new WebConsumer. + var customConsumer = new DesktopConsumer(customServiceDescription, consumer.TokenManager); + var response = customConsumer.ProcessUserAuthorization(requestToken, userCode); + return response; + } + } +} |