diff --git a/src/Microsoft.AspNet.Authentication.Facebook/FacebookAuthenticationHandler.cs b/src/Microsoft.AspNet.Authentication.Facebook/FacebookAuthenticationHandler.cs index cc9c1fdcf..e5823ff3a 100644 --- a/src/Microsoft.AspNet.Authentication.Facebook/FacebookAuthenticationHandler.cs +++ b/src/Microsoft.AspNet.Authentication.Facebook/FacebookAuthenticationHandler.cs @@ -51,10 +51,10 @@ protected override async Task ExchangeCodeAsync(string code, protected override async Task CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens) { - var endpoint = Options.UserInformationEndpoint + "?access_token=" + UrlEncoder.UrlEncode(tokens.AccessToken); + var endpoint = QueryHelpers.AddQueryString(Options.UserInformationEndpoint, "access_token", tokens.AccessToken); if (Options.SendAppSecretProof) { - endpoint += "&appsecret_proof=" + GenerateAppSecretProof(tokens.AccessToken); + endpoint = QueryHelpers.AddQueryString(endpoint, "appsecret_proof", GenerateAppSecretProof(tokens.AccessToken)); } var response = await Backchannel.GetAsync(endpoint, Context.RequestAborted); diff --git a/test/Microsoft.AspNet.Authentication.Test/Facebook/FacebookMiddlewareTests.cs b/test/Microsoft.AspNet.Authentication.Test/Facebook/FacebookMiddlewareTests.cs index 285e368e9..7ebe9cd3c 100644 --- a/test/Microsoft.AspNet.Authentication.Test/Facebook/FacebookMiddlewareTests.cs +++ b/test/Microsoft.AspNet.Authentication.Test/Facebook/FacebookMiddlewareTests.cs @@ -3,15 +3,21 @@ using System; using System.Net; +using System.Net.Http; +using System.Collections.Generic; +using System.Text; +using System.Linq; using System.Threading.Tasks; using Microsoft.AspNet.Authentication.OAuth; using Microsoft.AspNet.Builder; +using Microsoft.AspNet.DataProtection; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Authentication; using Microsoft.AspNet.TestHost; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.WebEncoders; using Shouldly; +using Newtonsoft.Json; using Xunit; namespace Microsoft.AspNet.Authentication.Facebook @@ -168,6 +174,76 @@ public async Task ChallengeWillTriggerRedirection() location.ShouldContain("state="); } + [Fact] + public async Task CustomUserInfoEndpointHasValidGraphQuery() + { + var customUserInfoEndpoint = "https://graph.facebook.com/me?fields=email,timezone,picture"; + string finalUserInfoEndpoint = string.Empty; + var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("FacebookTest")); + var server = CreateServer( + app => + { + app.UseFacebookAuthentication(); + app.UseCookieAuthentication(); + }, + services => + { + services.AddAuthentication(); + services.ConfigureFacebookAuthentication(options => + { + options.AppId = "Test App Id"; + options.AppSecret = "Test App Secret"; + options.StateDataFormat = stateFormat; + options.UserInformationEndpoint = customUserInfoEndpoint; + options.BackchannelHttpHandler = new TestHttpMessageHandler + { + Sender = req => + { + if (req.RequestUri.GetLeftPart(UriPartial.Path) == FacebookAuthenticationDefaults.TokenEndpoint) + { + var res = new HttpResponseMessage(HttpStatusCode.OK); + var tokenResponse = new Dictionary + { + { "access_token", "TestAuthToken" }, + }; + res.Content = new FormUrlEncodedContent(tokenResponse); + return res; + } + if (req.RequestUri.GetLeftPart(UriPartial.Path) == + new Uri(customUserInfoEndpoint).GetLeftPart(UriPartial.Path)) + { + finalUserInfoEndpoint = req.RequestUri.ToString(); + var res = new HttpResponseMessage(HttpStatusCode.OK); + var graphResponse = JsonConvert.SerializeObject(new + { + id = "TestProfileId", + name = "TestName" + }); + res.Content = new StringContent(graphResponse, Encoding.UTF8); + return res; + } + return null; + } + }; + }); + }, handler: null); + + var properties = new AuthenticationProperties(); + var correlationKey = ".AspNet.Correlation.Facebook"; + var correlationValue = "TestCorrelationId"; + properties.Items.Add(correlationKey, correlationValue); + properties.RedirectUri = "/me"; + var state = stateFormat.Protect(properties); + var transaction = await server.SendAsync( + "https://example.com/signin-facebook?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state), + correlationKey + "=" + correlationValue); + transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); + transaction.Response.Headers.Location.ToString().ShouldBe("/me"); + finalUserInfoEndpoint.Count(c => c == '?').ShouldBe(1); + finalUserInfoEndpoint.ShouldContain("fields=email,timezone,picture"); + finalUserInfoEndpoint.ShouldContain("&access_token="); + } + private static TestServer CreateServer(Action configure, Action configureServices, Func handler) { return TestServer.Create(app =>