diff --git a/eng/PatchConfig.props b/eng/PatchConfig.props index 5ce6494e432d..0a6db36788a2 100644 --- a/eng/PatchConfig.props +++ b/eng/PatchConfig.props @@ -15,6 +15,7 @@ Later on, this will be checked using this condition: + Microsoft.AspNetCore.Authentication.Google; diff --git a/src/Security/Authentication/Google/src/GoogleDefaults.cs b/src/Security/Authentication/Google/src/GoogleDefaults.cs index 04287031809f..2e6cf76e270d 100644 --- a/src/Security/Authentication/Google/src/GoogleDefaults.cs +++ b/src/Security/Authentication/Google/src/GoogleDefaults.cs @@ -1,6 +1,8 @@ // 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; + namespace Microsoft.AspNetCore.Authentication.Google { /// @@ -16,6 +18,22 @@ public static class GoogleDefaults public static readonly string TokenEndpoint = "https://www.googleapis.com/oauth2/v4/token"; - public static readonly string UserInformationEndpoint = "https://www.googleapis.com/plus/v1/people/me"; + public static readonly string UserInformationEndpoint; + + private const string UseGooglePlusSwitch = "Switch.Microsoft.AspNetCore.Authentication.Google.UsePlus"; + + internal static readonly bool UseGooglePlus; + + static GoogleDefaults() + { + if (AppContext.TryGetSwitch(UseGooglePlusSwitch, out UseGooglePlus) && UseGooglePlus) + { + UserInformationEndpoint = "https://www.googleapis.com/plus/v1/people/me"; + } + else + { + UserInformationEndpoint = "https://www.googleapis.com/oauth2/v2/userinfo"; + } + } } } diff --git a/src/Security/Authentication/Google/src/GoogleOptions.cs b/src/Security/Authentication/Google/src/GoogleOptions.cs index 34028bc52b56..03abaeaada79 100644 --- a/src/Security/Authentication/Google/src/GoogleOptions.cs +++ b/src/Security/Authentication/Google/src/GoogleOptions.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Security.Claims; -using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.OAuth; using Microsoft.AspNetCore.Http; @@ -27,11 +26,22 @@ public GoogleOptions() Scope.Add("email"); ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id"); - ClaimActions.MapJsonKey(ClaimTypes.Name, "displayName"); - ClaimActions.MapJsonSubKey(ClaimTypes.GivenName, "name", "givenName"); - ClaimActions.MapJsonSubKey(ClaimTypes.Surname, "name", "familyName"); - ClaimActions.MapJsonKey("urn:google:profile", "url"); - ClaimActions.MapCustomJson(ClaimTypes.Email, GoogleHelper.GetEmail); + if (GoogleDefaults.UseGooglePlus) + { + ClaimActions.MapJsonKey(ClaimTypes.Name, "displayName"); + ClaimActions.MapJsonSubKey(ClaimTypes.GivenName, "name", "givenName"); + ClaimActions.MapJsonSubKey(ClaimTypes.Surname, "name", "familyName"); + ClaimActions.MapJsonKey("urn:google:profile", "url"); + ClaimActions.MapCustomJson(ClaimTypes.Email, GoogleHelper.GetEmail); + } + else + { + ClaimActions.MapJsonKey(ClaimTypes.Name, "name"); + ClaimActions.MapJsonKey(ClaimTypes.GivenName, "given_name"); + ClaimActions.MapJsonKey(ClaimTypes.Surname, "family_name"); + ClaimActions.MapJsonKey("urn:google:profile", "link"); + ClaimActions.MapJsonKey(ClaimTypes.Email, "email"); + } } /// @@ -39,4 +49,4 @@ public GoogleOptions() /// public string AccessType { get; set; } } -} \ No newline at end of file +} diff --git a/src/Security/Authentication/test/GoogleTests.cs b/src/Security/Authentication/test/GoogleTests.cs index 511a658ff4ae..cba74a4bd944 100644 --- a/src/Security/Authentication/test/GoogleTests.cs +++ b/src/Security/Authentication/test/GoogleTests.cs @@ -809,45 +809,7 @@ public async Task ReplyPathWillAuthenticateValidAuthorizeCodeAndState(string cla { o.ClaimsIssuer = claimsIssuer; } - o.BackchannelHttpHandler = new TestHttpMessageHandler - { - Sender = req => - { - if (req.RequestUri.AbsoluteUri == "https://www.googleapis.com/oauth2/v4/token") - { - return ReturnJsonResponse(new - { - access_token = "Test Access Token", - expires_in = 3600, - token_type = "Bearer" - }); - } - else if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == "https://www.googleapis.com/plus/v1/people/me") - { - return ReturnJsonResponse(new - { - id = "Test User ID", - displayName = "Test Name", - name = new - { - familyName = "Test Family Name", - givenName = "Test Given Name" - }, - url = "Profile link", - emails = new[] - { - new - { - value = "Test email", - type = "account" - } - } - }); - } - - throw new NotImplementedException(req.RequestUri.AbsoluteUri); - } - }; + o.BackchannelHttpHandler = CreateBackchannel(); }); var properties = new AuthenticationProperties(); @@ -999,46 +961,7 @@ public async Task AuthenticatedEventCanGetRefreshToken() o.ClientId = "Test Id"; o.ClientSecret = "Test Secret"; o.StateDataFormat = stateFormat; - o.BackchannelHttpHandler = new TestHttpMessageHandler - { - Sender = req => - { - if (req.RequestUri.AbsoluteUri == "https://www.googleapis.com/oauth2/v4/token") - { - return ReturnJsonResponse(new - { - access_token = "Test Access Token", - expires_in = 3600, - token_type = "Bearer", - refresh_token = "Test Refresh Token" - }); - } - else if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == "https://www.googleapis.com/plus/v1/people/me") - { - return ReturnJsonResponse(new - { - id = "Test User ID", - displayName = "Test Name", - name = new - { - familyName = "Test Family Name", - givenName = "Test Given Name" - }, - url = "Profile link", - emails = new[] - { - new - { - value = "Test email", - type = "account" - } - } - }); - } - - throw new NotImplementedException(req.RequestUri.AbsoluteUri); - } - }; + o.BackchannelHttpHandler = CreateBackchannel(); o.Events = new OAuthEvents { OnCreatingTicket = context => @@ -1079,46 +1002,7 @@ public async Task NullRedirectUriWillRedirectToSlash() o.ClientId = "Test Id"; o.ClientSecret = "Test Secret"; o.StateDataFormat = stateFormat; - o.BackchannelHttpHandler = new TestHttpMessageHandler - { - Sender = req => - { - if (req.RequestUri.AbsoluteUri == "https://www.googleapis.com/oauth2/v4/token") - { - return ReturnJsonResponse(new - { - access_token = "Test Access Token", - expires_in = 3600, - token_type = "Bearer", - refresh_token = "Test Refresh Token" - }); - } - else if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == "https://www.googleapis.com/plus/v1/people/me") - { - return ReturnJsonResponse(new - { - id = "Test User ID", - displayName = "Test Name", - name = new - { - familyName = "Test Family Name", - givenName = "Test Given Name" - }, - url = "Profile link", - emails = new[] - { - new - { - value = "Test email", - type = "account" - } - } - }); - } - - throw new NotImplementedException(req.RequestUri.AbsoluteUri); - } - }; + o.BackchannelHttpHandler = CreateBackchannel(); o.Events = new OAuthEvents { OnTicketReceived = context => @@ -1169,46 +1053,7 @@ public async Task ValidateAuthenticatedContext() return Task.FromResult(0); } }; - o.BackchannelHttpHandler = new TestHttpMessageHandler - { - Sender = req => - { - if (req.RequestUri.AbsoluteUri == "https://www.googleapis.com/oauth2/v4/token") - { - return ReturnJsonResponse(new - { - access_token = "Test Access Token", - expires_in = 3600, - token_type = "Bearer", - refresh_token = "Test Refresh Token" - }); - } - else if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == "https://www.googleapis.com/plus/v1/people/me") - { - return ReturnJsonResponse(new - { - id = "Test User ID", - displayName = "Test Name", - name = new - { - familyName = "Test Family Name", - givenName = "Test Given Name" - }, - url = "Profile link", - emails = new[] - { - new - { - value = "Test email", - type = "account" - } - } - }); - } - - throw new NotImplementedException(req.RequestUri.AbsoluteUri); - } - }; + o.BackchannelHttpHandler = CreateBackchannel(); }); var properties = new AuthenticationProperties(); @@ -1439,29 +1284,20 @@ private HttpMessageHandler CreateBackchannel() { access_token = "Test Access Token", expires_in = 3600, - token_type = "Bearer" + token_type = "Bearer", + refresh_token = "Test Refresh Token" }); } - else if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == "https://www.googleapis.com/plus/v1/people/me") + else if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == "https://www.googleapis.com/oauth2/v2/userinfo") { return ReturnJsonResponse(new { id = "Test User ID", - displayName = "Test Name", - name = new - { - familyName = "Test Family Name", - givenName = "Test Given Name" - }, - url = "Profile link", - emails = new[] - { - new - { - value = "Test email", - type = "account" - } - } + name = "Test Name", + given_name = "Test Given Name", + family_name = "Test Family Name", + link = "Profile link", + email = "Test email", }); } diff --git a/src/Security/Security.sln b/src/Security/Security.sln index b8aa6968a45d..3d36597db9d3 100644 --- a/src/Security/Security.sln +++ b/src/Security/Security.sln @@ -96,12 +96,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Diagno EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.StaticFiles", "..\Middleware\StaticFiles\src\Microsoft.AspNetCore.StaticFiles.csproj", "{6FFBD7CD-2B7D-4EC9-8D18-54E53F852B04}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.IISIntegration", "..\Servers\IIS\IISIntegration\src\Microsoft.AspNetCore.Server.IISIntegration.csproj", "{43AF597A-FCB8-41A5-8279-345FEE9A61AD}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel", "..\Servers\Kestrel\Kestrel\src\Microsoft.AspNetCore.Server.Kestrel.csproj", "{707CBFB4-4D35-479E-9BAF-39B4DA9782DE}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Https", "..\Servers\Kestrel\Https\src\Microsoft.AspNetCore.Server.Kestrel.Https.csproj", "{AFE880E8-2E9E-46FD-BE87-DFC8192E7B2D}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.IISIntegration", "..\Servers\IIS\IISIntegration\src\Microsoft.AspNetCore.Server.IISIntegration.csproj", "{81D0E81F-4711-4C7B-BBD4-E168102D0D7D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -236,10 +236,6 @@ Global {6FFBD7CD-2B7D-4EC9-8D18-54E53F852B04}.Debug|Any CPU.Build.0 = Debug|Any CPU {6FFBD7CD-2B7D-4EC9-8D18-54E53F852B04}.Release|Any CPU.ActiveCfg = Release|Any CPU {6FFBD7CD-2B7D-4EC9-8D18-54E53F852B04}.Release|Any CPU.Build.0 = Release|Any CPU - {43AF597A-FCB8-41A5-8279-345FEE9A61AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {43AF597A-FCB8-41A5-8279-345FEE9A61AD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {43AF597A-FCB8-41A5-8279-345FEE9A61AD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {43AF597A-FCB8-41A5-8279-345FEE9A61AD}.Release|Any CPU.Build.0 = Release|Any CPU {707CBFB4-4D35-479E-9BAF-39B4DA9782DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {707CBFB4-4D35-479E-9BAF-39B4DA9782DE}.Debug|Any CPU.Build.0 = Debug|Any CPU {707CBFB4-4D35-479E-9BAF-39B4DA9782DE}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -248,6 +244,10 @@ Global {AFE880E8-2E9E-46FD-BE87-DFC8192E7B2D}.Debug|Any CPU.Build.0 = Debug|Any CPU {AFE880E8-2E9E-46FD-BE87-DFC8192E7B2D}.Release|Any CPU.ActiveCfg = Release|Any CPU {AFE880E8-2E9E-46FD-BE87-DFC8192E7B2D}.Release|Any CPU.Build.0 = Release|Any CPU + {81D0E81F-4711-4C7B-BBD4-E168102D0D7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {81D0E81F-4711-4C7B-BBD4-E168102D0D7D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {81D0E81F-4711-4C7B-BBD4-E168102D0D7D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {81D0E81F-4711-4C7B-BBD4-E168102D0D7D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -295,9 +295,9 @@ Global {B6CA96E4-674A-4616-9A38-DED07BE458E1} = {A3766414-EB5C-40F7-B031-121804ED5D0A} {54CBBAED-36D5-4855-BB4E-D1AE3523AA23} = {A3766414-EB5C-40F7-B031-121804ED5D0A} {6FFBD7CD-2B7D-4EC9-8D18-54E53F852B04} = {A3766414-EB5C-40F7-B031-121804ED5D0A} - {43AF597A-FCB8-41A5-8279-345FEE9A61AD} = {A3766414-EB5C-40F7-B031-121804ED5D0A} {707CBFB4-4D35-479E-9BAF-39B4DA9782DE} = {A3766414-EB5C-40F7-B031-121804ED5D0A} {AFE880E8-2E9E-46FD-BE87-DFC8192E7B2D} = {A3766414-EB5C-40F7-B031-121804ED5D0A} + {81D0E81F-4711-4C7B-BBD4-E168102D0D7D} = {A3766414-EB5C-40F7-B031-121804ED5D0A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {ABF8089E-43D0-4010-84A7-7A9DCFE49357}