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 · 15 comments

Comments

Projects
None yet
8 participants
@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: aspnet/AspNetCore#6069

@rhubrightj

This comment has been minimized.

Copy link

rhubrightj commented Dec 21, 2018

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

@ThoughtHopper

This comment has been minimized.

Copy link

ThoughtHopper commented Dec 21, 2018

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

This comment has been minimized.

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

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.

@hempels

This comment has been minimized.

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

This comment has been minimized.

Copy link
Member

Tratcher commented Dec 22, 2018

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

@hempels

This comment has been minimized.

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

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

This comment has been minimized.

Copy link

ThoughtHopper commented Jan 2, 2019

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

This comment has been minimized.

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 added a commit that referenced this issue Jan 3, 2019

@Tratcher

This comment has been minimized.

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 Jan 3, 2019

@rhubrightj

This comment has been minimized.

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

This comment has been minimized.

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment