Permalink
Browse files

added BasicAuth and Predicate middleware

  • Loading branch information...
1 parent b8d5bab commit c7fd3264cfd4187bbcb271b9e73af8e0d626ccfe @bvanderveen bvanderveen committed Nov 4, 2011
View
@@ -17,12 +17,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gate.AspNet.Tests", "src\Te
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gate.Kayak.Tests", "src\Tests\Gate.Kayak.Tests\Gate.Kayak.Tests.csproj", "{8AA0A98F-FCE3-4DEB-88A2-67B5C8F9845B}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Hosts", "Hosts", "{26168DEC-6A14-498B-89F4-34881B625D60}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gate.Middleware.Tests", "src\Tests\Gate.Middleware.Tests\Gate.Middleware.Tests.csproj", "{AFFF8587-C837-433F-913A-BF34B0885243}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gate.AspNet", "src\Hosts\Gate.AspNet\Gate.AspNet.csproj", "{F32E456A-F26E-4C5D-93B8-311941A714E4}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Hosts", "Hosts", "{26168DEC-6A14-498B-89F4-34881B625D60}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gate.Kayak", "src\Hosts\Gate.Kayak\Gate.Kayak.csproj", "{D96E8CF9-C2A5-4A35-814C-0B4FE9828B26}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gate.AspNet", "src\Hosts\Gate.AspNet\Gate.AspNet.csproj", "{F32E456A-F26E-4C5D-93B8-311941A714E4}"
+EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{C84C3CDC-FC22-4AF2-8759-4B407BF5AD56}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample.AspNet", "src\Samples\Sample.AspNet\Sample.AspNet.csproj", "{0D16BD06-1972-4714-9D79-7E84F82748F4}"
@@ -117,6 +119,18 @@ Global
{8AA0A98F-FCE3-4DEB-88A2-67B5C8F9845B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{8AA0A98F-FCE3-4DEB-88A2-67B5C8F9845B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{8AA0A98F-FCE3-4DEB-88A2-67B5C8F9845B}.Release|x86.ActiveCfg = Release|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Debug|x86.Build.0 = Debug|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Release|x86.ActiveCfg = Release|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Release|x86.Build.0 = Release|Any CPU
{B60C657C-80DA-4AA3-8796-AD920D5EB5A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B60C657C-80DA-4AA3-8796-AD920D5EB5A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B60C657C-80DA-4AA3-8796-AD920D5EB5A0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@@ -184,20 +198,23 @@ Global
{F32E456A-F26E-4C5D-93B8-311941A714E4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{F32E456A-F26E-4C5D-93B8-311941A714E4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{F32E456A-F26E-4C5D-93B8-311941A714E4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F32E456A-F26E-4C5D-93B8-311941A714E4}.Debug|x86.Build.0 = Debug|Any CPU
{F32E456A-F26E-4C5D-93B8-311941A714E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F32E456A-F26E-4C5D-93B8-311941A714E4}.Release|Any CPU.Build.0 = Release|Any CPU
{F32E456A-F26E-4C5D-93B8-311941A714E4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{F32E456A-F26E-4C5D-93B8-311941A714E4}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{F32E456A-F26E-4C5D-93B8-311941A714E4}.Release|x86.ActiveCfg = Release|Any CPU
+ {F32E456A-F26E-4C5D-93B8-311941A714E4}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{CF3647E1-E3CD-472D-96E2-7B44497D52D8} = {04624DF3-D446-482F-9EE7-44CB5E64B194}
{1BB1CEC7-EAAB-4B25-900B-4981DA873320} = {04624DF3-D446-482F-9EE7-44CB5E64B194}
{E4256EDF-0B54-4715-8E66-8D4D4887E15F} = {04624DF3-D446-482F-9EE7-44CB5E64B194}
{7459D8FB-7AF8-41FD-AA70-5D88FCC430A0} = {04624DF3-D446-482F-9EE7-44CB5E64B194}
{8AA0A98F-FCE3-4DEB-88A2-67B5C8F9845B} = {04624DF3-D446-482F-9EE7-44CB5E64B194}
- {F32E456A-F26E-4C5D-93B8-311941A714E4} = {26168DEC-6A14-498B-89F4-34881B625D60}
+ {AFFF8587-C837-433F-913A-BF34B0885243} = {04624DF3-D446-482F-9EE7-44CB5E64B194}
{D96E8CF9-C2A5-4A35-814C-0B4FE9828B26} = {26168DEC-6A14-498B-89F4-34881B625D60}
+ {F32E456A-F26E-4C5D-93B8-311941A714E4} = {26168DEC-6A14-498B-89F4-34881B625D60}
{0D16BD06-1972-4714-9D79-7E84F82748F4} = {C84C3CDC-FC22-4AF2-8759-4B407BF5AD56}
{0E89EFE3-63CE-4222-9C0B-DD1F5559DAAF} = {C84C3CDC-FC22-4AF2-8759-4B407BF5AD56}
{F31F4DF8-AA81-4FBC-BD33-16AEE1F53B86} = {C84C3CDC-FC22-4AF2-8759-4B407BF5AD56}
View
@@ -39,6 +39,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gate.Owin", "src\Gate.Owin\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gate.Middleware", "src\Gate.Middleware\Gate.Middleware.csproj", "{60C36D8F-BE53-4733-BD92-CFA103D46020}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gate.Middleware.Tests", "src\Tests\Gate.Middleware.Tests\Gate.Middleware.Tests.csproj", "{AFFF8587-C837-433F-913A-BF34B0885243}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -209,6 +211,16 @@ Global
{60C36D8F-BE53-4733-BD92-CFA103D46020}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{60C36D8F-BE53-4733-BD92-CFA103D46020}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{60C36D8F-BE53-4733-BD92-CFA103D46020}.Release|x86.ActiveCfg = Release|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {AFFF8587-C837-433F-913A-BF34B0885243}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -219,6 +231,7 @@ Global
{E4256EDF-0B54-4715-8E66-8D4D4887E15F} = {04624DF3-D446-482F-9EE7-44CB5E64B194}
{7459D8FB-7AF8-41FD-AA70-5D88FCC430A0} = {04624DF3-D446-482F-9EE7-44CB5E64B194}
{8AA0A98F-FCE3-4DEB-88A2-67B5C8F9845B} = {04624DF3-D446-482F-9EE7-44CB5E64B194}
+ {AFFF8587-C837-433F-913A-BF34B0885243} = {04624DF3-D446-482F-9EE7-44CB5E64B194}
{F32E456A-F26E-4C5D-93B8-311941A714E4} = {26168DEC-6A14-498B-89F4-34881B625D60}
{E7602355-82C2-4698-AB61-128B8A6E53CE} = {26168DEC-6A14-498B-89F4-34881B625D60}
{D96E8CF9-C2A5-4A35-814C-0B4FE9828B26} = {26168DEC-6A14-498B-89F4-34881B625D60}
@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Gate;
+using Gate.Owin;
+
+namespace Gate.Middleware
+{
+ public static partial class BasicAuthExtensions
+ {
+ public static string GetBasicAuth(this Environment e)
+ {
+ if (!e.Headers.ContainsKey("authorization"))
+ return null;
+
+ string authHeader = e.Headers["authorization"];
+
+ if (!authHeader.StartsWith("Basic "))
+ return null;
+
+ string authCred = authHeader.Substring("Basic ".Length);
+
+ return Encoding.ASCII.GetString(Convert.FromBase64String(authCred));
+ }
+
+ public static IAppBuilder RequireAuth(this IAppBuilder builder,
+ Func<string, bool> authenticates)
+ {
+ return builder.RequireAuth((e, c) =>
+ c(authenticates(e.GetBasicAuth())), "secure");
+ }
+
+ public static IAppBuilder RequireAuth(this IAppBuilder builder,
+ Action<Environment, Action<bool>> authenticates, string realm)
+ {
+ return builder.RequireAuth(authenticates,
+ b => b.Run(new FourOhOneUnauthorizedResponse(realm).Invoke));
+ }
+
+ public static IAppBuilder RequireAuth(this IAppBuilder builder,
+ Action<Environment, Action<bool>> authenticates, Action<IAppBuilder> unauthorized)
+ {
+ return builder.Unless(authenticates, unauthorized);
+ }
+
+ class FourOhOneUnauthorizedResponse
+ {
+ string realm;
+
+ public FourOhOneUnauthorizedResponse(string realm)
+ {
+ this.realm = realm;
+ }
+
+ public void Invoke(IDictionary<string, object> env, ResultDelegate result, Action<Exception> fault)
+ {
+ result(
+ "401 Authorization Required",
+ new Dictionary<string, string>()
+ {
+ { "WWW-Authenticate", "Basic Realm=\"" + realm + "\"" }
+ },
+ (Func<ArraySegment<byte>, Action, bool> onData, Action<Exception> onError, Action onComplete) =>
+ {
+ var response = @"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01 Transitional//EN""
+""http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"">
+<HTML>
+ <HEAD>
+ <TITLE>Error</TITLE>
+ </HEAD>
+ <BODY><H1>401 Unauthorized.</H1></BODY>
+</HTML>";
+ onData(new ArraySegment<byte>(Encoding.ASCII.GetBytes(response)), null);
+ onComplete();
+ return null;
+ });
+ }
+ }
+ }
+}
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -11,6 +11,7 @@
<RootNamespace>Gate.Middleware</RootNamespace>
<AssemblyName>Gate.Middleware</AssemblyName>
<FileAlignment>512</FileAlignment>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -32,14 +33,22 @@
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
- <Reference Include="System.Xml.Linq" />
- <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
- <Reference Include="System.Data" />
- <Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="BasicAuth.cs" />
+ <Compile Include="Predicate.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Gate.Owin\Gate.Owin.csproj">
+ <Project>{B60C657C-80DA-4AA3-8796-AD920D5EB5A0}</Project>
+ <Name>Gate.Owin</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Gate\Gate.csproj">
+ <Project>{BE3CCA19-0795-4477-A4D4-ABF45474ACBF}</Project>
+ <Name>Gate</Name>
+ </ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using Gate;
+using Gate.Owin;
+
+namespace Gate.Middleware
+{
+ public static class PredicateExtensions
+ {
+ static IAppBuilder Predicate(this IAppBuilder builder,
+ Action<Environment, Action<bool>> predicate, bool invert, AppDelegate stack)
+ {
+ return builder.Use(a => new PredicateMiddleware(predicate,
+ invert ? stack : a, invert ? a : stack).Invoke);
+ }
+
+ public static IAppBuilder Where(this IAppBuilder builder,
+ Action<Environment, Action<bool>> predicate, Action<IAppBuilder> stack)
+ {
+ return builder.Predicate(predicate, true, builder.Build(stack));
+ }
+
+ public static IAppBuilder Unless(this IAppBuilder builder,
+ Action<Environment, Action<bool>> predicate, Action<IAppBuilder> stack)
+ {
+ return builder.Predicate(predicate, false, builder.Build(stack));
+ }
+
+ class PredicateMiddleware
+ {
+ AppDelegate pass, fail;
+ Action<Environment, Action<bool>> predicate;
+
+ public PredicateMiddleware(Action<Environment, Action<bool>> predicate, AppDelegate pass, AppDelegate fail)
+ {
+ this.predicate = predicate;
+ this.pass = pass;
+ this.fail = fail;
+ }
+
+ public void Invoke(IDictionary<string, object> env, ResultDelegate result, Action<Exception> fault)
+ {
+ predicate(env as Environment ?? new Environment(env), b =>
+ {
+ if (b)
+ pass(env, result, fault);
+ else
+ fail(env, result, fault);
+ });
+ }
+ }
+ }
+}
+
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using Gate.Builder;
+using NUnit.Framework;
+using Gate.Middleware;
+using Gate.TestHelpers;
+
+namespace Gate.Middleware.Tests
+{
+ [TestFixture]
+ public class BasicAuthTests
+ {
+ [Test]
+ public void GetBasicAuth_returns_null_if_no_auth_header()
+ {
+ var e = new Environment() { Headers = new Dictionary<string, string>() };
+ Assert.That(e.GetBasicAuth(), Is.Null);
+ }
+
+ [Test]
+ public void GetBasicAuth_return_null_if_auth_header_value_isnt_Basic()
+ {
+ var e = new Environment() { Headers = new Dictionary<string, string>()
+ { { "authorization", "Foo" } } };
+ Assert.That(e.GetBasicAuth(), Is.Null);
+ }
+
+ [Test]
+ public void GetBasicAuth_decodes_basic_auth()
+ {
+ var e = new Environment() { Headers = new Dictionary<string, string>()
+ { { "authorization", "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" } } };
+ Assert.That(e.GetBasicAuth(), Is.EqualTo("Aladdin:open sesame"));
+ }
+
+ [Test]
+ public void RequireAuth_falls_through_if_authenticated()
+ {
+ var result = AppUtils.Call(AppBuilder.BuildConfiguration(b =>
+ b.RequireAuth((e, c) => c(true), "RealmString")
+ .Run(AppUtils.Simple("200 OK", null, null))));
+
+ Assert.That(result.Status, Is.EqualTo("200 OK"));
+ }
+
+ [Test]
+ public void RequireAuth_returns_401_if_not_authenticated()
+ {
+ var result = AppUtils.Call(AppBuilder.BuildConfiguration(b =>
+ b.RequireAuth((e, c) => c(false), "RealmString")
+ .Run(AppUtils.Simple("200 OK", null, null))));
+
+ Assert.That(result.Status, Is.EqualTo("401 Authorization Required"));
+ Assert.That(result.Headers["WWW-Authenticate"], Is.EqualTo("Basic Realm=\"RealmString\""));
+ }
+ }
+}
+
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>10.0.0</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{AFFF8587-C837-433F-913A-BF34B0885243}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <RootNamespace>Gate.Middleware.Tests</RootNamespace>
+ <AssemblyName>Gate.Middleware.Tests</AssemblyName>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug</OutputPath>
+ <DefineConstants>DEBUG</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>none</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Release</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <ItemGroup>
+ <Reference Include="nunit.framework">
+ <HintPath>..\..\..\packages\NUnit.2.5.9.10348\lib\nunit.framework.dll</HintPath>
+ </Reference>
+ <Reference Include="nunit.mocks">
+ <HintPath>..\..\..\packages\NUnit.2.5.9.10348\lib\nunit.mocks.dll</HintPath>
+ </Reference>
+ <Reference Include="pnunit.framework">
+ <HintPath>..\..\..\packages\NUnit.2.5.9.10348\lib\pnunit.framework.dll</HintPath>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\Gate.Middleware\Gate.Middleware.csproj">
+ <Project>{60C36D8F-BE53-4733-BD92-CFA103D46020}</Project>
+ <Name>Gate.Middleware</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Gate\Gate.csproj">
+ <Project>{BE3CCA19-0795-4477-A4D4-ABF45474ACBF}</Project>
+ <Name>Gate</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Gate.Owin\Gate.Owin.csproj">
+ <Project>{B60C657C-80DA-4AA3-8796-AD920D5EB5A0}</Project>
+ <Name>Gate.Owin</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Gate.TestHelpers\Gate.TestHelpers.csproj">
+ <Project>{E4256EDF-0B54-4715-8E66-8D4D4887E15F}</Project>
+ <Name>Gate.TestHelpers</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="PredicateTests.cs" />
+ <Compile Include="BasicAuthTests.cs" />
+ </ItemGroup>
+</Project>
Oops, something went wrong.

0 comments on commit c7fd326

Please sign in to comment.