Skip to content

Commit 678a4d2

Browse files
kinosangkevinchalet
authored andcommitted
Update the Weibo provider to get email address from the emails endpoint
1 parent 83626e2 commit 678a4d2

File tree

6 files changed

+60
-9
lines changed

6 files changed

+60
-9
lines changed

src/AspNet.Security.OAuth.Patreon/PatreonAuthenticationHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync([NotNull]
5454
var principal = new ClaimsPrincipal(identity);
5555
var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme);
5656

57-
var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens);
57+
var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens, payload);
5858
await Options.Events.CreatingTicket(context);
5959

6060
return context.Ticket;

src/AspNet.Security.OAuth.Vkontakte/VkontakteAuthenticationHandler.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,17 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync([NotNull]
4949
var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
5050
var user = (JObject) payload["response"][0];
5151

52-
var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), properties, Options.AuthenticationScheme);
53-
var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens, user);
54-
5552
identity.AddOptionalClaim(ClaimTypes.NameIdentifier, VkontakteAuthenticationHelper.GetId(user), Options.ClaimsIssuer)
5653
.AddOptionalClaim(ClaimTypes.GivenName, VkontakteAuthenticationHelper.GetFirstName(user), Options.ClaimsIssuer)
5754
.AddOptionalClaim(ClaimTypes.Surname, VkontakteAuthenticationHelper.GetLastName(user), Options.ClaimsIssuer)
5855
.AddOptionalClaim(ClaimTypes.Hash, VkontakteAuthenticationHelper.GetHash(user), Options.ClaimsIssuer)
5956
.AddOptionalClaim("urn:vkontakte:photo:link", VkontakteAuthenticationHelper.GetPhoto(user), Options.ClaimsIssuer)
6057
.AddOptionalClaim("urn:vkontakte:photo_thumb:link", VkontakteAuthenticationHelper.GetPhotoThumbnail(user), Options.ClaimsIssuer);
6158

59+
var principal = new ClaimsPrincipal(identity);
60+
var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme);
61+
62+
var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens, user);
6263
await Options.Events.CreatingTicket(context);
6364

6465
return context.Ticket;

src/AspNet.Security.OAuth.Weibo/WeiboAuthenticationDefaults.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,10 @@ public static class WeiboAuthenticationDefaults
4747
/// Default value for <see cref="OAuthOptions.UserInformationEndpoint"/>.
4848
/// </summary>
4949
public const string UserInformationEndpoint = "https://api.weibo.com/2/users/show.json";
50+
51+
/// <summary>
52+
/// Default value for <see cref="WeiboAuthenticationOptions.UserEmailsEndpoint"/>.
53+
/// </summary>
54+
public const string UserEmailsEndpoint = "https://api.weibo.com/2/account/profile/email.json";
5055
}
5156
}

src/AspNet.Security.OAuth.Weibo/WeiboAuthenticationHandler.cs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
using System.Collections.Generic;
8+
using System.Linq;
89
using System.Net.Http;
910
using System.Net.Http.Headers;
1011
using System.Security.Claims;
@@ -61,17 +62,55 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync([NotNull]
6162
.AddOptionalClaim("urn:weibo:avatar_large", WeiboAuthenticationHelper.GetAvatarLarge(payload), Options.ClaimsIssuer)
6263
.AddOptionalClaim("urn:weibo:avatar_hd", WeiboAuthenticationHelper.GetAvatarHD(payload), Options.ClaimsIssuer)
6364
.AddOptionalClaim("urn:weibo:cover_image_phone", WeiboAuthenticationHelper.GetCoverImagePhone(payload), Options.ClaimsIssuer)
64-
.AddOptionalClaim("urn:weibo:location", WeiboAuthenticationHelper.GetLocation(payload), Options.ClaimsIssuer);
65+
.AddOptionalClaim("urn:weibo:location", WeiboAuthenticationHelper.GetLocation(payload), Options.ClaimsIssuer);
66+
67+
// When the email address is not public, retrieve it from
68+
// the emails endpoint if the user:email scope is specified.
69+
if (!string.IsNullOrEmpty(Options.UserEmailsEndpoint) &&
70+
!identity.HasClaim(claim => claim.Type == ClaimTypes.Email) && Options.Scope.Contains("user:email"))
71+
{
72+
identity.AddOptionalClaim(ClaimTypes.Email, await GetEmailAsync(tokens), Options.ClaimsIssuer);
73+
}
6574

6675
var principal = new ClaimsPrincipal(identity);
6776
var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme);
6877

69-
var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens);
78+
var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens, payload);
7079
await Options.Events.CreatingTicket(context);
7180

7281
return context.Ticket;
7382
}
7483

7584
protected override string FormatScope() => string.Join(",", Options.Scope);
85+
86+
protected virtual async Task<string> GetEmailAsync([NotNull] OAuthTokenResponse tokens)
87+
{
88+
// See http://open.weibo.com/wiki/2/account/profile/email for more information about the /account/profile/email.json endpoint.
89+
var address = QueryHelpers.AddQueryString(Options.UserEmailsEndpoint, new Dictionary<string, string>
90+
{
91+
["access_token"] = tokens.AccessToken
92+
});
93+
94+
var request = new HttpRequestMessage(HttpMethod.Get, address);
95+
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
96+
97+
// Failed requests shouldn't cause an error: in this case, return null to indicate that the email address cannot be retrieved.
98+
var response = await Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Context.RequestAborted);
99+
if (!response.IsSuccessStatusCode)
100+
{
101+
Logger.LogWarning("An error occurred while retrieving the email address associated with the logged in user: " +
102+
"the remote server returned a {Status} response with the following payload: {Headers} {Body}.",
103+
/* Status: */ response.StatusCode,
104+
/* Headers: */ response.Headers.ToString(),
105+
/* Body: */ await response.Content.ReadAsStringAsync());
106+
107+
return null;
108+
}
109+
110+
var payload = JArray.Parse(await response.Content.ReadAsStringAsync());
111+
112+
return (from email in payload.AsJEnumerable()
113+
select email.Value<string>("email")).FirstOrDefault();
114+
}
76115
}
77116
}

src/AspNet.Security.OAuth.Weibo/WeiboAuthenticationOptions.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ public WeiboAuthenticationOptions()
2626
UserInformationEndpoint = WeiboAuthenticationDefaults.UserInformationEndpoint;
2727

2828
Scope.Add("email");
29-
}
29+
}
30+
31+
/// <summary>
32+
/// Gets or sets the address of the endpoint exposing
33+
/// the email addresses associated with the logged in user.
34+
/// </summary>
35+
public string UserEmailsEndpoint { get; set; } = WeiboAuthenticationDefaults.UserEmailsEndpoint;
3036
}
3137
}

src/AspNet.Security.OAuth.Weixin/WeixinAuthenticationHandler.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync([NotNull]
6969
var principal = new ClaimsPrincipal(identity);
7070
var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme);
7171

72-
var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens);
73-
72+
var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens, payload);
7473
await Options.Events.CreatingTicket(context);
74+
7575
return context.Ticket;
7676
}
7777

0 commit comments

Comments
 (0)