Repository navigation
Expand file tree
/
Copy pathGoogleHandler.cs
More file actions
137 lines (115 loc) · 5.57 KB
/
Copy pathGoogleHandler.cs
File metadata and controls
137 lines (115 loc) · 5.57 KB
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
137
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.WebUtilities;
using Newtonsoft.Json.Linq;
namespace Microsoft.AspNetCore.Authentication.Google
{
internal class GoogleHandler : OAuthHandler<GoogleOptions>
{
public GoogleHandler(HttpClient httpClient)
: base(httpClient)
{
}
protected override async Task<AuthenticationTicket> CreateTicketAsync(
ClaimsIdentity identity,
AuthenticationProperties properties,
OAuthTokenResponse tokens)
{
// Get the Google user
var request = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokens.AccessToken);
var response = await Backchannel.SendAsync(request, Context.RequestAborted);
if (!response.IsSuccessStatusCode)
{
throw new HttpRequestException($"An error occurred when retrieving user information ({response.StatusCode}). Please check if the authentication information is correct and the corresponding Google+ API is enabled.");
}
var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme);
var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens, payload);
var identifier = GoogleHelper.GetId(payload);
if (!string.IsNullOrEmpty(identifier))
{
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, identifier, ClaimValueTypes.String, Options.ClaimsIssuer));
}
var givenName = GoogleHelper.GetGivenName(payload);
if (!string.IsNullOrEmpty(givenName))
{
identity.AddClaim(new Claim(ClaimTypes.GivenName, givenName, ClaimValueTypes.String, Options.ClaimsIssuer));
}
var familyName = GoogleHelper.GetFamilyName(payload);
if (!string.IsNullOrEmpty(familyName))
{
identity.AddClaim(new Claim(ClaimTypes.Surname, familyName, ClaimValueTypes.String, Options.ClaimsIssuer));
}
var name = GoogleHelper.GetName(payload);
if (!string.IsNullOrEmpty(name))
{
identity.AddClaim(new Claim(ClaimTypes.Name, name, ClaimValueTypes.String, Options.ClaimsIssuer));
}
var email = GoogleHelper.GetEmail(payload);
if (!string.IsNullOrEmpty(email))
{
identity.AddClaim(new Claim(ClaimTypes.Email, email, ClaimValueTypes.String, Options.ClaimsIssuer));
}
var profile = GoogleHelper.GetProfile(payload);
if (!string.IsNullOrEmpty(profile))
{
identity.AddClaim(new Claim("urn:google:profile", profile, ClaimValueTypes.String, Options.ClaimsIssuer));
}
await Options.Events.CreatingTicket(context);
return context.Ticket;
}
// TODO: Abstract this properties override pattern into the base class?
protected override string BuildChallengeUrl(AuthenticationProperties properties, string redirectUri)
{
// Google Identity Platform Manual:
// https://developers.google.com/identity/protocols/OAuth2WebServer
var queryStrings = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
queryStrings.Add("response_type", "code");
queryStrings.Add("client_id", Options.ClientId);
queryStrings.Add("redirect_uri", redirectUri);
AddQueryString(queryStrings, properties, "scope", FormatScope());
AddQueryString(queryStrings, properties, "access_type", Options.AccessType);
AddQueryString(queryStrings, properties, "approval_prompt");
AddQueryString(queryStrings, properties, "prompt");
AddQueryString(queryStrings, properties, "login_hint");
AddQueryString(queryStrings, properties, "include_granted_scopes");
var state = Options.StateDataFormat.Protect(properties);
queryStrings.Add("state", state);
var authorizationEndpoint = QueryHelpers.AddQueryString(Options.AuthorizationEndpoint, queryStrings);
return authorizationEndpoint;
}
private static void AddQueryString(
IDictionary<string, string> queryStrings,
AuthenticationProperties properties,
string name,
string defaultValue = null)
{
string value;
if (!properties.Items.TryGetValue(name, out value))
{
value = defaultValue;
}
else
{
// Remove the parameter from AuthenticationProperties so it won't be serialized to state parameter
properties.Items.Remove(name);
}
if (value == null)
{
return;
}
queryStrings[name] = value;
}
}
}