Adding a basic smoke test for OpenIdConnect

Currently the mono variation is failing.
This commit is contained in:
Praburaj 2015-01-26 17:03:34 -08:00
parent c82cda4a78
commit e3637924ee
7 changed files with 272 additions and 4 deletions

View File

@ -3,7 +3,6 @@ using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Diagnostics;
using Microsoft.AspNet.Diagnostics.Entity;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Security;
using Microsoft.Framework.Cache.Memory;
using Microsoft.Framework.ConfigurationModel;

View File

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using Microsoft.AspNet.Http.Core.Collections;
using Microsoft.AspNet.WebUtilities;
using Microsoft.Framework.Logging;
using Xunit;
namespace E2ETests
{
public partial class SmokeTests
{
private void LoginWithOpenIdConnect()
{
_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;
_logger.WriteInformation("Signing in with OpenIdConnect account");
var formParameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("provider", "OpenIdConnect"),
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://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/oauth2/authorize", response.Headers.Location.AbsoluteUri.Replace(response.Headers.Location.Query, string.Empty));
var queryItems = new ReadableStringCollection(QueryHelpers.ParseQuery(response.Headers.Location.Query));
Assert.Equal<string>("c99497aa-3ee2-4707-b8a8-c33f51323fef", queryItems["client_id"]);
Assert.Equal<string>("form_post", queryItems["response_mode"]);
Assert.Equal<string>("code id_token", queryItems["response_type"]);
Assert.Equal<string>("openid profile", queryItems["scope"]);
Assert.Equal<string>("OpenIdConnect.AuthenticationProperties=ValidStateData", queryItems["state"]);
//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", "OpenIdConnect"),
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 OpenIdConnect middleware
var token = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("code", "AAABAAAAvPM1KaPlrEqdFSBzjqfTGMQtbI_OHOamje5gJL8fAgpLsNlGHTJmFBHKtpy8zM9Ck__IcUuEd7oirpHPB6yhq2m6e-hjLiJv1AcHNR8V27s0bk7eHak9LqRtE68A9L4hSBTP4L4Uafz9FUwoO9uGfPLrLdNA26KYV6YzkJHQ6JmLQdMviK-hK7bKU2n8Tszjj4izVPXRfoTIzZvGqLERofoTQ011ede6vOD87UaJ8qbYvmsLh1QoaS2pCh3ZKiCHkEjsbgUTYpBPQLo3qjeEXr34DHYdlgK_ICYLoIBTtpFixETFp6jMYr3QideJbUC9vKrscQ2xbEZ4uX7v5NMuvESRRaNqrQfQ9kwPO1-x3trbZWHHdKYgzrAiYeD7vYo1YdDCc6hDTEhferKW9eS2ThYR5leeTIVmQYXvGyE1LfsO0cvsxubBIuSVKq3tVDatQScWQo34V1fdAoB9cG8aQwtjxKo9BG-UkTFiVhMuLORPSDSN3xtKjjbSgj2rABQBFbpjRzhc-aiDgAnHMDtvPfFkftFUujbi3WtifoNraVUZyKvubOrU7Y4I1GgZgzS8eF-YMpdZUDwItlqJjPA6OcdqXQbzsvg1bhOUNUrttGLSESeSUcxd_NDTX-mHGfFf9GXPT8VO83v-WmSbcYr0bw7zhnPsqxgczCcgvZFQnCYDHfrocPfQri9qhcZ_t5TRgRjOkICAcsKX_Dz1Pme8fCAA"),
new KeyValuePair<string, string>("id_token", "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImtyaU1QZG1Cdng2OHNrVDgtbVBBQjNCc2VlQSJ9.eyJhdWQiOiJjOTk0OTdhYS0zZWUyLTQ3MDctYjhhOC1jMzNmNTEzMjNmZWYiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC80YWZiYzY4OS04MDViLTQ4Y2YtYTI0Yy1kNGFhMzI0OGEyNDgvIiwiaWF0IjoxNDIyMzA0MDQ5LCJuYmYiOjE0MjIzMDQwNDksImV4cCI6MTQyMjMwNzk0OSwidmVyIjoiMS4wIiwidGlkIjoiNGFmYmM2ODktODA1Yi00OGNmLWEyNGMtZDRhYTMyNDhhMjQ4IiwiYW1yIjpbInB3ZCJdLCJvaWQiOiJmODc2YWJlYi1kNmI1LTQ0ZTQtOTcxNi02MjY2YWMwMTgxYTgiLCJ1cG4iOiJ1c2VyM0BwcmFidXJhamdtYWlsLm9ubWljcm9zb2Z0LmNvbSIsInN1YiI6IlBVZGhjbFA1UGdJalNVOVAxUy1IZWxEYVNGU2YtbVhWMVk2MC1LMnZXcXciLCJnaXZlbl9uYW1lIjoiVXNlcjMiLCJmYW1pbHlfbmFtZSI6IlVzZXIzIiwibmFtZSI6IlVzZXIzIiwidW5pcXVlX25hbWUiOiJ1c2VyM0BwcmFidXJhamdtYWlsLm9ubWljcm9zb2Z0LmNvbSIsIm5vbmNlIjoiNjM1NTc5MDExNDk4NzcwNDQ5Lk1HRTBPRE01TmpNdE16ZGhaQzAwTnpObUxXRmpPREl0TWpGaU1URTVaRGsxWm1Nek1USmhabVExWkRBdFptSmtPUzAwTnpRM0xUZzRZV1V0TWpZNVlqVmlOREppTXpNNSIsImNfaGFzaCI6Im9hX2oxckRJdEhqY2tlRHBQbTA4bHciLCJwd2RfZXhwIjoiNjc4NDk5NCIsInB3ZF91cmwiOiJodHRwczovL3BvcnRhbC5taWNyb3NvZnRvbmxpbmUuY29tL0NoYW5nZVBhc3N3b3JkLmFzcHgifQ.PDVbcUPw_MXE13PTOHl1WQwoV763Lu4p-hPyc-K-UumsNwAGtQy6R5IMqNPxv86BymMdwXZjQqZPaldrjSJf7bFr9sCS_wh8IKCls4uumsRF0lC93yey5Qo7_N4NWjLw1f2QNuGcaaIimDjaoeZyGnCx84grtL-3TuSEhyGV2lc0BoovRSz_LZR4H4VnGWjVzdIZhb84LJWLjYClocWLnNdkYZAXgx4tuwAa8DckZL4JiCo1Lngpy9-ELWy8vdZqIBBwIEeO-bg9TTxxknd7kjG7OO5IKfiuAAt5121udsx9DB4TeQp5taEzFfPbOq4H3z41jlK0KCNPDDFbXU36rQ"),
new KeyValuePair<string, string>("state", "OpenIdConnect.AuthenticationProperties=ValidStateData"),
new KeyValuePair<string, string>("session_state", "17d814f8-618c-47a2-af6a-43df8a62279a")
};
response = _httpClient.PostAsync(string.Empty, new FormUrlEncodedContent(token.ToArray())).Result;
ThrowIfResponseStatusNotOk(response);
responseContent = response.Content.ReadAsStringAsync().Result;
}
}
}

View File

@ -0,0 +1,105 @@
using System;
using System.Diagnostics;
using System.Net.Http;
using Microsoft.AspNet.Testing.xunit;
using Microsoft.Framework.Logging;
using Xunit;
namespace E2ETests
{
public partial class SmokeTests
{
[ConditionalTheory]
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
[InlineData(ServerType.IISExpress, DotnetFlavor.DesktopClr, DotnetArchitecture.x86, "http://localhost:5001/")]
public void OpenIdConnect_OnX86(ServerType serverType, DotnetFlavor dotnetFlavor, DotnetArchitecture architecture, string applicationBaseUrl)
{
OpenIdConnectTestSuite(serverType, dotnetFlavor, architecture, applicationBaseUrl);
}
[ConditionalTheory]
[FrameworkSkipCondition(RuntimeFrameworks.DotNet)]
// Fails due to https://github.com/aspnet/XRE/issues/1129.
[InlineData(ServerType.Kestrel, DotnetFlavor.Mono, DotnetArchitecture.x86, "http://localhost:5004/")]
public void OpenIdConnect_OnMono(ServerType serverType, DotnetFlavor dotnetFlavor, DotnetArchitecture architecture, string applicationBaseUrl)
{
OpenIdConnectTestSuite(serverType, dotnetFlavor, architecture, applicationBaseUrl);
}
private void OpenIdConnectTestSuite(ServerType serverType, DotnetFlavor donetFlavor, DotnetArchitecture architecture, string applicationBaseUrl)
{
using (_logger.BeginScope("OpenIdConnectTestSuite"))
{
_logger.WriteInformation("Variation Details : HostType = {0}, DonetFlavor = {1}, Architecture = {2}, applicationBaseUrl = {3}",
serverType, donetFlavor, architecture, applicationBaseUrl);
_startParameters = new StartParameters
{
ServerType = serverType,
DotnetFlavor = donetFlavor,
DotnetArchitecture = architecture,
EnvironmentName = "OpenIdConnectTesting"
};
var testStartTime = DateTime.Now;
var musicStoreDbName = Guid.NewGuid().ToString().Replace("-", string.Empty);
_logger.WriteInformation("Pointing MusicStore DB to '{0}'", string.Format(CONNECTION_STRING_FORMAT, musicStoreDbName));
//Override the connection strings using environment based configuration
Environment.SetEnvironmentVariable("SQLAZURECONNSTR_DefaultConnection", string.Format(CONNECTION_STRING_FORMAT, musicStoreDbName));
_applicationBaseUrl = applicationBaseUrl;
Process hostProcess = null;
bool testSuccessful = false;
try
{
hostProcess = DeploymentUtility.StartApplication(_startParameters, musicStoreDbName, _logger);
if (serverType == ServerType.IISNativeModule || serverType == ServerType.IIS)
{
// Accomodate the vdir name.
_applicationBaseUrl += _startParameters.IISApplication.VirtualDirectoryName + "/";
}
_httpClientHandler = new HttpClientHandler();
_httpClient = new HttpClient(_httpClientHandler) { BaseAddress = new Uri(_applicationBaseUrl) };
HttpResponseMessage response = null;
string responseContent = null;
var initializationCompleteTime = DateTime.MinValue;
//Request to base address and check if various parts of the body are rendered & measure the cold startup time.
Helpers.Retry(() =>
{
response = _httpClient.GetAsync(string.Empty).Result;
responseContent = response.Content.ReadAsStringAsync().Result;
initializationCompleteTime = DateTime.Now;
}, logger: _logger);
_logger.WriteInformation("[Time]: Approximate time taken for application initialization : '{0}' seconds",
(initializationCompleteTime - testStartTime).TotalSeconds);
VerifyHomePage(response, responseContent);
// OpenIdConnect login.
LoginWithOpenIdConnect();
var testCompletionTime = DateTime.Now;
_logger.WriteInformation("[Time]: All tests completed in '{0}' seconds", (testCompletionTime - initializationCompleteTime).TotalSeconds);
_logger.WriteInformation("[Time]: Total time taken for this test variation '{0}' seconds", (testCompletionTime - testStartTime).TotalSeconds);
testSuccessful = true;
}
finally
{
if (!testSuccessful)
{
_logger.WriteError("Some tests failed. Proceeding with cleanup.");
}
DeploymentUtility.CleanUpApplication(_startParameters, hostProcess, musicStoreDbName, _logger);
}
}
}
}
}

View File

@ -0,0 +1,31 @@
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace MusicStore.Mocks.OpenIdConnect
{
public class OpenIdConnectBackChannelHttpHandler : HttpMessageHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = new HttpResponseMessage();
var basePath = Path.GetFullPath(Path.Combine(
Directory.GetCurrentDirectory(), "..", "..",
"test", "E2ETests", "compiler", "shared", "Mocks",
"OpenIdConnect"));
if (request.RequestUri.AbsoluteUri == "https://login.windows.net/[tenantName].onmicrosoft.com/.well-known/openid-configuration")
{
response.Content = new StringContent(File.ReadAllText(Path.Combine(basePath, "openid-configuration.json")));
}
else if (request.RequestUri.AbsoluteUri == "https://login.windows.net/common/discovery/keys")
{
response.Content = new StringContent(File.ReadAllText(Path.Combine(basePath, "keys.json")));
}
return Task.FromResult(response);
}
}
}

View File

@ -0,0 +1,26 @@
{
"keys": [
{
"kty": "RSA",
"use": "sig",
"kid": "kriMPdmBvx68skT8-mPAB3BseeA",
"x5t": "kriMPdmBvx68skT8-mPAB3BseeA",
"n": "kSCWg6q9iYxvJE2NIhSyOiKvqoWCO2GFipgH0sTSAs5FalHQosk9ZNTztX0ywS/AHsBeQPqYygfYVJL6/EgzVuwRk5txr9e3n1uml94fLyq/AXbwo9yAduf4dCHTP8CWR1dnDR+Qnz/4PYlWVEuuHHONOw/blbfdMjhY+C/BYM2E3pRxbohBb3x//CfueV7ddz2LYiH3wjz0QS/7kjPiNCsXcNyKQEOTkbHFi3mu0u13SQwNddhcynd/GTgWN8A+6SN1r4hzpjFKFLbZnBt77ACSiYx+IHK4Mp+NaVEi5wQtSsjQtI++XsokxRDqYLwus1I1SihgbV/STTg5enufuw==",
"e": "AQAB",
"x5c": [
"MIIDPjCCAiqgAwIBAgIQsRiM0jheFZhKk49YD0SK1TAJBgUrDgMCHQUAMC0xKzApBgNVBAMTImFjY291bnRzLmFjY2Vzc2NvbnRyb2wud2luZG93cy5uZXQwHhcNMTQwMTAxMDcwMDAwWhcNMTYwMTAxMDcwMDAwWjAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkSCWg6q9iYxvJE2NIhSyOiKvqoWCO2GFipgH0sTSAs5FalHQosk9ZNTztX0ywS/AHsBeQPqYygfYVJL6/EgzVuwRk5txr9e3n1uml94fLyq/AXbwo9yAduf4dCHTP8CWR1dnDR+Qnz/4PYlWVEuuHHONOw/blbfdMjhY+C/BYM2E3pRxbohBb3x//CfueV7ddz2LYiH3wjz0QS/7kjPiNCsXcNyKQEOTkbHFi3mu0u13SQwNddhcynd/GTgWN8A+6SN1r4hzpjFKFLbZnBt77ACSiYx+IHK4Mp+NaVEi5wQtSsjQtI++XsokxRDqYLwus1I1SihgbV/STTg5enufuwIDAQABo2IwYDBeBgNVHQEEVzBVgBDLebM6bK3BjWGqIBrBNFeNoS8wLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldIIQsRiM0jheFZhKk49YD0SK1TAJBgUrDgMCHQUAA4IBAQCJ4JApryF77EKC4zF5bUaBLQHQ1PNtA1uMDbdNVGKCmSf8M65b8h0NwlIjGGGy/unK8P6jWFdm5IlZ0YPTOgzcRZguXDPj7ajyvlVEQ2K2ICvTYiRQqrOhEhZMSSZsTKXFVwNfW6ADDkN3bvVOVbtpty+nBY5UqnI7xbcoHLZ4wYD251uj5+lo13YLnsVrmQ16NCBYq2nQFNPuNJw6t3XUbwBHXpF46aLT1/eGf/7Xx6iy8yPJX4DyrpFTutDz882RWofGEO5t4Cw+zZg70dJ/hH/ODYRMorfXEW+8uKmXMKmX2wyxMKvfiPbTy5LmAU8Jvjs2tLg4rOBcXWLAIarZ"
]
},
{
"kty": "RSA",
"use": "sig",
"kid": "MnC_VZcATfM5pOYiJHMba9goEKY",
"x5t": "MnC_VZcATfM5pOYiJHMba9goEKY",
"n": "vIqz+4+ER/vNWLON9yv8hIYV737JQ6rCl6XfzOC628seYUPf0TaGk91CFxefhzh23V9Tkq+RtwN1Vs/z57hO82kkzL+cQHZX3bMJD+GEGOKXCEXURN7VMyZWMAuzQoW9vFb1k3cR1RW/EW/P+C8bb2dCGXhBYqPfHyimvz2WarXhntPSbM5XyS5v5yCw5T/Vuwqqsio3V8wooWGMpp61y12NhN8bNVDQAkDPNu2DT9DXB1g0CeFINp/KAS/qQ2Kq6TSvRHJqxRR68RezYtje9KAqwqx4jxlmVAQy0T3+T+IAbsk1wRtWDndhO6s1Os+dck5TzyZ/dNOhfXgelixLUQ==",
"e": "AQAB",
"x5c": [
"MIIC4jCCAcqgAwIBAgIQQNXrmzhLN4VGlUXDYCRT3zANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTE0MTAyODAwMDAwMFoXDTE2MTAyNzAwMDAwMFowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALyKs/uPhEf7zVizjfcr/ISGFe9+yUOqwpel38zgutvLHmFD39E2hpPdQhcXn4c4dt1fU5KvkbcDdVbP8+e4TvNpJMy/nEB2V92zCQ/hhBjilwhF1ETe1TMmVjALs0KFvbxW9ZN3EdUVvxFvz/gvG29nQhl4QWKj3x8opr89lmq14Z7T0mzOV8kub+cgsOU/1bsKqrIqN1fMKKFhjKaetctdjYTfGzVQ0AJAzzbtg0/Q1wdYNAnhSDafygEv6kNiquk0r0RyasUUevEXs2LY3vSgKsKseI8ZZlQEMtE9/k/iAG7JNcEbVg53YTurNTrPnXJOU88mf3TToX14HpYsS1ECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAfolx45w0i8CdAUjjeAaYdhG9+NDHxop0UvNOqlGqYJexqPLuvX8iyUaYxNGzZxFgGI3GpKfmQP2JQWQ1E5JtY/n8iNLOKRMwqkuxSCKJxZJq4Sl/m/Yv7TS1P5LNgAj8QLCypxsWrTAmq2HSpkeSk4JBtsYxX6uhbGM/K1sEktKybVTHu22/7TmRqWTmOUy9wQvMjJb2IXdMGLG3hVntN/WWcs5w8vbt1i8Kk6o19W2MjZ95JaECKjBDYRlhG1KmSBtrsKsCBQoBzwH/rXfksTO9JoUYLXiW0IppB7DhNH4PJ5hZI91R8rR0H3/bKkLSuDaKLWSqMhozdhXsIIKvJQ=="
]
}
]
}

View File

@ -0,0 +1,34 @@
{
"issuer": "https://sts.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/",
"authorization_endpoint": "https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/oauth2/authorize",
"token_endpoint": "https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/oauth2/token",
"token_endpoint_auth_methods_supported": [
"client_secret_post",
"private_key_jwt"
],
"jwks_uri": "https://login.windows.net/common/discovery/keys",
"response_types_supported": [
"code",
"id_token",
"code id_token",
"token"
],
"response_modes_supported": [
"query",
"fragment",
"form_post"
],
"subject_types_supported": [
"pairwise"
],
"scopes_supported": [
"openid"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"microsoft_multi_refresh_token": true,
"check_session_iframe": "https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/oauth2/checksession",
"end_session_endpoint": "https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/oauth2/logout",
"userinfo_endpoint": "https://login.windows.net/4afbc689-805b-48cf-a24c-d4aa3248a248/openid/userinfo"
}

View File

@ -3,13 +3,14 @@ using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Diagnostics;
using Microsoft.AspNet.Diagnostics.Entity;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Security;
using Microsoft.Framework.Cache.Memory;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;
using Microsoft.Framework.Logging.Console;
using MusicStore.Mocks.Common;
using MusicStore.Mocks.OpenIdConnect;
using MusicStore.Models;
namespace MusicStore
@ -105,8 +106,11 @@ namespace MusicStore
app.UseOpenIdConnectAuthentication(options =>
{
options.Authority = "https://login.windows.net/[tenantName].onmicrosoft.com";
options.ClientId = "[ClientId]";
options.BackchannelHttpHandler = null; // TODO: Yet to implement the handler.
options.ClientId = "c99497aa-3ee2-4707-b8a8-c33f51323fef";
options.BackchannelHttpHandler = new OpenIdConnectBackChannelHttpHandler();
options.StateDataFormat = new CustomStateDataFormat();
options.TokenValidationParameters.ValidateLifetime = false;
options.ProtocolValidator.RequireNonce = false;
});
// Add MVC to the request pipeline