Skip to content

Commit

Permalink
#417 Update facebook to latest API versions
Browse files Browse the repository at this point in the history
  • Loading branch information
Tratcher committed Jan 31, 2017
1 parent 49b78c0 commit b32efb3
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 32 deletions.
6 changes: 3 additions & 3 deletions src/Microsoft.Owin.Security.Facebook/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ internal static class Constants
{
public const string DefaultAuthenticationType = "Facebook";

internal const string AuthorizationEndpoint = "https://www.facebook.com/dialog/oauth";
internal const string TokenEndpoint = "https://graph.facebook.com/oauth/access_token";
internal const string UserInformationEndpoint = "https://graph.facebook.com/me";
internal const string AuthorizationEndpoint = "https://www.facebook.com/v2.8/dialog/oauth";
internal const string TokenEndpoint = "https://graph.facebook.com/v2.8/oauth/access_token";
internal const string UserInformationEndpoint = "https://graph.facebook.com/v2.8/me";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,25 @@ protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
HttpResponseMessage tokenResponse = await _httpClient.GetAsync(Options.TokenEndpoint + "?" + tokenRequest, Request.CallCancelled);
tokenResponse.EnsureSuccessStatusCode();
string text = await tokenResponse.Content.ReadAsStringAsync();
IFormCollection form = WebHelpers.ParseForm(text);
JObject response = JObject.Parse(text);

string accessToken = form["access_token"];
string expires = form["expires"];
string graphAddress = Options.UserInformationEndpoint + "?access_token=" + Uri.EscapeDataString(accessToken);
string accessToken = response.Value<string>("access_token");

if (string.IsNullOrWhiteSpace(accessToken))
{
_logger.WriteWarning("Access token was not found");
return new AuthenticationTicket(null, properties);
}

string expires = response.Value<string>("expires_in");
string graphAddress = WebUtilities.AddQueryString(Options.UserInformationEndpoint, "access_token", accessToken);
if (Options.SendAppSecretProof)
{
graphAddress += "&appsecret_proof=" + GenerateAppSecretProof(accessToken);
graphAddress = WebUtilities.AddQueryString(graphAddress, "&appsecret_proof", GenerateAppSecretProof(accessToken));
}
if (Options.Fields.Count > 0)
{
graphAddress = WebUtilities.AddQueryString(graphAddress, "fields", string.Join(",", Options.Fields));
}

HttpResponseMessage graphResponse = await _httpClient.GetAsync(graphAddress, Request.CallCancelled);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public FacebookAuthenticationOptions()
Scope = new List<string>();
BackchannelTimeout = TimeSpan.FromSeconds(60);
SendAppSecretProof = true;
Fields = new List<string>();

AuthorizationEndpoint = Constants.AuthorizationEndpoint;
TokenEndpoint = Constants.TokenEndpoint;
Expand All @@ -45,19 +46,16 @@ public FacebookAuthenticationOptions()

/// <summary>
/// Gets or sets the URI where the client will be redirected to authenticate.
/// The default value is 'https://www.facebook.com/dialog/oauth'.
/// </summary>
public string AuthorizationEndpoint { get; set; }

/// <summary>
/// Gets or sets the URI the middleware will access to exchange the OAuth token.
/// The default value is 'https://graph.facebook.com/oauth/access_token'.
/// </summary>
public string TokenEndpoint { get; set; }

/// <summary>
/// Gets or sets the URI the middleware will access to obtain the user information.
/// The default value is 'https://graph.facebook.com/me'.
/// </summary>
public string UserInformationEndpoint { get; set; }

Expand Down Expand Up @@ -129,6 +127,12 @@ public string Caption
/// </summary>
public bool SendAppSecretProof { get; set; }

/// <summary>
/// The list of fields to retrieve from the UserInformationEndpoint.
/// https://developers.facebook.com/docs/graph-api/reference/user
/// </summary>
public IList<string> Fields { get; }

/// <summary>
/// An abstraction for reading and setting cookies during the authentication process.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public async Task Security_FacebookAuthentication(HostType hostType)

// Unauthenticated request - verify Redirect url
var response = await httpClient.GetAsync(applicationUrl);
Assert.Equal<string>("https://www.facebook.com/dialog/oauth", response.Headers.Location.AbsoluteUri.Replace(response.Headers.Location.Query, string.Empty));
Assert.Equal<string>("https://www.facebook.com/v2.8/dialog/oauth", response.Headers.Location.AbsoluteUri.Replace(response.Headers.Location.Query, string.Empty));
var queryItems = response.Headers.Location.ParseQueryString();
Assert.Equal<string>("code", queryItems["response_type"]);
Assert.Equal<string>("550624398330273", queryItems["client_id"]);
Expand Down Expand Up @@ -181,7 +181,7 @@ protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage
var response = new HttpResponseMessage();
var queryParameters = request.RequestUri.ParseQueryString();

if (request.RequestUri.AbsoluteUri.StartsWith("https://graph.facebook.com/oauth/access_token"))
if (request.RequestUri.AbsoluteUri.StartsWith("https://graph.facebook.com/v2.8/oauth/access_token"))
{
if (queryParameters["grant_type"] == "authorization_code")
{
Expand All @@ -190,7 +190,7 @@ protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage
Assert.True(queryParameters["redirect_uri"].EndsWith("signin-facebook"), "Redirect URI is not ending with /signin-facebook");
Assert.Equal<string>("550624398330273", queryParameters["client_id"]);
Assert.Equal<string>("10e56a291d6b618da61b1e0dae3a8954", queryParameters["client_secret"]);
response.Content = new StringContent("access_token=ValidAccessToken&expires=100");
response.Content = new StringContent("{\"access_token\":\"ValidAccessToken\",\"token_type\":\"Bearer\",\"expires_in\":\"100\"}", Encoding.UTF8, "application/json");
}
else if (queryParameters["code"] == "InvalidCert")
{
Expand Down Expand Up @@ -222,7 +222,7 @@ protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage
}
}
}
else if (request.RequestUri.AbsoluteUri.StartsWith("https://graph.facebook.com/me"))
else if (request.RequestUri.AbsoluteUri.StartsWith("https://graph.facebook.com/v2.8/me"))
{
Assert.NotEqual<string>(null, queryParameters["appsecret_proof"]);
if (queryParameters["access_token"] == "ValidAccessToken")
Expand Down
79 changes: 63 additions & 16 deletions tests/Katana.Sandbox.WebServer/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,21 +75,21 @@ public void Configuration(IAppBuilder app)
CookieManager = new SystemWebChunkingCookieManager()
});

// https://developers.facebook.com/apps/
app.UseFacebookAuthentication(new FacebookAuthenticationOptions
{
AppId = "454990987951096",
AppSecret = "ca7cbddf944f91f23c1ed776f265478e",
AuthorizationEndpoint = "https://www.facebook.com/v2.2/dialog/oauth",
TokenEndpoint = "https://graph.facebook.com/v2.2/oauth/access_token",
UserInformationEndpoint = "https://graph.facebook.com/v2.2/me",
AppId = Environment.GetEnvironmentVariable("facebook:appid"),
AppSecret = Environment.GetEnvironmentVariable("facebook:appsecret"),
Scope = { "email" },
Fields = { "name", "email" },
CookieManager = new SystemWebCookieManager()
// Scope = "email user_birthday user_website"
});

// https://console.developers.google.com/project
app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
{
ClientId = "1033034290282-6h0n78feiepoltpqkmsrqh1ngmeh4co7.apps.googleusercontent.com",
ClientSecret = "6l7lHh-B0_awzoTrlTGWh7km",
ClientId = Environment.GetEnvironmentVariable("google:clientid"),
ClientSecret = Environment.GetEnvironmentVariable("google:clientsecret"),
});

//// Flow to get user identifier in OpenID for migration to OAuth 2.0
Expand Down Expand Up @@ -117,9 +117,12 @@ public void Configuration(IAppBuilder app)
// }
//});

app.UseTwitterAuthentication("6XaCTaLbMqfj6ww3zvZ5g", "Il2eFzGIrYhz6BWjYhVXBPQSfZuS4xoHpSSyD9PI");
// https://apps.twitter.com/
// https://dev.twitter.com/web/sign-in/implementing
app.UseTwitterAuthentication(Environment.GetEnvironmentVariable("twitter:consumerkey"), Environment.GetEnvironmentVariable("twitter:consumersecret"));

app.UseMicrosoftAccountAuthentication("000000004C0EA787", "QZde5m5HHZPxdieV0lOy7bBVTbVqR9Ju");
// https://azure.microsoft.com/en-us/documentation/articles/active-directory-v2-app-registration/
app.UseMicrosoftAccountAuthentication(Environment.GetEnvironmentVariable("microsoftaccount:clientid"), Environment.GetEnvironmentVariable("microsoftaccount:clientsecret"));

// app.UseAspNetAuthSession();
/*
Expand All @@ -139,8 +142,8 @@ public void Configuration(IAppBuilder app)

app.UseOpenIdConnectAuthentication(new Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthenticationOptions()
{
Authority = "https://login.microsoftonline.com/tratcheroutlook.onmicrosoft.com",
ClientId = "",
Authority = Environment.GetEnvironmentVariable("oidc:authority"),
ClientId = Environment.GetEnvironmentVariable("oidc:clientid"),
RedirectUri = "https://localhost:44318/",
CookieManager = new SystemWebCookieManager()
});
Expand Down Expand Up @@ -207,6 +210,26 @@ public void Configuration(IAppBuilder app)
OnReceive = ReceiveRefreshToken,
}
});
*/
app.Map("/signout", map =>
{
map.Run(context =>
{
context.Authentication.SignOut("External");
var response = context.Response;
response.ContentType = "text/html";
response.Write("<body><html>Signed out. <a href=\"/\">Home</a></html></body>");
return Task.FromResult(0);
});
});
app.Map("/challenge", map =>
{
map.Run(context =>
{
context.Authentication.Challenge(new AuthenticationProperties() { RedirectUri = "/" }, context.Request.Query["scheme"]);
return Task.FromResult(0);
});
});
/*
app.Map("/Account/Login", map =>
{
Expand All @@ -218,6 +241,28 @@ public void Configuration(IAppBuilder app)
});
*/
app.Use((context, next) =>
{
var user = context.Authentication.User;
if (user == null || user.Identity == null || !user.Identity.IsAuthenticated)
{
var response = context.Response;
response.ContentType = "text/html";
response.Write("<html><body>Providers:<br>\r\n");
foreach (var provider in context.Authentication.GetAuthenticationTypes())
{
response.Write("- <a href=\"/challenge?scheme=");
response.Write(provider.AuthenticationType);
response.Write("\">");
response.Write(provider.AuthenticationType);
response.Write("</a><br>\r\n");
}
response.Write("</body></html>\r\n");
return Task.FromResult(0);
}
return next();
});
/*
app.Use((context, next) =>
{
var user = context.Authentication.User;
if (user == null || user.Identity == null || !user.Identity.IsAuthenticated)
Expand All @@ -228,23 +273,25 @@ public void Configuration(IAppBuilder app)
}
return next();
});

*/
app.Run(async context =>
{
var response = context.Response;
var user = context.Authentication.User;
var identity = user.Identities.First();
response.ContentType = "text/plain";
await response.WriteAsync("Details:\r\n");
response.ContentType = "text/html";
await response.WriteAsync("<html><body>Details:<br>\r\n");
foreach (var claim in identity.Claims)
{
response.Write("- ");
response.Write(claim.Type);
response.Write(": ");
response.Write(claim.Value);
response.Write("\r\n");
response.Write("<br>\r\n");
}
response.Write("<a href=\"/signout\">Signout</a>\r\n");
response.Write("</body></html>\r\n");
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public async Task ChallengeWillTriggerRedirection()
var transaction = await SendAsync(server, "http://example.com/challenge");
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
var location = transaction.Response.Headers.Location.AbsoluteUri;
location.ShouldContain("https://www.facebook.com/dialog/oauth");
location.ShouldContain("https://www.facebook.com/v2.8/dialog/oauth");
location.ShouldContain("?response_type=code");
location.ShouldContain("&client_id=");
location.ShouldContain("&redirect_uri=");
Expand Down

0 comments on commit b32efb3

Please sign in to comment.