1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
//-----------------------------------------------------------------------
// <copyright file="LinkedInClient.cs" company="Microsoft">
// Copyright (c) Microsoft. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.AspNet.Clients {
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth;
using DotNetOpenAuth.OAuth.ChannelElements;
using DotNetOpenAuth.OAuth.Messages;
/// <summary>
/// Represents LinkedIn authentication client.
/// </summary>
public sealed class LinkedInClient : OAuthClient {
#region Constants and Fields
/// <summary>
/// Describes the OAuth service provider endpoints for LinkedIn.
/// </summary>
public static readonly ServiceProviderDescription LinkedInServiceDescription = new ServiceProviderDescription {
RequestTokenEndpoint =
new MessageReceivingEndpoint(
"https://api.linkedin.com/uas/oauth/requestToken",
HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
UserAuthorizationEndpoint =
new MessageReceivingEndpoint(
"https://www.linkedin.com/uas/oauth/authenticate",
HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
AccessTokenEndpoint =
new MessageReceivingEndpoint(
"https://api.linkedin.com/uas/oauth/accessToken",
HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
};
#endregion
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="LinkedInClient"/> class.
/// </summary>
/// <remarks>
/// Tokens exchanged during the OAuth handshake are stored in cookies.
/// </remarks>
/// <param name="consumerKey">
/// The LinkedIn app's consumer key.
/// </param>
/// <param name="consumerSecret">
/// The LinkedIn app's consumer secret.
/// </param>
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope",
Justification = "We can't dispose the object because we still need it through the app lifetime.")]
public LinkedInClient(string consumerKey, string consumerSecret)
: this(consumerKey, consumerSecret, new CookieOAuthTokenManager()) { }
/// <summary>
/// Initializes a new instance of the <see cref="LinkedInClient"/> class.
/// </summary>
/// <param name="consumerKey">The consumer key.</param>
/// <param name="consumerSecret">The consumer secret.</param>
/// <param name="tokenManager">The token manager.</param>
public LinkedInClient(string consumerKey, string consumerSecret, IOAuthTokenManager tokenManager)
: base("linkedIn", LinkedInServiceDescription, new SimpleConsumerTokenManager(consumerKey, consumerSecret, tokenManager)) {
}
#endregion
#region Methods
/// <summary>
/// Check if authentication succeeded after user is redirected back from the service provider.
/// </summary>
/// <param name="response">The response token returned from service provider</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// Authentication result.
/// </returns>
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
Justification = "We don't care if the request fails.")]
protected override async Task<AuthenticationResult> VerifyAuthenticationCoreAsync(AuthorizedTokenResponse response, CancellationToken cancellationToken = default(CancellationToken)) {
// See here for Field Selectors API http://developer.linkedin.com/docs/DOC-1014
const string ProfileRequestUrl = "https://api.linkedin.com/v1/people/~:(id,first-name,last-name,headline,industry,summary)";
string accessToken = response.AccessToken;
var profileEndpoint = new MessageReceivingEndpoint(ProfileRequestUrl, HttpDeliveryMethods.GetRequest);
HttpRequestMessage request = await this.WebWorker.PrepareAuthorizedRequestAsync(profileEndpoint, accessToken, cancellationToken);
try {
using (var httpClient = new HttpClient()) {
using (HttpResponseMessage profileResponse = await httpClient.SendAsync(request, cancellationToken)) {
using (Stream responseStream = await profileResponse.Content.ReadAsStreamAsync()) {
XDocument document = LoadXDocumentFromStream(responseStream);
string userId = document.Root.Element("id").Value;
string firstName = document.Root.Element("first-name").Value;
string lastName = document.Root.Element("last-name").Value;
string userName = firstName + " " + lastName;
var extraData = new Dictionary<string, string>();
extraData.Add("accesstoken", accessToken);
extraData.Add("name", userName);
extraData.AddDataIfNotEmpty(document, "headline");
extraData.AddDataIfNotEmpty(document, "summary");
extraData.AddDataIfNotEmpty(document, "industry");
return new AuthenticationResult(
isSuccessful: true,
provider: this.ProviderName,
providerUserId: userId,
userName: userName,
extraData: extraData);
}
}
}
}
catch (Exception exception) {
return new AuthenticationResult(exception);
}
}
#endregion
}
}
|