Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Google+ shutdown impacts #251

Closed
fhtino opened this issue Dec 21, 2018 · 23 comments
Closed

Google+ shutdown impacts #251

fhtino opened this issue Dec 21, 2018 · 23 comments
Assignees
Labels
3 - Done bug PRI: 0 - Critical Blocks a critical product path. Must be handled immediately
Milestone

Comments

@fhtino
Copy link

fhtino commented Dec 21, 2018

As far as I can understand, I suppose this library will be impacted by Google+ API shutdown on March, 7 2019. Like AspNetCore, Katana uses deprecated API URL, like "https://www.googleapis.com/plus/v1/people/me"
Issue opened on AspNet core: dotnet/aspnetcore#6069

@rhubrightj
Copy link

Definitely a breaking change on my site... I hope it's as simple as just updating Microsoft.Owin.Security.Google NuGet pkg.

@ThoughtHopper
Copy link

Yup this will break our stuff.
Google has really screwed us up by pushing the date to end of march.

I tried changing the endpoints to the endpoints given back by the well-known configuration:
https://accounts.google.com/.well-known/openid-configuration

The current code works until it tries to retrieve the userinfo.
The response is not the same format as the response given by google+ apis.
Fails @ GoogleOAuth2AuthenticatedContext constructor parsing the givenName

For users like us, we do not really need to poke the userinfo endpoint, the id_token already contains information about the user. I guess in some cases it may be easier to poke the user endpoint than to actually verify the id_token.

Anyway, I hope there is an answer soon from the owners of the project, Google has threaten to start failing requests as early as January 28,2019.

@luronumen
Copy link

luronumen commented Dec 22, 2018

Hi @Tratcher

Could you please comment this issue? Is there any possibility to fix it thru the Microsoft.Owin.Security.Google NuGet package?
For more details about this issue you can check:

Thanks in advance!

@fhtino
Copy link
Author

fhtino commented Dec 22, 2018

Perhaps a couple of small changes could solve the issue.

In Microsoft.Owin.Security.Google.Constants

...
internal const string UserInformationEndpoint = "https://www.googleapis.com/userinfo/v2/me";   //OLD:"https://www.googleapis.com/plus/v1/people/me";
...

In Microsoft.Owin.Security.Google.GoogleOAuth2AuthenticatedContext

public GoogleOAuth2AuthenticatedContext(IOwinContext context, JObject user, string accessToken, string refreshToken, string expires)
...and...
public GoogleOAuth2AuthenticatedContext(IOwinContext context, JObject user, JObject tokenResponse)

{
...
// **** NEW ***
Id = TryGetValue(user, "id");
Name = TryGetValue(user, "name");
GivenName = TryGetValue(user, "given_name");
FamilyName = TryGetValue(user, "family_name");
Profile = TryGetValue(user, "link");
Email = TryGetValue(user, "email");

// *** OLD ***
//Id = TryGetValue(user, "id");
//Name = TryGetValue(user, "displayName");
//GivenName = TryGetValue(user, "name", "givenName");
//FamilyName = TryGetValue(user, "name", "familyName");
//Profile = TryGetValue(user, "url");
//Email = TryGetFirstValue(user, "emails", "value"); 
}

I tried the new code. The "id" and the other fields are filled with the same values. It seems backward compatible. The ClaimsIdentitity is filled with the same values.

@Tratcher
Copy link
Member

Tratcher commented Dec 22, 2018

Here's a temporary workaround. I tested it with 4.0 but it should also work with 3.1.


            app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
            {
                ClientId = Environment.GetEnvironmentVariable("google:clientid"),
                ClientSecret = Environment.GetEnvironmentVariable("google:clientsecret"),
                UserInformationEndpoint = "https://www.googleapis.com/oauth2/v2/userinfo",
                BackchannelHttpHandler = new GoogleUserInfoRemapper(new WebRequestHandler())
            });
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;

namespace Katana.Sandbox.WebServer
{
    internal class GoogleUserInfoRemapper : DelegatingHandler
    {
        public GoogleUserInfoRemapper(HttpMessageHandler innerHandler) : base(innerHandler) { }

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var response = await base.SendAsync(request, cancellationToken);

            if (!request.RequestUri.AbsoluteUri.Equals("https://www.googleapis.com/oauth2/v2/userinfo"))
            {
                return response;
            }

            response.EnsureSuccessStatusCode();
            var text = await response.Content.ReadAsStringAsync();
            JObject user = JObject.Parse(text);
            JObject legacyFormat = new JObject();

            JToken token;
            if (user.TryGetValue("id", out token))
            {
                legacyFormat["id"] = token;
            }
            if (user.TryGetValue("name", out token))
            {
                legacyFormat["displayName"] = token;
            }
            JToken given, family;
            if (user.TryGetValue("given_name", out given) && user.TryGetValue("family_name", out family))
            {
                var name = new JObject();
                name["givenName"] = given;
                name["familyName"] = family;
                legacyFormat["name"] = name;
            }
            if (user.TryGetValue("link", out token))
            {
                legacyFormat["url"] = token;
            }
            if (user.TryGetValue("email", out token))
            {
                var email = new JObject();
                email["value"] = token;
                legacyFormat["emails"] = new JArray(email);
            }
            if (user.TryGetValue("picture", out token))
            {
                var image = new JObject();
                image["url"] = token;
                legacyFormat["image"] = image;
            }

            text = legacyFormat.ToString();
            response.Content = new StringContent(text);
            return response;
        }
    }
}

[Edit: Updated with a different endpoint]

We'll see about getting a real fix into 4.0.1.

@Tratcher Tratcher self-assigned this Dec 22, 2018
@Tratcher Tratcher added this to the 4.0.1 milestone Dec 22, 2018
@Tratcher Tratcher added bug PRI: 0 - Critical Blocks a critical product path. Must be handled immediately labels Dec 22, 2018
@hempels
Copy link

hempels commented Dec 22, 2018

I think someone should try to figure out what the differences are (if any) in the data returned by using their openid connect endpoint versus their Me API. They might be the same under the hood or they might not.

@Tratcher
Copy link
Member

They're not, the workaround above accounts for the difference.

@hempels
Copy link

hempels commented Dec 23, 2018

I guess my real point was that if we were using a Me API from G+ before, I don't understand why we'd switch to an Open ID Connect API instead of using their other Me API that's outside of G+. Assuming the only reason for making the change is that one was deprecated, taking on any additional risk by switching paradigms seems unnecessary. I'm not opposed to it, I just don't understand the motivation.

@fhtino
Copy link
Author

fhtino commented Dec 23, 2018

For info: the two, not deprecated Google UserInfo APIs, return very similar json.
The remapping in GoogleOAuth2AuthenticatedContext class should solve the whole issue.

https://www.googleapis.com/userinfo/v2/me
{
  "id": "106...............784",
  "email": "foobar...@gmail.com",
  "verified_email": true,
  "name": "John Doe",
  "given_name": "John",
  "family_name": "Doe",
  "link": "https://plus.google.com/106...............784",
  "picture": "https://lh4.googleusercontent.com/-vGrMT7f_lSE/AAAAAAAAAAI/AAAAAAAAAAA/xxxxxxxxx/photo.jpg",
  "gender": "male",
  "locale": "en"
}

https://openidconnect.googleapis.com/v1/userinfo
{  
  "sub": "106...............784",
  "name": "John Doe",
  "given_name": "John",
  "family_name": "Doe",
  "profile": "https://plus.google.com/106...............784",
  "picture": "https://lh4.googleusercontent.com/-vGrMT7f_lSE/AAAAAAAAAAI/AAAAAAAAAAA/xxxxxxxxx/photo.jpg",
  "email": "foobar...@gmail.com",
  "email_verified": true,
  "gender": "male",
  "locale": "en"
}

@ADefWebserver
Copy link

ADefWebserver commented Dec 26, 2018

Here's a temporary workaround. I tested it with 4.0 but it should also work with 3.1.

I can confirm this worked on my .Net 4.5.2 project. I updated the Microsoft.Owin.Security.Google to 4.0.0 first. I disabled the Google+ API in the Google API Console (https://console.developers.google.com/apis) and I was able to log in using this updated code, and retrieve the properties of the logged in user.

@ThoughtHopper
Copy link

Good day, @Tratcher

I was just wondering if it's possible for you to give a tentative date of when this will be officially fixed.
I ask due to time constraints, planning, scheduling, development, testing, etc.
We need to know if we should wait for it or try to implement one of the workarounds suggested.

Much appreciated

@Tratcher
Copy link
Member

Tratcher commented Jan 3, 2019

@ThoughtHopper we don't have a specific date yet.

The fix here is easy enough, but releasing 4.0.1 requires updating a lot of infrastructure that's gotten out of date. You can track our progress at https://github.com/aspnet/AspNetKatana/milestone/8

@Tratcher
Copy link
Member

Tratcher commented Jan 3, 2019

Fixed by #253. I ended up using an OAuth2 specific endpoint and I updated the mitigation above to match.

@Tratcher Tratcher closed this as completed Jan 3, 2019
@rhubrightj
Copy link

rhubrightj commented Jan 5, 2019

@Tratcher , I disabled the google+ api as instructed and used the temporary workaround. Not working, is there another api on the google side i have to enable? I'm definitely missing something.

Edit: Actually as usual, a mistake on my end. Your workaround works, thank you sir!

@mamidon
Copy link

mamidon commented Jan 10, 2019

@Tratcher I actually did the same thing you did as a prototype in my own project -- can confirm that updating the user/auth/token URLs & addressing the slightly changed JSON is sufficient for migrating. Many thanks!

@Tratcher
Copy link
Member

FYI The 4.0.1 release has been published.

@luronumen
Copy link

I have updated my ASP.NET MVC projects for the 4.0.1 version without any issue.
Thank you very much @Tratcher !

@jbutler94127
Copy link

Currently, we have 4.0.0, and will update to 4.0.1. Is there an easy way to prove the upgrade will work after it's been totally deactivated? ie after upgrading, can I disable Google API+ and then still be able to register / login with Google credentials?

@Tratcher
Copy link
Member

@jbutler94127 correct, you can disable G+ now and verify your app still works.

@imukai
Copy link

imukai commented Jan 29, 2019

I tried doing the workaround in my core 1 project but new WebRequestHandler doesn't seem to be a thing. My project isn't using Microsoft.Owin but it is using Microsoft.AspNetCore.Authentication.Google v1.1 which has a recent prerelease package that might fix this.

But in lieu of that, any idea what the correct handler is to pass into your workaround class other than WebRequestHandler?

@Tratcher
Copy link
Member

Tratcher commented Jan 29, 2019

@imukai You can use HttpClientHandler instead of WebRequestHandler.

Note there are no patches planned for 1.1.

@imukai
Copy link

imukai commented Jan 30, 2019

That worked. I was able to disable their G+ API. Thank you. It's been a long while since I did anything with handlers and I couldn't figure out offhand which was the correct one to use.

The v1.1 of Microsoft.AspNetCore.Authentication.Google I have been using for 2 years already has a v2 and v3 (in pre-release) -- one day when I get around to upgrading the whole project from core 1 I'll update those at the same time and see what happens.

@jaglick
Copy link

jaglick commented Feb 20, 2019

@Tratcher There still seems to be an issue with the implementation when requesting additional scopes. See my post at googleapis/google-api-dotnet-client#1332 (comment).

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
3 - Done bug PRI: 0 - Critical Blocks a critical product path. Must be handled immediately
Projects
None yet
Development

No branches or pull requests