Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

400 lines
14 KiB
C#

// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Specialized;
using System.IO;
using System.Text;
using System.Web.Helpers;
using System.Web.Hosting;
using System.Web.Security;
using Moq;
using Xunit;
using Assert = Microsoft.TestCommon.AssertEx;
namespace System.Web.WebPages.Administration.Test
{
public class AdminPackageTest
{
[Fact]
public void GetAdminVirtualPathThrowsIfPathIsNull()
{
// Act & Assert
Assert.ThrowsArgumentNull(() => SiteAdmin.GetVirtualPath(null), "virtualPath");
}
[Fact]
public void GetAdminVirtualPathDoesNotAppendAdminVirtualPathIfPathStartsWithAdminVirtualPath()
{
// Act
string vpath = SiteAdmin.GetVirtualPath("~/_Admin/Foo");
// Assert
Assert.Equal("~/_Admin/Foo", vpath);
}
[Fact]
public void GetAdminVirtualPathAppendsAdminVirtualPath()
{
// Act
string vpath = SiteAdmin.GetVirtualPath("~/Foo");
// Assert
Assert.Equal("~/_Admin/Foo", vpath);
}
[Fact]
public void SetAuthCookieAddsAuthCookieToResponseCollection()
{
// Arrange
var mockResponse = new Mock<HttpResponseBase>();
var cookies = new HttpCookieCollection();
mockResponse.Setup(m => m.Cookies).Returns(cookies);
// Act
AdminSecurity.SetAuthCookie(mockResponse.Object);
// Assert
Assert.NotNull(cookies[".ASPXADMINAUTH"]);
}
[Fact]
public void GetAuthAdminCookieCreatesAnAuthTicketWithUserDataSetToAdmin()
{
// Arrange
var cookie = AdminSecurity.GetAuthCookie();
// Act
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
// Assert
Assert.Equal(".ASPXADMINAUTH", cookie.Name);
Assert.True(cookie.HttpOnly);
Assert.Equal(2, ticket.Version);
Assert.Equal("ADMIN", ticket.UserData);
}
[Fact]
public void IsAuthenticatedReturnsFalseIfAuthCookieNotInCollection()
{
// Arrange
var mockRequest = new Mock<HttpRequestBase>();
var cookies = new HttpCookieCollection();
mockRequest.Setup(m => m.Cookies).Returns(cookies);
// Act
bool authorized = AdminSecurity.IsAuthenticated(mockRequest.Object);
// Assert
Assert.False(authorized);
}
[Fact]
public void IsAuthenticatedReturnsFalseIfAuthCookieInCollectionAndIsNotAValidAdminAuthCookie()
{
// Arrange
var mockRequest = new Mock<HttpRequestBase>();
var cookies = new HttpCookieCollection();
mockRequest.Setup(m => m.Cookies).Returns(cookies);
cookies.Add(new HttpCookie(".ASPXADMINAUTH", "test"));
// Act
bool authorized = AdminSecurity.IsAuthenticated(mockRequest.Object);
// Assert
Assert.False(authorized);
}
[Fact]
public void IsAuthenticatedReturnsTrueIfAuthCookieIsValid()
{
// Arrange
var mockRequest = new Mock<HttpRequestBase>();
var cookies = new HttpCookieCollection();
mockRequest.Setup(m => m.Cookies).Returns(cookies);
cookies.Add(AdminSecurity.GetAuthCookie());
// Act
bool authorized = AdminSecurity.IsAuthenticated(mockRequest.Object);
// Assert
Assert.True(authorized);
}
[Fact]
public void GetRedirectUrlAppendsAppRelativePathAsReturnUrl()
{
// Arrange
var mockRequest = new Mock<HttpRequestBase>();
mockRequest.Setup(m => m.RawUrl).Returns("~/_Admin/foo/bar/baz");
mockRequest.Setup(m => m.QueryString).Returns(new NameValueCollection());
// Act
string redirectUrl = SiteAdmin.GetRedirectUrl(mockRequest.Object, "register", MakeAppRelative);
// Assert
Assert.Equal("~/_Admin/register?ReturnUrl=%7e%2f_Admin%2ffoo%2fbar%2fbaz", redirectUrl);
}
[Fact]
public void GetRedirectUrlDoesNotAppendsAppRelativePathAsReturnUrlIfAlreadyExists()
{
// Arrange
var mockRequest = new Mock<HttpRequestBase>();
mockRequest.Setup(m => m.RawUrl).Returns("~/_Admin/foo/bar/baz?ReturnUrl=~/foo");
var queryString = new NameValueCollection();
queryString["ReturnUrl"] = "~/foo";
mockRequest.Setup(m => m.QueryString).Returns(queryString);
// Act
string redirectUrl = SiteAdmin.GetRedirectUrl(mockRequest.Object, "register", MakeAppRelative);
// Assert
Assert.Equal("~/_Admin/register?ReturnUrl=%7e%2ffoo", redirectUrl);
}
[Fact]
public void GetReturnUrlReturnsNullIfNotSet()
{
// Arrange
var mockRequest = new Mock<HttpRequestBase>();
mockRequest.Setup(m => m.QueryString).Returns(new NameValueCollection());
// Act
string returlUrl = SiteAdmin.GetReturnUrl(mockRequest.Object);
// Assert
Assert.Null(returlUrl);
}
[Fact]
public void GetReturnUrlThrowsIfReturnUrlIsNotAppRelative()
{
// Arrange
var mockRequest = new Mock<HttpRequestBase>();
var queryString = new NameValueCollection();
queryString["ReturnUrl"] = "http://www.bing.com";
mockRequest.Setup(m => m.QueryString).Returns(queryString);
// Act & Assert
Assert.Throws<InvalidOperationException>(() => SiteAdmin.GetReturnUrl(mockRequest.Object), "The return URL specified for request redirection is invalid.");
}
[Fact]
public void GetReturnUrlReturnsReturlUrlQueryStringParameterIfItIsAppRelative()
{
// Arrange
var mockRequest = new Mock<HttpRequestBase>();
var queryString = new NameValueCollection();
queryString["ReturnUrl"] = "~/_Admin/bar?foo=1";
mockRequest.Setup(m => m.QueryString).Returns(queryString);
// Act
string returnUrl = SiteAdmin.GetReturnUrl(mockRequest.Object);
// Assert
Assert.Equal("~/_Admin/bar?foo=1", returnUrl);
}
[Fact]
public void SaveAdminPasswordUsesCryptoToWritePasswordAndSalt()
{
// Arrange
var password = "some-random-password";
MemoryStream ms = new MemoryStream();
// Act
bool passwordSaved = AdminSecurity.SaveTemporaryPassword(password, () => ms);
// Assert
Assert.True(passwordSaved);
string savedPassword = Encoding.Default.GetString(ms.ToArray());
// Trim everything after the new line. Cannot use the properties from the stream since it is already closed by the writer.
savedPassword = savedPassword.Substring(0, savedPassword.IndexOf(Environment.NewLine));
Assert.True(Crypto.VerifyHashedPassword(savedPassword, password));
}
[Fact]
public void SaveAdminPasswordReturnsFalseIfGettingStreamThrowsUnauthorizedAccessException()
{
// Act
bool passwordSaved = AdminSecurity.SaveTemporaryPassword("password", () => { throw new UnauthorizedAccessException(); });
// Assert
Assert.False(passwordSaved);
}
[Fact]
public void CheckPasswordReturnsTrueIfPasswordIsValid()
{
// Arrange
var ms = new MemoryStream();
var writer = new StreamWriter(ms);
writer.WriteLine(Crypto.HashPassword("password"));
writer.Flush();
ms.Seek(0, SeekOrigin.Begin);
// Act
bool passwordIsValid = AdminSecurity.CheckPassword("password", () => ms);
// Assert
Assert.True(passwordIsValid);
writer.Close();
}
[Fact]
public void HasAdminPasswordReturnsTrueIfAdminPasswordFileExists()
{
// Arrange
Mock<VirtualPathProvider> mockVpp = new Mock<VirtualPathProvider>();
mockVpp.Setup(m => m.FileExists("~/App_Data/Admin/Password.config")).Returns(true);
// Act
bool hasPassword = AdminSecurity.HasAdminPassword(mockVpp.Object);
// Assert
Assert.True(hasPassword);
}
[Fact]
public void HasAdminPasswordReturnsFalseIfAdminPasswordFileDoesNotExists()
{
// Arrange
Mock<VirtualPathProvider> mockVpp = new Mock<VirtualPathProvider>();
mockVpp.Setup(m => m.FileExists("~/App_Data/Admin/Password.config")).Returns(false);
// Act
bool hasPassword = AdminSecurity.HasAdminPassword(mockVpp.Object);
// Assert
Assert.False(hasPassword);
}
[Fact]
public void HasTemporaryPasswordReturnsTrueIfAdminPasswordFileExists()
{
// Arrange
Mock<VirtualPathProvider> mockVpp = new Mock<VirtualPathProvider>();
mockVpp.Setup(m => m.FileExists("~/App_Data/Admin/_Password.config")).Returns(true);
// Act
bool hasPassword = AdminSecurity.HasTemporaryPassword(mockVpp.Object);
// Assert
Assert.True(hasPassword);
}
[Fact]
public void HasTemporaryPasswordReturnsFalseIfAdminPasswordFileDoesNotExists()
{
// Arrange
Mock<VirtualPathProvider> mockVpp = new Mock<VirtualPathProvider>();
mockVpp.Setup(m => m.FileExists("~/App_Data/Admin/_Password.config")).Returns(false);
// Act
bool hasPassword = AdminSecurity.HasTemporaryPassword(mockVpp.Object);
// Assert
Assert.False(hasPassword);
}
[Fact]
public void NoPasswordOrTemporaryPasswordRedirectsToRegisterPage()
{
AssertSecure(requestUrl: "~/",
passwordExists: false,
temporaryPasswordExists: false,
expectedUrl: "~/_Admin/Register.cshtml?ReturnUrl=%7e%2f");
}
[Fact]
public void IfPasswordExistsRedirectsToLoginPage()
{
AssertSecure(requestUrl: "~/",
passwordExists: true,
temporaryPasswordExists: false,
expectedUrl: "~/_Admin/Login.cshtml?ReturnUrl=%7e%2f");
}
[Fact]
public void IfPasswordExistsRedirectsToLoginPageEvenIfTemporaryPasswordFileExists()
{
AssertSecure(requestUrl: "~/",
passwordExists: true,
temporaryPasswordExists: true,
expectedUrl: "~/_Admin/Login.cshtml?ReturnUrl=%7e%2f");
}
[Fact]
public void IfTemporaryPasswordExistsRedirectsToInstructionsPage()
{
AssertSecure(requestUrl: "~/",
passwordExists: false,
temporaryPasswordExists: true,
expectedUrl: "~/_Admin/EnableInstructions.cshtml?ReturnUrl=%7e%2f");
}
[Fact]
public void NoRedirectIfAlreadyGoingToRedirectPage()
{
AssertSecure(requestUrl: "~/_Admin/Register.cshtml",
passwordExists: false,
temporaryPasswordExists: false,
expectedUrl: null);
AssertSecure(requestUrl: "~/_Admin/Login.cshtml",
passwordExists: true,
temporaryPasswordExists: false,
expectedUrl: null);
AssertSecure(requestUrl: "~/_Admin/EnableInstructions.cshtml",
passwordExists: false,
temporaryPasswordExists: true,
expectedUrl: null);
}
private static void AssertSecure(string requestUrl, bool passwordExists, bool temporaryPasswordExists, string expectedUrl)
{
// Arrange
var vpp = new Mock<VirtualPathProvider>();
if (temporaryPasswordExists)
{
vpp.Setup(m => m.FileExists("~/App_Data/Admin/_Password.config")).Returns(true);
}
if (passwordExists)
{
vpp.Setup(m => m.FileExists("~/App_Data/Admin/Password.config")).Returns(true);
}
string redirectUrl = null;
var response = new Mock<HttpResponseBase>();
response.Setup(m => m.Redirect(It.IsAny<string>())).Callback<string>(url => redirectUrl = url);
var request = new Mock<HttpRequestBase>();
request.Setup(m => m.QueryString).Returns(new NameValueCollection());
request.Setup(m => m.RawUrl).Returns(requestUrl);
var cookies = new HttpCookieCollection();
request.Setup(m => m.Cookies).Returns(cookies);
var context = new Mock<HttpContextBase>();
context.Setup(m => m.Request).Returns(request.Object);
context.Setup(m => m.Response).Returns(response.Object);
var startPage = new Mock<StartPage>() { CallBase = true };
var page = new Mock<WebPageRenderingBase>();
page.Setup(m => m.VirtualPath).Returns(requestUrl);
startPage.Object.ChildPage = page.Object;
page.Setup(m => m.Context).Returns(context.Object);
// Act
AdminSecurity.Authorize(startPage.Object, vpp.Object, MakeAppRelative);
// Assert
Assert.Equal(expectedUrl, redirectUrl);
}
private static string MakeAppRelative(string path)
{
return path;
}
}
}