Move ClaimsIssuer to base AuthenticationOptions
Also step 1 of refactoring tests
This commit is contained in:
parent
f864244124
commit
ce48c1fc7d
|
|
@ -193,8 +193,8 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
_sessionKey = await Options.SessionStore.StoreAsync(model);
|
||||
var principal = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new[] { new Claim(SessionIdClaim, _sessionKey) },
|
||||
Options.AuthenticationScheme));
|
||||
new[] { new Claim(SessionIdClaim, _sessionKey, ClaimValueTypes.String, Options.ClaimsIssuer) },
|
||||
Options.ClaimsIssuer));
|
||||
model = new AuthenticationTicket(principal, null, Options.AuthenticationScheme);
|
||||
}
|
||||
var cookieValue = Options.TicketDataFormat.Protect(model);
|
||||
|
|
@ -243,7 +243,7 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
await Options.SessionStore.RenewAsync(_sessionKey, model);
|
||||
var principal = new ClaimsPrincipal(
|
||||
new ClaimsIdentity(
|
||||
new[] { new Claim(SessionIdClaim, _sessionKey) },
|
||||
new[] { new Claim(SessionIdClaim, _sessionKey, ClaimValueTypes.String, Options.ClaimsIssuer) },
|
||||
Options.AuthenticationScheme));
|
||||
model = new AuthenticationTicket(principal, null, Options.AuthenticationScheme);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ using Microsoft.AspNet.Http.Authentication;
|
|||
using Microsoft.AspNet.Http.Collections;
|
||||
using Microsoft.AspNet.Http.Extensions;
|
||||
using Microsoft.AspNet.WebUtilities;
|
||||
using Microsoft.Framework.WebEncoders;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.AspNet.Authentication.Facebook
|
||||
|
|
@ -65,34 +64,34 @@ namespace Microsoft.AspNet.Authentication.Facebook
|
|||
|
||||
var context = new FacebookAuthenticatedContext(Context, Options, user, tokens);
|
||||
var identity = new ClaimsIdentity(
|
||||
Options.AuthenticationScheme,
|
||||
Options.ClaimsIssuer,
|
||||
ClaimsIdentity.DefaultNameClaimType,
|
||||
ClaimsIdentity.DefaultRoleClaimType);
|
||||
if (!string.IsNullOrEmpty(context.Id))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, context.Id, ClaimValueTypes.String, Options.AuthenticationScheme));
|
||||
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, context.Id, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(context.UserName))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.UserName, ClaimValueTypes.String, Options.AuthenticationScheme));
|
||||
identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.UserName, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(context.Email))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Email, context.Email, ClaimValueTypes.String, Options.AuthenticationScheme));
|
||||
identity.AddClaim(new Claim(ClaimTypes.Email, context.Email, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(context.Name))
|
||||
{
|
||||
identity.AddClaim(new Claim("urn:facebook:name", context.Name, ClaimValueTypes.String, Options.AuthenticationScheme));
|
||||
identity.AddClaim(new Claim("urn:facebook:name", context.Name, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
|
||||
// Many Facebook accounts do not set the UserName field. Fall back to the Name field instead.
|
||||
if (string.IsNullOrEmpty(context.UserName))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.Name, ClaimValueTypes.String, Options.AuthenticationScheme));
|
||||
identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.Name, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(context.Link))
|
||||
{
|
||||
identity.AddClaim(new Claim("urn:facebook:link", context.Link, ClaimValueTypes.String, Options.AuthenticationScheme));
|
||||
identity.AddClaim(new Claim("urn:facebook:link", context.Link, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
context.Properties = properties;
|
||||
context.Principal = new ClaimsPrincipal(identity);
|
||||
|
|
@ -104,7 +103,7 @@ namespace Microsoft.AspNet.Authentication.Facebook
|
|||
|
||||
private string GenerateAppSecretProof(string accessToken)
|
||||
{
|
||||
using (HMACSHA256 algorithm = new HMACSHA256(Encoding.ASCII.GetBytes(Options.AppSecret)))
|
||||
using (var algorithm = new HMACSHA256(Encoding.ASCII.GetBytes(Options.AppSecret)))
|
||||
{
|
||||
var hash = algorithm.ComputeHash(Encoding.ASCII.GetBytes(accessToken));
|
||||
var builder = new StringBuilder();
|
||||
|
|
@ -124,4 +123,4 @@ namespace Microsoft.AspNet.Authentication.Facebook
|
|||
return string.Join(",", Options.Scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -33,39 +33,39 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
|
||||
var context = new GoogleAuthenticatedContext(Context, Options, user, tokens);
|
||||
var identity = new ClaimsIdentity(
|
||||
Options.AuthenticationScheme,
|
||||
Options.ClaimsIssuer,
|
||||
ClaimsIdentity.DefaultNameClaimType,
|
||||
ClaimsIdentity.DefaultRoleClaimType);
|
||||
|
||||
if (!string.IsNullOrEmpty(context.Id))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, context.Id,
|
||||
ClaimValueTypes.String, Options.AuthenticationScheme));
|
||||
ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(context.GivenName))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.GivenName, context.GivenName,
|
||||
ClaimValueTypes.String, Options.AuthenticationScheme));
|
||||
ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(context.FamilyName))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Surname, context.FamilyName,
|
||||
ClaimValueTypes.String, Options.AuthenticationScheme));
|
||||
ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(context.Name))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Name, context.Name, ClaimValueTypes.String,
|
||||
Options.AuthenticationScheme));
|
||||
Options.ClaimsIssuer));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(context.Email))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Email, context.Email, ClaimValueTypes.String,
|
||||
Options.AuthenticationScheme));
|
||||
Options.ClaimsIssuer));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(context.Profile))
|
||||
{
|
||||
identity.AddClaim(new Claim("urn:google:profile", context.Profile, ClaimValueTypes.String,
|
||||
Options.AuthenticationScheme));
|
||||
Options.ClaimsIssuer));
|
||||
}
|
||||
context.Properties = properties;
|
||||
context.Principal = new ClaimsPrincipal(identity);
|
||||
|
|
@ -120,4 +120,4 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
queryStrings[name] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.AspNet.Authentication.OAuth;
|
||||
using Microsoft.AspNet.Builder;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,8 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Authentication;
|
||||
using Microsoft.AspNet.Authentication.OAuth;
|
||||
using Microsoft.AspNet.Http;
|
||||
|
||||
namespace Microsoft.AspNet.Authentication.Google
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,18 +32,18 @@ namespace Microsoft.AspNet.Authentication.MicrosoftAccount
|
|||
var identity = new ClaimsIdentity(
|
||||
new[]
|
||||
{
|
||||
new Claim(ClaimTypes.NameIdentifier, context.Id, ClaimValueTypes.String, Options.AuthenticationScheme),
|
||||
new Claim(ClaimTypes.Name, context.Name, ClaimValueTypes.String, Options.AuthenticationScheme),
|
||||
new Claim("urn:microsoftaccount:id", context.Id, ClaimValueTypes.String, Options.AuthenticationScheme),
|
||||
new Claim("urn:microsoftaccount:name", context.Name, ClaimValueTypes.String, Options.AuthenticationScheme)
|
||||
new Claim(ClaimTypes.NameIdentifier, context.Id, ClaimValueTypes.String, Options.ClaimsIssuer),
|
||||
new Claim(ClaimTypes.Name, context.Name, ClaimValueTypes.String, Options.ClaimsIssuer),
|
||||
new Claim("urn:microsoftaccount:id", context.Id, ClaimValueTypes.String, Options.ClaimsIssuer),
|
||||
new Claim("urn:microsoftaccount:name", context.Name, ClaimValueTypes.String, Options.ClaimsIssuer)
|
||||
},
|
||||
Options.AuthenticationScheme,
|
||||
Options.ClaimsIssuer,
|
||||
ClaimsIdentity.DefaultNameClaimType,
|
||||
ClaimsIdentity.DefaultRoleClaimType);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(context.Email))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Email, context.Email, ClaimValueTypes.String, Options.AuthenticationScheme));
|
||||
identity.AddClaim(new Claim(ClaimTypes.Email, context.Email, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
context.Principal = new ClaimsPrincipal(identity);
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ namespace Microsoft.AspNet.Authentication.OAuth
|
|||
if (Options.StateDataFormat == null)
|
||||
{
|
||||
var dataProtector = dataProtectionProvider.CreateProtector(
|
||||
this.GetType().FullName, Options.AuthenticationScheme, "v1");
|
||||
GetType().FullName, Options.AuthenticationScheme, "v1");
|
||||
Options.StateDataFormat = new PropertiesDataFormat(dataProtector);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Authentication;
|
||||
|
||||
|
|
@ -106,11 +105,6 @@ namespace Microsoft.AspNet.Authentication.OAuth
|
|||
/// </summary>
|
||||
public string SignInScheme { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the issuer that should be used for any claims that are created
|
||||
/// </summary>
|
||||
public string ClaimsIssuer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type used to secure data handled by the middleware.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ namespace Microsoft.AspNet.Authentication.OAuthBearer
|
|||
|
||||
// notify user token was received
|
||||
var securityTokenReceivedNotification =
|
||||
new SecurityTokenReceivedNotification<HttpContext, OAuthBearerAuthenticationOptions>(Context, Options)
|
||||
new SecurityTokenReceivedNotification<HttpContext, OAuthBearerAuthenticationOptions>(Context, Options)
|
||||
{
|
||||
ProtocolMessage = Context,
|
||||
SecurityToken = token,
|
||||
|
|
@ -110,7 +110,7 @@ namespace Microsoft.AspNet.Authentication.OAuthBearer
|
|||
}
|
||||
else
|
||||
{
|
||||
IEnumerable<string> issuers = new[] { _configuration.Issuer };
|
||||
var issuers = new[] { _configuration.Issuer };
|
||||
validationParameters.ValidIssuers = (validationParameters.ValidIssuers == null ? issuers : validationParameters.ValidIssuers.Concat(issuers));
|
||||
}
|
||||
|
||||
|
|
@ -122,8 +122,8 @@ namespace Microsoft.AspNet.Authentication.OAuthBearer
|
|||
{
|
||||
if (validator.CanReadToken(token))
|
||||
{
|
||||
ClaimsPrincipal principal = validator.ValidateToken(token, validationParameters, out validatedToken);
|
||||
AuthenticationTicket ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), Options.AuthenticationScheme);
|
||||
var principal = validator.ValidateToken(token, validationParameters, out validatedToken);
|
||||
var ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), Options.AuthenticationScheme);
|
||||
var securityTokenValidatedNotification = new SecurityTokenValidatedNotification<HttpContext, OAuthBearerAuthenticationOptions>(Context, Options)
|
||||
{
|
||||
ProtocolMessage = Context,
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@ namespace Microsoft.AspNet.Authentication.OAuthBearer
|
|||
/// </summary>
|
||||
public class OAuthBearerAuthenticationMiddleware : AuthenticationMiddleware<OAuthBearerAuthenticationOptions>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Bearer authentication component which is added to an HTTP pipeline. This constructor is not
|
||||
/// called by application code directly, instead it is added by calling the the IAppBuilder UseOAuthBearerAuthentication
|
||||
|
|
@ -72,7 +70,7 @@ namespace Microsoft.AspNet.Authentication.OAuthBearer
|
|||
Options.MetadataAddress += ".well-known/openid-configuration";
|
||||
}
|
||||
|
||||
HttpClient httpClient = new HttpClient(ResolveHttpMessageHandler(Options));
|
||||
var httpClient = new HttpClient(ResolveHttpMessageHandler(Options));
|
||||
httpClient.Timeout = Options.BackchannelTimeout;
|
||||
httpClient.MaxResponseContentBufferSize = 1024 * 1024 * 10; // 10 MB
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens;
|
||||
using System.Net.Http;
|
||||
using Microsoft.AspNet.Authentication;
|
||||
using Microsoft.IdentityModel.Protocols;
|
||||
|
||||
namespace Microsoft.AspNet.Authentication.OAuthBearer
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ namespace Microsoft.AspNet.Authentication.Twitter
|
|||
return new AuthenticationTicket(properties, Options.AuthenticationScheme);
|
||||
}
|
||||
|
||||
string oauthVerifier = query.Get("oauth_verifier");
|
||||
var oauthVerifier = query.Get("oauth_verifier");
|
||||
if (string.IsNullOrWhiteSpace(oauthVerifier))
|
||||
{
|
||||
Logger.LogWarning("Missing or blank oauth_verifier");
|
||||
|
|
@ -93,12 +93,12 @@ namespace Microsoft.AspNet.Authentication.Twitter
|
|||
new ClaimsIdentity(
|
||||
new[]
|
||||
{
|
||||
new Claim(ClaimTypes.NameIdentifier, accessToken.UserId, "http://www.w3.org/2001/XMLSchema#string", Options.AuthenticationScheme),
|
||||
new Claim(ClaimTypes.Name, accessToken.ScreenName, "http://www.w3.org/2001/XMLSchema#string", Options.AuthenticationScheme),
|
||||
new Claim("urn:twitter:userid", accessToken.UserId, "http://www.w3.org/2001/XMLSchema#string", Options.AuthenticationScheme),
|
||||
new Claim("urn:twitter:screenname", accessToken.ScreenName, "http://www.w3.org/2001/XMLSchema#string", Options.AuthenticationScheme)
|
||||
new Claim(ClaimTypes.NameIdentifier, accessToken.UserId, "http://www.w3.org/2001/XMLSchema#string", Options.ClaimsIssuer),
|
||||
new Claim(ClaimTypes.Name, accessToken.ScreenName, "http://www.w3.org/2001/XMLSchema#string", Options.ClaimsIssuer),
|
||||
new Claim("urn:twitter:userid", accessToken.UserId, "http://www.w3.org/2001/XMLSchema#string", Options.ClaimsIssuer),
|
||||
new Claim("urn:twitter:screenname", accessToken.ScreenName, "http://www.w3.org/2001/XMLSchema#string", Options.ClaimsIssuer)
|
||||
},
|
||||
Options.AuthenticationScheme,
|
||||
Options.ClaimsIssuer,
|
||||
ClaimsIdentity.DefaultNameClaimType,
|
||||
ClaimsIdentity.DefaultRoleClaimType));
|
||||
context.Properties = requestToken.Properties;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,12 @@ namespace Microsoft.AspNet.Authentication
|
|||
Logger = loggerFactory.CreateLogger(this.GetType().FullName);
|
||||
UrlEncoder = encoder;
|
||||
|
||||
if (string.IsNullOrEmpty(Options.ClaimsIssuer))
|
||||
{
|
||||
// Default to something reasonable
|
||||
Options.ClaimsIssuer = Options.AuthenticationScheme;
|
||||
}
|
||||
|
||||
_next = next;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,11 @@ namespace Microsoft.AspNet.Authentication
|
|||
/// </summary>
|
||||
public bool AutomaticAuthentication { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the issuer that should be used for any claims that are created
|
||||
/// </summary>
|
||||
public string ClaimsIssuer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Additional information about the authentication type which is made available to the application.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
|
||||
using System;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
|
@ -21,7 +18,7 @@ namespace Microsoft.AspNet.Authentication
|
|||
/// <param name="identity"></param>
|
||||
public static void AddUserPrincipal([NotNull] HttpContext context, [NotNull] ClaimsPrincipal principal)
|
||||
{
|
||||
ClaimsPrincipal existingPrincipal = context.User;
|
||||
var existingPrincipal = context.User;
|
||||
if (existingPrincipal != null)
|
||||
{
|
||||
foreach (var existingClaimsIdentity in existingPrincipal.Identities)
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
[Fact]
|
||||
public async Task NormalRequestPassesThrough()
|
||||
{
|
||||
TestServer server = CreateServer(options =>
|
||||
var server = CreateServer(options =>
|
||||
{
|
||||
});
|
||||
HttpResponseMessage response = await server.CreateClient().GetAsync("http://example.com/normal");
|
||||
var response = await server.CreateClient().GetAsync("http://example.com/normal");
|
||||
response.StatusCode.ShouldBe(HttpStatusCode.OK);
|
||||
}
|
||||
|
||||
|
|
@ -39,13 +39,13 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
[InlineData(false)]
|
||||
public async Task ProtectedRequestShouldRedirectToLoginOnlyWhenAutomatic(bool auto)
|
||||
{
|
||||
TestServer server = CreateServer(options =>
|
||||
var server = CreateServer(options =>
|
||||
{
|
||||
options.LoginPath = new PathString("/login");
|
||||
options.AutomaticAuthentication = auto;
|
||||
});
|
||||
|
||||
Transaction transaction = await SendAsync(server, "http://example.com/protected");
|
||||
var transaction = await SendAsync(server, "http://example.com/protected");
|
||||
|
||||
transaction.Response.StatusCode.ShouldBe(auto ? HttpStatusCode.Redirect : HttpStatusCode.Unauthorized);
|
||||
if (auto)
|
||||
|
|
@ -61,13 +61,13 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
[InlineData(false)]
|
||||
public async Task ProtectedCustomRequestShouldRedirectToCustomLogin(bool auto)
|
||||
{
|
||||
TestServer server = CreateServer(options =>
|
||||
var server = CreateServer(options =>
|
||||
{
|
||||
options.LoginPath = new PathString("/login");
|
||||
options.AutomaticAuthentication = auto;
|
||||
});
|
||||
|
||||
Transaction transaction = await SendAsync(server, "http://example.com/protected/CustomRedirect");
|
||||
var transaction = await SendAsync(server, "http://example.com/protected/CustomRedirect");
|
||||
|
||||
transaction.Response.StatusCode.ShouldBe(auto ? HttpStatusCode.Redirect : HttpStatusCode.Unauthorized);
|
||||
if (auto)
|
||||
|
|
@ -102,15 +102,15 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
[Fact]
|
||||
public async Task SignInCausesDefaultCookieToBeCreated()
|
||||
{
|
||||
TestServer server = CreateServer(options =>
|
||||
var server = CreateServer(options =>
|
||||
{
|
||||
options.LoginPath = new PathString("/login");
|
||||
options.CookieName = "TestCookie";
|
||||
}, SignInAsAlice);
|
||||
|
||||
Transaction transaction = await SendAsync(server, "http://example.com/testpath");
|
||||
var transaction = await SendAsync(server, "http://example.com/testpath");
|
||||
|
||||
string setCookie = transaction.SetCookie;
|
||||
var setCookie = transaction.SetCookie;
|
||||
setCookie.ShouldStartWith("TestCookie=");
|
||||
setCookie.ShouldContain("; path=/");
|
||||
setCookie.ShouldContain("; HttpOnly");
|
||||
|
|
@ -122,7 +122,7 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
[Fact]
|
||||
public async Task SignInWrongAuthTypeThrows()
|
||||
{
|
||||
TestServer server = CreateServer(options =>
|
||||
var server = CreateServer(options =>
|
||||
{
|
||||
options.LoginPath = new PathString("/login");
|
||||
options.CookieName = "TestCookie";
|
||||
|
|
@ -134,7 +134,7 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
[Fact]
|
||||
public async Task SignOutWrongAuthTypeThrows()
|
||||
{
|
||||
TestServer server = CreateServer(options =>
|
||||
var server = CreateServer(options =>
|
||||
{
|
||||
options.LoginPath = new PathString("/login");
|
||||
options.CookieName = "TestCookie";
|
||||
|
|
@ -155,15 +155,15 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
string requestUri,
|
||||
bool shouldBeSecureOnly)
|
||||
{
|
||||
TestServer server = CreateServer(options =>
|
||||
var server = CreateServer(options =>
|
||||
{
|
||||
options.LoginPath = new PathString("/login");
|
||||
options.CookieName = "TestCookie";
|
||||
options.CookieSecure = cookieSecureOption;
|
||||
}, SignInAsAlice);
|
||||
|
||||
Transaction transaction = await SendAsync(server, requestUri);
|
||||
string setCookie = transaction.SetCookie;
|
||||
var transaction = await SendAsync(server, requestUri);
|
||||
var setCookie = transaction.SetCookie;
|
||||
|
||||
if (shouldBeSecureOnly)
|
||||
{
|
||||
|
|
@ -187,9 +187,9 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
options.CookieHttpOnly = true;
|
||||
}, SignInAsAlice, new Uri("http://example.com/base"));
|
||||
|
||||
Transaction transaction1 = await SendAsync(server1, "http://example.com/base/testpath");
|
||||
var transaction1 = await SendAsync(server1, "http://example.com/base/testpath");
|
||||
|
||||
string setCookie1 = transaction1.SetCookie;
|
||||
var setCookie1 = transaction1.SetCookie;
|
||||
|
||||
setCookie1.ShouldContain("TestCookie=");
|
||||
setCookie1.ShouldContain(" path=/foo");
|
||||
|
|
@ -197,16 +197,16 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
setCookie1.ShouldContain(" secure");
|
||||
setCookie1.ShouldContain(" HttpOnly");
|
||||
|
||||
TestServer server2 = CreateServer(options =>
|
||||
var server2 = CreateServer(options =>
|
||||
{
|
||||
options.CookieName = "SecondCookie";
|
||||
options.CookieSecure = CookieSecureOption.Never;
|
||||
options.CookieHttpOnly = false;
|
||||
}, SignInAsAlice, new Uri("http://example.com/base"));
|
||||
|
||||
Transaction transaction2 = await SendAsync(server2, "http://example.com/base/testpath");
|
||||
var transaction2 = await SendAsync(server2, "http://example.com/base/testpath");
|
||||
|
||||
string setCookie2 = transaction2.SetCookie;
|
||||
var setCookie2 = transaction2.SetCookie;
|
||||
|
||||
setCookie2.ShouldContain("SecondCookie=");
|
||||
setCookie2.ShouldContain(" path=/base");
|
||||
|
|
@ -219,14 +219,14 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
public async Task CookieContainsIdentity()
|
||||
{
|
||||
var clock = new TestClock();
|
||||
TestServer server = CreateServer(options =>
|
||||
var server = CreateServer(options =>
|
||||
{
|
||||
options.SystemClock = clock;
|
||||
}, SignInAsAlice);
|
||||
|
||||
Transaction transaction1 = await SendAsync(server, "http://example.com/testpath");
|
||||
var transaction1 = await SendAsync(server, "http://example.com/testpath");
|
||||
|
||||
Transaction transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
|
||||
FindClaimValue(transaction2, ClaimTypes.Name).ShouldBe("Alice");
|
||||
}
|
||||
|
|
@ -235,7 +235,7 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
public async Task CookieAppliesClaimsTransform()
|
||||
{
|
||||
var clock = new TestClock();
|
||||
TestServer server = CreateServer(options =>
|
||||
var server = CreateServer(options =>
|
||||
{
|
||||
options.SystemClock = clock;
|
||||
},
|
||||
|
|
@ -253,9 +253,9 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
return p;
|
||||
}));
|
||||
|
||||
Transaction transaction1 = await SendAsync(server, "http://example.com/testpath");
|
||||
var transaction1 = await SendAsync(server, "http://example.com/testpath");
|
||||
|
||||
Transaction transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
|
||||
FindClaimValue(transaction2, ClaimTypes.Name).ShouldBe("Alice");
|
||||
FindClaimValue(transaction2, "xform").ShouldBe("yup");
|
||||
|
|
@ -266,24 +266,24 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
public async Task CookieStopsWorkingAfterExpiration()
|
||||
{
|
||||
var clock = new TestClock();
|
||||
TestServer server = CreateServer(options =>
|
||||
var server = CreateServer(options =>
|
||||
{
|
||||
options.SystemClock = clock;
|
||||
options.ExpireTimeSpan = TimeSpan.FromMinutes(10);
|
||||
options.SlidingExpiration = false;
|
||||
}, SignInAsAlice);
|
||||
|
||||
Transaction transaction1 = await SendAsync(server, "http://example.com/testpath");
|
||||
var transaction1 = await SendAsync(server, "http://example.com/testpath");
|
||||
|
||||
Transaction transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
|
||||
clock.Add(TimeSpan.FromMinutes(7));
|
||||
|
||||
Transaction transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
|
||||
clock.Add(TimeSpan.FromMinutes(7));
|
||||
|
||||
Transaction transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
|
||||
transaction2.SetCookie.ShouldBe(null);
|
||||
FindClaimValue(transaction2, ClaimTypes.Name).ShouldBe("Alice");
|
||||
|
|
@ -297,7 +297,7 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
public async Task CookieExpirationCanBeOverridenInSignin()
|
||||
{
|
||||
var clock = new TestClock();
|
||||
TestServer server = CreateServer(options =>
|
||||
var server = CreateServer(options =>
|
||||
{
|
||||
options.SystemClock = clock;
|
||||
options.ExpireTimeSpan = TimeSpan.FromMinutes(10);
|
||||
|
|
@ -311,17 +311,17 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
return Task.FromResult<object>(null);
|
||||
});
|
||||
|
||||
Transaction transaction1 = await SendAsync(server, "http://example.com/testpath");
|
||||
var transaction1 = await SendAsync(server, "http://example.com/testpath");
|
||||
|
||||
Transaction transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
|
||||
clock.Add(TimeSpan.FromMinutes(3));
|
||||
|
||||
Transaction transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
|
||||
clock.Add(TimeSpan.FromMinutes(3));
|
||||
|
||||
Transaction transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
|
||||
transaction2.SetCookie.ShouldBe(null);
|
||||
FindClaimValue(transaction2, ClaimTypes.Name).ShouldBe("Alice");
|
||||
|
|
@ -335,7 +335,7 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
public async Task CookieExpirationCanBeOverridenInEvent()
|
||||
{
|
||||
var clock = new TestClock();
|
||||
TestServer server = CreateServer(options =>
|
||||
var server = CreateServer(options =>
|
||||
{
|
||||
options.SystemClock = clock;
|
||||
options.ExpireTimeSpan = TimeSpan.FromMinutes(10);
|
||||
|
|
@ -349,17 +349,17 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
};
|
||||
}, SignInAsAlice);
|
||||
|
||||
Transaction transaction1 = await SendAsync(server, "http://example.com/testpath");
|
||||
var transaction1 = await SendAsync(server, "http://example.com/testpath");
|
||||
|
||||
Transaction transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
|
||||
clock.Add(TimeSpan.FromMinutes(3));
|
||||
|
||||
Transaction transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
|
||||
clock.Add(TimeSpan.FromMinutes(3));
|
||||
|
||||
Transaction transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
|
||||
transaction2.SetCookie.ShouldBe(null);
|
||||
FindClaimValue(transaction2, ClaimTypes.Name).ShouldBe("Alice");
|
||||
|
|
@ -373,25 +373,25 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
public async Task CookieIsRenewedWithSlidingExpiration()
|
||||
{
|
||||
var clock = new TestClock();
|
||||
TestServer server = CreateServer(options =>
|
||||
var server = CreateServer(options =>
|
||||
{
|
||||
options.SystemClock = clock;
|
||||
options.ExpireTimeSpan = TimeSpan.FromMinutes(10);
|
||||
options.SlidingExpiration = true;
|
||||
}, SignInAsAlice);
|
||||
|
||||
Transaction transaction1 = await SendAsync(server, "http://example.com/testpath");
|
||||
var transaction1 = await SendAsync(server, "http://example.com/testpath");
|
||||
|
||||
Transaction transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
|
||||
clock.Add(TimeSpan.FromMinutes(4));
|
||||
|
||||
Transaction transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
|
||||
clock.Add(TimeSpan.FromMinutes(4));
|
||||
|
||||
// transaction4 should arrive with a new SetCookie value
|
||||
Transaction transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue);
|
||||
|
||||
clock.Add(TimeSpan.FromMinutes(4));
|
||||
|
||||
|
|
@ -410,13 +410,13 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
[Fact]
|
||||
public async Task AjaxRedirectsAsExtraHeaderOnTwoHundred()
|
||||
{
|
||||
TestServer server = CreateServer(options =>
|
||||
var server = CreateServer(options =>
|
||||
{
|
||||
options.LoginPath = new PathString("/login");
|
||||
options.AutomaticAuthentication = true;
|
||||
});
|
||||
|
||||
Transaction transaction = await SendAsync(server, "http://example.com/protected", ajaxRequest: true);
|
||||
var transaction = await SendAsync(server, "http://example.com/protected", ajaxRequest: true);
|
||||
|
||||
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.OK);
|
||||
var responded = transaction.Response.Headers.GetValues("X-Responded-JSON");
|
||||
|
|
@ -429,9 +429,7 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
public async Task CookieUsesPathBaseByDefault()
|
||||
{
|
||||
var clock = new TestClock();
|
||||
TestServer server = CreateServer(options =>
|
||||
{
|
||||
},
|
||||
var server = CreateServer(options => { },
|
||||
context =>
|
||||
{
|
||||
Assert.Equal(new PathString("/base"), context.Request.PathBase);
|
||||
|
|
@ -441,7 +439,7 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
},
|
||||
new Uri("http://example.com/base"));
|
||||
|
||||
Transaction transaction1 = await SendAsync(server, "http://example.com/base/testpath");
|
||||
var transaction1 = await SendAsync(server, "http://example.com/base/testpath");
|
||||
Assert.True(transaction1.SetCookie.Contains("path=/base"));
|
||||
}
|
||||
|
||||
|
|
@ -449,15 +447,15 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
public async Task CookieTurns401To403IfAuthenticated()
|
||||
{
|
||||
var clock = new TestClock();
|
||||
TestServer server = CreateServer(options =>
|
||||
var server = CreateServer(options =>
|
||||
{
|
||||
options.SystemClock = clock;
|
||||
},
|
||||
SignInAsAlice);
|
||||
|
||||
Transaction transaction1 = await SendAsync(server, "http://example.com/testpath");
|
||||
var transaction1 = await SendAsync(server, "http://example.com/testpath");
|
||||
|
||||
Transaction transaction2 = await SendAsync(server, "http://example.com/unauthorized", transaction1.CookieNameValue);
|
||||
var transaction2 = await SendAsync(server, "http://example.com/unauthorized", transaction1.CookieNameValue);
|
||||
|
||||
transaction2.Response.StatusCode.ShouldBe(HttpStatusCode.Forbidden);
|
||||
}
|
||||
|
|
@ -466,20 +464,20 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
public async Task CookieTurns401ToAccessDeniedWhenSetAndIfAuthenticated()
|
||||
{
|
||||
var clock = new TestClock();
|
||||
TestServer server = CreateServer(options =>
|
||||
var server = CreateServer(options =>
|
||||
{
|
||||
options.SystemClock = clock;
|
||||
options.AccessDeniedPath = new PathString("/accessdenied");
|
||||
},
|
||||
SignInAsAlice);
|
||||
|
||||
Transaction transaction1 = await SendAsync(server, "http://example.com/testpath");
|
||||
var transaction1 = await SendAsync(server, "http://example.com/testpath");
|
||||
|
||||
Transaction transaction2 = await SendAsync(server, "http://example.com/unauthorized", transaction1.CookieNameValue);
|
||||
var transaction2 = await SendAsync(server, "http://example.com/unauthorized", transaction1.CookieNameValue);
|
||||
|
||||
transaction2.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
|
||||
|
||||
Uri location = transaction2.Response.Headers.Location;
|
||||
var location = transaction2.Response.Headers.Location;
|
||||
location.LocalPath.ShouldBe("/accessdenied");
|
||||
}
|
||||
|
||||
|
|
@ -487,21 +485,21 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
public async Task CookieDoesNothingTo401IfNotAuthenticated()
|
||||
{
|
||||
var clock = new TestClock();
|
||||
TestServer server = CreateServer(options =>
|
||||
var server = CreateServer(options =>
|
||||
{
|
||||
options.SystemClock = clock;
|
||||
});
|
||||
|
||||
Transaction transaction1 = await SendAsync(server, "http://example.com/testpath");
|
||||
var transaction1 = await SendAsync(server, "http://example.com/testpath");
|
||||
|
||||
Transaction transaction2 = await SendAsync(server, "http://example.com/unauthorized", transaction1.CookieNameValue);
|
||||
var transaction2 = await SendAsync(server, "http://example.com/unauthorized", transaction1.CookieNameValue);
|
||||
|
||||
transaction2.Response.StatusCode.ShouldBe(HttpStatusCode.Unauthorized);
|
||||
}
|
||||
|
||||
private static string FindClaimValue(Transaction transaction, string claimType)
|
||||
{
|
||||
XElement claim = transaction.ResponseElement.Elements("claim").SingleOrDefault(elt => elt.Attribute("type").Value == claimType);
|
||||
var claim = transaction.ResponseElement.Elements("claim").SingleOrDefault(elt => elt.Attribute("type").Value == claimType);
|
||||
if (claim == null)
|
||||
{
|
||||
return null;
|
||||
|
|
@ -514,9 +512,9 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||
request.Headers.Add("Cookie", cookie);
|
||||
|
||||
HttpResponseMessage response2 = await server.CreateClient().SendAsync(request);
|
||||
string text = await response2.Content.ReadAsStringAsync();
|
||||
XElement me = XElement.Parse(text);
|
||||
var response2 = await server.CreateClient().SendAsync(request);
|
||||
var text = await response2.Content.ReadAsStringAsync();
|
||||
var me = XElement.Parse(text);
|
||||
return me;
|
||||
}
|
||||
|
||||
|
|
@ -525,6 +523,7 @@ namespace Microsoft.AspNet.Authentication.Cookies
|
|||
var server = TestServer.Create(app =>
|
||||
{
|
||||
app.UseCookieAuthentication(configureOptions);
|
||||
|
||||
if (claimsTransform != null)
|
||||
{
|
||||
app.UseClaimsTransformation();
|
||||
|
|
|
|||
|
|
@ -2,10 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Http;
|
||||
|
|
@ -29,8 +26,7 @@ namespace Microsoft.AspNet.Authentication.Facebook
|
|||
},
|
||||
services =>
|
||||
{
|
||||
services.AddWebEncoders();
|
||||
services.AddDataProtection();
|
||||
services.AddAuthentication();
|
||||
services.ConfigureFacebookAuthentication(options =>
|
||||
{
|
||||
options.AppId = "Test App Id";
|
||||
|
|
@ -58,7 +54,7 @@ namespace Microsoft.AspNet.Authentication.Facebook
|
|||
context.Authentication.Challenge("Facebook");
|
||||
return true;
|
||||
});
|
||||
var transaction = await SendAsync(server, "http://example.com/challenge");
|
||||
var transaction = await server.SendAsync("http://example.com/challenge");
|
||||
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
|
||||
var query = transaction.Response.Headers.Location.Query;
|
||||
query.ShouldContain("custom=test");
|
||||
|
|
@ -75,8 +71,7 @@ namespace Microsoft.AspNet.Authentication.Facebook
|
|||
},
|
||||
services =>
|
||||
{
|
||||
services.AddWebEncoders();
|
||||
services.AddDataProtection();
|
||||
services.AddAuthentication();
|
||||
services.ConfigureFacebookAuthentication(options =>
|
||||
{
|
||||
options.AppId = "Test App Id";
|
||||
|
|
@ -96,7 +91,7 @@ namespace Microsoft.AspNet.Authentication.Facebook
|
|||
context.Authentication.Challenge("Facebook");
|
||||
return true;
|
||||
});
|
||||
var transaction = await SendAsync(server, "http://example.com/challenge");
|
||||
var transaction = await server.SendAsync("http://example.com/challenge");
|
||||
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
|
||||
var location = transaction.Response.Headers.Location.AbsoluteUri;
|
||||
location.ShouldContain("https://www.facebook.com/v2.2/dialog/oauth");
|
||||
|
|
@ -125,34 +120,5 @@ namespace Microsoft.AspNet.Authentication.Facebook
|
|||
},
|
||||
configureServices);
|
||||
}
|
||||
|
||||
private static async Task<Transaction> SendAsync(TestServer server, string uri, string cookieHeader = null)
|
||||
{
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, uri);
|
||||
if (!string.IsNullOrEmpty(cookieHeader))
|
||||
{
|
||||
request.Headers.Add("Cookie", cookieHeader);
|
||||
}
|
||||
var transaction = new Transaction
|
||||
{
|
||||
Request = request,
|
||||
Response = await server.CreateClient().SendAsync(request),
|
||||
};
|
||||
if (transaction.Response.Headers.Contains("Set-Cookie"))
|
||||
{
|
||||
transaction.SetCookie = transaction.Response.Headers.GetValues("Set-Cookie").ToList();
|
||||
}
|
||||
transaction.ResponseText = await transaction.Response.Content.ReadAsStringAsync();
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
private class Transaction
|
||||
{
|
||||
public HttpRequestMessage Request { get; set; }
|
||||
public HttpResponseMessage Response { get; set; }
|
||||
public IList<string> SetCookie { get; set; }
|
||||
public string ResponseText { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,16 +2,12 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.AspNet.Authentication.DataHandler;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.DataProtection;
|
||||
|
|
@ -28,8 +24,6 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
{
|
||||
public class GoogleMiddlewareTests
|
||||
{
|
||||
private const string CookieAuthenticationScheme = "Cookie";
|
||||
|
||||
[Fact]
|
||||
public async Task ChallengeWillTriggerRedirection()
|
||||
{
|
||||
|
|
@ -38,7 +32,7 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
options.ClientId = "Test Id";
|
||||
options.ClientSecret = "Test Secret";
|
||||
});
|
||||
var transaction = await SendAsync(server, "https://example.com/challenge");
|
||||
var transaction = await server.SendAsync("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");
|
||||
|
|
@ -61,7 +55,7 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
options.ClientSecret = "Test Secret";
|
||||
options.AutomaticAuthentication = true;
|
||||
});
|
||||
var transaction = await SendAsync(server, "https://example.com/401");
|
||||
var transaction = await server.SendAsync("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");
|
||||
|
|
@ -79,7 +73,7 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
options.ClientId = "Test Id";
|
||||
options.ClientSecret = "Test Secret";
|
||||
});
|
||||
var transaction = await SendAsync(server, "https://example.com/challenge");
|
||||
var transaction = await server.SendAsync("https://example.com/challenge");
|
||||
Console.WriteLine(transaction.SetCookie);
|
||||
transaction.SetCookie.Single().ShouldContain(".AspNet.Correlation.Google=");
|
||||
}
|
||||
|
|
@ -93,7 +87,7 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
options.ClientSecret = "Test Secret";
|
||||
options.AutomaticAuthentication = true;
|
||||
});
|
||||
var transaction = await SendAsync(server, "https://example.com/401");
|
||||
var transaction = await server.SendAsync("https://example.com/401");
|
||||
Console.WriteLine(transaction.SetCookie);
|
||||
transaction.SetCookie.Single().ShouldContain(".AspNet.Correlation.Google=");
|
||||
}
|
||||
|
|
@ -106,7 +100,7 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
options.ClientId = "Test Id";
|
||||
options.ClientSecret = "Test Secret";
|
||||
});
|
||||
var transaction = await SendAsync(server, "https://example.com/challenge");
|
||||
var transaction = await server.SendAsync("https://example.com/challenge");
|
||||
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
|
||||
var query = transaction.Response.Headers.Location.Query;
|
||||
query.ShouldContain("&scope=" + UrlEncoder.Default.UrlEncode("openid profile email"));
|
||||
|
|
@ -121,7 +115,7 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
options.ClientSecret = "Test Secret";
|
||||
options.AutomaticAuthentication = true;
|
||||
});
|
||||
var transaction = await SendAsync(server, "https://example.com/401");
|
||||
var transaction = await server.SendAsync("https://example.com/401");
|
||||
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
|
||||
var query = transaction.Response.Headers.Location.Query;
|
||||
query.ShouldContain("&scope=" + UrlEncoder.Default.UrlEncode("openid profile email"));
|
||||
|
|
@ -155,7 +149,7 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
|
||||
return Task.FromResult<object>(null);
|
||||
});
|
||||
var transaction = await SendAsync(server, "https://example.com/challenge2");
|
||||
var transaction = await server.SendAsync("https://example.com/challenge2");
|
||||
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
|
||||
var query = transaction.Response.Headers.Location.Query;
|
||||
query.ShouldContain("scope=" + UrlEncoder.Default.UrlEncode("https://www.googleapis.com/auth/plus.login"));
|
||||
|
|
@ -179,7 +173,7 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
}
|
||||
};
|
||||
});
|
||||
var transaction = await SendAsync(server, "https://example.com/challenge");
|
||||
var transaction = await server.SendAsync("https://example.com/challenge");
|
||||
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
|
||||
var query = transaction.Response.Headers.Location.Query;
|
||||
query.ShouldContain("custom=test");
|
||||
|
|
@ -222,14 +216,16 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
options.ClientId = "Test Id";
|
||||
options.ClientSecret = "Test Secret";
|
||||
});
|
||||
var transaction = await SendAsync(server, "https://example.com/signin-google?code=TestCode");
|
||||
var transaction = await server.SendAsync("https://example.com/signin-google?code=TestCode");
|
||||
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task ReplyPathWillAuthenticateValidAuthorizeCodeAndState()
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("CustomIssuer")]
|
||||
public async Task ReplyPathWillAuthenticateValidAuthorizeCodeAndState(string claimsIssuer)
|
||||
{
|
||||
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("GoogleTest"));
|
||||
var server = CreateServer(options =>
|
||||
|
|
@ -237,6 +233,7 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
options.ClientId = "Test Id";
|
||||
options.ClientSecret = "Test Secret";
|
||||
options.StateDataFormat = stateFormat;
|
||||
options.ClaimsIssuer = claimsIssuer;
|
||||
options.BackchannelHttpHandler = new TestHttpMessageHandler
|
||||
{
|
||||
Sender = req =>
|
||||
|
|
@ -283,23 +280,24 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
properties.Items.Add(correlationKey, correlationValue);
|
||||
properties.RedirectUri = "/me";
|
||||
var state = stateFormat.Protect(properties);
|
||||
var transaction = await SendAsync(server,
|
||||
var transaction = await server.SendAsync(
|
||||
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state),
|
||||
correlationKey + "=" + correlationValue);
|
||||
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
|
||||
transaction.Response.Headers.Location.ToString().ShouldBe("/me");
|
||||
transaction.SetCookie.Count.ShouldBe(2);
|
||||
transaction.SetCookie[0].ShouldContain(correlationKey);
|
||||
transaction.SetCookie[1].ShouldContain(".AspNet.Cookie");
|
||||
transaction.SetCookie[1].ShouldContain(".AspNet." + TestExtensions.CookieAuthenticationScheme);
|
||||
|
||||
var authCookie = transaction.AuthenticationCookieValue;
|
||||
transaction = await SendAsync(server, "https://example.com/me", authCookie);
|
||||
transaction = await server.SendAsync("https://example.com/me", authCookie);
|
||||
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.OK);
|
||||
transaction.FindClaimValue(ClaimTypes.Name).ShouldBe("Test Name");
|
||||
transaction.FindClaimValue(ClaimTypes.NameIdentifier).ShouldBe("Test User ID");
|
||||
transaction.FindClaimValue(ClaimTypes.GivenName).ShouldBe("Test Given Name");
|
||||
transaction.FindClaimValue(ClaimTypes.Surname).ShouldBe("Test Family Name");
|
||||
transaction.FindClaimValue(ClaimTypes.Email).ShouldBe("Test email");
|
||||
var expectedIssuer = claimsIssuer ?? GoogleAuthenticationDefaults.AuthenticationScheme;
|
||||
transaction.FindClaimValue(ClaimTypes.Name, expectedIssuer).ShouldBe("Test Name");
|
||||
transaction.FindClaimValue(ClaimTypes.NameIdentifier, expectedIssuer).ShouldBe("Test User ID");
|
||||
transaction.FindClaimValue(ClaimTypes.GivenName, expectedIssuer).ShouldBe("Test Given Name");
|
||||
transaction.FindClaimValue(ClaimTypes.Surname, expectedIssuer).ShouldBe("Test Family Name");
|
||||
transaction.FindClaimValue(ClaimTypes.Email, expectedIssuer).ShouldBe("Test email");
|
||||
|
||||
// Ensure claims transformation
|
||||
transaction.FindClaimValue("xform").ShouldBe("yup");
|
||||
|
|
@ -328,7 +326,7 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
properties.Items.Add(correlationKey, correlationValue);
|
||||
properties.RedirectUri = "/me";
|
||||
var state = stateFormat.Protect(properties);
|
||||
var transaction = await SendAsync(server,
|
||||
var transaction = await server.SendAsync(
|
||||
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state),
|
||||
correlationKey + "=" + correlationValue);
|
||||
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
|
||||
|
|
@ -358,7 +356,7 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
properties.Items.Add(correlationKey, correlationValue);
|
||||
properties.RedirectUri = "/me";
|
||||
var state = stateFormat.Protect(properties);
|
||||
var transaction = await SendAsync(server,
|
||||
var transaction = await server.SendAsync(
|
||||
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state),
|
||||
correlationKey + "=" + correlationValue);
|
||||
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
|
||||
|
|
@ -419,7 +417,7 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
OnAuthenticated = context =>
|
||||
{
|
||||
var refreshToken = context.RefreshToken;
|
||||
context.Principal.AddIdentity(new ClaimsIdentity(new Claim[] { new Claim("RefreshToken", refreshToken) }, "Google"));
|
||||
context.Principal.AddIdentity(new ClaimsIdentity(new Claim[] { new Claim("RefreshToken", refreshToken, ClaimValueTypes.String, "Google") }, "Google"));
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
};
|
||||
|
|
@ -430,17 +428,17 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
properties.Items.Add(correlationKey, correlationValue);
|
||||
properties.RedirectUri = "/me";
|
||||
var state = stateFormat.Protect(properties);
|
||||
var transaction = await SendAsync(server,
|
||||
var transaction = await server.SendAsync(
|
||||
"https://example.com/signin-google?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state),
|
||||
correlationKey + "=" + correlationValue);
|
||||
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
|
||||
transaction.Response.Headers.Location.ToString().ShouldBe("/me");
|
||||
transaction.SetCookie.Count.ShouldBe(2);
|
||||
transaction.SetCookie[0].ShouldContain(correlationKey);
|
||||
transaction.SetCookie[1].ShouldContain(".AspNet.Cookie");
|
||||
transaction.SetCookie[1].ShouldContain(".AspNet." + TestExtensions.CookieAuthenticationScheme);
|
||||
|
||||
var authCookie = transaction.AuthenticationCookieValue;
|
||||
transaction = await SendAsync(server, "https://example.com/me", authCookie);
|
||||
transaction = await server.SendAsync("https://example.com/me", authCookie);
|
||||
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.OK);
|
||||
transaction.FindClaimValue("RefreshToken").ShouldBe("Test Refresh Token");
|
||||
}
|
||||
|
|
@ -453,40 +451,13 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
return res;
|
||||
}
|
||||
|
||||
private static async Task<Transaction> SendAsync(TestServer server, string uri, string cookieHeader = null)
|
||||
{
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, uri);
|
||||
if (!string.IsNullOrEmpty(cookieHeader))
|
||||
{
|
||||
request.Headers.Add("Cookie", cookieHeader);
|
||||
}
|
||||
var transaction = new Transaction
|
||||
{
|
||||
Request = request,
|
||||
Response = await server.CreateClient().SendAsync(request),
|
||||
};
|
||||
if (transaction.Response.Headers.Contains("Set-Cookie"))
|
||||
{
|
||||
transaction.SetCookie = transaction.Response.Headers.GetValues("Set-Cookie").ToList();
|
||||
}
|
||||
transaction.ResponseText = await transaction.Response.Content.ReadAsStringAsync();
|
||||
|
||||
if (transaction.Response.Content != null &&
|
||||
transaction.Response.Content.Headers.ContentType != null &&
|
||||
transaction.Response.Content.Headers.ContentType.MediaType == "text/xml")
|
||||
{
|
||||
transaction.ResponseElement = XElement.Parse(transaction.ResponseText);
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
|
||||
private static TestServer CreateServer(Action<GoogleAuthenticationOptions> configureOptions, Func<HttpContext, Task> testpath = null)
|
||||
{
|
||||
return TestServer.Create(app =>
|
||||
{
|
||||
app.UseCookieAuthentication(options =>
|
||||
{
|
||||
options.AuthenticationScheme = CookieAuthenticationScheme;
|
||||
options.AuthenticationScheme = TestExtensions.CookieAuthenticationScheme;
|
||||
options.AutomaticAuthentication = true;
|
||||
});
|
||||
app.UseGoogleAuthentication(configureOptions);
|
||||
|
|
@ -502,7 +473,7 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
}
|
||||
else if (req.Path == new PathString("/me"))
|
||||
{
|
||||
Describe(res, context.User);
|
||||
res.Describe(context.User);
|
||||
}
|
||||
else if (req.Path == new PathString("/unauthorized"))
|
||||
{
|
||||
|
|
@ -535,7 +506,7 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
services.AddAuthentication();
|
||||
services.Configure<ExternalAuthenticationOptions>(options =>
|
||||
{
|
||||
options.SignInScheme = CookieAuthenticationScheme;
|
||||
options.SignInScheme = TestExtensions.CookieAuthenticationScheme;
|
||||
});
|
||||
services.ConfigureClaimsTransformation(p =>
|
||||
{
|
||||
|
|
@ -547,79 +518,5 @@ namespace Microsoft.AspNet.Authentication.Google
|
|||
});
|
||||
}
|
||||
|
||||
private static void Describe(HttpResponse res, ClaimsPrincipal user)
|
||||
{
|
||||
res.StatusCode = 200;
|
||||
res.ContentType = "text/xml";
|
||||
var xml = new XElement("xml");
|
||||
if (user != null)
|
||||
{
|
||||
foreach (var identity in user.Identities)
|
||||
{
|
||||
xml.Add(identity.Claims.Select(claim => new XElement("claim", new XAttribute("type", claim.Type), new XAttribute("value", claim.Value))));
|
||||
}
|
||||
}
|
||||
using (var memory = new MemoryStream())
|
||||
{
|
||||
using (var writer = new XmlTextWriter(memory, Encoding.UTF8))
|
||||
{
|
||||
xml.WriteTo(writer);
|
||||
}
|
||||
res.Body.Write(memory.ToArray(), 0, memory.ToArray().Length);
|
||||
}
|
||||
}
|
||||
|
||||
private class TestHttpMessageHandler : HttpMessageHandler
|
||||
{
|
||||
public Func<HttpRequestMessage, HttpResponseMessage> Sender { get; set; }
|
||||
|
||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
|
||||
{
|
||||
if (Sender != null)
|
||||
{
|
||||
return Task.FromResult(Sender(request));
|
||||
}
|
||||
|
||||
return Task.FromResult<HttpResponseMessage>(null);
|
||||
}
|
||||
}
|
||||
|
||||
private class Transaction
|
||||
{
|
||||
public HttpRequestMessage Request { get; set; }
|
||||
public HttpResponseMessage Response { get; set; }
|
||||
|
||||
public IList<string> SetCookie { get; set; }
|
||||
|
||||
public string ResponseText { get; set; }
|
||||
public XElement ResponseElement { get; set; }
|
||||
|
||||
public string AuthenticationCookieValue
|
||||
{
|
||||
get
|
||||
{
|
||||
if (SetCookie != null && SetCookie.Count > 0)
|
||||
{
|
||||
var authCookie = SetCookie.SingleOrDefault(c => c.Contains(".AspNet.Cookie="));
|
||||
if (authCookie != null)
|
||||
{
|
||||
return authCookie.Substring(0, authCookie.IndexOf(';'));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public string FindClaimValue(string claimType)
|
||||
{
|
||||
var claim = ResponseElement.Elements("claim").SingleOrDefault(elt => elt.Attribute("type").Value == claimType);
|
||||
if (claim == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return claim.Attribute("value").Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,11 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.AspNet.Authentication.DataHandler;
|
||||
using Microsoft.AspNet.Authentication.MicrosoftAccount;
|
||||
using Microsoft.AspNet.Builder;
|
||||
|
|
@ -43,13 +38,8 @@ namespace Microsoft.AspNet.Authentication.Tests.MicrosoftAccount
|
|||
context.Response.Redirect(context.RedirectUri + "&custom=test");
|
||||
}
|
||||
};
|
||||
},
|
||||
context =>
|
||||
{
|
||||
context.Authentication.Challenge("Microsoft");
|
||||
return true;
|
||||
});
|
||||
var transaction = await SendAsync(server, "http://example.com/challenge");
|
||||
var transaction = await server.SendAsync("http://example.com/challenge");
|
||||
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
|
||||
var query = transaction.Response.Headers.Location.Query;
|
||||
query.ShouldContain("custom=test");
|
||||
|
|
@ -63,13 +53,8 @@ namespace Microsoft.AspNet.Authentication.Tests.MicrosoftAccount
|
|||
{
|
||||
options.ClientId = "Test Client Id";
|
||||
options.ClientSecret = "Test Client Secret";
|
||||
},
|
||||
context =>
|
||||
{
|
||||
context.Authentication.Challenge("Microsoft");
|
||||
return true;
|
||||
});
|
||||
var transaction = await SendAsync(server, "http://example.com/challenge");
|
||||
var transaction = await server.SendAsync("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");
|
||||
|
|
@ -83,7 +68,7 @@ namespace Microsoft.AspNet.Authentication.Tests.MicrosoftAccount
|
|||
[Fact]
|
||||
public async Task AuthenticatedEventCanGetRefreshToken()
|
||||
{
|
||||
ISecureDataFormat<AuthenticationProperties> stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("MsftTest"));
|
||||
var stateFormat = new PropertiesDataFormat(new EphemeralDataProtectionProvider().CreateProtector("MsftTest"));
|
||||
var server = CreateServer(
|
||||
options =>
|
||||
{
|
||||
|
|
@ -127,15 +112,10 @@ namespace Microsoft.AspNet.Authentication.Tests.MicrosoftAccount
|
|||
OnAuthenticated = context =>
|
||||
{
|
||||
var refreshToken = context.RefreshToken;
|
||||
context.Principal.AddIdentity(new ClaimsIdentity(new Claim[] { new Claim("RefreshToken", refreshToken) }));
|
||||
context.Principal.AddIdentity(new ClaimsIdentity(new Claim[] { new Claim("RefreshToken", refreshToken, ClaimValueTypes.String, "Microsoft") }, "Microsoft"));
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
};
|
||||
},
|
||||
context =>
|
||||
{
|
||||
Describe(context.Response, context.User);
|
||||
return true;
|
||||
});
|
||||
var properties = new AuthenticationProperties();
|
||||
var correlationKey = ".AspNet.Correlation.Microsoft";
|
||||
|
|
@ -143,34 +123,46 @@ namespace Microsoft.AspNet.Authentication.Tests.MicrosoftAccount
|
|||
properties.Items.Add(correlationKey, correlationValue);
|
||||
properties.RedirectUri = "/me";
|
||||
var state = stateFormat.Protect(properties);
|
||||
var transaction = await SendAsync(server,
|
||||
var transaction = await server.SendAsync(
|
||||
"https://example.com/signin-microsoft?code=TestCode&state=" + UrlEncoder.Default.UrlEncode(state),
|
||||
correlationKey + "=" + correlationValue);
|
||||
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
|
||||
transaction.Response.Headers.Location.ToString().ShouldBe("/me");
|
||||
transaction.SetCookie.Count.ShouldBe(2);
|
||||
transaction.SetCookie[0].ShouldContain(correlationKey);
|
||||
transaction.SetCookie[1].ShouldContain(".AspNet.External");
|
||||
transaction.SetCookie[1].ShouldContain(".AspNet." + TestExtensions.CookieAuthenticationScheme);
|
||||
|
||||
var authCookie = transaction.AuthenticationCookieValue;
|
||||
transaction = await SendAsync(server, "https://example.com/me", authCookie);
|
||||
transaction = await server.SendAsync("https://example.com/me", authCookie);
|
||||
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.OK);
|
||||
transaction.FindClaimValue("RefreshToken").ShouldBe("Test Refresh Token");
|
||||
}
|
||||
|
||||
private static TestServer CreateServer(Action<MicrosoftAccountAuthenticationOptions> configureOptions, Func<HttpContext, bool> handler)
|
||||
private static TestServer CreateServer(Action<MicrosoftAccountAuthenticationOptions> configureOptions)
|
||||
{
|
||||
return TestServer.Create(app =>
|
||||
{
|
||||
app.UseCookieAuthentication(options =>
|
||||
{
|
||||
options.AuthenticationScheme = "External";
|
||||
options.AuthenticationScheme = TestExtensions.CookieAuthenticationScheme;
|
||||
options.AutomaticAuthentication = true;
|
||||
});
|
||||
app.UseMicrosoftAccountAuthentication(configureOptions);
|
||||
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
if (handler == null || !handler(context))
|
||||
var req = context.Request;
|
||||
var res = context.Response;
|
||||
if (req.Path == new PathString("/challenge"))
|
||||
{
|
||||
context.Authentication.Challenge("Microsoft");
|
||||
res.StatusCode = 401;
|
||||
}
|
||||
else if (req.Path == new PathString("/me"))
|
||||
{
|
||||
res.Describe(context.User);
|
||||
}
|
||||
else
|
||||
{
|
||||
await next();
|
||||
}
|
||||
|
|
@ -181,38 +173,11 @@ namespace Microsoft.AspNet.Authentication.Tests.MicrosoftAccount
|
|||
services.AddAuthentication();
|
||||
services.Configure<ExternalAuthenticationOptions>(options =>
|
||||
{
|
||||
options.SignInScheme = "External";
|
||||
options.SignInScheme = TestExtensions.CookieAuthenticationScheme;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static async Task<Transaction> SendAsync(TestServer server, string uri, string cookieHeader = null)
|
||||
{
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, uri);
|
||||
if (!string.IsNullOrEmpty(cookieHeader))
|
||||
{
|
||||
request.Headers.Add("Cookie", cookieHeader);
|
||||
}
|
||||
var transaction = new Transaction
|
||||
{
|
||||
Request = request,
|
||||
Response = await server.CreateClient().SendAsync(request),
|
||||
};
|
||||
if (transaction.Response.Headers.Contains("Set-Cookie"))
|
||||
{
|
||||
transaction.SetCookie = transaction.Response.Headers.GetValues("Set-Cookie").ToList();
|
||||
}
|
||||
transaction.ResponseText = await transaction.Response.Content.ReadAsStringAsync();
|
||||
|
||||
if (transaction.Response.Content != null &&
|
||||
transaction.Response.Content.Headers.ContentType != null &&
|
||||
transaction.Response.Content.Headers.ContentType.MediaType == "text/xml")
|
||||
{
|
||||
transaction.ResponseElement = XElement.Parse(transaction.ResponseText);
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
|
||||
private static HttpResponseMessage ReturnJsonResponse(object content)
|
||||
{
|
||||
var res = new HttpResponseMessage(HttpStatusCode.OK);
|
||||
|
|
@ -220,78 +185,5 @@ namespace Microsoft.AspNet.Authentication.Tests.MicrosoftAccount
|
|||
res.Content = new StringContent(text, Encoding.UTF8, "application/json");
|
||||
return res;
|
||||
}
|
||||
|
||||
private static void Describe(HttpResponse res, ClaimsPrincipal principal)
|
||||
{
|
||||
res.StatusCode = 200;
|
||||
res.ContentType = "text/xml";
|
||||
var xml = new XElement("xml");
|
||||
if (principal != null)
|
||||
{
|
||||
foreach (var identity in principal.Identities)
|
||||
{
|
||||
xml.Add(identity.Claims.Select(claim => new XElement("claim", new XAttribute("type", claim.Type), new XAttribute("value", claim.Value))));
|
||||
}
|
||||
}
|
||||
using (var memory = new MemoryStream())
|
||||
{
|
||||
using (var writer = new XmlTextWriter(memory, Encoding.UTF8))
|
||||
{
|
||||
xml.WriteTo(writer);
|
||||
}
|
||||
res.Body.Write(memory.ToArray(), 0, memory.ToArray().Length);
|
||||
}
|
||||
}
|
||||
|
||||
private class TestHttpMessageHandler : HttpMessageHandler
|
||||
{
|
||||
public Func<HttpRequestMessage, HttpResponseMessage> Sender { get; set; }
|
||||
|
||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
|
||||
{
|
||||
if (Sender != null)
|
||||
{
|
||||
return Task.FromResult(Sender(request));
|
||||
}
|
||||
|
||||
return Task.FromResult<HttpResponseMessage>(null);
|
||||
}
|
||||
}
|
||||
|
||||
private class Transaction
|
||||
{
|
||||
public HttpRequestMessage Request { get; set; }
|
||||
public HttpResponseMessage Response { get; set; }
|
||||
public IList<string> SetCookie { get; set; }
|
||||
public string ResponseText { get; set; }
|
||||
public XElement ResponseElement { get; set; }
|
||||
|
||||
public string AuthenticationCookieValue
|
||||
{
|
||||
get
|
||||
{
|
||||
if (SetCookie != null && SetCookie.Count > 0)
|
||||
{
|
||||
var authCookie = SetCookie.SingleOrDefault(c => c.Contains(".AspNet.External="));
|
||||
if (authCookie != null)
|
||||
{
|
||||
return authCookie.Substring(0, authCookie.IndexOf(';'));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public string FindClaimValue(string claimType)
|
||||
{
|
||||
XElement claim = ResponseElement.Elements("claim").SingleOrDefault(elt => elt.Attribute("type").Value == claimType);
|
||||
if (claim == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return claim.Attribute("value").Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
|
|
@ -36,7 +35,7 @@ namespace Microsoft.AspNet.Authentication.OAuthBearer
|
|||
};
|
||||
});
|
||||
|
||||
string newBearerToken = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImtyaU1QZG1Cdng2OHNrVDgtbVBBQjNCc2VlQSJ9.eyJhdWQiOiJodHRwczovL1R1c2hhclRlc3Qub25taWNyb3NvZnQuY29tL1RvZG9MaXN0U2VydmljZS1NYW51YWxKd3QiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9hZmJlY2UwMy1hZWFhLTRmM2YtODVlNy1jZTA4ZGQyMGNlNTAvIiwiaWF0IjoxNDE4MzMwNjE0LCJuYmYiOjE0MTgzMzA2MTQsImV4cCI6MTQxODMzNDUxNCwidmVyIjoiMS4wIiwidGlkIjoiYWZiZWNlMDMtYWVhYS00ZjNmLTg1ZTctY2UwOGRkMjBjZTUwIiwiYW1yIjpbInB3ZCJdLCJvaWQiOiI1Mzk3OTdjMi00MDE5LTQ2NTktOWRiNS03MmM0Yzc3NzhhMzMiLCJ1cG4iOiJWaWN0b3JAVHVzaGFyVGVzdC5vbm1pY3Jvc29mdC5jb20iLCJ1bmlxdWVfbmFtZSI6IlZpY3RvckBUdXNoYXJUZXN0Lm9ubWljcm9zb2Z0LmNvbSIsInN1YiI6IkQyMm9aMW9VTzEzTUFiQXZrdnFyd2REVE80WXZJdjlzMV9GNWlVOVUwYnciLCJmYW1pbHlfbmFtZSI6Ikd1cHRhIiwiZ2l2ZW5fbmFtZSI6IlZpY3RvciIsImFwcGlkIjoiNjEzYjVhZjgtZjJjMy00MWI2LWExZGMtNDE2Yzk3ODAzMGI3IiwiYXBwaWRhY3IiOiIwIiwic2NwIjoidXNlcl9pbXBlcnNvbmF0aW9uIiwiYWNyIjoiMSJ9.N_Kw1EhoVGrHbE6hOcm7ERdZ7paBQiNdObvp2c6T6n5CE8p0fZqmUd-ya_EqwElcD6SiKSiP7gj0gpNUnOJcBl_H2X8GseaeeMxBrZdsnDL8qecc6_ygHruwlPltnLTdka67s1Ow4fDSHaqhVTEk6lzGmNEcbNAyb0CxQxU6o7Fh0yHRiWoLsT8yqYk8nKzsHXfZBNby4aRo3_hXaa4i0SZLYfDGGYPdttG4vT_u54QGGd4Wzbonv2gjDlllOVGOwoJS6kfl1h8mk0qxdiIaT_ChbDWgkWvTB7bTvBE-EgHgV0XmAo0WtJeSxgjsG3KhhEPsONmqrSjhIUV4IVnF2w";
|
||||
var newBearerToken = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImtyaU1QZG1Cdng2OHNrVDgtbVBBQjNCc2VlQSJ9.eyJhdWQiOiJodHRwczovL1R1c2hhclRlc3Qub25taWNyb3NvZnQuY29tL1RvZG9MaXN0U2VydmljZS1NYW51YWxKd3QiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9hZmJlY2UwMy1hZWFhLTRmM2YtODVlNy1jZTA4ZGQyMGNlNTAvIiwiaWF0IjoxNDE4MzMwNjE0LCJuYmYiOjE0MTgzMzA2MTQsImV4cCI6MTQxODMzNDUxNCwidmVyIjoiMS4wIiwidGlkIjoiYWZiZWNlMDMtYWVhYS00ZjNmLTg1ZTctY2UwOGRkMjBjZTUwIiwiYW1yIjpbInB3ZCJdLCJvaWQiOiI1Mzk3OTdjMi00MDE5LTQ2NTktOWRiNS03MmM0Yzc3NzhhMzMiLCJ1cG4iOiJWaWN0b3JAVHVzaGFyVGVzdC5vbm1pY3Jvc29mdC5jb20iLCJ1bmlxdWVfbmFtZSI6IlZpY3RvckBUdXNoYXJUZXN0Lm9ubWljcm9zb2Z0LmNvbSIsInN1YiI6IkQyMm9aMW9VTzEzTUFiQXZrdnFyd2REVE80WXZJdjlzMV9GNWlVOVUwYnciLCJmYW1pbHlfbmFtZSI6Ikd1cHRhIiwiZ2l2ZW5fbmFtZSI6IlZpY3RvciIsImFwcGlkIjoiNjEzYjVhZjgtZjJjMy00MWI2LWExZGMtNDE2Yzk3ODAzMGI3IiwiYXBwaWRhY3IiOiIwIiwic2NwIjoidXNlcl9pbXBlcnNvbmF0aW9uIiwiYWNyIjoiMSJ9.N_Kw1EhoVGrHbE6hOcm7ERdZ7paBQiNdObvp2c6T6n5CE8p0fZqmUd-ya_EqwElcD6SiKSiP7gj0gpNUnOJcBl_H2X8GseaeeMxBrZdsnDL8qecc6_ygHruwlPltnLTdka67s1Ow4fDSHaqhVTEk6lzGmNEcbNAyb0CxQxU6o7Fh0yHRiWoLsT8yqYk8nKzsHXfZBNby4aRo3_hXaa4i0SZLYfDGGYPdttG4vT_u54QGGd4Wzbonv2gjDlllOVGOwoJS6kfl1h8mk0qxdiIaT_ChbDWgkWvTB7bTvBE-EgHgV0XmAo0WtJeSxgjsG3KhhEPsONmqrSjhIUV4IVnF2w";
|
||||
var response = await SendAsync(server, "http://example.com/oauth", newBearerToken);
|
||||
response.Response.StatusCode.ShouldBe(HttpStatusCode.OK);
|
||||
}
|
||||
|
|
@ -339,6 +338,7 @@ namespace Microsoft.AspNet.Authentication.OAuthBearer
|
|||
services => services.AddAuthentication());
|
||||
}
|
||||
|
||||
// TODO: see if we can share the TestExtensions SendAsync method (only diff is auth header)
|
||||
private static async Task<Transaction> SendAsync(TestServer server, string uri, string authorizationHeader = null)
|
||||
{
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, uri);
|
||||
|
|
@ -364,14 +364,5 @@ namespace Microsoft.AspNet.Authentication.OAuthBearer
|
|||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
private class Transaction
|
||||
{
|
||||
public HttpRequestMessage Request { get; set; }
|
||||
public HttpResponseMessage Response { get; set; }
|
||||
public IList<string> SetCookie { get; set; }
|
||||
public string ResponseText { get; set; }
|
||||
public XElement ResponseElement { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.IdentityModel.Protocols;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNet.Authentication.Tests.OpenIdConnect
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Principal;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Authentication;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -17,7 +15,7 @@ namespace Microsoft.AspNet.Authentication
|
|||
[Fact]
|
||||
public void AddingToAnonymousIdentityDoesNotKeepAnonymousIdentity()
|
||||
{
|
||||
HttpContext context = new DefaultHttpContext();
|
||||
var context = new DefaultHttpContext();
|
||||
context.User.ShouldNotBe(null);
|
||||
context.User.Identity.IsAuthenticated.ShouldBe(false);
|
||||
|
||||
|
|
@ -36,7 +34,7 @@ namespace Microsoft.AspNet.Authentication
|
|||
[Fact]
|
||||
public void AddingExistingIdentityChangesDefaultButPreservesPrior()
|
||||
{
|
||||
HttpContext context = new DefaultHttpContext();
|
||||
var context = new DefaultHttpContext();
|
||||
context.User = new GenericPrincipal(new GenericIdentity("Test1", "Alpha"), null);
|
||||
|
||||
context.User.Identity.AuthenticationType.ShouldBe("Alpha");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.TestHost;
|
||||
|
||||
namespace Microsoft.AspNet.Authentication
|
||||
{
|
||||
public static class TestExtensions
|
||||
{
|
||||
public const string CookieAuthenticationScheme = "External";
|
||||
|
||||
public static async Task<Transaction> SendAsync(this TestServer server, string uri, string cookieHeader = null)
|
||||
{
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, uri);
|
||||
if (!string.IsNullOrEmpty(cookieHeader))
|
||||
{
|
||||
request.Headers.Add("Cookie", cookieHeader);
|
||||
}
|
||||
var transaction = new Transaction
|
||||
{
|
||||
Request = request,
|
||||
Response = await server.CreateClient().SendAsync(request),
|
||||
};
|
||||
if (transaction.Response.Headers.Contains("Set-Cookie"))
|
||||
{
|
||||
transaction.SetCookie = transaction.Response.Headers.GetValues("Set-Cookie").ToList();
|
||||
}
|
||||
transaction.ResponseText = await transaction.Response.Content.ReadAsStringAsync();
|
||||
|
||||
if (transaction.Response.Content != null &&
|
||||
transaction.Response.Content.Headers.ContentType != null &&
|
||||
transaction.Response.Content.Headers.ContentType.MediaType == "text/xml")
|
||||
{
|
||||
transaction.ResponseElement = XElement.Parse(transaction.ResponseText);
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
|
||||
public static void Describe(this HttpResponse res, ClaimsPrincipal principal)
|
||||
{
|
||||
res.StatusCode = 200;
|
||||
res.ContentType = "text/xml";
|
||||
var xml = new XElement("xml");
|
||||
if (principal != null)
|
||||
{
|
||||
foreach (var identity in principal.Identities)
|
||||
{
|
||||
xml.Add(identity.Claims.Select(claim =>
|
||||
new XElement("claim", new XAttribute("type", claim.Type),
|
||||
new XAttribute("value", claim.Value),
|
||||
new XAttribute("issuer", claim.Issuer))));
|
||||
}
|
||||
}
|
||||
using (var memory = new MemoryStream())
|
||||
{
|
||||
using (var writer = new XmlTextWriter(memory, Encoding.UTF8))
|
||||
{
|
||||
xml.WriteTo(writer);
|
||||
}
|
||||
res.Body.Write(memory.ToArray(), 0, memory.ToArray().Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Authentication
|
||||
{
|
||||
public class TestHttpMessageHandler : HttpMessageHandler
|
||||
{
|
||||
public Func<HttpRequestMessage, HttpResponseMessage> Sender { get; set; }
|
||||
|
||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
|
||||
{
|
||||
if (Sender != null)
|
||||
{
|
||||
return Task.FromResult(Sender(request));
|
||||
}
|
||||
|
||||
return Task.FromResult<HttpResponseMessage>(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Microsoft.AspNet.Authentication
|
||||
{
|
||||
public class Transaction
|
||||
{
|
||||
public HttpRequestMessage Request { get; set; }
|
||||
public HttpResponseMessage Response { get; set; }
|
||||
|
||||
public IList<string> SetCookie { get; set; }
|
||||
|
||||
public string ResponseText { get; set; }
|
||||
public XElement ResponseElement { get; set; }
|
||||
|
||||
public string AuthenticationCookieValue
|
||||
{
|
||||
get
|
||||
{
|
||||
if (SetCookie != null && SetCookie.Count > 0)
|
||||
{
|
||||
var authCookie = SetCookie.SingleOrDefault(c => c.Contains(".AspNet." + TestExtensions.CookieAuthenticationScheme + "="));
|
||||
if (authCookie != null)
|
||||
{
|
||||
return authCookie.Substring(0, authCookie.IndexOf(';'));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public string FindClaimValue(string claimType, string issuer = null)
|
||||
{
|
||||
var claim = ResponseElement.Elements("claim")
|
||||
.SingleOrDefault(elt => elt.Attribute("type").Value == claimType &&
|
||||
(issuer == null || elt.Attribute("issuer").Value == issuer));
|
||||
if (claim == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return claim.Attribute("value").Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
|
|
@ -57,7 +55,7 @@ namespace Microsoft.AspNet.Authentication.Twitter
|
|||
context.Authentication.Challenge("Twitter");
|
||||
return true;
|
||||
});
|
||||
var transaction = await SendAsync(server, "http://example.com/challenge");
|
||||
var transaction = await server.SendAsync("http://example.com/challenge");
|
||||
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
|
||||
var query = transaction.Response.Headers.Location.Query;
|
||||
query.ShouldContain("custom=test");
|
||||
|
|
@ -95,7 +93,7 @@ namespace Microsoft.AspNet.Authentication.Twitter
|
|||
context.Authentication.Challenge("Twitter");
|
||||
return true;
|
||||
});
|
||||
var transaction = await SendAsync(server, "http://example.com/challenge");
|
||||
var transaction = await server.SendAsync("http://example.com/challenge");
|
||||
transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect);
|
||||
var location = transaction.Response.Headers.Location.AbsoluteUri;
|
||||
location.ShouldContain("https://twitter.com/oauth/authenticate?oauth_token=");
|
||||
|
|
@ -130,49 +128,5 @@ namespace Microsoft.AspNet.Authentication.Twitter
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static async Task<Transaction> SendAsync(TestServer server, string uri, string cookieHeader = null)
|
||||
{
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, uri);
|
||||
if (!string.IsNullOrEmpty(cookieHeader))
|
||||
{
|
||||
request.Headers.Add("Cookie", cookieHeader);
|
||||
}
|
||||
var transaction = new Transaction
|
||||
{
|
||||
Request = request,
|
||||
Response = await server.CreateClient().SendAsync(request),
|
||||
};
|
||||
if (transaction.Response.Headers.Contains("Set-Cookie"))
|
||||
{
|
||||
transaction.SetCookie = transaction.Response.Headers.GetValues("Set-Cookie").ToList();
|
||||
}
|
||||
transaction.ResponseText = await transaction.Response.Content.ReadAsStringAsync();
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
private class TestHttpMessageHandler : HttpMessageHandler
|
||||
{
|
||||
public Func<HttpRequestMessage, HttpResponseMessage> Sender { get; set; }
|
||||
|
||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
|
||||
{
|
||||
if (Sender != null)
|
||||
{
|
||||
return Task.FromResult(Sender(request));
|
||||
}
|
||||
|
||||
return Task.FromResult<HttpResponseMessage>(null);
|
||||
}
|
||||
}
|
||||
|
||||
private class Transaction
|
||||
{
|
||||
public HttpRequestMessage Request { get; set; }
|
||||
public HttpResponseMessage Response { get; set; }
|
||||
public IList<string> SetCookie { get; set; }
|
||||
public string ResponseText { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue