Skip to content
Browse files

work on providing a generic authentication process for OpenRasta

Basic authentication is supported
Removed the old Digest authentication but code still there as having issues with building subprojects
  • Loading branch information...
1 parent 418d388 commit 25ee8bfbf610cea17626a9e7dfede565f662d7bb @scottlittlewood committed Sep 8, 2010
Showing with 929 additions and 70 deletions.
  1. +0 −3 src/core/OpenRasta.Tests.Integration/Binding/CustomSurrogates.cs
  2. +3 −1 src/core/OpenRasta.Tests.Integration/OpenRasta.Tests.Integration.csproj
  3. +111 −0 src/core/OpenRasta.Tests.Unit/Authentication/Basic/BasicAuthenticationScheme_Specification.cs
  4. +16 −14 src/core/OpenRasta.Tests.Unit/OpenRasta.Tests.Unit.csproj
  5. +109 −0 src/core/OpenRasta.Tests.Unit/Pipeline/Contributors/AuthenticationChallenger_Specification.cs
  6. +160 −0 src/core/OpenRasta.Tests.Unit/Pipeline/Contributors/Authentication_Specification.cs
  7. 0 .../OpenRasta.Tests.Unit/{Web → }/Pipeline/Contributors/HandlerMethodFiltersInvoker_Specification.cs
  8. 0 src/core/OpenRasta.Tests.Unit/{Web → }/Pipeline/Contributors/HandlerMethodInvoker_Specification.cs
  9. 0 ...sta.Tests.Unit/{Web → }/Pipeline/Contributors/HandlerMethodrequestEntityResolver_Specification.cs
  10. 0 src/core/OpenRasta.Tests.Unit/{Web → }/Pipeline/Contributors/HandlerResolver_Specification.cs
  11. 0 src/core/OpenRasta.Tests.Unit/{Web → }/Pipeline/Contributors/HttpMethodOverrider_Specification.cs
  12. 0 .../OpenRasta.Tests.Unit/{Web → }/Pipeline/Contributors/InvalidRequestEntityRemover_Specification.cs
  13. 0 ...OpenRasta.Tests.Unit/{Web → }/Pipeline/Contributors/OperationCreationContributor_Specification.cs
  14. 0 src/core/OpenRasta.Tests.Unit/{Web → }/Pipeline/Contributors/OperationProcessors_Specification.cs
  15. 0 src/core/OpenRasta.Tests.Unit/{Web → }/Pipeline/Contributors/RequestEntityReader_Specification.cs
  16. 0 src/core/OpenRasta.Tests.Unit/{Web → }/Pipeline/Contributors/ResourceTypeResolver_Specification.cs
  17. 0 .../OpenRasta.Tests.Unit/{Web → }/Pipeline/Contributors/ResponseEntityCodecResolver_Specification.cs
  18. 0 src/core/OpenRasta.Tests.Unit/{Web → }/Pipeline/Contributors/ResponseEntityWriter_Specification.cs
  19. 0 ...core/OpenRasta.Tests.Unit/{Web → }/Pipeline/Contributors/UriDecoratorsController_Specification.cs
  20. 0 src/core/OpenRasta.Tests.Unit/{Web → }/Pipeline/DigestCredentialsReader_Specification.cs
  21. 0 src/core/OpenRasta.Tests.Unit/{Web → }/Pipeline/PipelineRunner_Specification.cs
  22. +6 −24 src/core/OpenRasta.Tests.Unit/openrasta_context.cs
  23. +26 −0 src/core/OpenRasta/Authentication/AuthenticationResult.cs
  24. +18 −0 src/core/OpenRasta/Authentication/Basic/BasicAuthRequestHeader.cs
  25. +55 −0 src/core/OpenRasta/Authentication/Basic/BasicAuthenticationScheme.cs
  26. +8 −0 src/core/OpenRasta/Authentication/Basic/IBasicAuthenticator.cs
  27. +156 −0 src/core/OpenRasta/Authentication/Digest/DigestAuthRequestHeader.cs
  28. +34 −0 src/core/OpenRasta/Authentication/Digest/DigestAuthenticationScheme.cs
  29. +8 −0 src/core/OpenRasta/Authentication/Digest/IDigestAuthenticator.cs
  30. +13 −0 src/core/OpenRasta/Authentication/IAuthenticationScheme.cs
  31. +2 −1 src/core/OpenRasta/Configuration/DefaultDependencyRegistrar.cs
  32. +22 −5 src/core/OpenRasta/OpenRasta.csproj
  33. +41 −0 src/core/OpenRasta/Pipeline/Contributors/AuthenticationChallengerContributor.cs
  34. +91 −0 src/core/OpenRasta/Pipeline/Contributors/AuthenticationContributor.cs
  35. +5 −0 src/core/OpenRasta/Pipeline/KnownStages.cs
  36. +0 −21 src/core/OpenRasta/Security/RequiresAuthenticationAttribute.cs
  37. +27 −0 src/core/OpenRasta/Security/RequiresAuthenticationInterceptor.cs
  38. +17 −0 src/core/OpenRasta/StringExtensions.cs
  39. +1 −1 src/openbastard/OpenBastard/OpenBastard.csproj
View
3 src/core/OpenRasta.Tests.Integration/Binding/CustomSurrogates.cs
@@ -1,7 +1,6 @@
using System;
using System.Net;
using System.Text;
-using DigestAuthentication_Specification;
using NUnit.Framework;
using OpenRasta.Configuration;
using OpenRasta.Configuration.Fluent;
@@ -47,8 +46,6 @@ public surrogates_context()
{
ConfigureServer(() =>
{
- DependencyManager.GetService<IDependencyResolver>()
- .AddDependency<IAuthenticationProvider, FakeAuthProvider>();
ResourceSpace.Has.ResourcesOfType<Customer>()
.AtUri("/customer/{id}")
View
4 src/core/OpenRasta.Tests.Integration/OpenRasta.Tests.Integration.csproj
@@ -73,7 +73,6 @@
<Compile Include="Regressions\78.cs" />
<Compile Include="Regressions\96.cs" />
<Compile Include="Regressions\135.cs" />
- <Compile Include="Security\DigestAuthentication_Specification.cs" />
<Compile Include="server_context.cs" />
<Compile Include="Stubs\Customer.cs" />
<Compile Include="Stubs\CustomerHandler.cs" />
@@ -99,6 +98,9 @@
<Name>OpenRasta.Testing</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <Folder Include="Security\" />
+ </ItemGroup>
<Import Project="..\..\..\build\defaults.targets" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
View
111 ...core/OpenRasta.Tests.Unit/Authentication/Basic/BasicAuthenticationScheme_Specification.cs
@@ -0,0 +1,111 @@
+using Moq;
+using NUnit.Framework;
+using OpenRasta.Authentication;
+using OpenRasta.Authentication.Basic;
+using OpenRasta.Hosting.InMemory;
+using OpenRasta.Testing;
+
+namespace BasicAuthenticationScheme_Specification
+{
+ [TestFixture]
+ public class BasicAuthenticationScheme_Specification
+ {
+ Mock<IBasicAuthenticator> _mockAuthenticator;
+ InMemoryRequest _request;
+ BasicAuthenticationScheme _basicScheme;
+
+ [SetUp]
+ public void BeforeEachTest()
+ {
+ _mockAuthenticator = new Mock<IBasicAuthenticator>();
+ _request = new InMemoryRequest();
+ _basicScheme = new BasicAuthenticationScheme(_mockAuthenticator.Object);
+ }
+
+ [TearDown]
+ public void AfterEachTest()
+ {
+ _mockAuthenticator.VerifyAll();
+ }
+
+ [Test]
+ public void Given_AValidBasicAuthHeader_When_TheRequestIsAuthenticated_Then_TheResult_IsSuccess_And_UsernameIsSet_And_RolesAreSet()
+ {
+ // given
+ string validAuthString = "Basic U2F1c2FnZTphbmQgbWFzaA==";
+ string username = "Sausage";
+ string password = "and mash";
+
+ string[] userRoles = new[] { "Admin", "Manager", "Developer" };
+
+ _request.Headers["Authorization"] = validAuthString;
+
+ _mockAuthenticator
+ .Expect(auth => auth.Authenticate(It.Is<BasicAuthRequestHeader>(h => h.Username == username && h.Password == password)))
+ .Returns(new AuthenticationResult.Success(username, userRoles));
+
+ // when
+ var result = _basicScheme.Authenticate(_request);
+
+ // then
+ result.ShouldBeOfType<AuthenticationResult.Success>();
+ var success = result as AuthenticationResult.Success;
+
+ success.Username.ShouldBe(username);
+ success.Roles.ShouldHaveSameElementsAs(userRoles);
+ }
+
+ [Test]
+ public void Given_AMalformedBasicAuthHeader_When_TheRequestIsAuthenticated_Then_TheResult_IsMalformed()
+ {
+ // given
+ string malformedAuthString = "Basic notAValidBase64String!!!";
+ _request.Headers["Authorization"] = malformedAuthString;
+
+ // when
+ var result = _basicScheme.Authenticate(_request);
+
+ // then
+ result.ShouldBeOfType<AuthenticationResult.MalformedCredentials>();
+ }
+
+ [Test]
+ public void Given_ABasicAuthenticatorReturnsFailed_When_TheRequestIsAuthenticated_Then_TheResult_IsFailed()
+ {
+ // given
+ string authString = "Basic U2F1c2FnZTphbmQgbWFzaA==";
+ string username = "Sausage";
+ string password = "and mash";
+ _request.Headers["Authorization"] = authString;
+
+ _mockAuthenticator
+ .Expect(auth => auth.Authenticate(It.Is<BasicAuthRequestHeader>(h => h.Username == username && h.Password == password)))
+ .Returns(new AuthenticationResult.Failed());
+
+ // when
+ var result = _basicScheme.Authenticate(_request);
+
+ // then
+ result.ShouldBeOfType<AuthenticationResult.Failed>();
+ }
+
+ [Test]
+ public void Given_ABasicAuthenticatorWithARealm_When_ChallengingAResponse_Then_TheResponseHasAWWWAuthenticateHeader()
+ {
+ // given
+ string realm = "Lex Luthors Palace";
+ var response = new InMemoryResponse();
+
+ _mockAuthenticator
+ .ExpectGet(auth => auth.Realm)
+ .Returns(realm);
+
+ // when
+ _basicScheme.Challenge(response);
+
+ // then
+ var expectedChallengeHeader = string.Format("Basic realm=\"{0}\"", realm);
+ response.Headers.ShouldContain("WWW-Authenticate", expectedChallengeHeader);
+ }
+ }
+}
View
30 src/core/OpenRasta.Tests.Unit/OpenRasta.Tests.Unit.csproj
@@ -61,6 +61,7 @@
<Compile Include="..\..\CommonInfo.cs">
<Link>Properties\CommonInfo.cs</Link>
</Compile>
+ <Compile Include="Authentication\Basic\BasicAuthenticationScheme_Specification.cs" />
<Compile Include="Binding\DefaultBinderLocator_Specification.cs" />
<Compile Include="Binding\KeyedValuesBinder_Specification.cs" />
<Compile Include="Codecs\ApplicationOctetStreamCodec_Specification.cs" />
@@ -109,6 +110,8 @@
<Compile Include="OperationModel\MethodBased\MethodBasedOperation_Specification.cs" />
<Compile Include="OperationModel\MethodBased\TypeExclusionFilter_Specification.cs" />
<Compile Include="OperationModel\OperationHydration_Spec.cs" />
+ <Compile Include="Pipeline\Contributors\AuthenticationChallenger_Specification.cs" />
+ <Compile Include="Pipeline\Contributors\Authentication_Specification.cs" />
<Compile Include="Security\RequiresAuthenticationInterceptor_Specification.cs" />
<Compile Include="Security\RequiresRoleInterceptor_Specification.cs" />
<Compile Include="TypeSystem\Members_Specification.cs" />
@@ -149,20 +152,19 @@
<Compile Include="Web\Markup\TextArea_Specification.cs" />
<Compile Include="Web\Markup\TextNode_Specification.cs" />
<Compile Include="Web\Markup\XhtmlDOM_Specification.cs" />
- <Compile Include="Web\Pipeline\Contributors\HandlerMethodFiltersInvoker_Specification.cs" />
- <Compile Include="Web\Pipeline\Contributors\OperationCreationContributor_Specification.cs" />
- <Compile Include="Web\Pipeline\Contributors\OperationProcessors_Specification.cs" />
- <Compile Include="Web\Pipeline\Contributors\ResponseEntityWriter_Specification.cs" />
- <Compile Include="Web\Pipeline\Contributors\ResponseEntityCodecResolver_Specification.cs" />
- <Compile Include="Web\Pipeline\Contributors\HandlerMethodInvoker_Specification.cs" />
- <Compile Include="Web\Pipeline\Contributors\RequestEntityReader_Specification.cs" />
- <Compile Include="Web\Pipeline\Contributors\InvalidRequestEntityRemover_Specification.cs" />
- <Compile Include="Web\Pipeline\Contributors\HandlerResolver_Specification.cs" />
- <Compile Include="Web\Pipeline\Contributors\HttpMethodOverrider_Specification.cs" />
- <Compile Include="Web\Pipeline\Contributors\ResourceTypeResolver_Specification.cs" />
- <Compile Include="Web\Pipeline\Contributors\UriDecoratorsController_Specification.cs" />
- <Compile Include="Web\Pipeline\DigestCredentialsReader_Specification.cs" />
- <Compile Include="Web\Pipeline\PipelineRunner_Specification.cs" />
+ <Compile Include="Pipeline\Contributors\HandlerMethodFiltersInvoker_Specification.cs" />
+ <Compile Include="Pipeline\Contributors\OperationCreationContributor_Specification.cs" />
+ <Compile Include="Pipeline\Contributors\OperationProcessors_Specification.cs" />
+ <Compile Include="Pipeline\Contributors\ResponseEntityWriter_Specification.cs" />
+ <Compile Include="Pipeline\Contributors\ResponseEntityCodecResolver_Specification.cs" />
+ <Compile Include="Pipeline\Contributors\HandlerMethodInvoker_Specification.cs" />
+ <Compile Include="Pipeline\Contributors\RequestEntityReader_Specification.cs" />
+ <Compile Include="Pipeline\Contributors\InvalidRequestEntityRemover_Specification.cs" />
+ <Compile Include="Pipeline\Contributors\HandlerResolver_Specification.cs" />
+ <Compile Include="Pipeline\Contributors\HttpMethodOverrider_Specification.cs" />
+ <Compile Include="Pipeline\Contributors\ResourceTypeResolver_Specification.cs" />
+ <Compile Include="Pipeline\Contributors\UriDecoratorsController_Specification.cs" />
+ <Compile Include="Pipeline\PipelineRunner_Specification.cs" />
<Compile Include="UriTemplate_Specification.cs" />
<Compile Include="Web\Reflection_Specification.cs" />
<Compile Include="Web\TemplatedUriResolver_Specification.cs" />
View
109 ...core/OpenRasta.Tests.Unit/Pipeline/Contributors/AuthenticationChallenger_Specification.cs
@@ -0,0 +1,109 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Moq;
+using NUnit.Framework;
+using OpenRasta.Authentication;
+using OpenRasta.DI;
+using OpenRasta.Pipeline;
+using OpenRasta.Pipeline.Contributors;
+using OpenRasta.Testing;
+using OpenRasta.Tests;
+using OpenRasta.Web;
+
+namespace given_an_authentication_contributor
+{
+ public abstract class given_an_authentication_contributor : openrasta_context
+ {
+ protected override void SetUp()
+ {
+ base.SetUp();
+ given_pipeline_contributor<AuthenticationChallengerContributor>();
+ }
+ }
+
+ public class when_the_pipeline_is_notified_IOperationExecution : given_an_authentication_contributor
+ {
+ [Test]
+ public void then_authentication_challenger_is_invoked()
+ {
+ // given
+
+ // when
+ when_sending_notification<KnownStages.IOperationExecution>();
+
+ // then
+ IsContributorExecuted.ShouldBeTrue();
+ }
+ }
+
+ public class when_the_pipeline_is_notified_IResponseCoding : given_an_authentication_contributor
+ {
+ [Test]
+ public void then_authentication_challenger_is_invoked()
+ {
+ // given
+
+ // when
+ when_sending_notification<KnownStages.IResponseCoding>();
+
+ // then
+ IsContributorExecuted.ShouldBeTrue();
+ }
+ }
+
+ namespace _and_scheme
+ {
+
+ public abstract class _and_scheme : given_an_authentication_contributor
+ {
+ protected Mock<IAuthenticationScheme> mockScheme = new Mock<IAuthenticationScheme>();
+
+ protected override void SetUp()
+ {
+ base.SetUp();
+ given_dependency(mockScheme.Object);
+ given_pipeline_contributor<AuthenticationChallengerContributor>();
+ }
+ }
+
+ public class when_the_context_is_unauthorized : _and_scheme
+ {
+ [Test]
+ public void then_the_authentication_scheme_is_challenged()
+ {
+ // given
+ Context.OperationResult = new OperationResult.Unauthorized();
+
+ // when
+ when_sending_notification<KnownStages.IOperationExecution>();
+
+ // then
+ mockScheme.Verify(s => s.Challenge(Context.Response));
+ }
+ }
+
+ public class when_the_context_is_ok : given_an_authentication_contributor
+ {
+ [Test]
+ public void then_the_authentication_scheme_is_not_challenged()
+ {
+ // given
+ var mockScheme = new Mock<IAuthenticationScheme>(MockBehavior.Strict);
+
+ given_dependency(mockScheme.Object);
+
+ Context.OperationResult = new OperationResult.OK();
+
+ // when
+ when_sending_notification<KnownStages.IOperationExecution>();
+
+ // then
+ mockScheme.VerifyAll();
+ }
+ }
+ }
+}
+
+
View
160 src/core/OpenRasta.Tests.Unit/Pipeline/Contributors/Authentication_Specification.cs
@@ -0,0 +1,160 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Moq;
+using NUnit.Framework;
+using OpenRasta.Authentication;
+using OpenRasta.DI;
+using OpenRasta.Pipeline;
+using OpenRasta.Pipeline.Contributors;
+using OpenRasta.Testing;
+using OpenRasta.Tests;
+using OpenRasta.Web;
+
+namespace Authentication_Specification
+{
+ [TestFixture]
+ public class Authentication_Specification : openrasta_context
+ {
+ [Test]
+ public void Authentication_IsInvokedAfterIBegin()
+ {
+ // given
+ given_pipeline_contributor<AuthenticationContributor>();
+
+ // when
+ when_sending_notification<KnownStages.IBegin>();
+
+ // then
+ IsContributorExecuted.ShouldBeTrue();
+ }
+
+ [Test]
+ public void Authentication_IsInvokedBeforeIHandlerSelection()
+ {
+ // given
+ given_pipeline_contributor<AuthenticationContributor>();
+
+ // when
+ when_sending_notification<KnownStages.IHandlerSelection>();
+
+ // then
+ IsContributorExecuted.ShouldBeTrue();
+ }
+
+ [Test]
+ public void NoAuthHeader()
+ {
+ // given
+ given_pipeline_contributor<AuthenticationContributor>();
+
+ // when
+ var result = when_sending_notification<KnownStages.IHandlerSelection>();
+
+ // then
+ result.ShouldBe(PipelineContinuation.Continue);
+ }
+
+ [Test]
+ public void AuthHeaderWithUnsupportedScheme()
+ {
+ // given
+ given_pipeline_contributor<AuthenticationContributor>();
+
+ Context.Request.Headers.Add("Authorization", "BASIC anythinghere");
+
+ // when
+ var result = when_sending_notification<KnownStages.IHandlerSelection>();
+
+ // then
+ Context.Response.Headers["Warning"].ShouldBe("Unsupported Authentication Scheme");
+ result.ShouldBe(PipelineContinuation.Continue);
+ }
+
+ [Test]
+ public void AuthHeaderWithMalformedHeader()
+ {
+ // given
+ given_pipeline_contributor<AuthenticationContributor>();
+
+ var mockScheme = new Mock<IAuthenticationScheme>();
+
+ mockScheme.ExpectGet(s => s.Name).Returns("BASIC");
+
+ mockScheme
+ .Expect(s => s.Authenticate(It.IsAny<IRequest>()))
+ .Returns(new AuthenticationResult.MalformedCredentials());
+
+ given_dependency(mockScheme.Object);
+
+ Context.Request.Headers.Add("Authorization", "BASIC anythinghere");
+
+ // when
+ var result = when_sending_notification<KnownStages.IHandlerSelection>();
+
+ // then
+ Context.Response.Headers["Warning"].ShouldBe("Malformed credentials");
+ Context.OperationResult.ShouldBeOfType<OperationResult.BadRequest>();
+ result.ShouldBe(PipelineContinuation.RenderNow);
+ }
+
+ [Test]
+ public void AuthHeaderWithInvalidCredentials()
+ {
+ // given
+ given_pipeline_contributor<AuthenticationContributor>();
+
+ var mockScheme = new Mock<IAuthenticationScheme>();
+
+ mockScheme.ExpectGet(s => s.Name).Returns("BASIC");
+
+ mockScheme
+ .Expect(s => s.Authenticate(It.IsAny<IRequest>()))
+ .Returns(new AuthenticationResult.Failed());
+
+ given_dependency(mockScheme.Object);
+
+ Context.Request.Headers.Add("Authorization", "BASIC anythinghere");
+
+ // when
+ var result = when_sending_notification<KnownStages.IHandlerSelection>();
+
+ // then
+ Context.OperationResult.ShouldBeOfType<OperationResult.Unauthorized>();
+ result.ShouldBe(PipelineContinuation.Continue);
+ }
+
+ [Test]
+ public void AuthHeaderWithValidCredentials()
+ {
+ // given
+ given_pipeline_contributor<AuthenticationContributor>();
+
+ var mockScheme = new Mock<IAuthenticationScheme>();
+
+ mockScheme.ExpectGet(s => s.Name).Returns("BASIC");
+
+ var username = "someUsername";
+ var roles = new[] { "role1", "role2" };
+
+ mockScheme
+ .Expect(s => s.Authenticate(It.IsAny<IRequest>()))
+ .Returns(new AuthenticationResult.Success(username, roles));
+
+ given_dependency(mockScheme.Object);
+
+ Context.Request.Headers.Add("Authorization", "BASIC anythinghere");
+
+ // when
+ var result = when_sending_notification<KnownStages.IHandlerSelection>();
+
+ // then
+ result.ShouldBe(PipelineContinuation.Continue);
+
+ Context.User.Identity.Name.ShouldBe(username);
+ Context.User.IsInRole(roles[0]);
+ Context.User.IsInRole(roles[1]);
+ }
+ }
+}
View
0 ...dlerMethodFiltersInvoker_Specification.cs → ...dlerMethodFiltersInvoker_Specification.cs
File renamed without changes.
View
0 ...ors/HandlerMethodInvoker_Specification.cs → ...ors/HandlerMethodInvoker_Specification.cs
File renamed without changes.
View
0 ...hodrequestEntityResolver_Specification.cs → ...hodrequestEntityResolver_Specification.cs
File renamed without changes.
View
0 ...ributors/HandlerResolver_Specification.cs → ...ributors/HandlerResolver_Specification.cs
File renamed without changes.
View
0 ...tors/HttpMethodOverrider_Specification.cs → ...tors/HttpMethodOverrider_Specification.cs
File renamed without changes.
View
0 ...alidRequestEntityRemover_Specification.cs → ...alidRequestEntityRemover_Specification.cs
File renamed without changes.
View
0 ...ationCreationContributor_Specification.cs → ...ationCreationContributor_Specification.cs
File renamed without changes.
View
0 ...tors/OperationProcessors_Specification.cs → ...tors/OperationProcessors_Specification.cs
File renamed without changes.
View
0 ...tors/RequestEntityReader_Specification.cs → ...tors/RequestEntityReader_Specification.cs
File renamed without changes.
View
0 ...ors/ResourceTypeResolver_Specification.cs → ...ors/ResourceTypeResolver_Specification.cs
File renamed without changes.
View
0 ...ponseEntityCodecResolver_Specification.cs → ...ponseEntityCodecResolver_Specification.cs
File renamed without changes.
View
0 ...ors/ResponseEntityWriter_Specification.cs → ...ors/ResponseEntityWriter_Specification.cs
File renamed without changes.
View
0 .../UriDecoratorsController_Specification.cs → .../UriDecoratorsController_Specification.cs
File renamed without changes.
View
0 .../DigestCredentialsReader_Specification.cs → .../DigestCredentialsReader_Specification.cs
File renamed without changes.
View
0 .../Pipeline/PipelineRunner_Specification.cs → .../Pipeline/PipelineRunner_Specification.cs
File renamed without changes.
View
30 src/core/OpenRasta.Tests.Unit/openrasta_context.cs
@@ -56,6 +56,12 @@ protected IUriResolver UriResolver
get { return Resolver.Resolve<IUriResolver>(); }
}
+ public void given_dependency<TInterface>(TInterface instance)
+ {
+ Resolver.AddDependencyInstance(typeof(TInterface), instance, DependencyLifetime.Singleton);
+
+ }
+
public T given_pipeline_contributor<T>() where T : class, IPipelineContributor
{
return given_pipeline_contributor<T>(null);
@@ -189,11 +195,6 @@ protected void given_response_entity(object responseEntity)
Context.OperationResult = new OperationResult.OK { ResponseResource = responseEntity };
}
- protected void GivenAUser(string username, string password)
- {
- var provider = Resolver.Resolve<IAuthenticationProvider>() as InMemAuthenticationProvider;
- provider.Passwords[username] = password;
- }
protected TestErrorCollector Errors { get; private set; }
protected override void SetUp()
{
@@ -202,8 +203,6 @@ protected override void SetUp()
Pipeline = null;
_actions = new Dictionary<Type, Func<ICommunicationContext, PipelineContinuation>>();
var manager = Host.HostManager;
- if (!Resolver.HasDependency(typeof(IAuthenticationProvider)))
- Resolver.AddDependency<IAuthenticationProvider, InMemAuthenticationProvider>();
Resolver.AddDependencyInstance(typeof(IErrorCollector), Errors = new TestErrorCollector());
Resolver.AddDependency<IPathManager, PathManager>();
@@ -217,23 +216,6 @@ protected override void TearDown()
DependencyManager.UnsetResolver();
}
- public class InMemAuthenticationProvider : IAuthenticationProvider
- {
- public Dictionary<string, string> Passwords = new Dictionary<string, string>();
-
- public Credentials GetByUsername(string username)
- {
- if (username == null || !Passwords.ContainsKey(username))
- return null;
- return new Credentials
- {
- Username = username,
- Password = Passwords[username],
- Roles = new string[0]
- };
- }
- }
-
public class SinglePipeline<T> : IPipeline, IPipelineExecutionOrder, IPipelineExecutionOrderAnd where T : class, IPipelineContributor
{
internal Dictionary<Type, Func<ICommunicationContext, PipelineContinuation>> _actions;
View
26 src/core/OpenRasta/Authentication/AuthenticationResult.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Security.Principal;
+using OpenRasta.Pipeline.Contributors;
+
+namespace OpenRasta.Authentication
+{
+ public class AuthenticationResult
+ {
+ public class MalformedCredentials : AuthenticationResult { }
+
+ public class Failed : AuthenticationResult { }
+
+ public class Success : AuthenticationResult
+ {
+ public string Username { get; private set; }
+ public string[] Roles { get; private set; }
+
+ public Success(string username, params string[] roles)
+ {
+ Username = username;
+ Roles = roles;
+ }
+ }
+ }
+}
View
18 src/core/OpenRasta/Authentication/Basic/BasicAuthRequestHeader.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Text;
+using OpenRasta;
+
+namespace OpenRasta.Authentication.Basic
+{
+ public class BasicAuthRequestHeader
+ {
+ public string Username { get; private set; }
+ public string Password { get; private set; }
+
+ internal BasicAuthRequestHeader(string username, string password)
+ {
+ Username = username;
+ Password = password;
+ }
+ }
+}
View
55 src/core/OpenRasta/Authentication/Basic/BasicAuthenticationScheme.cs
@@ -0,0 +1,55 @@
+using OpenRasta.Web;
+
+namespace OpenRasta.Authentication.Basic
+{
+ public class BasicAuthenticationScheme : IAuthenticationScheme
+ {
+ const string SCHEME = "Basic";
+
+ private readonly IBasicAuthenticator _basicAuthenticator;
+
+ public string Name { get { return SCHEME; } }
+
+ public BasicAuthenticationScheme(IBasicAuthenticator basicAuthenticator)
+ {
+ _basicAuthenticator = basicAuthenticator;
+ }
+
+ public AuthenticationResult Authenticate(IRequest request)
+ {
+ BasicAuthRequestHeader credentials = ExtractBasicHeader(request.Headers["Authorization"]);
+
+ if (credentials != null)
+ {
+ return _basicAuthenticator.Authenticate(credentials);
+ }
+
+ return new AuthenticationResult.MalformedCredentials();
+ }
+
+ public void Challenge(IResponse response)
+ {
+ response.Headers["WWW-Authenticate"] = string.Format("{0} realm=\"{1}\"", SCHEME, _basicAuthenticator.Realm);
+ }
+
+ internal static BasicAuthRequestHeader ExtractBasicHeader(string value)
+ {
+ try
+ {
+ var basicBase64Credentials = value.Split(' ')[1];
+
+ var basicCredentials = basicBase64Credentials.FromBase64String().Split(':');
+
+ if (basicCredentials.Length != 2)
+ return null;
+
+ return new BasicAuthRequestHeader(basicCredentials[0], basicCredentials[1]);
+ }
+ catch
+ {
+ return null;
+ }
+
+ }
+ }
+}
View
8 src/core/OpenRasta/Authentication/Basic/IBasicAuthenticator.cs
@@ -0,0 +1,8 @@
+namespace OpenRasta.Authentication.Basic
+{
+ public interface IBasicAuthenticator
+ {
+ string Realm { get; }
+ AuthenticationResult Authenticate(BasicAuthRequestHeader header);
+ }
+}
View
156 src/core/OpenRasta/Authentication/Digest/DigestAuthRequestHeader.cs
@@ -0,0 +1,156 @@
+using System;
+using System.Security.Cryptography;
+using System.Text;
+using OpenRasta;
+
+namespace OpenRasta.Authentication.Digest
+{
+ public enum DigestAlgorithm
+ {
+ MD5
+ }
+
+ public class DigestAuthResponseChallenge
+ {
+ public string Realm { get; private set; } // realm=""
+
+ public string Username { get; private set; } // qop=""
+ public string Password { get; private set; } // qop=""
+ public string Salt { get; private set; } // qop=""
+ public string QualityOfProtection { get; private set; } // qop=""
+ public string ServerNonce { get; private set; } // nonce=""
+ public string ClientNonce { get; private set; } // cnonce=""
+ public string Uri { get; private set; } // uri=""
+ public string Response { get; private set; } // response=""
+ public string Digest { get; private set; } // digest=""
+ public string Opaque { get; private set; } // opaque=""
+ public string RequestCounter { get; private set; } // nc=""
+ public bool Stale { get; private set; } // stale=""
+ public DigestAlgorithm Algorithm { get; private set; } // algorithm=""
+
+ public DigestAuthResponseChallenge(string realm, string serverNonce, byte[] opaqueData, bool stale)
+ {
+
+ }
+
+ public string GetCalculatedResponse(string httpMethod)
+ {
+ // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
+ string A1 = String.Format("{0}:{1}:{2}", Username, Realm, Password);
+
+ // H(A1) = MD5(A1)
+ string HA1 = GetMD5HashBinHex(A1);
+
+ // A2 = Method ":" digest-uri-value
+ string A2 = String.Format("{0}:{1}", httpMethod, Uri);
+
+ // H(A2)
+ string HA2 = GetMD5HashBinHex(A2);
+
+ // KD(secret, data) = H(concat(secret, ":", data))
+ // if qop == auth:
+ // request-digest = <"> < KD ( H(A1), unq(nonce-value)
+ // ":" nc-value
+ // ":" unq(cnonce-value)
+ // ":" unq(qop-value)
+ // ":" H(A2)
+ // ) <">
+ // if qop is missing,
+ // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
+ string unhashedDigest;
+ if (QualityOfProtection != null)
+ {
+ unhashedDigest = String.Format("{0}:{1}:{2}:{3}:{4}:{5}",
+ HA1,
+ ServerNonce,
+ RequestCounter,
+ ClientNonce,
+ QualityOfProtection,
+ HA2);
+ }
+ else
+ {
+ unhashedDigest = String.Format("{0}:{1}:{2}",
+ HA1,
+ RequestCounter,
+ HA2);
+ }
+
+ return GetMD5HashBinHex(unhashedDigest);
+ }
+
+ static string GetMD5HashBinHex(string toBeHashed)
+ {
+ MD5 hash = MD5.Create();
+ byte[] result = hash.ComputeHash(Encoding.ASCII.GetBytes(toBeHashed));
+
+ var sb = new StringBuilder();
+ foreach (byte b in result)
+ sb.Append(b.ToString("x2"));
+ return sb.ToString();
+ }
+ }
+
+ public class DigestAuthRequestParameters
+ {
+ private const string SchemeName = "DIGEST";
+ private const string SchemeNameWithSpace = SchemeName + " ";
+
+ public string Username { get; private set; } // username=""
+ public string Realm { get; private set; } // realm=""
+
+ public string QualityOfProtection { get; private set; } // qop=""
+ public string ServerNonce { get; private set; } // nonce=""
+ public string ClientNonce { get; private set; } // cnonce=""
+ public string Uri { get; private set; } // uri=""
+ public string Response { get; private set; } // response=""
+ public string Digest { get; private set; } // digest=""
+ public string Opaque { get; private set; } // opaque=""
+ public string RequestCounter { get; private set; } // nc=""
+
+ public DigestAuthRequestParameters(string username)
+ {
+ Username = username;
+ }
+
+ public static DigestAuthRequestParameters Parse(string value)
+ {
+ if (value.IsNullOrWhiteSpace()) return null;
+
+ if (!value.ToUpper().StartsWith(SchemeNameWithSpace)) return null;
+
+ var basicBase64Credentials = value.Split(' ')[1];
+ var basicCredentials = Encoding.UTF8.GetString(Convert.FromBase64String(basicBase64Credentials)).Split(':');
+
+ var username = basicCredentials[0];
+ var password = basicCredentials[1];
+
+ return new DigestAuthRequestParameters(username, password);
+ }
+
+ public static bool TryParse(string value, out DigestAuthRequestParameters credentials)
+ {
+ credentials = null;
+
+ if (string.IsNullOrWhiteSpace(value)) return false;
+
+ if (!value.ToUpper().StartsWith(SchemeNameWithSpace)) return false;
+
+ var basicBase64Credentials = value.Split(' ')[1];
+
+ credentials = ExtractBasicCredentials(basicBase64Credentials);
+
+ return true;
+ }
+
+ private static DigestAuthRequestParameters ExtractDigestCredentials(string basicCredentialsAsBase64)
+ {
+ var basicCredentials = basicCredentialsAsBase64.FromBase64String().Split(':');
+
+ var username = basicCredentials[0];
+ var password = basicCredentials[1];
+
+ return new DigestAuthRequestParameters(username, password);
+ }
+ }
+}
View
34 src/core/OpenRasta/Authentication/Digest/DigestAuthenticationScheme.cs
@@ -0,0 +1,34 @@
+using OpenRasta.Authentication.Basic;
+using OpenRasta.Web;
+
+namespace OpenRasta.Authentication.Digest
+{
+ public class DigestAuthenticationScheme : IAuthenticationScheme
+ {
+ private readonly IDigestAuthenticator _digestAuthenticator;
+
+ public string Name { get { return "Basic"; } }
+
+ public DigestAuthenticationScheme(IDigestAuthenticator digestAuthenticator)
+ {
+ _digestAuthenticator = digestAuthenticator;
+ }
+
+ public AuthenticationResult Authenticate(IRequest request)
+ {
+ DigestAuthRequestParameters credentials;
+
+ if (DigestAuthRequestParameters.TryParse(request.Headers["Authorization"], out credentials))
+ {
+ return _digestAuthenticator.Authenticate(credentials);
+ }
+
+ return new AuthenticationResult.MalformedCredentials();
+ }
+
+ public void Challenge(IResponse response)
+ {
+ response.Headers["WWW-Authenticate"] = string.Format("Basic realm=\"{0}\"", _digestAuthenticator.Realm);
+ }
+ }
+}
View
8 src/core/OpenRasta/Authentication/Digest/IDigestAuthenticator.cs
@@ -0,0 +1,8 @@
+namespace OpenRasta.Authentication.Digest
+{
+ public interface IDigestAuthenticator
+ {
+ string Realm { get; }
+ AuthenticationResult Authenticate(DigestAuthRequestParameters header);
+ }
+}
View
13 src/core/OpenRasta/Authentication/IAuthenticationScheme.cs
@@ -0,0 +1,13 @@
+using OpenRasta.Web;
+
+namespace OpenRasta.Authentication
+{
+ public interface IAuthenticationScheme
+ {
+ string Name { get; }
+
+ AuthenticationResult Authenticate(IRequest request);
+
+ void Challenge(IResponse response);
+ }
+}
View
3 src/core/OpenRasta/Configuration/DefaultDependencyRegistrar.cs
@@ -346,7 +346,8 @@ void AddDefaultContributors()
AddPipelineContributor<ResourceTypeResolverContributor>();
AddPipelineContributor<HandlerResolverContributor>();
- AddPipelineContributor<DigestAuthorizerContributor>();
+ AddPipelineContributor<AuthenticationContributor>();
+ AddPipelineContributor<AuthenticationChallengerContributor>();
AddPipelineContributor<OperationCreatorContributor>();
AddPipelineContributor<OperationFilterContributor>();
View
27 src/core/OpenRasta/OpenRasta.csproj
@@ -60,6 +60,11 @@
<Compile Include="..\..\CommonInfo.cs">
<Link>Properties\CommonInfo.cs</Link>
</Compile>
+ <Compile Include="Authentication\AuthenticationResult.cs" />
+ <Compile Include="Authentication\Basic\BasicAuthenticationScheme.cs" />
+ <Compile Include="Authentication\Basic\BasicAuthRequestHeader.cs" />
+ <Compile Include="Authentication\Basic\IBasicAuthenticator.cs" />
+ <Compile Include="Authentication\IAuthenticationScheme.cs" />
<Compile Include="Binding\BinderAttribute.cs" />
<Compile Include="Binding\DefaultObjectBinderLocator.cs" />
<Compile Include="Binding\BindingResult.cs" />
@@ -122,6 +127,11 @@
<Compile Include="Diagnostics\LogSource.cs" />
<Compile Include="Diagnostics\NullErrorCollector.cs" />
<Compile Include="Diagnostics\OperationContextErrorCollector.cs" />
+ <Compile Include="Pipeline\Contributors\AuthenticationChallengerContributor.cs" />
+ <Compile Include="Pipeline\Contributors\AuthenticationContributor.cs" />
+ <Compile Include="Pipeline\Contributors\DigestAuthorizerContributor.cs">
+ <SubType>Code</SubType>
+ </Compile>
<Compile Include="Pipeline\Diagnostics\PipelineLogSource.cs" />
<Compile Include="DI\Internal\ContextStoreDependency.cs" />
<Compile Include="DI\Internal\ContextStoreExtensions.cs" />
@@ -142,7 +152,8 @@
<Compile Include="Configuration\MetaModel\Handlers\DependencyRegistrationModelHandler.cs" />
<Compile Include="Handlers\HandlerRepository.cs" />
<Compile Include="Handlers\IHandlerRepository.cs" />
- <Compile Include="Configuration\Fluent\ICodecDefinition.cs" /> <Compile Include="Configuration\Fluent\ICodecParentDefinition.cs" />
+ <Compile Include="Configuration\Fluent\ICodecDefinition.cs" />
+ <Compile Include="Configuration\Fluent\ICodecParentDefinition.cs" />
<Compile Include="Configuration\Fluent\ICodecWithMediaTypeDefinition.cs" />
<Compile Include="Configuration\Fluent\IHandlerForResourceWithUriDefinition.cs" />
<Compile Include="Configuration\Fluent\IHandlerParentDefinition.cs" />
@@ -215,6 +226,16 @@
<Compile Include="OperationModel\OutputMember.cs" />
<Compile Include="Pipeline\IContextStore.cs" />
<Compile Include="Pipeline\IContextStoreDependencyCleaner.cs" />
+ <Compile Include="Security\Credentials.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Security\DigestHeader.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Security\IAuthenticationProvider.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Security\RequiresAuthenticationInterceptor.cs" />
<Compile Include="Security\RequiresRoleAttribute.cs" />
<Compile Include="Security\RequiresRoleInterceptor.cs" />
<Compile Include="TypeSystem\DebuggerStrings.cs" />
@@ -411,9 +432,6 @@
<Compile Include="IO\ByteArrayExtension.cs" />
<Compile Include="IO\HistoryStream.cs" />
<Compile Include="IO\StreamExtensions.cs" />
- <Compile Include="Security\DigestHeader.cs" />
- <Compile Include="Security\IAuthenticationProvider.cs" />
- <Compile Include="Security\Credentials.cs" />
<Compile Include="UriTemplate.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UriTemplateEqualityComparer.cs" />
@@ -431,7 +449,6 @@
<Compile Include="Pipeline\ContributorCall.cs" />
<Compile Include="Pipeline\Contributors\AbstractOperationProcessing.cs" />
<Compile Include="Pipeline\Contributors\BootstrapperContributor.cs" />
- <Compile Include="Pipeline\Contributors\DigestAuthorizerContributor.cs" />
<Compile Include="OperationModel\IOperationCreator.cs" />
<Compile Include="OperationModel\IOperation.cs" />
<Compile Include="OperationModel\IOperationFilter.cs" />
View
41 src/core/OpenRasta/Pipeline/Contributors/AuthenticationChallengerContributor.cs
@@ -0,0 +1,41 @@
+using OpenRasta.Authentication;
+using OpenRasta.DI;
+using OpenRasta.Diagnostics;
+using OpenRasta.Web;
+
+namespace OpenRasta.Pipeline.Contributors
+{
+ public class AuthenticationChallengerContributor : IPipelineContributor
+ {
+ readonly IDependencyResolver _resolver;
+ public ILogger Log { get; set; }
+
+ public AuthenticationChallengerContributor(IDependencyResolver resolver)
+ {
+ _resolver = resolver;
+ }
+
+ public void Initialize(IPipeline pipelineRunner)
+ {
+ pipelineRunner.Notify(ChallengeIfUnauthorized)
+ .After<KnownStages.IOperationExecution>()
+ .And
+ .Before<KnownStages.IResponseCoding>();
+ }
+
+ private PipelineContinuation ChallengeIfUnauthorized(ICommunicationContext context)
+ {
+ if (context.OperationResult is OperationResult.Unauthorized)
+ {
+ var supportedSchemes = _resolver.ResolveAll<IAuthenticationScheme>();
+
+ foreach (var scheme in supportedSchemes)
+ {
+ scheme.Challenge(context.Response);
+ }
+ }
+
+ return PipelineContinuation.Continue;
+ }
+ }
+}
View
91 src/core/OpenRasta/Pipeline/Contributors/AuthenticationContributor.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Principal;
+using OpenRasta.Authentication;
+using OpenRasta.DI;
+using OpenRasta.Diagnostics;
+using OpenRasta.Web;
+
+namespace OpenRasta.Pipeline.Contributors
+{
+ public class AuthenticationContributor : KnownStages.IAuthentication
+ {
+ readonly IDependencyResolver _resolver;
+ public ILogger Log { get; set; }
+
+ public AuthenticationContributor(IDependencyResolver resolver)
+ {
+ _resolver = resolver;
+ }
+
+ public void Initialize(IPipeline pipelineRunner)
+ {
+ pipelineRunner.Notify(AuthoriseRequest)
+ .After<KnownStages.IBegin>()
+ .And
+ .Before<KnownStages.IHandlerSelection>();
+ }
+
+ private PipelineContinuation AuthoriseRequest(ICommunicationContext context)
+ {
+ var requestedAuthSchemeName= ExtractRequestedAuthScheme(context.Request);
+
+ if (requestedAuthSchemeName == null)
+ return PipelineContinuation.Continue;
+
+ var authenticators = _resolver.ResolveAll<IAuthenticationScheme>();
+
+ var schemeToUse = authenticators.SingleOrDefault(scheme => string.Equals(scheme.Name, requestedAuthSchemeName, StringComparison.InvariantCultureIgnoreCase));
+
+ if(schemeToUse == null)
+ {
+ context.Response.Headers["Warning"] = "Unsupported Authentication Scheme";
+ return PipelineContinuation.Continue;
+ }
+
+ var authResult = schemeToUse.Authenticate(context.Request);
+
+ if (authResult is AuthenticationResult.Success)
+ {
+ var success = (authResult as AuthenticationResult.Success);
+ context.User = CreatePrincipal(success, schemeToUse);
+ }
+
+ if (authResult is AuthenticationResult.MalformedCredentials)
+ {
+ context.OperationResult = new OperationResult.BadRequest();
+ context.Response.Headers["Warning"] = "Malformed credentials";
+ return PipelineContinuation.RenderNow;
+ }
+
+ if (authResult is AuthenticationResult.Failed)
+ {
+ context.OperationResult = new OperationResult.Unauthorized();
+ }
+
+ return PipelineContinuation.Continue;
+ }
+
+ static string ExtractRequestedAuthScheme(IRequest request)
+ {
+ var authRequestHeader = request.Headers["Authorization"];
+
+ if (string.IsNullOrEmpty(authRequestHeader))
+ return null;
+
+ var requestedAuthSchemeName = authRequestHeader.Split(' ')[0];
+
+ if (string.IsNullOrEmpty(requestedAuthSchemeName))
+ return null;
+
+ return requestedAuthSchemeName;
+ }
+
+ static IPrincipal CreatePrincipal(AuthenticationResult.Success success, IAuthenticationScheme scheme)
+ {
+ var identity = new GenericIdentity(success.Username, scheme.Name);
+ return new GenericPrincipal(identity, success.Roles);
+ }
+ }
+}
View
5 src/core/OpenRasta/Pipeline/KnownStages.cs
@@ -16,6 +16,11 @@ public static class KnownStages
public interface IBegin : IPipelineContributor { }
/// <summary>
+ /// Represents the stage at which http authentication will take place
+ /// </summary>
+ public interface IAuthentication : IPipelineContributor { }
+
+ /// <summary>
/// Represents the stage at which the URI is matched to find a resource.
/// </summary>
public interface IUriMatching : IPipelineContributor { }
View
21 src/core/OpenRasta/Security/RequiresAuthenticationAttribute.cs
@@ -28,27 +28,6 @@ public override IEnumerable<IOperationInterceptor> GetInterceptors(IOperation op
};
}
}
-
- public class RequiresAuthenticationInterceptor : OperationInterceptor
- {
- readonly ICommunicationContext _context;
-
- public RequiresAuthenticationInterceptor(ICommunicationContext context)
- {
- _context = context;
- }
-
- public override bool BeforeExecute(IOperation operation)
- {
- if (_context.User == null || _context.User.Identity == null || !_context.User.Identity.IsAuthenticated)
- {
- _context.OperationResult = new OperationResult.Unauthorized();
- return false;
- }
-
- return true;
- }
- }
}
#region Full license
View
27 src/core/OpenRasta/Security/RequiresAuthenticationInterceptor.cs
@@ -0,0 +1,27 @@
+using OpenRasta.OperationModel;
+using OpenRasta.OperationModel.Interceptors;
+using OpenRasta.Web;
+
+namespace OpenRasta.Security
+{
+ public class RequiresAuthenticationInterceptor : OperationInterceptor
+ {
+ readonly ICommunicationContext _context;
+
+ public RequiresAuthenticationInterceptor(ICommunicationContext context)
+ {
+ _context = context;
+ }
+
+ public override bool BeforeExecute(IOperation operation)
+ {
+ if (_context.User == null || _context.User.Identity == null || !_context.User.Identity.IsAuthenticated)
+ {
+ _context.OperationResult = new OperationResult.Unauthorized();
+ return false;
+ }
+
+ return true;
+ }
+ }
+}
View
17 src/core/OpenRasta/StringExtensions.cs
@@ -10,6 +10,7 @@
#endregion
using System;
+using System.Text;
namespace OpenRasta
{
@@ -23,11 +24,27 @@ public static bool IsEmpty(this string target)
{
return target == string.Empty;
}
+
public static bool IsNullOrEmpty(this string target)
{
return string.IsNullOrEmpty(target);
}
+ public static bool IsNullOrWhiteSpace(this string target)
+ {
+ return string.IsNullOrEmpty(target) || target.IsWhiteSpace() ;
+ }
+
+ public static bool IsWhiteSpace(this string target)
+ {
+ return target.Trim() == string.Empty;
+ }
+
+ public static string FromBase64String(this string value)
+ {
+ return Encoding.UTF8.GetString(Convert.FromBase64String(value));
+ }
+
public static Uri ToUri(this string target)
{
return ToUri(target, UriKind.RelativeOrAbsolute);
View
2 src/openbastard/OpenBastard/OpenBastard.csproj
@@ -20,7 +20,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
- <DocumentationFile>..\..\bin\OpenRasta.Codecs.SharpView\OpenRasta.Codecs.SharpView.xml</DocumentationFile>
+ <DocumentationFile>..\..\..\bin\vs\bin\Debug\OpenBastard\OpenBastard.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>

12 comments on commit 25ee8bf

@cloud66

Cool! I've been looking for something like this as I need to support Basic, Digest and OAuth for my services. Any ideas on merge time with master?

@scottlittlewood
Owner

Currently there is only support for Basic Authentication in my branch as that was my requirement at work.

I've not made a pull request to Seb yet as this is a breaking change for current digest authentication techniques.

We're also looking at getting Digest and OAuth built in so that it supports all 3 out of the Box :)

Feel free to fork/merge and contribute :)

@cloud66

Thanks! Do you mind pointing me to the right direction of getting the basic authentication working please? I am planning to get myself familiar with that and then start working on the other schemes. I just need a bit of kickstart in the right direction. Thanks,

@scottlittlewood
Owner

In order to provide Basic Authentication using the code from my branch you'll need to configure OpenRasta as shown below.

The general design of the authentication contributor is that it will look for registered schemes (in this case Basic) and pass the request on to the scheme to perform authentication processing.

The authentication schemes are then dependant on an authenticator that we register (CustomBasicAuthenticator in this case).

The plan is to implement a DigestAuthenticationScheme that is dependant on an IDigestAuthenticator as the header information is different for the various schemes.

Hope this helps.

Feedback/comments are welcome :)

public class Configuration : IConfigurationSource
{
    public void Configure()
    {
        using (OpenRastaConfiguration.Manual)
        {
            ResourceSpace.Uses.BasicAuthentication<CustomBasicAuthenticator>();

            ResourceSpace.Has.ResourcesOfType<HomeResource>()
                .AtUri("/")
                .And.AtUri("/home")
                .HandledBy<HomeHandler>()
                .TranscodedBy<XmlSerializerCodec>();
        }
    }
}

public static class ExtensionsToIUses
{
    public static void BasicAuthentication<TBasicAuthenticator>(this IUses uses) where TBasicAuthenticator : class, IBasicAuthenticator
    {
        uses.CustomDependency<IAuthenticationScheme, BasicAuthenticationScheme>(DependencyLifetime.Transient);

        uses.CustomDependency<IBasicAuthenticator, TBasicAuthenticator>(DependencyLifetime.Transient);
    }
}

public class CustomBasicAuthenticator : IBasicAuthenticator
{
    public string Realm { get { return "your-realm-here"; } }

    public CustomBasicAuthenticator()
    {
    }

    public AuthenticationResult Authenticate(BasicAuthRequestHeader header)
    {
        /* use the information in the header to check credentials against your service/db */
        if (true)
        {
            return new AuthenticationResult.Success(header.Username);
        }

        return new AuthenticationResult.Failed();
    }
}
@cloud66

Awesome! Thanks. Implemented the Digest as well and now am looking for the best way to support different authentication schemes for different services.

@jasiedu

When do youplan to merge your branch with Seb's?

@scottlittlewood
Owner

Seb has accepted the pull request it's in the openwrap branch of the main openrasta-stable repository. I'm currently working on adding Digest Authentication back in using the new authentication model, hopefully I'll get a workable commit done in the next week.

@jasiedu

Can you point me to it? Do i need to download Openwrap to use OpenRasta? This is a little confusing. And do you have a link to the openrasta-stable repository? There appear to be a lot of versions.

@scottlittlewood
Owner

The main remote repository is here: https://github.com/openrasta/openrasta-stable
If you choose to use the openwrap branch then I believe you will need to install openwrap from www.openwrap.org.

@jasiedu

So is this https://github.com/openrasta/openrasta-stable different from "the openwrap branch" one? If so, which is the cannonical version? I work for an organization and we are trying to adopt OR. But the issue with the different branches(versions?) is scaring me off.
Why can't we have one release/branch at the same location?

@scottlittlewood
Owner

As far as I know the openwrap branch is in development at the moment. The master branch at https://github.com/openrasta/openrasta-stable. Has the latest build but if you look at the network graph I believe the 7digital branch has some fixes and improvements.

You can pull changes from any remote branch and build locally. I'm not quite sure what the recommended version is you might be best asking @serialseb on twitter that question.

He's the main developer on the framework and has a lot of knowledge on where the project is going.

There is also the googlegroups where you can ask questions and they are responded to pretty quickly. http://groups.google.com/group/openrasta/

I'm sorry if I've not answered all your questions but my knowledge is still a little basic in these 'operational' areas and I'm just getting use to git(hub) and the OpenRasta framework myself.

@jasiedu

Thanks a lot. You have been very, very helpful.

Please sign in to comment.
Something went wrong with that request. Please try again.