diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2008-11-02 21:46:06 -0800 |
---|---|---|
committer | Andrew <andrewarnott@gmail.com> | 2008-11-02 21:46:06 -0800 |
commit | 71e99449ee02155f34bb4928313c2200246b8a78 (patch) | |
tree | 8368303d42afe232a460c6cf7afc062d1270fc17 /src | |
parent | 916966f88a3ed3246374efb625804b11bdda6fa5 (diff) | |
download | DotNetOpenAuth-71e99449ee02155f34bb4928313c2200246b8a78.zip DotNetOpenAuth-71e99449ee02155f34bb4928313c2200246b8a78.tar.gz DotNetOpenAuth-71e99449ee02155f34bb4928313c2200246b8a78.tar.bz2 |
First stab at building specific application Consumer classes for ease of adoption.
Diffstat (limited to 'src')
-rw-r--r-- | src/DotNetOAuth.Test/CommonConsumers/CommonConsumerBaseTest.cs | 37 | ||||
-rw-r--r-- | src/DotNetOAuth.Test/DotNetOAuth.Test.csproj | 1 | ||||
-rw-r--r-- | src/DotNetOAuth.Test/Settings.StyleCop | 5 | ||||
-rw-r--r-- | src/DotNetOAuth/CommonConsumers/CommonConsumerBase.cs | 61 | ||||
-rw-r--r-- | src/DotNetOAuth/CommonConsumers/GoogleConsumer.cs | 119 | ||||
-rw-r--r-- | src/DotNetOAuth/DotNetOAuth.csproj | 5 |
6 files changed, 228 insertions, 0 deletions
diff --git a/src/DotNetOAuth.Test/CommonConsumers/CommonConsumerBaseTest.cs b/src/DotNetOAuth.Test/CommonConsumers/CommonConsumerBaseTest.cs new file mode 100644 index 0000000..f61b34e --- /dev/null +++ b/src/DotNetOAuth.Test/CommonConsumers/CommonConsumerBaseTest.cs @@ -0,0 +1,37 @@ +//-----------------------------------------------------------------------
+// <copyright file="CommonConsumerBaseTest.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.Test.CommonConsumers {
+ using System.Collections.Generic;
+ using System.Linq;
+ using DotNetOAuth.CommonConsumers;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ [TestClass]
+ public class CommonConsumerBaseTest : TestBase {
+ private enum SomeFlags : int {
+ None = 0,
+ Flag1 = 0x1,
+ Flag2 = 0x2,
+ Flag1and2 = 0x3,
+ Flag3 = 0x4,
+ All = 0x7,
+ }
+
+ [TestMethod]
+ public void GetIndividualFlagsTest() {
+ Assert.IsFalse(CommonConsumerBase_Accessor.GetIndividualFlags(SomeFlags.None).Any());
+ Assert.AreEqual(SomeFlags.Flag1, (SomeFlags)CommonConsumerBase_Accessor.GetIndividualFlags(SomeFlags.Flag1).Single());
+ IList<long> flags = CommonConsumerBase_Accessor.GetIndividualFlags(SomeFlags.Flag1and2).ToList();
+ Assert.AreEqual(SomeFlags.Flag1, (SomeFlags)flags[0]);
+ Assert.AreEqual(SomeFlags.Flag2, (SomeFlags)flags[1]);
+ flags = CommonConsumerBase_Accessor.GetIndividualFlags(SomeFlags.All).ToList();
+ Assert.AreEqual(SomeFlags.Flag1, (SomeFlags)flags[0]);
+ Assert.AreEqual(SomeFlags.Flag2, (SomeFlags)flags[1]);
+ Assert.AreEqual(SomeFlags.Flag3, (SomeFlags)flags[2]);
+ }
+ }
+}
diff --git a/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj b/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj index 14a1a39..04389be 100644 --- a/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj +++ b/src/DotNetOAuth.Test/DotNetOAuth.Test.csproj @@ -60,6 +60,7 @@ <ItemGroup>
<Compile Include="ChannelElements\SigningBindingElementBaseTests.cs" />
<Compile Include="ChannelElements\HmacSha1SigningBindingElementTests.cs" />
+ <Compile Include="CommonConsumers\CommonConsumerBaseTest.cs" />
<Compile Include="ConsumerDescription.cs" />
<Compile Include="Messaging\CollectionAssert.cs" />
<Compile Include="Messaging\MessageSerializerTests.cs" />
diff --git a/src/DotNetOAuth.Test/Settings.StyleCop b/src/DotNetOAuth.Test/Settings.StyleCop index 100fae5..c423ea4 100644 --- a/src/DotNetOAuth.Test/Settings.StyleCop +++ b/src/DotNetOAuth.Test/Settings.StyleCop @@ -7,6 +7,11 @@ <BooleanProperty Name="Enabled">False</BooleanProperty>
</RuleSettings>
</Rule>
+ <Rule Name="EnumerationItemsMustBeDocumented">
+ <RuleSettings>
+ <BooleanProperty Name="Enabled">False</BooleanProperty>
+ </RuleSettings>
+ </Rule>
</Rules>
<AnalyzerSettings />
</Analyzer>
diff --git a/src/DotNetOAuth/CommonConsumers/CommonConsumerBase.cs b/src/DotNetOAuth/CommonConsumers/CommonConsumerBase.cs new file mode 100644 index 0000000..c3f9209 --- /dev/null +++ b/src/DotNetOAuth/CommonConsumers/CommonConsumerBase.cs @@ -0,0 +1,61 @@ +//-----------------------------------------------------------------------
+// <copyright file="CommonConsumerBase.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.CommonConsumers {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOAuth.ChannelElements;
+
+ /// <summary>
+ /// A useful base class to derive from for Consumers written against a specific Service Provider.
+ /// </summary>
+ public abstract class CommonConsumerBase {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="CommonConsumerBase"/> class.
+ /// </summary>
+ /// <param name="serviceDescription">The service description.</param>
+ /// <param name="tokenManager">The token manager.</param>
+ /// <param name="consumerKey">The consumer key.</param>
+ protected CommonConsumerBase(ServiceProviderDescription serviceDescription, ITokenManager tokenManager, string consumerKey) {
+ if (serviceDescription == null) {
+ throw new ArgumentNullException("serviceDescription");
+ }
+ if (tokenManager == null) {
+ throw new ArgumentNullException("tokenManager");
+ }
+ if (consumerKey == null) {
+ throw new ArgumentNullException("consumerKey");
+ }
+ this.Consumer = new WebConsumer(serviceDescription, tokenManager) {
+ ConsumerKey = consumerKey,
+ };
+ }
+
+ /// <summary>
+ /// Gets the consumer.
+ /// </summary>
+ protected WebConsumer Consumer { get; private set; }
+
+ /// <summary>
+ /// Enumerates through the individual set bits in a flag enum.
+ /// </summary>
+ /// <param name="flags">The flags enum value.</param>
+ /// <returns>An enumeration of just the <i>set</i> bits in the flags enum.</returns>
+ protected static IEnumerable<long> GetIndividualFlags(Enum flags) {
+ long flagsLong = Convert.ToInt64(flags);
+ for (int i = 0; i < sizeof(long) * 8; i++) { // long is the type behind the largest enum
+ // Select an individual application from the scopes.
+ long individualFlagPosition = (long)Math.Pow(2, i);
+ long individualFlag = flagsLong & individualFlagPosition;
+ if (individualFlag == individualFlagPosition) {
+ yield return individualFlag;
+ }
+ }
+ }
+ }
+}
diff --git a/src/DotNetOAuth/CommonConsumers/GoogleConsumer.cs b/src/DotNetOAuth/CommonConsumers/GoogleConsumer.cs new file mode 100644 index 0000000..b8c14e7 --- /dev/null +++ b/src/DotNetOAuth/CommonConsumers/GoogleConsumer.cs @@ -0,0 +1,119 @@ +//-----------------------------------------------------------------------
+// <copyright file="GoogleConsumer.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOAuth.CommonConsumers {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Xml.Linq;
+ using DotNetOAuth.ChannelElements;
+ using DotNetOAuth.Messaging;
+
+ /// <summary>
+ /// A consumer capable of communicating with Google Data APIs.
+ /// </summary>
+ public class GoogleConsumer : CommonConsumerBase {
+ /// <summary>
+ /// The Consumer to use for accessing Google data APIs.
+ /// </summary>
+ private static readonly ServiceProviderDescription GoogleDescription = 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.Contacts, "http://www.google.com/m8/feeds/" },
+ { Applications.Calendar, "http://www.google.com/calendar/feeds/" },
+ };
+
+ /// <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>
+ /// Initializes a new instance of the <see cref="GoogleConsumer"/> class.
+ /// </summary>
+ /// <param name="tokenManager">The token manager.</param>
+ /// <param name="consumerKey">The consumer key.</param>
+ public GoogleConsumer(ITokenManager tokenManager, string consumerKey)
+ : base(GoogleDescription, tokenManager, consumerKey) {
+ }
+
+ /// <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>
+ /// Requests authorization from Google to access data from a set of Google applications.
+ /// </summary>
+ /// <param name="requestedAccessScope">The requested access scope.</param>
+ public void RequestAuthorization(Applications requestedAccessScope) {
+ Uri callback = MessagingUtilities.GetRequestUrlFromContext().StripQueryArgumentsWithPrefix(Protocol.Default.ParameterPrefix);
+ var extraParameters = new Dictionary<string, string> {
+ { "scope", this.GetScopeUri(requestedAccessScope) },
+ };
+ var request = this.Consumer.PrepareRequestUserAuthorization(callback, extraParameters, null);
+ this.Consumer.Channel.Send(request).Send();
+ }
+
+ /// <summary>
+ /// Gets the access token on the next page request after a call to <see cref="RequestAuthorization"/>.
+ /// </summary>
+ /// <returns>The access token that should be stored for later use.</returns>
+ public string GetAccessToken() {
+ var response = this.Consumer.ProcessUserAuthorization();
+ return response != null ? response.AccessToken : null;
+ }
+
+ /// <summary>
+ /// Gets the Gmail address book's contents.
+ /// </summary>
+ /// <param name="accessToken">The access token previously retrieved from the <see cref="GetAccessToken"/> method.</param>
+ /// <returns>An XML document returned by Google.</returns>
+ public XDocument GetContacts(string accessToken) {
+ var response = this.PrepareAuthorizedRequestAndSend(GetContactsEndpoint, accessToken);
+ XDocument result = XDocument.Parse(response.Body);
+ return result;
+ }
+
+ /// <summary>
+ /// A general method for sending OAuth-authorized requests for user data from Google.
+ /// </summary>
+ /// <param name="endpoint">The Google URL to retrieve the data from.</param>
+ /// <param name="accessToken">The access token previously retrieved from the <see cref="GetAccessToken"/> method.</param>
+ /// <returns>Whatever the response Google sends.</returns>
+ public Response PrepareAuthorizedRequestAndSend(MessageReceivingEndpoint endpoint, string accessToken) {
+ return this.Consumer.PrepareAuthorizedRequestAndSend(endpoint, accessToken);
+ }
+
+ /// <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>
+ private string GetScopeUri(Applications scope) {
+ return string.Join(" ", GetIndividualFlags(scope).Select(app => DataScopeUris[(Applications)app]).ToArray());
+ }
+ }
+}
diff --git a/src/DotNetOAuth/DotNetOAuth.csproj b/src/DotNetOAuth/DotNetOAuth.csproj index 742a34b..0ec21f6 100644 --- a/src/DotNetOAuth/DotNetOAuth.csproj +++ b/src/DotNetOAuth/DotNetOAuth.csproj @@ -58,6 +58,9 @@ </Reference>
<Reference Include="System.Web" />
<Reference Include="System.XML" />
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="ChannelElements\OAuthConsumerMessageTypeProvider.cs" />
@@ -69,6 +72,8 @@ <Compile Include="ChannelElements\SigningBindingElementChain.cs" />
<Compile Include="ChannelElements\StandardTokenGenerator.cs" />
<Compile Include="ChannelElements\TokenType.cs" />
+ <Compile Include="CommonConsumers\CommonConsumerBase.cs" />
+ <Compile Include="CommonConsumers\GoogleConsumer.cs" />
<Compile Include="ConsumerBase.cs" />
<Compile Include="DesktopConsumer.cs" />
<Compile Include="GlobalSuppressions.cs" />
|