diff --git a/src/Microsoft.Owin.Security.Google/Constants.cs b/src/Microsoft.Owin.Security.Google/Constants.cs index 08151033..5ee0744e 100644 --- a/src/Microsoft.Owin.Security.Google/Constants.cs +++ b/src/Microsoft.Owin.Security.Google/Constants.cs @@ -6,5 +6,9 @@ namespace Microsoft.Owin.Security.Google internal static class Constants { internal const string DefaultAuthenticationType = "Google"; + + internal const string AuthorizationEndpoint = "https://accounts.google.com/o/oauth2/v2/auth"; + internal const string TokenEndpoint = "https://www.googleapis.com/oauth2/v4/token"; + internal const string UserInformationEndpoint = "https://www.googleapis.com/plus/v1/people/me"; } } diff --git a/src/Microsoft.Owin.Security.Google/GoogleOAuth2AuthenticationHandler.cs b/src/Microsoft.Owin.Security.Google/GoogleOAuth2AuthenticationHandler.cs index 7ff96e93..b0e24392 100644 --- a/src/Microsoft.Owin.Security.Google/GoogleOAuth2AuthenticationHandler.cs +++ b/src/Microsoft.Owin.Security.Google/GoogleOAuth2AuthenticationHandler.cs @@ -17,10 +17,6 @@ namespace Microsoft.Owin.Security.Google { internal class GoogleOAuth2AuthenticationHandler : AuthenticationHandler { - private const string TokenEndpoint = "https://accounts.google.com/o/oauth2/token"; - private const string UserInfoEndpoint = "https://www.googleapis.com/plus/v1/people/me"; - private const string AuthorizeEndpoint = "https://accounts.google.com/o/oauth2/auth"; - private readonly ILogger _logger; private readonly HttpClient _httpClient; @@ -76,7 +72,7 @@ namespace Microsoft.Owin.Security.Google // Request the token HttpResponseMessage tokenResponse = - await _httpClient.PostAsync(TokenEndpoint, new FormUrlEncodedContent(body)); + await _httpClient.PostAsync(Options.TokenEndpoint, new FormUrlEncodedContent(body)); tokenResponse.EnsureSuccessStatusCode(); string text = await tokenResponse.Content.ReadAsStringAsync(); @@ -91,7 +87,7 @@ namespace Microsoft.Owin.Security.Google } // Get the Google user - HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, UserInfoEndpoint); + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); HttpResponseMessage graphResponse = await _httpClient.SendAsync(request, Request.CallCancelled); graphResponse.EnsureSuccessStatusCode(); @@ -204,7 +200,7 @@ namespace Microsoft.Owin.Security.Google string state = Options.StateDataFormat.Protect(properties); queryStrings.Add("state", state); - string authorizationEndpoint = WebUtilities.AddQueryString(AuthorizeEndpoint, + string authorizationEndpoint = WebUtilities.AddQueryString(Options.AuthorizationEndpoint, queryStrings); var redirectContext = new GoogleOAuth2ApplyRedirectContext( diff --git a/src/Microsoft.Owin.Security.Google/GoogleOAuth2AuthenticationOptions.cs b/src/Microsoft.Owin.Security.Google/GoogleOAuth2AuthenticationOptions.cs index 918a3721..655e5c53 100644 --- a/src/Microsoft.Owin.Security.Google/GoogleOAuth2AuthenticationOptions.cs +++ b/src/Microsoft.Owin.Security.Google/GoogleOAuth2AuthenticationOptions.cs @@ -30,6 +30,10 @@ namespace Microsoft.Owin.Security.Google Scope = new List(); BackchannelTimeout = TimeSpan.FromSeconds(60); CookieManager = new CookieManager(); + + AuthorizationEndpoint = Constants.AuthorizationEndpoint; + TokenEndpoint = Constants.TokenEndpoint; + UserInformationEndpoint = Constants.UserInformationEndpoint; } /// @@ -42,6 +46,21 @@ namespace Microsoft.Owin.Security.Google /// public string ClientSecret { get; set; } + /// + /// Gets or sets the URI where the client will be redirected to authenticate. + /// + public string AuthorizationEndpoint { get; set; } + + /// + /// Gets or sets the URI the middleware will access to exchange the OAuth token. + /// + public string TokenEndpoint { get; set; } + + /// + /// Gets or sets the URI the middleware will access to obtain the user information. + /// + public string UserInformationEndpoint { get; set; } + /// /// Gets or sets the a pinned certificate validator to use to validate the endpoints used /// in back channel communications belong to Google. diff --git a/tests/FunctionalTests/Facts/Security/Google/GoogleOAuth2Authentication.cs b/tests/FunctionalTests/Facts/Security/Google/GoogleOAuth2Authentication.cs index da481a72..f7601ed2 100644 --- a/tests/FunctionalTests/Facts/Security/Google/GoogleOAuth2Authentication.cs +++ b/tests/FunctionalTests/Facts/Security/Google/GoogleOAuth2Authentication.cs @@ -34,7 +34,7 @@ namespace FunctionalTests.Facts.Security.Google // Unauthenticated request - verify Redirect url var response = await httpClient.GetAsync(applicationUrl); - Assert.Equal("https://accounts.google.com/o/oauth2/auth", response.Headers.Location.AbsoluteUri.Replace(response.Headers.Location.Query, string.Empty)); + Assert.Equal("https://accounts.google.com/o/oauth2/v2/auth", response.Headers.Location.AbsoluteUri.Replace(response.Headers.Location.Query, string.Empty)); var queryItems = response.Headers.Location.ParseQueryString(); Assert.Equal("code", queryItems["response_type"]); Assert.Equal("offline", queryItems["access_type"]); @@ -176,7 +176,7 @@ namespace FunctionalTests.Facts.Security.Google { var response = new HttpResponseMessage(); - if (request.RequestUri.AbsoluteUri.StartsWith("https://accounts.google.com/o/oauth2/token")) + if (request.RequestUri.AbsoluteUri.StartsWith("https://www.googleapis.com/oauth2/v4/token")) { var formData = await request.Content.ReadAsFormDataAsync(); if (formData["grant_type"] == "authorization_code") diff --git a/tests/FunctionalTests/Facts/Security/Google/GoogleOAuth2AuthorizeParameters.cs b/tests/FunctionalTests/Facts/Security/Google/GoogleOAuth2AuthorizeParameters.cs index d90bdfb8..b6d79d35 100644 --- a/tests/FunctionalTests/Facts/Security/Google/GoogleOAuth2AuthorizeParameters.cs +++ b/tests/FunctionalTests/Facts/Security/Google/GoogleOAuth2AuthorizeParameters.cs @@ -26,7 +26,7 @@ namespace FunctionalTests.Facts.Security.Google // Unauthenticated request - verify Redirect url var response = await httpClient.GetAsync(applicationUrl); - Assert.Equal("https://accounts.google.com/o/oauth2/auth", response.Headers.Location.AbsoluteUri.Replace(response.Headers.Location.Query, string.Empty)); + Assert.Equal("https://accounts.google.com/o/oauth2/v2/auth", response.Headers.Location.AbsoluteUri.Replace(response.Headers.Location.Query, string.Empty)); var queryItems = response.Headers.Location.ParseQueryString(); Assert.Equal("custom_accessType", queryItems["access_type"]); Assert.Equal("custom_approval_prompt", queryItems["approval_prompt"]); diff --git a/tests/Katana.Sandbox.WebServer/Startup.cs b/tests/Katana.Sandbox.WebServer/Startup.cs index ed74fc4e..90c6ad59 100644 --- a/tests/Katana.Sandbox.WebServer/Startup.cs +++ b/tests/Katana.Sandbox.WebServer/Startup.cs @@ -72,7 +72,8 @@ namespace Katana.Sandbox.WebServer CookieManager = new SystemWebCookieManager() }); - // https://console.developers.google.com/project + // https://console.developers.google.com/apis/credentials + // https://developers.google.com/identity/protocols/OAuth2WebServer app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions() { ClientId = Environment.GetEnvironmentVariable("google:clientid"), diff --git a/tests/Microsoft.Owin.Security.Tests/Google/GoogleOAuth2MiddlewareTests.cs b/tests/Microsoft.Owin.Security.Tests/Google/GoogleOAuth2MiddlewareTests.cs index a9d84b89..e546266d 100644 --- a/tests/Microsoft.Owin.Security.Tests/Google/GoogleOAuth2MiddlewareTests.cs +++ b/tests/Microsoft.Owin.Security.Tests/Google/GoogleOAuth2MiddlewareTests.cs @@ -39,7 +39,7 @@ namespace Microsoft.Owin.Security.Tests.Google var transaction = await SendAsync(server, "https://example.com/challenge"); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); var location = transaction.Response.Headers.Location.ToString(); - location.ShouldContain("https://accounts.google.com/o/oauth2/auth?response_type=code"); + location.ShouldContain("https://accounts.google.com/o/oauth2/v2/auth?response_type=code"); location.ShouldContain("&client_id="); location.ShouldContain("&redirect_uri="); location.ShouldContain("&scope="); @@ -62,7 +62,7 @@ namespace Microsoft.Owin.Security.Tests.Google var transaction = await SendAsync(server, "https://example.com/401"); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); var location = transaction.Response.Headers.Location.ToString(); - location.ShouldContain("https://accounts.google.com/o/oauth2/auth?response_type=code"); + location.ShouldContain("https://accounts.google.com/o/oauth2/v2/auth?response_type=code"); location.ShouldContain("&client_id="); location.ShouldContain("&redirect_uri="); location.ShouldContain("&scope="); @@ -224,7 +224,7 @@ namespace Microsoft.Owin.Security.Tests.Google { Sender = async req => { - if (req.RequestUri.AbsoluteUri == "https://accounts.google.com/o/oauth2/token") + if (req.RequestUri.AbsoluteUri == "https://www.googleapis.com/oauth2/v4/token") { return await ReturnJsonResponse(new { @@ -355,7 +355,7 @@ namespace Microsoft.Owin.Security.Tests.Google { Sender = async req => { - if (req.RequestUri.AbsoluteUri == "https://accounts.google.com/o/oauth2/token") + if (req.RequestUri.AbsoluteUri == "https://www.googleapis.com/oauth2/v4/token") { return await ReturnJsonResponse(new {