Skip to content

Commit

Permalink
Merge pull request NancyFx#1106 from jugglingnutcase/adjust-default-d…
Browse files Browse the repository at this point in the history
…iagnostics

Switch off the default diagnostic provider
  • Loading branch information
grumpydev committed Jun 20, 2013
2 parents dac306b + 8488c08 commit 398b685
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/Nancy.Tests/Nancy.Tests.csproj
Expand Up @@ -140,6 +140,7 @@
<Compile Include="Unit\DefaultNancyBootstrapperFixture.cs" />
<Compile Include="Unit\DefaultResponseFormatterFactoryFixture.cs" />
<Compile Include="Unit\Diagnostics\ConcurrentLimitedCollectionFixture.cs" />
<Compile Include="Unit\Diagnostics\CustomInteractiveDiagnosticsFixture.cs" />
<Compile Include="Unit\Diagnostics\DiagnosticsHookFixture.cs" />
<Compile Include="Unit\ErrorHandling\DefaultStatusCodeHandlerFixture.cs" />
<Compile Include="Unit\Extensions\TypeExtensionsFixture.cs" />
Expand Down
@@ -0,0 +1,138 @@
namespace Nancy.Tests.Unit.Diagnostics
{
using System;
using System.Collections.Generic;
using System.Linq;

using Fakes;
using FakeItEasy;
using Nancy.Bootstrapper;
using Nancy.Cookies;
using Nancy.Cryptography;
using Nancy.Culture;
using Nancy.Diagnostics;
using Nancy.ModelBinding;
using Nancy.Responses.Negotiation;
using Nancy.Testing;
using Xunit;

public class CustomInteractiveDiagnosticsHookFixture
{
private const string DiagsCookieName = "__ncd";

private readonly CryptographyConfiguration cryptoConfig;

private readonly IObjectSerializer objectSerializer;

public CustomInteractiveDiagnosticsHookFixture()
{
this.cryptoConfig = CryptographyConfiguration.Default;
this.objectSerializer = new DefaultObjectSerializer();
}

private class FakeDiagnostics : IDiagnostics
{
private readonly DiagnosticsConfiguration diagnosticsConfiguration;
private readonly IEnumerable<IDiagnosticsProvider> diagnosticProviders;
private readonly IRootPathProvider rootPathProvider;
private readonly IEnumerable<ISerializer> serializers;
private readonly IRequestTracing requestTracing;
private readonly NancyInternalConfiguration configuration;
private readonly IModelBinderLocator modelBinderLocator;
private readonly IEnumerable<IResponseProcessor> responseProcessors;
private readonly ICultureService cultureService;

public FakeDiagnostics(DiagnosticsConfiguration diagnosticsConfiguration, IEnumerable<IDiagnosticsProvider> diagnosticProviders, IRootPathProvider rootPathProvider, IEnumerable<ISerializer> serializers, IRequestTracing requestTracing, NancyInternalConfiguration configuration, IModelBinderLocator modelBinderLocator, IEnumerable<IResponseProcessor> responseProcessors, ICultureService cultureService)
{
this.diagnosticsConfiguration = diagnosticsConfiguration;
this.diagnosticProviders = (new IDiagnosticsProvider[] { new FakeDiagnosticsProvider() }).ToArray();
this.rootPathProvider = rootPathProvider;
this.serializers = serializers;
this.requestTracing = requestTracing;
this.configuration = configuration;
this.modelBinderLocator = modelBinderLocator;
this.responseProcessors = responseProcessors;
this.cultureService = cultureService;
}

public void Initialize(IPipelines pipelines)
{
DiagnosticsHook.Enable(this.diagnosticsConfiguration, pipelines, this.diagnosticProviders, this.rootPathProvider, this.serializers, this.requestTracing, this.configuration, this.modelBinderLocator, this.responseProcessors, this.cultureService);
}
}

private class FakeDiagnosticsProvider : IDiagnosticsProvider
{
public string Name
{
get { return "Fake testing provider"; }
}

public string Description
{
get { return "Fake testing provider"; }
}

public object DiagnosticObject
{
get { return this; }
}
}

[Fact]
public void Should_return_main_page_with_valid_auth_cookie()
{
// Given
var diagsConfig = new DiagnosticsConfiguration { Password = "password", CryptographyConfiguration = this.cryptoConfig };

var bootstrapper = new ConfigurableBootstrapper(with =>
{
with.EnableAutoRegistration();
with.DiagnosticsConfiguration(diagsConfig);
with.Diagnostics<FakeDiagnostics>();
});

var browser = new Browser(bootstrapper);

// When
var result = browser.Get(diagsConfig.Path + "/interactive/providers/", with =>
{
with.Cookie(DiagsCookieName, this.GetSessionCookieValue("password"));
});

// Then should see our fake provider and not the default testing provider
result.Body.AsString().ShouldContain("Fake testing provider");
result.Body.AsString().ShouldNotContain("Testing Diagnostic Provider");
}

private string GetSessionCookieValue(string password, DateTime? expiry = null)
{
var salt = DiagnosticsSession.GenerateRandomSalt();
var hash = DiagnosticsSession.GenerateSaltedHash(password, salt);
var session = new DiagnosticsSession
{
Hash = hash,
Salt = salt,
Expiry = expiry.HasValue ? expiry.Value : DateTime.Now.AddMinutes(15),
};

var serializedSession = this.objectSerializer.Serialize(session);

var encryptedSession = this.cryptoConfig.EncryptionProvider.Encrypt(serializedSession);
var hmacBytes = this.cryptoConfig.HmacProvider.GenerateHmac(encryptedSession);
var hmacString = Convert.ToBase64String(hmacBytes);

return String.Format("{1}{0}", encryptedSession, hmacString);
}

private DiagnosticsSession DecodeCookie(INancyCookie nancyCookie)
{
var cookieValue = nancyCookie.Value;
var hmacStringLength = Base64Helpers.GetBase64Length(this.cryptoConfig.HmacProvider.HmacLength);
var encryptedSession = cookieValue.Substring(hmacStringLength);
var decrypted = this.cryptoConfig.EncryptionProvider.Decrypt(encryptedSession);

return this.objectSerializer.Deserialize(decrypted) as DiagnosticsSession;
}
}
}
31 changes: 29 additions & 2 deletions src/Nancy.Tests/Unit/Diagnostics/DiagnosticsHookFixture.cs
Expand Up @@ -29,7 +29,8 @@ public void Should_return_info_page_if_password_null()
// Given
var diagsConfig = new DiagnosticsConfiguration { Password = null, CryptographyConfiguration = this.cryptoConfig };

var bootstrapper = new ConfigurableBootstrapper(with =>{
var bootstrapper = new ConfigurableBootstrapper(with =>
{
with.EnableAutoRegistration();
with.DiagnosticsConfiguration(diagsConfig);
with.Diagnostics<DefaultDiagnostics>();
Expand Down Expand Up @@ -244,6 +245,32 @@ public void Should_use_rolling_expiry_for_auth_cookie()
.Expiry.ShouldNotEqual(expiryDate);
}

[Fact]
public void Should_return_diagnostic_example()
{
// Given no custom interactive diagnostic providers
var diagsConfig = new DiagnosticsConfiguration { Password = "password", CryptographyConfiguration = this.cryptoConfig };

var bootstrapper = new ConfigurableBootstrapper(with =>
{
with.EnableAutoRegistration();
with.DiagnosticsConfiguration(diagsConfig);
with.Diagnostics<DefaultDiagnostics>();
});

var browser = new Browser(bootstrapper);

// When querying the list of interactive providers
var result = browser.Get(diagsConfig.Path + "/interactive/providers/", with =>
{
with.Cookie(DiagsCookieName, this.GetSessionCookieValue("password"));
});

// Then we should see the fake testing provider and not the Nancy provided testing example
result.Body.AsString().ShouldNotContain("Fake testing provider");
result.Body.AsString().Contains("Testing Diagnostic Provider");
}

private string GetSessionCookieValue(string password, DateTime? expiry = null)
{
var salt = DiagnosticsSession.GenerateRandomSalt();
Expand All @@ -270,7 +297,7 @@ private DiagnosticsSession DecodeCookie(INancyCookie nancyCookie)
var hmacStringLength = Base64Helpers.GetBase64Length(this.cryptoConfig.HmacProvider.HmacLength);
var encryptedSession = cookieValue.Substring(hmacStringLength);
var decrypted = this.cryptoConfig.EncryptionProvider.Decrypt(encryptedSession);

return this.objectSerializer.Deserialize(decrypted) as DiagnosticsSession;
}
}
Expand Down
18 changes: 17 additions & 1 deletion src/Nancy/Diagnostics/InteractiveDiagnostics.cs
Expand Up @@ -15,7 +15,23 @@ public class InteractiveDiagnostics : IInteractiveDiagnostics

public InteractiveDiagnostics(IEnumerable<IDiagnosticsProvider> providers)
{
this.providers = providers.ToArray();
var customProvidersAvailable = providers.Any(provider =>
{
Type providerType = provider.GetType();
return providerType != typeof(Nancy.Diagnostics.TestingDiagnosticProvider) &
providerType != typeof(Nancy.Routing.DefaultRouteCacheProvider);
});

if (customProvidersAvailable)
{
// Exclude only the TestingDiagnosticProvider
this.providers = providers.Where(provider => provider.GetType() != typeof(Nancy.Diagnostics.TestingDiagnosticProvider)).ToArray();
}
else
{
this.providers = providers.ToArray();
}

this.BuildAvailableDiagnostics();
}
Expand Down

0 comments on commit 398b685

Please sign in to comment.