Skip to content
This repository has been archived by the owner on Jan 24, 2021. It is now read-only.

Add CookieBasedSessionsConfiguration #1409

Merged
merged 4 commits into from Mar 16, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Nancy.Tests/Nancy.Tests.csproj
Expand Up @@ -218,6 +218,7 @@
<Compile Include="Unit\Security\DefaultCsrfTokenValidatorFixture.cs" />
<Compile Include="Unit\Security\ModuleSecurityFixture.cs" />
<Compile Include="Unit\Security\UserIdentityExtensionsFixture.cs" />
<Compile Include="Unit\Sessions\CookieBasedSessionsConfigurationFixture.cs" />
<Compile Include="Unit\Sessions\CookieBasedSessionsFixture.cs" />
<Compile Include="Unit\Cryptography\RijndaelEncryptionProviderFixture.cs" />
<Compile Include="Unit\Sessions\DefaultSessionObjectFormatterFixture.cs" />
Expand Down
@@ -0,0 +1,85 @@
namespace Nancy.Testing.Tests
{
using FakeItEasy;

using Nancy.Cryptography;
using Nancy.Session;
using Nancy.Tests;
using Xunit;

public class CookieBasesSessionsConfigurationFixture
{
private readonly CookieBasedSessionsConfiguration config;

public CookieBasesSessionsConfigurationFixture()
{
var cryptographyConfiguration = new CryptographyConfiguration(
new RijndaelEncryptionProvider(new PassphraseKeyGenerator("SuperSecretPass", new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 })),
new DefaultHmacProvider(new PassphraseKeyGenerator("UberSuperSecure", new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 })));

this.config = new CookieBasedSessionsConfiguration()
{
CryptographyConfiguration = cryptographyConfiguration,
Serializer = A.Fake<IObjectSerializer>()
};
}

[Fact]
public void Should_be_valid_with_all_properties_set()
{
var result = this.config.IsValid;

result.ShouldBeTrue();
}

[Fact]
public void Should_not_be_valid_with_empty_cookiename()
{
this.config.CookieName = "";

var result = this.config.IsValid;

result.ShouldBeFalse();
}

[Fact]
public void Should_not_be_valid_with_null_serializer()
{
this.config.Serializer = null;

var result = this.config.IsValid;

result.ShouldBeFalse();
}

[Fact]
public void Should_not_be_valid_with_null_cryptography_configuration()
{
this.config.CryptographyConfiguration = null;

var result = this.config.IsValid;

result.ShouldBeFalse();
}

[Fact]
public void Should_not_be_valid_with_null_encryption_provider()
{
this.config.CryptographyConfiguration = new CryptographyConfiguration(null, this.config.CryptographyConfiguration.HmacProvider);

var result = this.config.IsValid;

result.ShouldBeFalse();
}

[Fact]
public void Should_not_be_valid_with_null_hmac_provider()
{
this.config.CryptographyConfiguration = new CryptographyConfiguration(this.config.CryptographyConfiguration.EncryptionProvider, null);

var result = this.config.IsValid;

result.ShouldBeFalse();
}
}
}
114 changes: 98 additions & 16 deletions src/Nancy.Tests/Unit/Sessions/CookieBasedSessionsFixture.cs
Expand Up @@ -26,19 +26,24 @@ public class CookieBasedSessionsFixture
private readonly IEncryptionProvider fakeEncryptionProvider;
private readonly CookieBasedSessions cookieStore;
private readonly IHmacProvider fakeHmacProvider;
private readonly IObjectSerializer fakeObjectSerializer;

private RijndaelEncryptionProvider rijndaelEncryptionProvider;

private DefaultHmacProvider defaultHmacProvider;

private IObjectSerializer defaultObjectSerializer;

public CookieBasedSessionsFixture()
{
this.fakeEncryptionProvider = A.Fake<IEncryptionProvider>();
this.fakeHmacProvider = A.Fake<IHmacProvider>();
this.cookieStore = new CookieBasedSessions(this.fakeEncryptionProvider, this.fakeHmacProvider, new Fakes.FakeObjectSerializer());
this.fakeObjectSerializer = new Fakes.FakeObjectSerializer();
this.cookieStore = new CookieBasedSessions(this.fakeEncryptionProvider, this.fakeHmacProvider, this.fakeObjectSerializer);

this.rijndaelEncryptionProvider = new RijndaelEncryptionProvider(new PassphraseKeyGenerator("password", new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }, 1000));
this.defaultHmacProvider = new DefaultHmacProvider(new PassphraseKeyGenerator("anotherpassword", new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }, 1000));
this.defaultObjectSerializer = new DefaultObjectSerializer();
}

[Fact]
Expand Down Expand Up @@ -76,7 +81,7 @@ public void Should_save_the_session_cookie()

response.Cookies.Count.ShouldEqual(1);
var cookie = response.Cookies.First();
cookie.Name.ShouldEqual(CookieBasedSessions.GetCookieName());
cookie.Name.ShouldEqual(this.cookieStore.CookieName);
cookie.Value.ShouldEqual("encrypted=key1=val1;key2=val2;");
cookie.Expires.ShouldBeNull();
cookie.Path.ShouldBeNull();
Expand Down Expand Up @@ -179,7 +184,7 @@ public void Should_only_not_add_response_cookie_if_it_has_not_changed()
var hooks = A.Fake<IPipelines>();
A.CallTo(() => hooks.BeforeRequest).Returns(beforePipeline);
A.CallTo(() => hooks.AfterRequest).Returns(afterPipeline);
CookieBasedSessions.Enable(hooks, new CryptographyConfiguration(this.fakeEncryptionProvider, this.fakeHmacProvider)).WithSerializer(new Fakes.FakeObjectSerializer());
CookieBasedSessions.Enable(hooks, new CryptographyConfiguration(this.fakeEncryptionProvider, this.fakeHmacProvider)).WithSerializer(this.fakeObjectSerializer);
var request = CreateRequest("encryptedkey1=value1");
A.CallTo(() => this.fakeEncryptionProvider.Decrypt("encryptedkey1=value1")).Returns("key1=value1;");
var response = A.Fake<Response>();
Expand All @@ -199,7 +204,7 @@ public void Should_add_response_cookie_if_it_has_changed()
var hooks = A.Fake<IPipelines>();
A.CallTo(() => hooks.BeforeRequest).Returns(beforePipeline);
A.CallTo(() => hooks.AfterRequest).Returns(afterPipeline);
CookieBasedSessions.Enable(hooks, new CryptographyConfiguration(this.fakeEncryptionProvider, this.fakeHmacProvider)).WithSerializer(new Fakes.FakeObjectSerializer());
CookieBasedSessions.Enable(hooks, new CryptographyConfiguration(this.fakeEncryptionProvider, this.fakeHmacProvider)).WithSerializer(this.fakeObjectSerializer);
var request = CreateRequest("encryptedkey1=value1");
A.CallTo(() => this.fakeEncryptionProvider.Decrypt("encryptedkey1=value1")).Returns("key1=value1;");
var response = A.Fake<Response>();
Expand Down Expand Up @@ -264,14 +269,14 @@ public void Should_be_able_to_save_a_complex_object_to_session()
var response = new Response();
var session = new Session(new Dictionary<string, object>());
var payload = new DefaultSessionObjectFormatterFixture.Payload(27, true, "Test string");
var store = new CookieBasedSessions(this.rijndaelEncryptionProvider, this.defaultHmacProvider, new DefaultObjectSerializer());
var store = new CookieBasedSessions(this.rijndaelEncryptionProvider, this.defaultHmacProvider, this.defaultObjectSerializer);
session["testObject"] = payload;

store.Save(session, response);

response.Cookies.Count.ShouldEqual(1);
var cookie = response.Cookies.First();
cookie.Name.ShouldEqual(CookieBasedSessions.GetCookieName());
cookie.Name.ShouldEqual(store.CookieName);
cookie.Value.ShouldNotBeNull();
cookie.Value.ShouldNotBeEmpty();
}
Expand All @@ -282,7 +287,7 @@ public void Should_be_able_to_load_an_object_previously_saved_to_session()
var response = new Response();
var session = new Session(new Dictionary<string, object>());
var payload = new DefaultSessionObjectFormatterFixture.Payload(27, true, "Test string");
var store = new CookieBasedSessions(this.rijndaelEncryptionProvider, this.defaultHmacProvider, new DefaultObjectSerializer());
var store = new CookieBasedSessions(this.rijndaelEncryptionProvider, this.defaultHmacProvider, this.defaultObjectSerializer);
session["testObject"] = payload;
store.Save(session, response);
var request = new Request("GET", "/", "http");
Expand Down Expand Up @@ -330,9 +335,9 @@ public void Should_load_valid_test_data()
{
var inputValue = ValidHmac + ValidData;
inputValue = HttpUtility.UrlEncode(inputValue);
var store = new CookieBasedSessions(this.rijndaelEncryptionProvider, this.defaultHmacProvider, new DefaultObjectSerializer());
var store = new CookieBasedSessions(this.rijndaelEncryptionProvider, this.defaultHmacProvider, this.defaultObjectSerializer);
var request = new Request("GET", "/", "http");
request.Cookies.Add(CookieBasedSessions.GetCookieName(), inputValue);
request.Cookies.Add(store.CookieName, inputValue);

var result = store.Load(request);

Expand All @@ -345,9 +350,9 @@ public void Should_return_blank_session_if_hmac_changed()
{
var inputValue = "b" + ValidHmac.Substring(1) + ValidData;
inputValue = HttpUtility.UrlEncode(inputValue);
var store = new CookieBasedSessions(this.rijndaelEncryptionProvider, this.defaultHmacProvider, new DefaultObjectSerializer());
var store = new CookieBasedSessions(this.rijndaelEncryptionProvider, this.defaultHmacProvider, this.defaultObjectSerializer);
var request = new Request("GET", "/", "http");
request.Cookies.Add(CookieBasedSessions.GetCookieName(), inputValue);
request.Cookies.Add(store.CookieName, inputValue);

var result = store.Load(request);

Expand All @@ -359,9 +364,9 @@ public void Should_return_blank_session_if_hmac_missing()
{
var inputValue = ValidData;
inputValue = HttpUtility.UrlEncode(inputValue);
var store = new CookieBasedSessions(this.rijndaelEncryptionProvider, this.defaultHmacProvider, new DefaultObjectSerializer());
var store = new CookieBasedSessions(this.rijndaelEncryptionProvider, this.defaultHmacProvider, this.defaultObjectSerializer);
var request = new Request("GET", "/", "http");
request.Cookies.Add(CookieBasedSessions.GetCookieName(), inputValue);
request.Cookies.Add(store.CookieName, inputValue);

var result = store.Load(request);

Expand All @@ -373,22 +378,99 @@ public void Should_return_blank_session_if_encrypted_data_modified()
{
var inputValue = ValidHmac + ValidData.Substring(0, ValidData.Length - 1) + "Z";
inputValue = HttpUtility.UrlEncode(inputValue);
var store = new CookieBasedSessions(this.rijndaelEncryptionProvider, this.defaultHmacProvider, new DefaultObjectSerializer());
var store = new CookieBasedSessions(this.rijndaelEncryptionProvider, this.defaultHmacProvider, this.defaultObjectSerializer);
var request = new Request("GET", "/", "http");
request.Cookies.Add(CookieBasedSessions.GetCookieName(), inputValue);
request.Cookies.Add(store.CookieName, inputValue);

var result = store.Load(request);

result.Count.ShouldEqual(0);
}

[Fact]
public void Should_use_CookieName_when_config_provides_cookiename_value()
{
//Given
var cryptoConfig = new CryptographyConfiguration(this.fakeEncryptionProvider, this.fakeHmacProvider);
var storeConfig = new CookieBasedSessionsConfiguration(cryptoConfig)
{
CookieName = "NamedCookie",
Serializer = this.fakeObjectSerializer
};
var store = new CookieBasedSessions(storeConfig);

//When
var response = new Response();
var session = new Session(new Dictionary<string, object>
{
{"key1", "val1"},
});
session["key2"] = "val2";
store.Save(session, response);

//Then
response.Cookies.ShouldHave(c => c.Name == storeConfig.CookieName);
}

[Fact]
public void Should_set_Domain_when_config_provides_domain_value()
{
//Given
var cryptoConfig = new CryptographyConfiguration(this.fakeEncryptionProvider, this.fakeHmacProvider);
var storeConfig = new CookieBasedSessionsConfiguration(cryptoConfig)
{
Domain = ".nancyfx.org",
Serializer = this.fakeObjectSerializer
};
var store = new CookieBasedSessions(storeConfig);

//When
var response = new Response();
var session = new Session(new Dictionary<string, object>
{
{"key1", "val1"},
});
session["key2"] = "val2";
store.Save(session, response);

//Then
var cookie = response.Cookies.First(c => c.Name == storeConfig.CookieName);
cookie.Domain.ShouldEqual(storeConfig.Domain);
}

[Fact]
public void Should_set_Path_when_config_provides_path_value()
{
//Given
var cryptoConfig = new CryptographyConfiguration(this.fakeEncryptionProvider, this.fakeHmacProvider);
var storeConfig = new CookieBasedSessionsConfiguration(cryptoConfig)
{
Path = "/",
Serializer = this.fakeObjectSerializer
};
var store = new CookieBasedSessions(storeConfig);

//When
var response = new Response();
var session = new Session(new Dictionary<string, object>
{
{"key1", "val1"},
});
session["key2"] = "val2";
store.Save(session, response);

//Then
var cookie = response.Cookies.First(c => c.Name == storeConfig.CookieName);
cookie.Path.ShouldEqual(storeConfig.Path);
}

private Request CreateRequest(string sessionValue, bool load = true)
{
var headers = new Dictionary<string, IEnumerable<string>>(1);

if (!string.IsNullOrEmpty(sessionValue))
{
headers.Add("cookie", new[] { CookieBasedSessions.GetCookieName()+ "=" + HttpUtility.UrlEncode(sessionValue) });
headers.Add("cookie", new[] { this.cookieStore.CookieName+ "=" + HttpUtility.UrlEncode(sessionValue) });
}

var request = new Request("GET", new Url { Path = "/", Scheme = "http", Port = 9001, BasePath = "goku.power" }, CreateRequestStream(), headers);
Expand Down
1 change: 1 addition & 0 deletions src/Nancy/Nancy.csproj
Expand Up @@ -260,6 +260,7 @@
<Compile Include="Routing\Trie\RouteResolverTrie.cs" />
<Compile Include="Routing\Trie\SegmentMatch.cs" />
<Compile Include="Routing\Trie\TrieNodeFactory.cs" />
<Compile Include="Session\CookieBasedSessionsConfiguration.cs" />
<Compile Include="StaticContent.cs" />
<Compile Include="Conventions\ViewLocationConventions.cs" />
<Compile Include="Cryptography\Base64Helpers.cs" />
Expand Down