diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2013-05-27 09:32:17 -0700 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2013-05-27 09:32:17 -0700 |
commit | 5a0a8ee4c55f323a6c1fbdb619cd89b7d28a94ba (patch) | |
tree | 026bb7a58fc6b80b680f2b5be2a25ddf1efbf0f5 /samples/DotNetOpenAuth.ApplicationBlock | |
parent | e4c746826690259eddba106e8a44d1b52b542faf (diff) | |
parent | 064220dbab72b00f23abd041bf4a30ea87a00d88 (diff) | |
download | DotNetOpenAuth-5a0a8ee4c55f323a6c1fbdb619cd89b7d28a94ba.zip DotNetOpenAuth-5a0a8ee4c55f323a6c1fbdb619cd89b7d28a94ba.tar.gz DotNetOpenAuth-5a0a8ee4c55f323a6c1fbdb619cd89b7d28a94ba.tar.bz2 |
Merge branch 'v4.3'
Conflicts:
samples/OAuthClient/Default.aspx
samples/OAuthClient/Facebook.aspx.cs
samples/OAuthClient/Web.config
samples/OAuthClient/WindowsLive.aspx.cs
samples/OAuthClient/packages.config
src/DotNetOpenAuth.Core/Messaging/OutgoingWebResponse.cs
src/DotNetOpenAuth.Core/Messaging/StandardWebRequestHandler.cs
src/DotNetOpenAuth.OAuth.Consumer/OAuth/ConsumerBase.cs
src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1HmacSha1HttpMessageHandler.cs
src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1HttpMessageHandlerBase.cs
src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1PlainTextMessageHandler.cs
src/DotNetOpenAuth.OAuth.Consumer/OAuth/OAuth1RsaSha1HttpMessageHandler.cs
src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs
src/packages/repositories.config
src/version.txt
Diffstat (limited to 'samples/DotNetOpenAuth.ApplicationBlock')
19 files changed, 1520 insertions, 200 deletions
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/AzureADClaims.cs b/samples/DotNetOpenAuth.ApplicationBlock/AzureADClaims.cs new file mode 100644 index 0000000..7856539 --- /dev/null +++ b/samples/DotNetOpenAuth.ApplicationBlock/AzureADClaims.cs @@ -0,0 +1,77 @@ +//----------------------------------------------------------------------- +// <copyright file="AzureADClaims.cs" company="Microsoft"> +// Copyright (c) Microsoft. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.ApplicationBlock +{ + using System; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Runtime.Serialization; + + /// <summary> + /// Contains clains of a AzureAD token. + /// </summary> + /// <remarks> + /// Technically, this class doesn't need to be public, but because we want to make it serializable in medium trust, it has to be public. + /// </remarks> + [DataContract] + [EditorBrowsable(EditorBrowsableState.Never)] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "AzureAD", Justification = "Brand name")] + public class AzureADClaims + { + #region Public Properties + + /// <summary> + /// Gets or sets the audience. + /// </summary> + /// <value> The audience token is valid for. </value> + [DataMember(Name = "aud")] + public string Aud { get; set; } + + /// <summary> + /// Gets or sets the issuer. + /// </summary> + /// <value> The issuer. </value> + [DataMember(Name = "iss")] + public string Iss { get; set; } + + /// <summary> + /// Gets or sets the early expiry time. + /// </summary> + /// <value> The early expiry time. </value> + [DataMember(Name = "nbf")] + public string Nbf { get; set; } + + /// <summary> + /// Gets or sets the expiry time. + /// </summary> + /// <value> The expiry time. </value> + [DataMember(Name = "exp")] + public string Exp { get; set; } + + /// <summary> + /// Gets or sets the id of the user. + /// </summary> + /// <value> The id of the user. </value> + [DataMember(Name = "oid")] + public string Oid { get; set; } + + /// <summary> + /// Gets or sets the id of the tenant. + /// </summary> + /// <value> The tenant . </value> + [DataMember(Name = "tid")] + public string Tid { get; set; } + + /// <summary> + /// Gets or sets the appid of application. + /// </summary> + /// <value> The id of the application. </value> + [DataMember(Name = "appid")] + public string Appid { get; set; } + #endregion + } +} diff --git a/samples/DotNetOpenAuth.ApplicationBlock/AzureADGraph.cs b/samples/DotNetOpenAuth.ApplicationBlock/AzureADGraph.cs new file mode 100644 index 0000000..625a0fe --- /dev/null +++ b/samples/DotNetOpenAuth.ApplicationBlock/AzureADGraph.cs @@ -0,0 +1,62 @@ +//----------------------------------------------------------------------- +// <copyright file="AzureADGraph.cs" company="Microsoft"> +// Copyright (c) Microsoft. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.ApplicationBlock +{ + using System; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Runtime.Serialization; + + /// <summary> + /// Contains data of a AzureAD user. + /// </summary> + /// <remarks> + /// Technically, this class doesn't need to be public, but because we want to make it serializable in medium trust, it has to be public. + /// </remarks> + [DataContract] + [EditorBrowsable(EditorBrowsableState.Never)] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "AzureAD", Justification = "Brand name")] + public class AzureADGraph { + #region Public Properties + + /// <summary> + /// Gets or sets the firstname. + /// </summary> + /// <value> The first name. </value> + [DataMember(Name = "givenName")] + public string GivenName { get; set; } + + /// <summary> + /// Gets or sets the lastname. + /// </summary> + /// <value> The last name. </value> + [DataMember(Name = "surname")] + public string Surname { get; set; } + + /// <summary> + /// Gets or sets the email. + /// </summary> + /// <value> The email. </value> + [DataMember(Name = "userPrincipalName")] + public string UserPrincipalName { get; set; } + + /// <summary> + /// Gets or sets the fullname. + /// </summary> + /// <value> The fullname. </value> + [DataMember(Name = "displayName")] + public string DisplayName { get; set; } + + /// <summary> + /// Gets or sets the id. + /// </summary> + /// <value> The id. </value> + [DataMember(Name = "objectId")] + public string ObjectId { get; set; } + #endregion + } +} diff --git a/samples/DotNetOpenAuth.ApplicationBlock/AzureADHeader.cs b/samples/DotNetOpenAuth.ApplicationBlock/AzureADHeader.cs new file mode 100644 index 0000000..532c405 --- /dev/null +++ b/samples/DotNetOpenAuth.ApplicationBlock/AzureADHeader.cs @@ -0,0 +1,51 @@ +//----------------------------------------------------------------------- +// <copyright file="AzureADHeader.cs" company="Microsoft"> +// Copyright (c) Microsoft. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.ApplicationBlock +{ + using System; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Runtime.Serialization; + + /// <summary> + /// Contains header of AzureAD JWT token. + /// </summary> + /// <remarks> + /// Technically, this class doesn't need to be public, but because we want to make it serializable in medium trust, it has to be public. + /// </remarks> + [DataContract] + [EditorBrowsable(EditorBrowsableState.Never)] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "AzureAD", Justification = "Brand name")] + + public class AzureADHeader + { + #region Public Properties + + /// <summary> + /// Gets or sets the type of token. Will always be JWT + /// </summary> + /// <value> The type of token. </value> + [DataMember(Name = "typ")] + public string Typ { get; set; } + + /// <summary> + /// Gets or sets the algo of the header. + /// </summary> + /// <value> The algo of encoding. </value> + [DataMember(Name = "alg")] + public string Alg { get; set; } + + /// <summary> + /// Gets or sets the thumbprint of the header. + /// </summary> + /// <value> The thumbprint of the cert used to encode. </value> + [DataMember(Name = "x5t")] + public string X5t { get; set; } + + #endregion + } +} diff --git a/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj b/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj index 19f26b5..5f97992 100644 --- a/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj +++ b/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj @@ -82,6 +82,7 @@ <Reference Include="System.Runtime.Serialization" /> <Reference Include="System.ServiceModel.Web" /> <Reference Include="System.Web" /> + <Reference Include="System.Web.Extensions" /> <Reference Include="System.Xml.Linq"> <RequiredTargetFramework>3.5</RequiredTargetFramework> </Reference> @@ -92,21 +93,28 @@ <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> + <Compile Include="AzureADClaims.cs" /> + <Compile Include="azureadclient.cs" /> + <Compile Include="AzureADGraph.cs" /> + <Compile Include="AzureADHeader.cs" /> <Compile Include="CustomExtensions\Acme.cs" /> <Compile Include="CustomExtensions\AcmeRequest.cs" /> <Compile Include="CustomExtensions\AcmeResponse.cs" /> - <Compile Include="Facebook\FacebookClient.cs" /> - <Compile Include="Facebook\FacebookGraph.cs" /> + <Compile Include="OAuth2\Facebook\FacebookClient.cs" /> + <Compile Include="OAuth2\Facebook\FacebookGraph.cs" /> <Compile Include="CustomExtensions\UIRequestAtRelyingPartyFactory.cs" /> - <Compile Include="GoogleConsumer.cs" /> <Compile Include="HttpAsyncHandlerBase.cs" /> <Compile Include="InMemoryClientAuthorizationTracker.cs" /> + <Compile Include="OAuth1\GoogleConsumer.cs" /> + <Compile Include="OAuth2\Google\GoogleClient.cs" /> + <Compile Include="OAuth2\Google\GoogleGraph.cs" /> + <Compile Include="OAuth2\IOAuth2Graph.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> - <Compile Include="TwitterConsumer.cs" /> + <Compile Include="OAuth1\TwitterConsumer.cs" /> <Compile Include="Util.cs" /> - <Compile Include="WindowsLiveClient.cs" /> - <Compile Include="WindowsLiveGraph.cs" /> - <Compile Include="YammerConsumer.cs" /> + <Compile Include="OAuth2\WindowsLive\WindowsLiveClient.cs" /> + <Compile Include="OAuth2\WindowsLive\WindowsLiveGraph.cs" /> + <Compile Include="OAuth1\YammerConsumer.cs" /> <Compile Include="YubikeyRelyingParty.cs" /> </ItemGroup> <ItemGroup> diff --git a/samples/DotNetOpenAuth.ApplicationBlock/Facebook/FacebookClient.cs b/samples/DotNetOpenAuth.ApplicationBlock/Facebook/FacebookClient.cs deleted file mode 100644 index a24e5b3..0000000 --- a/samples/DotNetOpenAuth.ApplicationBlock/Facebook/FacebookClient.cs +++ /dev/null @@ -1,28 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="FacebookClient.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.Text; - using System.Web; - using DotNetOpenAuth.Messaging; - using DotNetOpenAuth.OAuth2; - - public class FacebookClient : WebServerClient { - private static readonly AuthorizationServerDescription FacebookDescription = new AuthorizationServerDescription { - TokenEndpoint = new Uri("https://graph.facebook.com/oauth/access_token"), - AuthorizationEndpoint = new Uri("https://graph.facebook.com/oauth/authorize"), - }; - - /// <summary> - /// Initializes a new instance of the <see cref="FacebookClient"/> class. - /// </summary> - public FacebookClient() : base(FacebookDescription) { - } - } -} diff --git a/samples/DotNetOpenAuth.ApplicationBlock/Facebook/FacebookGraph.cs b/samples/DotNetOpenAuth.ApplicationBlock/Facebook/FacebookGraph.cs deleted file mode 100644 index 909ae9a..0000000 --- a/samples/DotNetOpenAuth.ApplicationBlock/Facebook/FacebookGraph.cs +++ /dev/null @@ -1,54 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="FacebookGraph.cs" company="Outercurve Foundation"> -// Copyright (c) Outercurve Foundation. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.ApplicationBlock.Facebook { - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Runtime.Serialization; - using System.Runtime.Serialization.Json; - using System.Text; - - [DataContract] - public class FacebookGraph { - private static DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(FacebookGraph)); - - [DataMember(Name = "id")] - public long Id { get; set; } - - [DataMember(Name = "name")] - public string Name { get; set; } - - [DataMember(Name = "first_name")] - public string FirstName { get; set; } - - [DataMember(Name = "last_name")] - public string LastName { get; set; } - - [DataMember(Name = "link")] - public Uri Link { get; set; } - - [DataMember(Name = "birthday")] - public string Birthday { get; set; } - - public static FacebookGraph Deserialize(string json) { - if (string.IsNullOrEmpty(json)) { - throw new ArgumentNullException("json"); - } - - return Deserialize(new MemoryStream(Encoding.UTF8.GetBytes(json))); - } - - public static FacebookGraph Deserialize(Stream jsonStream) { - if (jsonStream == null) { - throw new ArgumentNullException("jsonStream"); - } - - return (FacebookGraph)jsonSerializer.ReadObject(jsonStream); - } - } -} diff --git a/samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs b/samples/DotNetOpenAuth.ApplicationBlock/OAuth1/GoogleConsumer.cs index a7c062e..a7c062e 100644 --- a/samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs +++ b/samples/DotNetOpenAuth.ApplicationBlock/OAuth1/GoogleConsumer.cs diff --git a/samples/DotNetOpenAuth.ApplicationBlock/TwitterConsumer.cs b/samples/DotNetOpenAuth.ApplicationBlock/OAuth1/TwitterConsumer.cs index 7c9f678..7c9f678 100644 --- a/samples/DotNetOpenAuth.ApplicationBlock/TwitterConsumer.cs +++ b/samples/DotNetOpenAuth.ApplicationBlock/OAuth1/TwitterConsumer.cs diff --git a/samples/DotNetOpenAuth.ApplicationBlock/YammerConsumer.cs b/samples/DotNetOpenAuth.ApplicationBlock/OAuth1/YammerConsumer.cs index 1dff5b6..1dff5b6 100644 --- a/samples/DotNetOpenAuth.ApplicationBlock/YammerConsumer.cs +++ b/samples/DotNetOpenAuth.ApplicationBlock/OAuth1/YammerConsumer.cs diff --git a/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/Facebook/FacebookClient.cs b/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/Facebook/FacebookClient.cs new file mode 100644 index 0000000..b8717f7 --- /dev/null +++ b/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/Facebook/FacebookClient.cs @@ -0,0 +1,105 @@ +//----------------------------------------------------------------------- +// <copyright file="FacebookClient.cs" company="Outercurve Foundation"> +// Copyright (c) Outercurve Foundation. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.ApplicationBlock { + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Net; + using System.Text; + using System.Web; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuth2; + + public class FacebookClient : WebServerClient { + private static readonly AuthorizationServerDescription FacebookDescription = new AuthorizationServerDescription { + TokenEndpoint = new Uri("https://graph.facebook.com/oauth/access_token"), + AuthorizationEndpoint = new Uri("https://graph.facebook.com/oauth/authorize"), + ProtocolVersion = ProtocolVersion.V20 + }; + + /// <summary> + /// Initializes a new instance of the <see cref="FacebookClient"/> class. + /// </summary> + public FacebookClient() + : base(FacebookDescription) { + } + + public IOAuth2Graph GetGraph(IAuthorizationState authState, string[] fields = null) { + if ((authState != null) && (authState.AccessToken != null)) { + string fieldsStr = (fields == null) || (fields.Length == 0) ? FacebookGraph.Fields.Defaults : string.Join(",", fields); + + WebRequest request = WebRequest.Create("https://graph.Facebook.com/me?access_token=" + Uri.EscapeDataString(authState.AccessToken) + "&fields=" + fieldsStr); + WebResponse response = request.GetResponse(); + + if (response != null) { + Stream responseStream = response.GetResponseStream(); + + if (responseStream != null) { + return FacebookGraph.Deserialize(responseStream); + } + } + } + + return null; + } + + /// <summary> + /// Well-known permissions defined by Facebook. + /// </summary> + /// <remarks> + /// This sample includes just a few permissions. For a complete list of permissions please refer to: + /// https://developers.facebook.com/docs/reference/login/ + /// </remarks> + public static class Scopes { + #region Email Permissions + /// <summary> + /// Provides access to the user's primary email address in the email property. Do not spam users. Your use of email must comply both with Facebook policies and with the CAN-SPAM Act. + /// </summary> + public const string Email = "email"; + #endregion + + #region Extended Permissions + /// <summary> + /// Provides access to any friend lists the user created. All user's friends are provided as part of basic data, this extended permission grants access to the lists of friends a user has created, and should only be requested if your application utilizes lists of friends. + /// </summary> + public const string ReadFriendlists = "read_friendlists"; + + /// <summary> + /// Provides read access to the Insights data for pages, applications, and domains the user owns. + /// </summary> + public const string ReadInsights = "read_insights"; + #endregion + + #region Extended Profile Properties + /// <summary> + /// Provides access to the "About Me" section of the profile in the about property + /// </summary> + public const string UserAboutMe = "user_about_me"; + + /// <summary> + /// Provides access to the user's list of activities as the activities connection + /// </summary> + public const string UserActivities = "user_activities"; + + /// <summary> + /// Provides access to the birthday with year as the birthday property. Note that your app may determine if a user is "old enough" to use an app by obtaining the age_range public profile property + /// </summary> + public const string UserBirthday = "user_birthday"; + #endregion + + #region Open Graph Permissions + #endregion + + #region Page Permissions + #endregion + + #region Public Profile and Friend List + #endregion + } + } +} diff --git a/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/Facebook/FacebookGraph.cs b/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/Facebook/FacebookGraph.cs new file mode 100644 index 0000000..a62b410 --- /dev/null +++ b/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/Facebook/FacebookGraph.cs @@ -0,0 +1,303 @@ +//----------------------------------------------------------------------- +// <copyright file="FacebookGraph.cs" company="Outercurve Foundation"> +// Copyright (c) Outercurve Foundation. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.ApplicationBlock { + using System; + using System.Collections.Generic; + using System.Globalization; + using System.IO; + using System.Linq; + using System.Runtime.Serialization; + using System.Runtime.Serialization.Json; + using System.Text; + + //// Documentation: https://developers.facebook.com/docs/reference/api/user/ + + [DataContract] + public class FacebookGraph : IOAuth2Graph { + private static DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(FacebookGraph)); + + /// <summary> + /// Gets or sets the user's Facebook ID + /// </summary> + [DataMember(Name = "id")] + public string Id { get; set; } + + /// <summary> + /// Gets or sets the user's full name + /// </summary> + [DataMember(Name = "name")] + public string Name { get; set; } + + /// <summary> + /// Gets or sets the user's first name + /// </summary> + [DataMember(Name = "first_name")] + public string FirstName { get; set; } + + /// <summary> + /// Gets or sets the user's middle name + /// </summary> + [DataMember(Name = "middle_name")] + public string MiddleName { get; set; } + + /// <summary> + /// Gets or sets the user's last name + /// </summary> + [DataMember(Name = "last_name")] + public string LastName { get; set; } + + /// <summary> + /// Gets or sets the user's gender: female or male + /// </summary> + [DataMember(Name = "gender")] + public string Gender { get; set; } + + /// <summary> + /// Gets or sets the user's locale + /// </summary> + [DataMember(Name = "locale")] + public string Locale { get; set; } + + /// <summary> + /// Gets or sets the user's languages + /// </summary> + [DataMember(Name = "languages")] + public FacebookIdName[] Languages { get; set; } + + /// <summary> + /// Gets or sets the URL of the profile for the user on Facebook + /// </summary> + [DataMember(Name = "link")] + public Uri Link { get; set; } + + /// <summary> + /// Gets or sets the user's Facebook username + /// </summary> + [DataMember(Name = "username")] + public string Username { get; set; } + + // age_range + + // third_party_id + + // installed + + /// <summary> + /// Gets or sets the user's timezone offset from UTC + /// </summary> + [DataMember(Name = "timezone")] + public int? Timezone { get; set; } + + /// <summary> + /// Gets or sets the last time the user's profile was updated; changes to the languages, link, timezone, verified, interested_in, favorite_athletes, favorite_teams, and video_upload_limits are not not reflected in this value + /// string containing an ISO-8601 datetime + /// </summary> + [DataMember(Name = "updated_time")] + public string UpdatedTime { get; set; } + + // verified + + // bio + + /// <summary> + /// Gets or sets the user's birthday + /// Date string in MM/DD/YYYY format + /// </summary> + [DataMember(Name = "birthday")] + public string Birthday { get; set; } + + [Obsolete] + [DataMember(Name = "birthday_date")] + public string BirthdayDate { get; set; } + + // cover + + // currency + + // devices + + // education + + /// <summary> + /// Gets or sets the proxied or contact email address granted by the user + /// </summary> + [DataMember(Name = "email")] + public string Email { get; set; } + + /// <summary> + /// Gets or sets the user's hometown + /// </summary> + [DataMember(Name = "hometown")] + public FacebookIdName Hometown { get; set; } + + /// <summary> + /// Gets or sets the genders the user is interested in + /// </summary> + [DataMember(Name = "interested_in")] + public string[] InterestedIn { get; set; } + + /// <summary> + /// Gets or sets the user's current city + /// </summary> + [DataMember(Name = "location")] + public FacebookIdName Location { get; set; } + + /// <summary> + /// Gets or sets the user's political view + /// </summary> + [DataMember(Name = "political")] + public string Political { get; set; } + + // payment_pricepoints + + /// <summary> + /// Gets or sets the user's favorite athletes; this field is deprecated and will be removed in the near future + /// </summary> + [Obsolete] + [DataMember(Name = "favorite_athletes")] + public FacebookIdName[] FavoriteAthletes { get; set; } + + /// <summary> + /// Gets or sets the user's favorite teams; this field is deprecated and will be removed in the near future + /// </summary> + [Obsolete] + [DataMember(Name = "favorite_teams")] + public FacebookIdName[] FavoriteTeams { get; set; } + + /// <summary> + /// Gets or sets the URL of the user's profile pic (only returned if you explicitly specify a 'fields=picture' param) + /// If the "October 2012 Breaking Changes" migration setting is enabled for your app, this field will be an object with the url and is_silhouette fields; is_silhouette is true if the user has not uploaded a profile picture + /// </summary> + [DataMember(Name = "picture")] + public FacebookPicture Picture { get; set; } + + /// <summary> + /// Gets or sets the user's favorite quotes + /// </summary> + [DataMember(Name = "quotes")] + public Uri Quotes { get; set; } + + /// <summary> + /// Gets or sets the user's relationship status: Single, In a relationship, Engaged, Married, It's complicated, In an open relationship, Widowed, Separated, Divorced, In a civil union, In a domestic partnership + /// </summary> + [DataMember(Name = "relationship_status")] + public string RelationshipStatus { get; set; } + + /// <summary> + /// Gets or sets the user's religion + /// </summary> + [DataMember(Name = "religion")] + public string Religion { get; set; } + + // security_settings + + /// <summary> + /// Gets or sets the user's significant other + /// </summary> + [DataMember(Name = "significant_other")] + public FacebookIdName SignificantOther { get; set; } + + // video_upload_limits + + /// <summary> + /// Gets or sets the URL of the user's personal website + /// </summary> + [DataMember(Name = "website")] + public Uri Website { get; set; } + + public DateTime? BirthdayDT { + get { + if (!string.IsNullOrEmpty(this.Birthday) && (this.Locale != null)) { + CultureInfo ci = new CultureInfo(this.Locale.Replace('_', '-')); + return DateTime.Parse(this.Birthday, ci); + } + + return null; + } + } + + public Uri AvatarUrl { + get { + if ((this.Picture != null) && (this.Picture.Data != null) && (this.Picture.Data.Url != null)) { + return this.Picture.Data.Url; + } + + return null; + } + } + + public HumanGender GenderEnum { + get { + if (this.Gender == "male") { + return HumanGender.Male; + } else if (this.Gender == "female") { + return HumanGender.Female; + } + + return HumanGender.Unknown; + } + } + + public static FacebookGraph Deserialize(string json) { + if (string.IsNullOrEmpty(json)) { + throw new ArgumentNullException("json"); + } + + return Deserialize(new MemoryStream(Encoding.UTF8.GetBytes(json))); + } + + public static FacebookGraph Deserialize(Stream jsonStream) { + if (jsonStream == null) { + throw new ArgumentNullException("jsonStream"); + } + + return (FacebookGraph)jsonSerializer.ReadObject(jsonStream); + } + + public static class Fields { + public const string Defaults = "id,name,first_name,middle_name,last_name,gender,locale,link,username"; + + public const string Birthday = "locale,birthday"; + + public const string Email = "email"; + + public const string Picture = "picture"; + } + + /// <summary> + /// Obsolete: used only before October 2012 + /// </summary> + [Obsolete] + [DataContract] + public class FacebookPicture { + [DataMember(Name = "data")] + public FacebookPictureData Data { get; set; } + } + + /// <summary> + /// Obsolete: used only before October 2012 + /// </summary> + [Obsolete] + [DataContract] + public class FacebookPictureData { + [DataMember(Name = "url")] + public Uri Url { get; set; } + + [DataMember(Name = "is_silhouette")] + public bool IsSilhouette { get; set; } + } + + [DataContract] + public class FacebookIdName { + [DataMember(Name = "id")] + public string Id { get; set; } + + [DataMember(Name = "name")] + public string Name { get; set; } + } + } +} diff --git a/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/Google/GoogleClient.cs b/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/Google/GoogleClient.cs new file mode 100644 index 0000000..1e1a486 --- /dev/null +++ b/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/Google/GoogleClient.cs @@ -0,0 +1,110 @@ +//----------------------------------------------------------------------- +// <copyright file="GoogleClient.cs" company="Outercurve Foundation"> +// Copyright (c) Outercurve Foundation. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.ApplicationBlock { + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Net; + using System.Text; + using System.Web; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuth2; + + //// https://accounts.google.com/o/oauth2/auth + + public class GoogleClient : WebServerClient { + private static readonly AuthorizationServerDescription GoogleDescription = new AuthorizationServerDescription { + TokenEndpoint = new Uri("https://accounts.google.com/o/oauth2/token"), + AuthorizationEndpoint = new Uri("https://accounts.google.com/o/oauth2/auth"), + //// RevokeEndpoint = new Uri("https://accounts.google.com/o/oauth2/revoke"), + ProtocolVersion = ProtocolVersion.V20 + }; + + /// <summary> + /// Initializes a new instance of the <see cref="GoogleClient"/> class. + /// </summary> + public GoogleClient() + : base(GoogleDescription) { + } + + public IOAuth2Graph GetGraph(IAuthorizationState authState, string[] fields = null) { + if ((authState != null) && (authState.AccessToken != null)) { + WebRequest request = WebRequest.Create("https://www.googleapis.com/oauth2/v1/userinfo?access_token=" + Uri.EscapeDataString(authState.AccessToken)); + WebResponse response = request.GetResponse(); + + if (response != null) { + Stream responseStream = response.GetResponseStream(); + + if (responseStream != null) { + return GoogleGraph.Deserialize(responseStream); + } + } + } + + return null; + } + + /// <summary> + /// Well-known scopes defined by Google. + /// </summary> + /// <remarks> + /// This sample includes just a few scopes. For a complete list of permissions please refer to: + /// https://developers.google.com/accounts/docs/OAuth2Login + /// </remarks> + public static class Scopes { + public const string PlusMe = "https://www.googleapis.com/auth/plus.me"; + + /// <summary> + /// Scopes that cover queries for user data. + /// </summary> + public static class UserInfo { + /// <summary> + /// Gain read-only access to basic profile information, including a user identifier, name, profile photo, profile URL, country, language, timezone, and birthdate. + /// </summary> + public const string Profile = "https://www.googleapis.com/auth/userinfo.profile"; + + /// <summary> + /// Gain read-only access to the user's email address. + /// </summary> + public const string Email = "https://www.googleapis.com/auth/userinfo.email"; + } + + public static class Drive { + /// <summary> + /// Full, permissive scope to access all of a user's files. Request this scope only when it is strictly necessary. + /// </summary> + public const string Default = "https://www.googleapis.com/auth/drive"; + + /// <summary> + /// Per-file access to files created or opened by the app + /// </summary> + public const string File = "https://www.googleapis.com/auth/drive.file"; + + /// <summary> + /// Allows apps read-only access to the list of Drive apps a user has installed + /// </summary> + public const string AppsReadonly = "https://www.googleapis.com/auth/drive.apps.readonly"; + + /// <summary> + /// Allows read-only access to file metadata and file content + /// </summary> + public const string Readonly = "https://www.googleapis.com/auth/drive.readonly"; + + /// <summary> + /// Allows read-only access to file metadata, but does not allow any access to read or download file content + /// </summary> + public const string Metadata = "https://www.googleapis.com/auth/drive.readonly.metadata"; + + /// <summary> + /// Special scope used to let users approve installation of an app + /// </summary> + public const string Install = "https://www.googleapis.com/auth/drive.install"; + } + } + } +} diff --git a/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/Google/GoogleGraph.cs b/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/Google/GoogleGraph.cs new file mode 100644 index 0000000..44adcaf --- /dev/null +++ b/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/Google/GoogleGraph.cs @@ -0,0 +1,152 @@ +//----------------------------------------------------------------------- +// <copyright file="GoogleGraph.cs" company="Andras Fuchs"> +// Copyright (c) Outercurve Foundation. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.ApplicationBlock { + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Runtime.Serialization; + using System.Runtime.Serialization.Json; + using System.Text; + + //// Documentation: https://developers.google.com/accounts/docs/OAuth2Login + + [DataContract] + public class GoogleGraph : IOAuth2Graph { + private static DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(GoogleGraph)); + + /// <summary> + /// Gets or sets the value of this field is an immutable identifier for the logged-in user, and may be used when creating and managing user sessions in your application. This identifier is the same regardless of the client_id. This provides the ability to correlate profile information across multiple applications in the same organization. The value of this field is the same as the value of the userid field returned by the TokenInfo endpoint. + /// </summary> + [DataMember(Name = "id", IsRequired = true)] + public string Id { get; set; } + + /// <summary> + /// Gets or sets the email address of the logged in user + /// </summary> + [DataMember(Name = "email")] + public string Email { get; set; } + + /// <summary> + /// Gets or sets a flag that indicates whether or not Google has been able to verify the email address. + /// </summary> + [DataMember(Name = "verified_email")] + public bool? VerifiedEmail { get; set; } + + /// <summary> + /// Gets or sets the full name of the logged in user + /// </summary> + [DataMember(Name = "name", IsRequired = true)] + public string Name { get; set; } + + /// <summary> + /// Gets or sets the first name of the logged in user + /// </summary> + [DataMember(Name = "given_name")] + public string GivenName { get; set; } + + /// <summary> + /// Gets or sets the last name of the logged in user + /// </summary> + [DataMember(Name = "family_name")] + public string FamilyName { get; set; } + + /// <summary> + /// Gets or sets the URL to the user's profile picture. If the user has no public profile, this field is not included. + /// </summary> + [DataMember(Name = "picture")] + public Uri Picture { get; set; } + + /// <summary> + /// Gets or sets the user's registered locale. If the user has no public profile, this field is not included. + /// </summary> + [DataMember(Name = "locale")] + public string Locale { get; set; } + + /// <summary> + /// Gets or sets the default timezone of the logged in user + /// </summary> + [DataMember(Name = "timezone")] + public string Timezone { get; set; } + + /// <summary> + /// Gets or sets the gender of the logged in user (other|female|male) + /// </summary> + [DataMember(Name = "gender")] + public string Gender { get; set; } + + [DataMember(Name = "birthday")] + public string Birthday { get; set; } + + [DataMember(Name = "link")] + public Uri Link { get; set; } + + public Uri AvatarUrl { + get { + return this.Picture; + } + } + + public DateTime? BirthdayDT { + get { + if (!string.IsNullOrEmpty(this.Birthday) && (!this.Birthday.StartsWith("0000"))) { + return DateTime.ParseExact(this.Birthday, "yyyy-MM-dd", null); + } + + return null; + } + } + + public HumanGender GenderEnum { + get { + if (this.Gender == "male") { + return HumanGender.Male; + } else if (this.Gender == "female") { + return HumanGender.Female; + } else if (this.Gender == "other") { + return HumanGender.Other; + } + + return HumanGender.Unknown; + } + } + + public string FirstName { + get { + return this.GivenName; + } + } + + public string LastName { + get { + return this.FamilyName; + } + } + + public string UpdatedTime { + get { + return null; + } + } + + public static GoogleGraph Deserialize(string json) { + if (string.IsNullOrEmpty(json)) { + throw new ArgumentNullException("json"); + } + + return Deserialize(new MemoryStream(Encoding.UTF8.GetBytes(json))); + } + + public static GoogleGraph Deserialize(Stream jsonStream) { + if (jsonStream == null) { + throw new ArgumentNullException("jsonStream"); + } + + return (GoogleGraph)jsonSerializer.ReadObject(jsonStream); + } + } +} diff --git a/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/IOAuth2Graph.cs b/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/IOAuth2Graph.cs new file mode 100644 index 0000000..b479cc0 --- /dev/null +++ b/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/IOAuth2Graph.cs @@ -0,0 +1,54 @@ +namespace DotNetOpenAuth.ApplicationBlock { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + + public enum HumanGender { + /// <summary> + /// The gender is unknown. + /// </summary> + Unknown, + + /// <summary> + /// The gender is male. + /// </summary> + Male, + + /// <summary> + /// The gender is female. + /// </summary> + Female, + + /// <summary> + /// Hmmmm... What could this be? + /// </summary> + Other, + } + + public interface IOAuth2Graph { + string Id { get; } + + Uri Link { get; } + + string Name { get; } + + string FirstName { get; } + + string LastName { get; } + + string Gender { get; } + + string Locale { get; } + + DateTime? BirthdayDT { get; } + + string Email { get; } + + Uri AvatarUrl { get; } + + string UpdatedTime { get; } + + HumanGender GenderEnum { get; } + } +} diff --git a/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/WindowsLive/WindowsLiveClient.cs b/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/WindowsLive/WindowsLiveClient.cs new file mode 100644 index 0000000..7f7af18 --- /dev/null +++ b/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/WindowsLive/WindowsLiveClient.cs @@ -0,0 +1,180 @@ +//----------------------------------------------------------------------- +// <copyright file="WindowsLiveClient.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.ApplicationBlock { + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Net; + using System.Text; + using System.Web; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuth2; + + public class WindowsLiveClient : WebServerClient { + private static readonly AuthorizationServerDescription WindowsLiveDescription = new AuthorizationServerDescription { + TokenEndpoint = new Uri("https://oauth.live.com/token"), + AuthorizationEndpoint = new Uri("https://oauth.live.com/authorize"), + ProtocolVersion = ProtocolVersion.V20 + }; + + /// <summary> + /// Initializes a new instance of the <see cref="WindowsLiveClient"/> class. + /// </summary> + public WindowsLiveClient() + : base(WindowsLiveDescription) { + } + + public IOAuth2Graph GetGraph(IAuthorizationState authState, string[] fields = null) { + if ((authState != null) && (authState.AccessToken != null)) { + WebRequest request = WebRequest.Create("https://apis.live.net/v5.0/me?access_token=" + Uri.EscapeDataString(authState.AccessToken)); + WebResponse response = request.GetResponse(); + + if (response != null) { + Stream responseStream = response.GetResponseStream(); + + if (responseStream != null) { + // string debugJsonStr = new StreamReader(responseStream).ReadToEnd(); + WindowsLiveGraph windowsLiveGraph = WindowsLiveGraph.Deserialize(responseStream); + + // picture type resolution test 1 + // &type=small 96x96 + // &type=medium 96x96 + // &type=large 448x448 + windowsLiveGraph.AvatarUrl = new Uri("https://apis.live.net/v5.0/me/picture?access_token=" + Uri.EscapeDataString(authState.AccessToken)); + + return windowsLiveGraph; + } + } + } + + return null; + } + + /// <summary> + /// Well-known scopes defined by the Windows Live service. + /// </summary> + /// <remarks> + /// This sample includes just a few scopes. For a complete list of scopes please refer to: + /// http://msdn.microsoft.com/en-us/library/hh243646.aspx + /// </remarks> + public static class Scopes { + #region Core Scopes + + /// <summary> + /// The ability of an app to read and update a user's info at any time. Without this scope, an app can access the user's info only while the user is signed in to Live Connect and is using your app. + /// </summary> + public const string OfflineAccess = "wl.offline_access"; + + /// <summary> + /// Single sign-in behavior. With single sign-in, users who are already signed in to Live Connect are also signed in to your website. + /// </summary> + public const string SignIn = "wl.signin"; + + /// <summary> + /// Read access to a user's basic profile info. Also enables read access to a user's list of contacts. + /// </summary> + public const string Basic = "wl.basic"; + + #endregion + + #region Extended Scopes + + /// <summary> + /// Read access to a user's birthday info including birth day, month, and year. + /// </summary> + public const string Birthday = "wl.birthday"; + + /// <summary> + /// Read access to a user's calendars and events. + /// </summary> + public const string Calendars = "wl.calendars"; + + /// <summary> + /// Read and write access to a user's calendars and events. + /// </summary> + public const string CalendarsUpdate = "wl.calendars_update"; + + /// <summary> + /// Read access to the birth day and birth month of a user's contacts. Note that this also gives read access to the user's birth day, birth month, and birth year. + /// </summary> + public const string ContactsBirthday = "wl.contacts_birthday"; + + /// <summary> + /// Creation of new contacts in the user's address book. + /// </summary> + public const string ContactsCreate = "wl.contacts_create"; + + /// <summary> + /// Read access to a user's calendars and events. Also enables read access to any calendars and events that other users have shared with the user. + /// </summary> + public const string ContactsCalendars = "wl.contacts_calendars"; + + /// <summary> + /// Read access to a user's albums, photos, videos, and audio, and their associated comments and tags. Also enables read access to any albums, photos, videos, and audio that other users have shared with the user. + /// </summary> + public const string ContactsPhotos = "wl.contacts_photos"; + + /// <summary> + /// Read access to Microsoft SkyDrive files that other users have shared with the user. Note that this also gives read access to the user's files stored in SkyDrive. + /// </summary> + public const string ContactsSkydrive = "wl.contacts_skydrive"; + + /// <summary> + /// Read access to a user's personal, preferred, and business email addresses. + /// </summary> + public const string Emails = "wl.emails"; + + /// <summary> + /// Creation of events on the user's default calendar. + /// </summary> + public const string EventsCreate = "wl.events_create"; + + /// <summary> + /// Enables signing in to the Windows Live Messenger Extensible Messaging and Presence Protocol (XMPP) service. + /// </summary> + public const string Messenger = "wl.messenger"; + + /// <summary> + /// Read access to a user's personal, business, and mobile phone numbers. + /// </summary> + public const string PhoneNumbers = "wl.phone_numbers"; + + /// <summary> + /// Read access to a user's photos, videos, audio, and albums. + /// </summary> + public const string Photos = "wl.photos"; + + /// <summary> + /// Read access to a user's postal addresses. + /// </summary> + public const string PostalAddresses = "wl.postal_addresses"; + + /// <summary> + /// Enables updating a user's status message. + /// </summary> + public const string Share = "wl.share"; + + /// <summary> + /// Read access to a user's files stored in SkyDrive. + /// </summary> + public const string Skydrive = "wl.skydrive"; + + /// <summary> + /// Read and write access to a user's files stored in SkyDrive. + /// </summary> + public const string SkydriveUpdate = "wl.skydrive_update"; + + /// <summary> + /// Read access to a user's employer and work position information. + /// </summary> + public const string WorkProfile = "wl.work_profile"; + + #endregion + } + } +} diff --git a/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/WindowsLive/WindowsLiveGraph.cs b/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/WindowsLive/WindowsLiveGraph.cs new file mode 100644 index 0000000..8b4e1f8 --- /dev/null +++ b/samples/DotNetOpenAuth.ApplicationBlock/OAuth2/WindowsLive/WindowsLiveGraph.cs @@ -0,0 +1,299 @@ +//----------------------------------------------------------------------- +// <copyright file="WindowsLiveGraph.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.ApplicationBlock { + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Runtime.Serialization; + using System.Runtime.Serialization.Json; + using System.Text; + + //// Documentation: http://msdn.microsoft.com/en-us/library/live/hh243648.aspx#user + + [DataContract] + public class WindowsLiveGraph : IOAuth2Graph { + private static DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(WindowsLiveGraph)); + + /// <summary> + /// Gets or sets the user's ID. + /// </summary> + [DataMember(Name = "id", IsRequired = true)] + public string Id { get; set; } + + /// <summary> + /// Gets or sets the user's full name. + /// </summary> + [DataMember(Name = "name", IsRequired = true)] + public string Name { get; set; } + + /// <summary> + /// Gets or sets the user's first name. + /// </summary> + [DataMember(Name = "first_name")] + public string FirstName { get; set; } + + /// <summary> + /// Gets or sets the user's last name. + /// </summary> + [DataMember(Name = "last_name")] + public string LastName { get; set; } + + /// <summary> + /// Gets or sets the URL of the user's profile page. + /// </summary> + [DataMember(Name = "link")] + public Uri Link { get; set; } + + /// <summary> + /// Gets or sets the day of the user's birth date, or null if no birth date is specified. + /// </summary> + [DataMember(Name = "birth_day")] + public int? BirthDay { get; set; } + + /// <summary> + /// Gets or sets the month of the user's birth date, or null if no birth date is specified. + /// </summary> + [DataMember(Name = "birth_month")] + public int? BirthMonth { get; set; } + + /// <summary> + /// Gets or sets the year of the user's birth date, or null if no birth date is specified. + /// </summary> + [DataMember(Name = "birth_year")] + public int? BirthYear { get; set; } + + /// <summary> + /// Gets or sets an array that contains the user's work info. + /// </summary> + [DataMember(Name = "work")] + public WindowsLiveWorkProfile[] Work { get; set; } + + /// <summary> + /// Gets or sets the user's gender. Valid values are "male", "female", or null if the user's gender is not specified. + /// </summary> + [DataMember(Name = "gender")] + public string Gender { get; set; } + + /// <summary> + /// Gets or sets the user's email addresses. + /// </summary> + [DataMember(Name = "emails")] + public WindowsLiveEmails Emails { get; set; } + + /// <summary> + /// Gets or sets the user's postal addresses. + /// </summary> + [DataMember(Name = "addresses")] + public WindowsLiveAddresses Addresses { get; set; } + + /// <summary> + /// Gets or sets the user's phone numbers. + /// </summary> + [DataMember(Name = "phones")] + public WindowsLivePhones Phones { get; set; } + + /// <summary> + /// Gets or sets the user's locale code. + /// </summary> + [DataMember(Name = "locale", IsRequired = true)] + public string Locale { get; set; } + + /// <summary> + /// Gets or sets the time, in ISO 8601 format, at which the user last updated the object. + /// </summary> + [DataMember(Name = "updated_time")] + public string UpdatedTime { get; set; } + + public string Email { + get { + return this.Emails.Account; + } + } + + public Uri AvatarUrl { get; set; } + + public DateTime? BirthdayDT { + get { + if (this.BirthYear.HasValue && this.BirthMonth.HasValue && this.BirthDay.HasValue) { + return new DateTime(this.BirthYear.Value, this.BirthMonth.Value, this.BirthDay.Value); + } + + return null; + } + } + + public HumanGender GenderEnum { + get { + if (this.Gender == "male") { + return HumanGender.Male; + } else if (this.Gender == "female") { + return HumanGender.Female; + } + + return HumanGender.Unknown; + } + } + + public static WindowsLiveGraph Deserialize(string json) { + if (string.IsNullOrEmpty(json)) { + throw new ArgumentNullException("json"); + } + + return Deserialize(new MemoryStream(Encoding.UTF8.GetBytes(json))); + } + + public static WindowsLiveGraph Deserialize(Stream jsonStream) { + if (jsonStream == null) { + throw new ArgumentNullException("jsonStream"); + } + + return (WindowsLiveGraph)jsonSerializer.ReadObject(jsonStream); + } + + [DataContract] + public class WindowsLiveEmails { + /// <summary> + /// Gets or sets the user's preferred email address, or null if one is not specified. + /// </summary> + [DataMember(Name = "preferred")] + public string Preferred { get; set; } + + /// <summary> + /// Gets or sets the email address that is associated with the account. + /// </summary> + [DataMember(Name = "account", IsRequired = true)] + public string Account { get; set; } + + /// <summary> + /// Gets or sets the user's personal email address, or null if one is not specified. + /// </summary> + [DataMember(Name = "personal")] + public string Personal { get; set; } + + /// <summary> + /// Gets or sets the user's business email address, or null if one is not specified. + /// </summary> + [DataMember(Name = "business")] + public string Business { get; set; } + + /// <summary> + /// Gets or sets the user's "alternate" email address, or null if one is not specified. + /// </summary> + [DataMember(Name = "other")] + public string Other { get; set; } + } + + [DataContract] + public class WindowsLivePhones { + /// <summary> + /// Gets or sets the user's personal phone number, or null if one is not specified. + /// </summary> + [DataMember(Name = "personal")] + public string Personal { get; set; } + + /// <summary> + /// Gets or sets the user's business phone number, or null if one is not specified. + /// </summary> + [DataMember(Name = "business")] + public string Business { get; set; } + + /// <summary> + /// Gets or sets the user's mobile phone number, or null if one is not specified. + /// </summary> + [DataMember(Name = "mobile")] + public string Mobile { get; set; } + } + + [DataContract] + public class WindowsLiveAddress { + /// <summary> + /// Gets or sets the street address, or null if one is not specified. + /// </summary> + [DataMember(Name = "street")] + public string Street { get; set; } + + /// <summary> + /// Gets or sets the second line of the street address, or null if one is not specified. + /// </summary> + [DataMember(Name = "street_2")] + public string Street2 { get; set; } + + /// <summary> + /// Gets or sets the city of the address, or null if one is not specified. + /// </summary> + [DataMember(Name = "city")] + public string City { get; set; } + + /// <summary> + /// Gets or sets the state of the address, or null if one is not specified. + /// </summary> + [DataMember(Name = "state")] + public string State { get; set; } + + /// <summary> + /// Gets or sets the postal code of the address, or null if one is not specified. + /// </summary> + [DataMember(Name = "postal_code")] + public string PostalCode { get; set; } + + /// <summary> + /// Gets or sets the region of the address, or null if one is not specified. + /// </summary> + [DataMember(Name = "region")] + public string Region { get; set; } + } + + [DataContract] + public class WindowsLiveAddresses { + /// <summary> + /// Gets or sets the user's personal postal address. + /// </summary> + [DataMember(Name = "personal")] + public WindowsLiveAddress Personal { get; set; } + + /// <summary> + /// Gets or sets the user's business postal address. + /// </summary> + [DataMember(Name = "business")] + public WindowsLiveAddress Business { get; set; } + } + + [DataContract] + public class WindowsLiveWorkProfile { + /// <summary> + /// Gets or sets info about the user's employer. + /// </summary> + [DataMember(Name = "employer")] + public WindowsLiveEmployer Employer { get; set; } + + /// <summary> + /// Gets or sets info about the user's employer. + /// </summary> + [DataMember(Name = "position")] + public WindowsLivePosition Position { get; set; } + } + + [DataContract] + public class WindowsLiveEmployer { + /// <summary> + /// Gets or sets the name of the user's employer, or null if the employer's name is not specified. + /// </summary> + [DataMember(Name = "name")] + public string Name { get; set; } + } + + [DataContract] + public class WindowsLivePosition { + /// <summary> + /// Gets or sets the name of the user's work position, or null if the name of the work position is not specified. + /// </summary> + [DataMember(Name = "name")] + public string Name { get; set; } + } + } +} diff --git a/samples/DotNetOpenAuth.ApplicationBlock/WindowsLiveClient.cs b/samples/DotNetOpenAuth.ApplicationBlock/WindowsLiveClient.cs deleted file mode 100644 index a2e1058..0000000 --- a/samples/DotNetOpenAuth.ApplicationBlock/WindowsLiveClient.cs +++ /dev/null @@ -1,51 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="WindowsLiveClient.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.ApplicationBlock { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Text; - using DotNetOpenAuth.OAuth2; - - public class WindowsLiveClient : WebServerClient { - private static readonly AuthorizationServerDescription WindowsLiveDescription = new AuthorizationServerDescription { - TokenEndpoint = new Uri("https://oauth.live.com/token"), - AuthorizationEndpoint = new Uri("https://oauth.live.com/authorize"), - }; - - /// <summary> - /// Initializes a new instance of the <see cref="WindowsLiveClient"/> class. - /// </summary> - public WindowsLiveClient() - : base(WindowsLiveDescription) { - } - - /// <summary> - /// Well-known scopes defined by the Windows Live service. - /// </summary> - /// <remarks> - /// This sample includes just a few scopes. For a complete list of scopes please refer to: - /// http://msdn.microsoft.com/en-us/library/hh243646.aspx - /// </remarks> - public static class Scopes { - /// <summary> - /// The ability of an app to read and update a user's info at any time. Without this scope, an app can access the user's info only while the user is signed in to Live Connect and is using your app. - /// </summary> - public const string OfflineAccess = "wl.offline_access"; - - /// <summary> - /// Single sign-in behavior. With single sign-in, users who are already signed in to Live Connect are also signed in to your website. - /// </summary> - public const string SignIn = "wl.signin"; - - /// <summary> - /// Read access to a user's basic profile info. Also enables read access to a user's list of contacts. - /// </summary> - public const string Basic = "wl.basic"; - } - } -} diff --git a/samples/DotNetOpenAuth.ApplicationBlock/WindowsLiveGraph.cs b/samples/DotNetOpenAuth.ApplicationBlock/WindowsLiveGraph.cs deleted file mode 100644 index 4801226..0000000 --- a/samples/DotNetOpenAuth.ApplicationBlock/WindowsLiveGraph.cs +++ /dev/null @@ -1,60 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="WindowsLiveGraph.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.ApplicationBlock { - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Runtime.Serialization; - using System.Runtime.Serialization.Json; - using System.Text; - - [DataContract] - public class WindowsLiveGraph { - private static DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(WindowsLiveGraph)); - - [DataMember(Name = "id")] - public string Id { get; set; } - - [DataMember(Name = "name")] - public string Name { get; set; } - - [DataMember(Name = "first_name")] - public string FirstName { get; set; } - - [DataMember(Name = "last_name")] - public string LastName { get; set; } - - [DataMember(Name = "link")] - public Uri Link { get; set; } - - [DataMember(Name = "gender")] - public string Gender { get; set; } - - [DataMember(Name = "updated_time")] - public string UpdatedTime { get; set; } - - [DataMember(Name = "locale")] - public string Locale { get; set; } - - public static WindowsLiveGraph Deserialize(string json) { - if (string.IsNullOrEmpty(json)) { - throw new ArgumentNullException("json"); - } - - return Deserialize(new MemoryStream(Encoding.UTF8.GetBytes(json))); - } - - public static WindowsLiveGraph Deserialize(Stream jsonStream) { - if (jsonStream == null) { - throw new ArgumentNullException("jsonStream"); - } - - return (WindowsLiveGraph)jsonSerializer.ReadObject(jsonStream); - } - } -} diff --git a/samples/DotNetOpenAuth.ApplicationBlock/azureadclient.cs b/samples/DotNetOpenAuth.ApplicationBlock/azureadclient.cs new file mode 100644 index 0000000..70a97b4 --- /dev/null +++ b/samples/DotNetOpenAuth.ApplicationBlock/azureadclient.cs @@ -0,0 +1,112 @@ +//----------------------------------------------------------------------- +// <copyright file="AzureADClient.cs" company="Microsoft"> +// Copyright (c) Microsoft. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.ApplicationBlock +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Web.Script.Serialization; + using DotNetOpenAuth.OAuth2; + + public class AzureADClient : WebServerClient + { + private static readonly AuthorizationServerDescription AzureADDescription = new AuthorizationServerDescription + { + TokenEndpoint = new Uri("https://login.windows.net/common/oauth2/token"), + AuthorizationEndpoint = new Uri("https://login.windows.net/common/oauth2/authorize?resource=00000002-0000-0000-c000-000000000000/graph.windows.net"), + }; + + /// <summary> + /// Initializes a new instance of the <see cref="AzureADClient"/> class. + /// </summary> + public AzureADClient() + : base(AzureADDescription) + { + } + + #region Methods + + /// <summary> + /// Parses the access token into an AzureAD token. + /// </summary> + /// <param name="token"> + /// The token as a string. + /// </param> + /// <returns> + /// The claims as an object and null in case of failure. + /// </returns> + public AzureADClaims ParseAccessToken(string token) + { + try + { + // This is the encoded JWT token split into the 3 parts + string[] strparts = token.Split('.'); + + // Decparts has the header and claims section decoded from JWT + string jwtHeader, jwtClaims; + string jwtb64Header, jwtb64Claims, jwtb64Sig; + byte[] jwtSig; + if (strparts.Length != 3) + { + return null; + } + jwtb64Header = strparts[0]; + jwtb64Claims = strparts[1]; + jwtb64Sig = strparts[2]; + jwtHeader = Base64URLdecode(jwtb64Header); + jwtClaims = Base64URLdecode(jwtb64Claims); + jwtSig = Base64URLdecodebyte(jwtb64Sig); + + JavaScriptSerializer s1 = new JavaScriptSerializer(); + + AzureADClaims claimsAD = s1.Deserialize<AzureADClaims>(jwtClaims); + AzureADHeader headerAD = s1.Deserialize<AzureADHeader>(jwtHeader); + + return claimsAD; + } + catch (Exception) + { + return null; + } + } + + /// <summary> + /// Base64 decode function except that it switches -_ to +/ before base64 decode + /// </summary> + /// <param name="str"> + /// The string to be base64urldecoded. + /// </param> + /// <returns> + /// Decoded string as string using UTF8 encoding. + /// </returns> + private static string Base64URLdecode(string str) + { + System.Text.UTF8Encoding encoder = new System.Text.UTF8Encoding(); + return encoder.GetString(Base64URLdecodebyte(str)); + } + + /// <summary> + /// Base64 decode function except that it switches -_ to +/ before base64 decode + /// </summary> + /// <param name="str"> + /// The string to be base64urldecoded. + /// </param> + /// <returns> + /// Decoded string as bytes. + /// </returns> + private static byte[] Base64URLdecodebyte(string str) + { + // First replace chars and then pad per spec + str = str.Replace('-', '+').Replace('_', '/'); + str = str.PadRight(str.Length + ((4 - (str.Length % 4)) % 4), '='); + return Convert.FromBase64String(str); + } + + #endregion + } +} |