Adding some mocks for Google, Facebook and Twitter for E2Evalidation

Social mock tests are not executed right now due to 2 issues:
1. Identity extensions related to Social are not in yet.
2. Helios currently does not support loading of environment based startup class.
This commit is contained in:
Praburaj 2014-09-08 18:02:03 -07:00
parent 7e77078160
commit 093caaae7e
16 changed files with 841 additions and 1 deletions

View File

@ -0,0 +1,32 @@
using Microsoft.AspNet.Http.Security;
using Microsoft.AspNet.Security;
using Newtonsoft.Json;
namespace MusicStore.Mocks.Common
{
public class CustomStateDataFormat : ISecureDataFormat<AuthenticationProperties>
{
private static string lastSavedAuthenticationProperties;
public string Protect(AuthenticationProperties data)
{
lastSavedAuthenticationProperties = Serialize(data);
return "ValidStateData";
}
public AuthenticationProperties Unprotect(string state)
{
return state == "ValidStateData" ? DeSerialize(lastSavedAuthenticationProperties) : null;
}
private string Serialize(AuthenticationProperties data)
{
return JsonConvert.SerializeObject(data, Formatting.Indented);
}
private AuthenticationProperties DeSerialize(string state)
{
return JsonConvert.DeserializeObject<AuthenticationProperties>(state);
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace System.Net
{
public static class Extensions
{
/// <summary>
/// https://github.com/aspnet/HttpAbstractions/issues/121 - Helpers implemented here until that.
/// </summary>
/// <returns></returns>
public static Dictionary<string, string> ParseQueryString(this Uri uri)
{
var queryParameters = Uri.UnescapeDataString(uri.Query.TrimStart('?')).Split(new char[] { '&' }, StringSplitOptions.RemoveEmptyEntries);
var queryItemCollection = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
if (queryParameters != null && queryParameters.Length > 0)
{
foreach (var queryParameter in queryParameters)
{
var queryParameterParts = queryParameter.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries);
var value = queryParameterParts.Length == 1 ? string.Empty : queryParameterParts[1];
queryItemCollection.Add(queryParameterParts[0], value);
}
}
return queryItemCollection;
}
}
}

View File

@ -0,0 +1,15 @@
using System;
namespace MusicStore.Mocks.Common
{
internal class Helpers
{
internal static void ThrowIfConditionFailed(Func<bool> condition, string errorMessage)
{
if (!condition())
{
throw new Exception(errorMessage);
}
}
}
}

View File

@ -0,0 +1,48 @@
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Net;
using MusicStore.Mocks.Common;
namespace MusicStore.Mocks.Facebook
{
/// <summary>
/// Summary description for FacebookMockBackChannelHttpHandler
/// </summary>
public class FacebookMockBackChannelHttpHandler : WebRequestHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = new HttpResponseMessage();
var queryParameters = request.RequestUri.ParseQueryString();
if (request.RequestUri.AbsoluteUri.StartsWith("https://graph.facebook.com/oauth/access_token"))
{
if (queryParameters["grant_type"] == "authorization_code")
{
if (queryParameters["code"] == "ValidCode")
{
Helpers.ThrowIfConditionFailed(() => queryParameters["redirect_uri"].EndsWith("signin-facebook"), "Redirect URI is not ending with /signin-facebook");
Helpers.ThrowIfConditionFailed(() => queryParameters["client_id"] == "[AppId]", "Invalid client Id received");
Helpers.ThrowIfConditionFailed(() => queryParameters["client_secret"] == "[AppSecret]", "Invalid client secret received");
response.Content = new StringContent("access_token=ValidAccessToken&expires=100");
}
}
}
else if (request.RequestUri.AbsoluteUri.StartsWith("https://graph.facebook.com/me"))
{
Helpers.ThrowIfConditionFailed(() => queryParameters["appsecret_proof"] != null, "appsecret_proof is null");
if (queryParameters["access_token"] == "ValidAccessToken")
{
response.Content = new StringContent("{\"id\":\"Id\",\"name\":\"AspnetvnextTest AspnetvnextTest\",\"first_name\":\"AspnetvnextTest\",\"last_name\":\"AspnetvnextTest\",\"link\":\"https:\\/\\/www.facebook.com\\/myLink\",\"username\":\"AspnetvnextTest.AspnetvnextTest.7\",\"gender\":\"male\",\"email\":\"AspnetvnextTest\\u0040gmail.com\",\"timezone\":-7,\"locale\":\"en_US\",\"verified\":true,\"updated_time\":\"2013-08-06T20:38:48+0000\",\"CertValidatorInvoked\":\"ValidAccessToken\"}");
}
else
{
response.Content = new StringContent("{\"error\":{\"message\":\"Invalid OAuth access token.\",\"type\":\"OAuthException\",\"code\":190}}");
}
}
return await Task.FromResult(response);
}
}
}

View File

@ -0,0 +1,56 @@
using Microsoft.AspNet.Security.Facebook;
using Microsoft.AspNet.Security.OAuth;
using MusicStore.Mocks.Common;
using System;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace MusicStore.Mocks.Facebook
{
/// <summary>
/// Summary description for FacebookNotifications
/// </summary>
internal class FacebookNotifications
{
internal static async Task OnAuthenticated(FacebookAuthenticatedContext context)
{
if (context.Identity != null)
{
Helpers.ThrowIfConditionFailed(() => context.AccessToken == "ValidAccessToken", "");
Helpers.ThrowIfConditionFailed(() => context.Email == "AspnetvnextTest@gmail.com", "");
Helpers.ThrowIfConditionFailed(() => context.Id == "Id", "");
Helpers.ThrowIfConditionFailed(() => context.Link == "https://www.facebook.com/myLink", "");
Helpers.ThrowIfConditionFailed(() => context.Name == "AspnetvnextTest AspnetvnextTest", "");
Helpers.ThrowIfConditionFailed(() => context.UserName == "AspnetvnextTest.AspnetvnextTest.7", "");
Helpers.ThrowIfConditionFailed(() => context.User.SelectToken("id").ToString() == context.Id, "");
Helpers.ThrowIfConditionFailed(() => context.ExpiresIn.Value == TimeSpan.FromSeconds(100), "");
Helpers.ThrowIfConditionFailed(() => context.AccessToken == "ValidAccessToken", "");
context.Identity.AddClaim(new Claim("ManageStore", "false"));
}
await Task.FromResult(0);
}
internal static async Task OnReturnEndpoint(OAuthReturnEndpointContext context)
{
if (context.Identity != null && context.SignInAsAuthenticationType == "External")
{
//This way we will know all notifications were fired.
var manageStoreClaim = context.Identity.Claims.Where(c => c.Type == "ManageStore" && c.Value == "false").FirstOrDefault();
if (manageStoreClaim != null)
{
context.Identity.RemoveClaim(manageStoreClaim);
context.Identity.AddClaim(new Claim("ManageStore", "true"));
}
}
await Task.FromResult(0);
}
internal static void OnApplyRedirect(OAuthApplyRedirectContext context)
{
context.Response.Redirect(context.RedirectUri + "&custom_redirect_uri=custom");
}
}
}

View File

@ -0,0 +1,48 @@
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Text;
using Microsoft.AspNet.WebUtilities;
namespace MusicStore.Mocks.Google
{
/// <summary>
/// Summary description for GoogleMockBackChannelHttpHandler
/// </summary>
public class GoogleMockBackChannelHttpHandler : WebRequestHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = new HttpResponseMessage();
if (request.RequestUri.AbsoluteUri.StartsWith("https://accounts.google.com/o/oauth2/token"))
{
var formData = FormHelpers.ParseForm(await request.Content.ReadAsStringAsync());
if (formData["grant_type"] == "authorization_code")
{
if (formData["code"] == "ValidCode")
{
if (formData["redirect_uri"] != null && formData["redirect_uri"].EndsWith("signin-google") &&
formData["client_id"] == "[ClientId]" && formData["client_secret"] == "[ClientSecret]")
{
response.Content = new StringContent("{\"access_token\":\"ValidAccessToken\",\"refresh_token\":\"ValidRefreshToken\",\"token_type\":\"Bearer\",\"expires_in\":\"1200\",\"id_token\":\"Token\"}", Encoding.UTF8, "application/json");
}
}
}
}
else if (request.RequestUri.AbsoluteUri.StartsWith("https://www.googleapis.com/plus/v1/people/me"))
{
if (request.Headers.Authorization.Parameter == "ValidAccessToken")
{
response.Content = new StringContent("{ \"kind\": \"plus#person\",\n \"etag\": \"\\\"YFr-hUROXQN7IOa3dUHg9dQ8eq0/2hY18HdHEP8NLykSTVEiAhkKsBE\\\"\",\n \"gender\": \"male\",\n \"emails\": [\n {\n \"value\": \"AspnetvnextTest@gmail.com\",\n \"type\": \"account\"\n }\n ],\n \"objectType\": \"person\",\n \"id\": \"106790274378320830963\",\n \"displayName\": \"AspnetvnextTest AspnetvnextTest\",\n \"name\": {\n \"familyName\": \"AspnetvnextTest\",\n \"givenName\": \"FirstName\"\n },\n \"url\": \"https://plus.google.com/106790274378320830963\",\n \"image\": {\n \"url\": \"https://lh3.googleusercontent.com/-XdUIqdMkCWA/AAAAAAAAAAI/AAAAAAAAAAA/4252rscbv5M/photo.jpg?sz=50\"\n },\n \"isPlusUser\": true,\n \"language\": \"en\",\n \"circledByCount\": 0,\n \"verified\": false\n}\n", Encoding.UTF8, "application/json");
}
else
{
response.Content = new StringContent("{\"error\":{\"message\":\"Invalid OAuth access token.\",\"type\":\"OAuthException\",\"code\":190}}");
}
}
return response;
}
}
}

View File

@ -0,0 +1,55 @@
using Microsoft.AspNet.Security.Google;
using Microsoft.AspNet.Security.OAuth;
using MusicStore.Mocks.Common;
using System;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace MusicStore.Mocks.Google
{
/// <summary>
/// Summary description for GoogleNotifications
/// </summary>
internal class GoogleNotifications
{
internal static async Task OnAuthenticated(GoogleAuthenticatedContext context)
{
if (context.Identity != null)
{
Helpers.ThrowIfConditionFailed(() => context.AccessToken == "ValidAccessToken", "Access token is not valid");
Helpers.ThrowIfConditionFailed(() => context.RefreshToken == "ValidRefreshToken", "Refresh token is not valid");
Helpers.ThrowIfConditionFailed(() => context.Email == "AspnetvnextTest@gmail.com", "Email is not valid");
Helpers.ThrowIfConditionFailed(() => context.Id == "106790274378320830963", "Id is not valid");
Helpers.ThrowIfConditionFailed(() => context.FamilyName == "AspnetvnextTest", "FamilyName is not valid");
Helpers.ThrowIfConditionFailed(() => context.Name == "AspnetvnextTest AspnetvnextTest", "Name is not valid");
Helpers.ThrowIfConditionFailed(() => context.ExpiresIn.Value == TimeSpan.FromSeconds(1200), "ExpiresIn is not valid");
Helpers.ThrowIfConditionFailed(() => context.User != null, "User object is not valid");
context.Identity.AddClaim(new Claim("ManageStore", "false"));
}
await Task.FromResult(0);
}
internal static async Task OnReturnEndpoint(OAuthReturnEndpointContext context)
{
if (context.Identity != null && context.SignInAsAuthenticationType == "External")
{
//This way we will know all notifications were fired.
var manageStoreClaim = context.Identity.Claims.Where(c => c.Type == "ManageStore" && c.Value == "false").FirstOrDefault();
if (manageStoreClaim != null)
{
context.Identity.RemoveClaim(manageStoreClaim);
context.Identity.AddClaim(new Claim("ManageStore", "true"));
}
}
await Task.FromResult(0);
}
internal static void OnApplyRedirect(OAuthApplyRedirectContext context)
{
context.Response.Redirect(context.RedirectUri + "&custom_redirect_uri=custom");
}
}
}

View File

@ -0,0 +1 @@
Only for testing purposes. Not needed for production deployments.

View File

@ -0,0 +1,192 @@
using System;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Diagnostics;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Security.Cookies;
using Microsoft.Data.Entity;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Framework.DependencyInjection;
using MusicStore.Models;
using Microsoft.AspNet.Security.Facebook;
using Microsoft.AspNet.Security.Google;
using Microsoft.AspNet.Security.Twitter;
using Microsoft.AspNet.Security.MicrosoftAccount;
using Microsoft.AspNet.Security;
using Microsoft.AspNet.MemoryCache;
using MusicStore.Mocks.Common;
using MusicStore.Mocks.Facebook;
using MusicStore.Mocks.Twitter;
using MusicStore.Mocks.Google;
namespace MusicStore
{
public class StartupSocialTesting
{
public void Configure(IBuilder app)
{
Console.WriteLine("Social Testing mode...");
//Below code demonstrates usage of multiple configuration sources. For instance a setting say 'setting1' is found in both the registered sources,
//then the later source will win. By this way a Local config can be overridden by a different setting while deployed remotely.
var configuration = new Configuration();
configuration.AddJsonFile("LocalConfig.json");
configuration.AddEnvironmentVariables(); //All environment variables in the process's context flow in as configuration values.
//Error page middleware displays a nice formatted HTML page for any unhandled exceptions in the request pipeline.
//Note: ErrorPageOptions.ShowAll to be used only at development time. Not recommended for production.
app.UseErrorPage(ErrorPageOptions.ShowAll);
app.SetDefaultSignInAsAuthenticationType("External");
app.UseServices(services =>
{
//If this type is present - we're on mono
var runningOnMono = Type.GetType("Mono.Runtime") != null;
// Add EF services to the services container
if (runningOnMono)
{
services.AddEntityFramework()
.AddInMemoryStore();
}
else
{
services.AddEntityFramework()
.AddSqlServer();
}
services.AddScoped<MusicStoreContext>();
// Configure DbContext
services.SetupOptions<MusicStoreDbContextOptions>(options =>
{
options.DefaultAdminUserName = configuration.Get("DefaultAdminUsername");
options.DefaultAdminPassword = configuration.Get("DefaultAdminPassword");
if (runningOnMono)
{
options.UseInMemoryStore();
}
else
{
options.UseSqlServer(configuration.Get("Data:DefaultConnection:ConnectionString"));
}
});
// Add Identity services to the services container
services.AddIdentitySqlServer<MusicStoreContext, ApplicationUser>()
.AddAuthentication();
// Add MVC services to the services container
services.AddMvc();
//Add all SignalR related services to IoC.
services.AddSignalR();
//Add InMemoryCache
//Currently not able to AddSingleTon
services.AddInstance<IMemoryCache>(new MemoryCache());
});
//Configure SignalR
app.UseSignalR();
// Add static files to the request pipeline
app.UseStaticFiles();
// Add cookie-based authentication to the request pipeline
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "External",
AuthenticationMode = AuthenticationMode.Passive,
ExpireTimeSpan = TimeSpan.FromMinutes(5)
});
// Add cookie-based authentication to the request pipeline
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = ClaimsIdentityOptions.DefaultAuthenticationType,
LoginPath = new PathString("/Account/Login")
});
app.UseTwoFactorSignInCookies();
var facebookOptions = new FacebookAuthenticationOptions()
{
AppId = "[AppId]",
AppSecret = "[AppSecret]",
Notifications = new FacebookAuthenticationNotifications()
{
OnAuthenticated = FacebookNotifications.OnAuthenticated,
OnReturnEndpoint = FacebookNotifications.OnReturnEndpoint,
OnApplyRedirect = FacebookNotifications.OnApplyRedirect
},
BackchannelHttpHandler = new FacebookMockBackChannelHttpHandler(),
StateDataFormat = new CustomStateDataFormat()
};
facebookOptions.Scope.Add("email");
facebookOptions.Scope.Add("read_friendlists");
facebookOptions.Scope.Add("user_checkins");
app.UseFacebookAuthentication(facebookOptions);
app.UseGoogleAuthentication(new GoogleAuthenticationOptions()
{
ClientId = "[ClientId]",
ClientSecret = "[ClientSecret]",
AccessType = "offline",
Notifications = new GoogleAuthenticationNotifications()
{
OnAuthenticated = GoogleNotifications.OnAuthenticated,
OnReturnEndpoint = GoogleNotifications.OnReturnEndpoint,
OnApplyRedirect = GoogleNotifications.OnApplyRedirect
},
StateDataFormat = new CustomStateDataFormat(),
BackchannelHttpHandler = new GoogleMockBackChannelHttpHandler()
});
app.UseTwitterAuthentication(new TwitterAuthenticationOptions()
{
ConsumerKey = "[ConsumerKey]",
ConsumerSecret = "[ConsumerSecret]",
Notifications = new TwitterAuthenticationNotifications()
{
OnAuthenticated = TwitterNotifications.OnAuthenticated,
OnReturnEndpoint = TwitterNotifications.OnReturnEndpoint,
OnApplyRedirect = TwitterNotifications.OnApplyRedirect
},
StateDataFormat = new CustomTwitterStateDataFormat(),
BackchannelHttpHandler = new TwitterMockBackChannelHttpHandler()
});
app.UseMicrosoftAccountAuthentication(new MicrosoftAccountAuthenticationOptions()
{
Caption = "MicrosoftAccount - Requires project changes",
ClientId = "[ClientId]",
ClientSecret = "[ClientSecret]",
});
// Add MVC to the request pipeline
app.UseMvc(routes =>
{
routes.MapRoute(
name: "areaRoute",
template: "{area:exists}/{controller}/{action}",
defaults: new { action = "Index" });
routes.MapRoute(
name: "default",
template: "{controller}/{action}/{id?}",
defaults: new { controller = "Home", action = "Index" });
routes.MapRoute(
name: "api",
template: "{controller}/{id?}");
});
//Populates the MusicStore sample data
SampleData.InitializeMusicStoreDatabaseAsync(app.ApplicationServices).Wait();
}
}
}

View File

@ -0,0 +1,36 @@
using Microsoft.AspNet.Security;
using Microsoft.AspNet.Security.Twitter.Messages;
using Newtonsoft.Json;
namespace MusicStore.Mocks.Twitter
{
/// <summary>
/// Summary description for CustomTwitterStateDataFormat
/// </summary>
public class CustomTwitterStateDataFormat : ISecureDataFormat<RequestToken>
{
private static string lastSavedRequestToken;
public string Protect(RequestToken data)
{
data.Token = "valid_oauth_token";
lastSavedRequestToken = Serialize(data);
return "valid_oauth_token";
}
public RequestToken Unprotect(string state)
{
return state == "valid_oauth_token" ? DeSerialize(lastSavedRequestToken) : null;
}
private string Serialize(RequestToken data)
{
return JsonConvert.SerializeObject(data, Formatting.Indented);
}
private RequestToken DeSerialize(string state)
{
return JsonConvert.DeserializeObject<RequestToken>(state);
}
}
}

View File

@ -0,0 +1,63 @@
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.WebUtilities;
using System.Collections.Generic;
using System.Net;
namespace MusicStore.Mocks.Twitter
{
/// <summary>
/// Summary description for TwitterMockBackChannelHttpHandler
/// </summary>
public class TwitterMockBackChannelHttpHandler : WebRequestHandler
{
private static bool RequestTokenEndpointInvoked = false;
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = new HttpResponseMessage();
Console.WriteLine(request.RequestUri.AbsoluteUri);
if (request.RequestUri.AbsoluteUri.StartsWith("https://api.twitter.com/oauth/access_token"))
{
var formData = FormHelpers.ParseForm(await request.Content.ReadAsStringAsync());
if (formData["oauth_verifier"] == "valid_oauth_verifier")
{
if (RequestTokenEndpointInvoked)
{
var response_Form_data = new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("oauth_token", "valid_oauth_token"),
new KeyValuePair<string, string>("oauth_token_secret", "valid_oauth_token_secret"),
new KeyValuePair<string, string>("user_id", "valid_user_id"),
new KeyValuePair<string, string>("screen_name", "valid_screen_name"),
};
response.Content = new FormUrlEncodedContent(response_Form_data);
}
else
{
response.StatusCode = HttpStatusCode.InternalServerError;
response.Content = new StringContent("RequestTokenEndpoint is not invoked");
}
}
}
else if (request.RequestUri.AbsoluteUri.StartsWith("https://api.twitter.com/oauth/request_token"))
{
var response_Form_data = new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("oauth_callback_confirmed", "true"),
new KeyValuePair<string, string>("oauth_token", "valid_oauth_token"),
new KeyValuePair<string, string>("oauth_token_secret", "valid_oauth_token_secret")
};
RequestTokenEndpointInvoked = true;
response.Content = new FormUrlEncodedContent(response_Form_data);
}
return response;
}
}
}

View File

@ -0,0 +1,49 @@
using Microsoft.AspNet.Security.Twitter;
using MusicStore.Mocks.Common;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace MusicStore.Mocks.Twitter
{
/// <summary>
/// Summary description for TwitterNotifications
/// </summary>
internal class TwitterNotifications
{
internal static async Task OnAuthenticated(TwitterAuthenticatedContext context)
{
if (context.Identity != null)
{
Helpers.ThrowIfConditionFailed(() => context.UserId == "valid_user_id", "UserId is not valid");
Helpers.ThrowIfConditionFailed(() => context.ScreenName == "valid_screen_name", "ScreenName is not valid");
Helpers.ThrowIfConditionFailed(() => context.AccessToken == "valid_oauth_token", "AccessToken is not valid");
Helpers.ThrowIfConditionFailed(() => context.AccessTokenSecret == "valid_oauth_token_secret", "AccessTokenSecret is not valid");
context.Identity.AddClaim(new Claim("ManageStore", "false"));
}
await Task.FromResult(0);
}
internal static async Task OnReturnEndpoint(TwitterReturnEndpointContext context)
{
if (context.Identity != null && context.SignInAsAuthenticationType == "External")
{
//This way we will know all notifications were fired.
var manageStoreClaim = context.Identity.Claims.Where(c => c.Type == "ManageStore" && c.Value == "false").FirstOrDefault();
if (manageStoreClaim != null)
{
context.Identity.RemoveClaim(manageStoreClaim);
context.Identity.AddClaim(new Claim("ManageStore", "true"));
}
}
await Task.FromResult(0);
}
internal static void OnApplyRedirect(TwitterApplyRedirectContext context)
{
context.Response.Redirect(context.RedirectUri + "&custom_redirect_uri=custom");
}
}
}

View File

@ -1,4 +1,4 @@
using System.Net;
using System.Collections.Generic;
namespace System.Net
{
@ -16,5 +16,27 @@ namespace System.Net
return null;
}
/// <summary>
/// https://github.com/aspnet/HttpAbstractions/issues/121 - Helpers implemented here until that.
/// </summary>
/// <returns></returns>
public static Dictionary<string, string> ParseQueryString(this Uri uri)
{
var queryParameters = Uri.UnescapeDataString(uri.Query.TrimStart('?')).Split(new char[] { '&' }, StringSplitOptions.RemoveEmptyEntries);
var queryItemCollection = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
if (queryParameters != null && queryParameters.Length > 0)
{
foreach (var queryParameter in queryParameters)
{
var queryParameterParts = queryParameter.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries);
var value = queryParameterParts.Length == 1 ? string.Empty : queryParameterParts[1];
queryItemCollection.Add(queryParameterParts[0], value);
}
}
return queryItemCollection;
}
}
}

View File

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net;
using Xunit;
namespace E2ETests
{
public partial class SmokeTests
{
private void LoginWithFacebook()
{
httpClientHandler = new HttpClientHandler() { AllowAutoRedirect = false };
httpClient = new HttpClient(httpClientHandler) { BaseAddress = new Uri(ApplicationBaseUrl) };
var response = httpClient.GetAsync("Account/Login").Result;
ThrowIfResponseStatusNotOk(response);
var responseContent = response.Content.ReadAsStringAsync().Result;
Console.WriteLine("Signing in with Facebook account");
var formParameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("provider", "Facebook"),
new KeyValuePair<string, string>("returnUrl", "/"),
new KeyValuePair<string, string>("__RequestVerificationToken", HtmlDOMHelper.RetrieveAntiForgeryToken(responseContent, "/Account/ExternalLogin")),
};
var content = new FormUrlEncodedContent(formParameters.ToArray());
response = httpClient.PostAsync("Account/ExternalLogin", content).Result;
Assert.Equal<string>("https://www.facebook.com/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>("[AppId]", queryItems["client_id"]);
Assert.Equal<string>(ApplicationBaseUrl + "signin-facebook", queryItems["redirect_uri"]);
Assert.Equal<string>("email,read_friendlists,user_checkins", queryItems["scope"]);
Assert.Equal<string>("ValidStateData", queryItems["state"]);
Assert.Equal<string>("custom", queryItems["custom_redirect_uri"]);
//Check for the correlation cookie
Assert.NotNull(httpClientHandler.CookieContainer.GetCookies(new Uri(ApplicationBaseUrl)).GetCookieWithName(".AspNet.Correlation.Facebook"));
//This is just to generate a correlation cookie. Previous step would generate this cookie, but we have reset the handler now.
httpClientHandler = new HttpClientHandler() { AllowAutoRedirect = true };
httpClient = new HttpClient(httpClientHandler) { BaseAddress = new Uri(ApplicationBaseUrl) };
response = httpClient.GetAsync("Account/Login").Result;
responseContent = response.Content.ReadAsStringAsync().Result;
formParameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("provider", "Facebook"),
new KeyValuePair<string, string>("returnUrl", "/"),
new KeyValuePair<string, string>("__RequestVerificationToken", HtmlDOMHelper.RetrieveAntiForgeryToken(responseContent, "/Account/ExternalLogin")),
};
content = new FormUrlEncodedContent(formParameters.ToArray());
response = httpClient.PostAsync("Account/ExternalLogin", content).Result;
//Post a message to the Facebook middleware
response = httpClient.GetAsync("signin-facebook?code=ValidCode&state=ValidStateData").Result;
//This should land us in ExternalLoginCallBack - this action is not implemented yet. We need to wait to complete automation.
//Correlation cookie not getting cleared after successful signin?
//Assert.Null(httpClientHandler.CookieContainer.GetCookies(new Uri(ApplicationBaseUrl)).GetCookieWithName(".AspNet.Correlation.Facebook"));
}
}
}

View File

@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net;
using Xunit;
namespace E2ETests
{
public partial class SmokeTests
{
private void LoginWithGoogle()
{
httpClientHandler = new HttpClientHandler() { AllowAutoRedirect = false };
httpClient = new HttpClient(httpClientHandler) { BaseAddress = new Uri(ApplicationBaseUrl) };
var response = httpClient.GetAsync("Account/Login").Result;
ThrowIfResponseStatusNotOk(response);
var responseContent = response.Content.ReadAsStringAsync().Result;
Console.WriteLine("Signing in with Google account");
var formParameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("provider", "Google"),
new KeyValuePair<string, string>("returnUrl", "/"),
new KeyValuePair<string, string>("__RequestVerificationToken", HtmlDOMHelper.RetrieveAntiForgeryToken(responseContent, "/Account/ExternalLogin")),
};
var content = new FormUrlEncodedContent(formParameters.ToArray());
response = httpClient.PostAsync("Account/ExternalLogin", content).Result;
Assert.Equal<string>("https://accounts.google.com/o/oauth2/auth", 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>("offline", queryItems["access_type"]);
Assert.Equal<string>("[ClientId]", queryItems["client_id"]);
Assert.Equal<string>(ApplicationBaseUrl + "signin-google", queryItems["redirect_uri"]);
Assert.Equal<string>("openid profile email", queryItems["scope"]);
Assert.Equal<string>("ValidStateData", queryItems["state"]);
Assert.Equal<string>("custom", queryItems["custom_redirect_uri"]);
//Check for the correlation cookie
Assert.NotNull(httpClientHandler.CookieContainer.GetCookies(new Uri(ApplicationBaseUrl)).GetCookieWithName(".AspNet.Correlation.Google"));
//This is just to generate a correlation cookie. Previous step would generate this cookie, but we have reset the handler now.
httpClientHandler = new HttpClientHandler() { AllowAutoRedirect = true };
httpClient = new HttpClient(httpClientHandler) { BaseAddress = new Uri(ApplicationBaseUrl) };
response = httpClient.GetAsync("Account/Login").Result;
responseContent = response.Content.ReadAsStringAsync().Result;
formParameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("provider", "Google"),
new KeyValuePair<string, string>("returnUrl", "/"),
new KeyValuePair<string, string>("__RequestVerificationToken", HtmlDOMHelper.RetrieveAntiForgeryToken(responseContent, "/Account/ExternalLogin")),
};
content = new FormUrlEncodedContent(formParameters.ToArray());
response = httpClient.PostAsync("Account/ExternalLogin", content).Result;
//Post a message to the Google middleware
response = httpClient.GetAsync("signin-google?code=ValidCode&state=ValidStateData").Result;
//This should land us in ExternalLoginCallBack - this action is not implemented yet. We need to wait to complete automation.
//Correlation cookie not getting cleared after successful signin?
//Assert.Null(httpClientHandler.CookieContainer.GetCookies(new Uri(ApplicationBaseUrl)).GetCookieWithName(".AspNet.Correlation.Google"));
}
}
}

View File

@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net;
using Xunit;
namespace E2ETests
{
/// <summary>
/// Summary description for TwitterLoginScenarios
/// </summary>
public partial class SmokeTests
{
private void LoginWithTwitter()
{
httpClientHandler = new HttpClientHandler() { AllowAutoRedirect = false };
httpClient = new HttpClient(httpClientHandler) { BaseAddress = new Uri(ApplicationBaseUrl) };
var response = httpClient.GetAsync("Account/Login").Result;
ThrowIfResponseStatusNotOk(response);
var responseContent = response.Content.ReadAsStringAsync().Result;
Console.WriteLine("Signing in with Twitter account");
var formParameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("provider", "Twitter"),
new KeyValuePair<string, string>("returnUrl", "/"),
new KeyValuePair<string, string>("__RequestVerificationToken", HtmlDOMHelper.RetrieveAntiForgeryToken(responseContent, "/Account/ExternalLogin")),
};
var content = new FormUrlEncodedContent(formParameters.ToArray());
response = httpClient.PostAsync("Account/ExternalLogin", content).Result;
Assert.Equal<string>("https://twitter.com/oauth/authenticate", response.Headers.Location.AbsoluteUri.Replace(response.Headers.Location.Query, string.Empty));
var queryItems = response.Headers.Location.ParseQueryString();
Assert.Equal<string>("custom", queryItems["custom_redirect_uri"]);
Assert.Equal<string>("valid_oauth_token", queryItems["oauth_token"]);
//Check for the correlation cookie
Assert.NotNull(httpClientHandler.CookieContainer.GetCookies(new Uri(ApplicationBaseUrl))["__TwitterState"]);
//This is just to generate a correlation cookie. Previous step would generate this cookie, but we have reset the handler now.
httpClientHandler = new HttpClientHandler() { AllowAutoRedirect = true };
httpClient = new HttpClient(httpClientHandler) { BaseAddress = new Uri(ApplicationBaseUrl) };
response = httpClient.GetAsync("Account/Login").Result;
responseContent = response.Content.ReadAsStringAsync().Result;
formParameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("provider", "Twitter"),
new KeyValuePair<string, string>("returnUrl", "/"),
new KeyValuePair<string, string>("__RequestVerificationToken", HtmlDOMHelper.RetrieveAntiForgeryToken(responseContent, "/Account/ExternalLogin")),
};
content = new FormUrlEncodedContent(formParameters.ToArray());
response = httpClient.PostAsync("Account/ExternalLogin", content).Result;
//Post a message to the Facebook middleware
response = httpClient.GetAsync("signin-twitter?oauth_token=valid_oauth_token&oauth_verifier=valid_oauth_verifier").Result;
//This should land us in ExternalLoginCallBack - this action is not implemented yet. We need to wait to complete automation.
//Correlation cookie not getting cleared after successful signin?
//Assert.Null(httpClientHandler.CookieContainer.GetCookies(new Uri(ApplicationBaseUrl))["__TwitterState"]);
}
}
}