#489 Update MicrosoftAccount provider

This commit is contained in:
Chris R 2017-02-07 15:10:05 -08:00
Родитель 06b7b5c236
Коммит 89e3cc5b58
6 изменённых файлов: 56 добавлений и 45 удалений

Просмотреть файл

@ -6,5 +6,9 @@ namespace Microsoft.Owin.Security.MicrosoftAccount
internal static class Constants
{
internal const string DefaultAuthenticationType = "Microsoft";
internal const string AuthorizationEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
internal const string TokenEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
internal const string UserInformationEndpoint = "https://graph.microsoft.com/v1.0/me";
}
}

Просмотреть файл

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.Owin.Infrastructure;
@ -15,9 +16,6 @@ namespace Microsoft.Owin.Security.MicrosoftAccount
{
internal class MicrosoftAccountAuthenticationHandler : AuthenticationHandler<MicrosoftAccountAuthenticationOptions>
{
private const string TokenEndpoint = "https://login.live.com/oauth20_token.srf";
private const string GraphApiEndpoint = "https://apis.live.net/v5.0/me";
private readonly ILogger _logger;
private readonly HttpClient _httpClient;
@ -79,7 +77,7 @@ namespace Microsoft.Owin.Security.MicrosoftAccount
var requestContent = new FormUrlEncodedContent(tokenRequestParameters);
HttpResponseMessage response = await _httpClient.PostAsync(TokenEndpoint, requestContent, Request.CallCancelled);
HttpResponseMessage response = await _httpClient.PostAsync(Options.TokenEndpoint, requestContent, Request.CallCancelled);
response.EnsureSuccessStatusCode();
string oauthTokenResponse = await response.Content.ReadAsStringAsync();
@ -97,9 +95,11 @@ namespace Microsoft.Owin.Security.MicrosoftAccount
return new AuthenticationTicket(null, properties);
}
HttpResponseMessage graphResponse = await _httpClient.GetAsync(
GraphApiEndpoint + "?access_token=" + Uri.EscapeDataString(accessToken), Request.CallCancelled);
var graphRequest = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint);
graphRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var graphResponse = await _httpClient.SendAsync(graphRequest, Request.CallCancelled);
graphResponse.EnsureSuccessStatusCode();
string accountString = await graphResponse.Content.ReadAsStringAsync();
JObject accountInformation = JObject.Parse(accountString);
@ -165,13 +165,13 @@ namespace Microsoft.Owin.Security.MicrosoftAccount
// LiveID requires a scope string, so if the user didn't set one we go for the least possible.
if (string.IsNullOrWhiteSpace(scope))
{
scope = "wl.basic";
scope = "https://graph.microsoft.com/user.read";
}
string state = Options.StateDataFormat.Protect(extra);
string authorizationEndpoint =
"https://login.live.com/oauth20_authorize.srf" +
Options.AuthorizationEndpoint +
"?client_id=" + Uri.EscapeDataString(Options.ClientId) +
"&scope=" + Uri.EscapeDataString(scope) +
"&response_type=code" +

Просмотреть файл

@ -27,6 +27,10 @@ namespace Microsoft.Owin.Security.MicrosoftAccount
Scope = new List<string>();
BackchannelTimeout = TimeSpan.FromSeconds(60);
CookieManager = new CookieManager();
AuthorizationEndpoint = Constants.AuthorizationEndpoint;
TokenEndpoint = Constants.TokenEndpoint;
UserInformationEndpoint = Constants.UserInformationEndpoint;
}
/// <summary>
@ -62,6 +66,21 @@ namespace Microsoft.Owin.Security.MicrosoftAccount
/// </summary>
public string ClientSecret { get; set; }
/// <summary>
/// Gets or sets the URI where the client will be redirected to authenticate.
/// </summary>
public string AuthorizationEndpoint { get; set; }
/// <summary>
/// Gets or sets the URI the middleware will access to exchange the OAuth token.
/// </summary>
public string TokenEndpoint { get; set; }
/// <summary>
/// Gets or sets the URI the middleware will access to obtain the user information.
/// </summary>
public string UserInformationEndpoint { get; set; }
/// <summary>
/// Gets or sets timeout value in milliseconds for back channel communications with Microsoft.
/// </summary>

Просмотреть файл

@ -52,17 +52,13 @@ namespace Microsoft.Owin.Security.MicrosoftAccount
}
Id = userId.ToString();
Name = PropertyValueIfExists("name", userAsDictionary);
FirstName = PropertyValueIfExists("first_name", userAsDictionary);
LastName = PropertyValueIfExists("last_name", userAsDictionary);
if (userAsDictionary.ContainsKey("emails"))
Name = PropertyValueIfExists("displayName", userAsDictionary);
FirstName = PropertyValueIfExists("givenName", userAsDictionary);
LastName = PropertyValueIfExists("surname", userAsDictionary);
Email = PropertyValueIfExists("mail", userAsDictionary);
if (Email == null)
{
JToken emailsNode = user["emails"];
foreach (var childAsProperty in emailsNode.OfType<JProperty>().Where(childAsProperty => childAsProperty.Name == "preferred"))
{
Email = childAsProperty.Value.ToString();
}
Email = PropertyValueIfExists("userPrincipalName", userAsDictionary);
}
}
@ -72,17 +68,13 @@ namespace Microsoft.Owin.Security.MicrosoftAccount
public JObject User { get; private set; }
/// <summary>
/// Gets the access token provided by the Microsoft authenication service
/// Gets the access token provided by the Microsoft authentication service
/// </summary>
public string AccessToken { get; private set; }
/// <summary>
/// Gets the refresh token provided by Microsoft authentication service
/// </summary>
/// <remarks>
/// Refresh token is only available when wl.offline_access is request.
/// Otherwise, it is null.
/// </remarks>
public string RefreshToken { get; private set; }
/// <summary>

Просмотреть файл

@ -46,12 +46,12 @@ namespace FunctionalTests.Facts.Security.MicrosoftAccount
// Unauthenticated request - verify Redirect url
var response = await httpClient.GetAsync(applicationUrl);
Assert.Equal<string>("https://login.live.com/oauth20_authorize.srf", response.Headers.Location.AbsoluteUri.Replace(response.Headers.Location.Query, string.Empty));
Assert.Equal<string>("https://login.microsoftonline.com/common/oauth2/v2.0/authorize", 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>("000000004C0F442C", queryItems["client_id"]);
Assert.Equal<string>(applicationUrl + "signin-microsoft", queryItems["redirect_uri"]);
Assert.Equal<string>("wl.basic wl.signin", queryItems["scope"]);
Assert.Equal<string>("https://graph.microsoft.com/user.read", queryItems["scope"]);
Assert.Equal<string>("ValidStateData", queryItems["state"]);
Assert.Equal<string>("custom", queryItems["custom_redirect_uri"]);
@ -173,9 +173,6 @@ namespace FunctionalTests.Facts.Security.MicrosoftAccount
StateDataFormat = new CustomStateDataFormat(),
};
option.Scope.Add("wl.basic");
option.Scope.Add("wl.signin");
app.UseMicrosoftAccountAuthentication(option);
app.UseExternalApplication("Microsoft");
}
@ -185,9 +182,12 @@ namespace FunctionalTests.Facts.Security.MicrosoftAccount
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = new HttpResponseMessage();
var response = new HttpResponseMessage()
{
Content = new StringContent("")
};
if (request.RequestUri.AbsoluteUri.StartsWith("https://login.live.com/oauth20_token.srf"))
if (request.RequestUri.AbsoluteUri.StartsWith("https://login.microsoftonline.com/common/oauth2/v2.0/token"))
{
var formData = request.Content.ReadAsFormDataAsync().Result;
@ -198,7 +198,7 @@ namespace FunctionalTests.Facts.Security.MicrosoftAccount
if (formData["redirect_uri"] != null && formData["redirect_uri"].EndsWith("signin-microsoft") &&
formData["client_id"] == "000000004C0F442C" && formData["client_secret"] == "EkXbW-Vr6Rqzi6pugl1jWIBsDotKLmqR")
{
response.Content = new StringContent("{\"token_type\":\"bearer\",\"expires_in\":3600,\"scope\":\"wl.basic\",\"access_token\":\"ValidAccessToken\",\"refresh_token\":\"ValidRefreshToken\",\"authentication_token\":\"ValidAuthenticationToken\"}");
response.Content = new StringContent("{\"token_type\":\"bearer\",\"expires_in\":3600,\"scope\":\"https://graph.microsoft.com/user.read\",\"access_token\":\"ValidAccessToken\",\"refresh_token\":\"ValidRefreshToken\",\"authentication_token\":\"ValidAuthenticationToken\"}");
}
}
else if (formData["code"] == "InvalidCert")
@ -231,12 +231,11 @@ namespace FunctionalTests.Facts.Security.MicrosoftAccount
}
}
}
else if (request.RequestUri.AbsoluteUri.StartsWith("https://apis.live.net/v5.0/me"))
else if (request.RequestUri.AbsoluteUri.StartsWith("https://graph.microsoft.com/v1.0/me"))
{
var queryParameters = request.RequestUri.ParseQueryString();
if (queryParameters["access_token"] == "ValidAccessToken")
if (request.Headers.Authorization.Parameter == "ValidAccessToken")
{
response.Content = new StringContent("{\r \"id\": \"fccf9a24999f4f4f\", \r \"name\": \"Owinauthtester Owinauthtester\", \r \"first_name\": \"Owinauthtester\", \r \"last_name\": \"Owinauthtester\", \r \"link\": \"https://profile.live.com/\", \r \"gender\": null, \r \"locale\": \"en_US\", \r \"updated_time\": \"2013-08-27T22:18:14+0000\"\r}");
response.Content = new StringContent("{\r \"id\": \"fccf9a24999f4f4f\", \r \"displayName\": \"Owinauthtester Owinauthtester\", \r \"givenName\": \"Owinauthtester\", \r \"surname\": \"Owinauthtester\", \r \"link\": \"https://profile.live.com/\", \r \"gender\": null, \r \"locale\": \"en_US\", \r \"updated_time\": \"2013-08-27T22:18:14+0000\"\r}");
}
else
{

Просмотреть файл

@ -65,7 +65,7 @@ namespace Microsoft.Owin.Security.Tests.MicrosoftAccount
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://login.live.com/oauth20_authorize.srf");
location.ShouldContain("https://login.microsoftonline.com/common/oauth2/v2.0/authorize");
location.ShouldContain("response_type=code");
location.ShouldContain("client_id=");
location.ShouldContain("redirect_uri=");
@ -84,7 +84,7 @@ namespace Microsoft.Owin.Security.Tests.MicrosoftAccount
{
Sender = async req =>
{
if (req.RequestUri.AbsoluteUri == "https://login.live.com/oauth20_token.srf")
if (req.RequestUri.AbsoluteUri == "https://login.microsoftonline.com/common/oauth2/v2.0/token")
{
return await ReturnJsonResponse(new
{
@ -94,18 +94,15 @@ namespace Microsoft.Owin.Security.Tests.MicrosoftAccount
refresh_token = "Test Refresh Token"
});
}
else if (req.RequestUri.GetLeftPart(UriPartial.Path) == "https://apis.live.net/v5.0/me")
else if (req.RequestUri.GetLeftPart(UriPartial.Path) == "https://graph.microsoft.com/v1.0/me")
{
return await ReturnJsonResponse(new
{
id = "Test User ID",
name = "Test Name",
first_name = "Test Given Name",
last_name = "Test Family Name",
emails = new
{
preferred = "Test email"
}
displayName = "Test Name",
givenName = "Test Given Name",
surname = "Test Family Name",
mail = "Test email"
});
}