Skip to content
This repository was archived by the owner on Dec 13, 2018. It is now read-only.

Commit 5cc1fea

Browse files
committed
Add CookiePolicy Middleware
1 parent 1c0768f commit 5cc1fea

17 files changed

+797
-2
lines changed

Security.sln

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Authorizat
4646
EndProject
4747
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Authorization", "src\Microsoft.AspNet.Authorization\Microsoft.AspNet.Authorization.xproj", "{6AB3E514-5894-4131-9399-DC7D5284ADDB}"
4848
EndProject
49+
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.CookiePolicy", "src\Microsoft.AspNet.CookiePolicy\Microsoft.AspNet.CookiePolicy.xproj", "{86183DC3-02A8-4A68-8B60-71ECEC066E79}"
50+
EndProject
51+
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.CookiePolicy.Test", "test\Microsoft.AspNet.CookiePolicy.Test\Microsoft.AspNet.CookiePolicy.Test.xproj", "{1790E052-646F-4529-B90E-6FEA95520D69}"
52+
EndProject
4953
Global
5054
GlobalSection(SolutionConfigurationPlatforms) = preSolution
5155
Debug|Any CPU = Debug|Any CPU
@@ -242,6 +246,30 @@ Global
242246
{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|Mixed Platforms.Build.0 = Release|Any CPU
243247
{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|x86.ActiveCfg = Release|Any CPU
244248
{6AB3E514-5894-4131-9399-DC7D5284ADDB}.Release|x86.Build.0 = Release|Any CPU
249+
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
250+
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|Any CPU.Build.0 = Debug|Any CPU
251+
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
252+
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
253+
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|x86.ActiveCfg = Debug|Any CPU
254+
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Debug|x86.Build.0 = Debug|Any CPU
255+
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|Any CPU.ActiveCfg = Release|Any CPU
256+
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|Any CPU.Build.0 = Release|Any CPU
257+
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
258+
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|Mixed Platforms.Build.0 = Release|Any CPU
259+
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|x86.ActiveCfg = Release|Any CPU
260+
{86183DC3-02A8-4A68-8B60-71ECEC066E79}.Release|x86.Build.0 = Release|Any CPU
261+
{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
262+
{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|Any CPU.Build.0 = Debug|Any CPU
263+
{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
264+
{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
265+
{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|x86.ActiveCfg = Debug|Any CPU
266+
{1790E052-646F-4529-B90E-6FEA95520D69}.Debug|x86.Build.0 = Debug|Any CPU
267+
{1790E052-646F-4529-B90E-6FEA95520D69}.Release|Any CPU.ActiveCfg = Release|Any CPU
268+
{1790E052-646F-4529-B90E-6FEA95520D69}.Release|Any CPU.Build.0 = Release|Any CPU
269+
{1790E052-646F-4529-B90E-6FEA95520D69}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
270+
{1790E052-646F-4529-B90E-6FEA95520D69}.Release|Mixed Platforms.Build.0 = Release|Any CPU
271+
{1790E052-646F-4529-B90E-6FEA95520D69}.Release|x86.ActiveCfg = Release|Any CPU
272+
{1790E052-646F-4529-B90E-6FEA95520D69}.Release|x86.Build.0 = Release|Any CPU
245273
EndGlobalSection
246274
GlobalSection(SolutionProperties) = preSolution
247275
HideSolutionNode = FALSE
@@ -263,5 +291,7 @@ Global
263291
{2755BFE5-7421-4A31-A644-F817DF5CAA98} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
264292
{7AF5AD96-EB6E-4D0E-8ABE-C0B543C0F4C2} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
265293
{6AB3E514-5894-4131-9399-DC7D5284ADDB} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
294+
{86183DC3-02A8-4A68-8B60-71ECEC066E79} = {4D2B6A51-2F9F-44F5-8131-EA5CAC053652}
295+
{1790E052-646F-4529-B90E-6FEA95520D69} = {7BF11F3A-60B6-4796-B504-579C67FFBA34}
266296
EndGlobalSection
267297
EndGlobal
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using Microsoft.AspNet.Http;
5+
6+
namespace Microsoft.AspNet.CookiePolicy
7+
{
8+
public class AppendCookieContext
9+
{
10+
public AppendCookieContext(HttpContext context, CookieOptions options, string name, string value)
11+
{
12+
Context = context;
13+
CookieOptions = options;
14+
CookieName = name;
15+
CookieValue = value;
16+
}
17+
18+
public HttpContext Context { get; }
19+
public CookieOptions CookieOptions { get; }
20+
public string CookieName { get; set; }
21+
public string CookieValue { get; set; }
22+
}
23+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using Microsoft.AspNet.CookiePolicy;
6+
7+
namespace Microsoft.AspNet.Builder
8+
{
9+
/// <summary>
10+
/// Extension methods provided by the cookie policy middleware
11+
/// </summary>
12+
public static class CookiePolicyAppBuilderExtensions
13+
{
14+
/// <summary>
15+
/// Adds a cookie policy middleware to your web application pipeline.
16+
/// </summary>
17+
/// <param name="app">The IApplicationBuilder passed to your configuration method</param>
18+
/// <param name="options">The options for the middleware</param>
19+
/// <returns>The original app parameter</returns>
20+
public static IApplicationBuilder UseCookiePolicy(this IApplicationBuilder app, CookiePolicyOptions options)
21+
{
22+
return app.UseMiddleware<CookiePolicyMiddleware>(options);
23+
}
24+
25+
/// <summary>
26+
/// Adds a cookie policy middleware to your web application pipeline.
27+
/// </summary>
28+
/// <param name="app">The IApplicationBuilder passed to your configuration method</param>
29+
/// <param name="configureOptions">Used to configure the options for the middleware</param>
30+
/// <returns>The original app parameter</returns>
31+
public static IApplicationBuilder UseCookiePolicy(this IApplicationBuilder app, Action<CookiePolicyOptions> configureOptions)
32+
{
33+
var options = new CookiePolicyOptions();
34+
if (configureOptions != null)
35+
{
36+
configureOptions(options);
37+
}
38+
return app.UseCookiePolicy(options);
39+
}
40+
}
41+
}
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Threading.Tasks;
6+
using Microsoft.AspNet.Builder;
7+
using Microsoft.AspNet.Http;
8+
using Microsoft.AspNet.Http.Features;
9+
using Microsoft.AspNet.Http.Features.Internal;
10+
11+
namespace Microsoft.AspNet.CookiePolicy
12+
{
13+
public class CookiePolicyMiddleware
14+
{
15+
private readonly RequestDelegate _next;
16+
17+
public CookiePolicyMiddleware(
18+
RequestDelegate next,
19+
CookiePolicyOptions options)
20+
{
21+
Options = options;
22+
_next = next;
23+
}
24+
25+
public CookiePolicyOptions Options { get; set; }
26+
27+
public Task Invoke(HttpContext context)
28+
{
29+
var feature = context.Features.Get<IResponseCookiesFeature>() ?? new ResponseCookiesFeature(context.Features);
30+
context.Features.Set<IResponseCookiesFeature>(new CookiesWrapperFeature(context, Options, feature));
31+
return _next(context);
32+
}
33+
34+
private class CookiesWrapperFeature : IResponseCookiesFeature
35+
{
36+
public CookiesWrapperFeature(HttpContext context, CookiePolicyOptions options, IResponseCookiesFeature feature)
37+
{
38+
Wrapper = new CookiesWrapper(context, options, feature);
39+
}
40+
41+
public IResponseCookies Wrapper { get; }
42+
43+
public IResponseCookies Cookies
44+
{
45+
get
46+
{
47+
return Wrapper;
48+
}
49+
}
50+
}
51+
52+
private class CookiesWrapper : IResponseCookies
53+
{
54+
public CookiesWrapper(HttpContext context, CookiePolicyOptions options, IResponseCookiesFeature feature)
55+
{
56+
Context = context;
57+
Feature = feature;
58+
Policy = options;
59+
}
60+
61+
public HttpContext Context { get; }
62+
63+
public IResponseCookiesFeature Feature { get; }
64+
65+
public IResponseCookies Cookies
66+
{
67+
get
68+
{
69+
return Feature.Cookies;
70+
}
71+
}
72+
73+
public CookiePolicyOptions Policy { get; }
74+
75+
private bool PolicyRequiresCookieOptions()
76+
{
77+
return Policy.HttpOnly != HttpOnlyPolicy.None || Policy.Secure != SecurePolicy.None;
78+
}
79+
80+
public void Append(string key, string value)
81+
{
82+
if (PolicyRequiresCookieOptions() || Policy.OnAppendCookie != null)
83+
{
84+
Append(key, value, new CookieOptions());
85+
}
86+
else
87+
{
88+
Cookies.Append(key, value);
89+
}
90+
}
91+
92+
public void Append(string key, string value, CookieOptions options)
93+
{
94+
if (options == null)
95+
{
96+
throw new ArgumentNullException(nameof(options));
97+
}
98+
99+
ApplyPolicy(options);
100+
if (Policy.OnAppendCookie != null)
101+
{
102+
var context = new AppendCookieContext(Context, options, key, value);
103+
Policy.OnAppendCookie(context);
104+
key = context.CookieName;
105+
value = context.CookieValue;
106+
}
107+
Cookies.Append(key, value, options);
108+
}
109+
110+
public void Delete(string key)
111+
{
112+
if (PolicyRequiresCookieOptions() || Policy.OnDeleteCookie != null)
113+
{
114+
Delete(key, new CookieOptions());
115+
}
116+
else
117+
{
118+
Cookies.Delete(key);
119+
}
120+
}
121+
122+
public void Delete(string key, CookieOptions options)
123+
{
124+
if (options == null)
125+
{
126+
throw new ArgumentNullException(nameof(options));
127+
}
128+
129+
ApplyPolicy(options);
130+
if (Policy.OnDeleteCookie != null)
131+
{
132+
var context = new DeleteCookieContext(Context, options, key);
133+
Policy.OnDeleteCookie(context);
134+
key = context.CookieName;
135+
}
136+
Cookies.Delete(key, options);
137+
}
138+
139+
private void ApplyPolicy(CookieOptions options)
140+
{
141+
switch (Policy.Secure)
142+
{
143+
case SecurePolicy.Always:
144+
options.Secure = true;
145+
break;
146+
case SecurePolicy.SameAsRequest:
147+
options.Secure = Context.Request.IsHttps;
148+
break;
149+
case SecurePolicy.None:
150+
break;
151+
default:
152+
throw new InvalidOperationException();
153+
}
154+
switch (Policy.HttpOnly)
155+
{
156+
case HttpOnlyPolicy.Always:
157+
options.HttpOnly = true;
158+
break;
159+
case HttpOnlyPolicy.None:
160+
break;
161+
default:
162+
throw new InvalidOperationException();
163+
}
164+
}
165+
}
166+
}
167+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
6+
namespace Microsoft.AspNet.CookiePolicy
7+
{
8+
public class CookiePolicyOptions
9+
{
10+
public HttpOnlyPolicy HttpOnly { get; set; } = HttpOnlyPolicy.None;
11+
public SecurePolicy Secure { get; set; } = SecurePolicy.None;
12+
13+
public Action<AppendCookieContext> OnAppendCookie { get; set; }
14+
public Action<DeleteCookieContext> OnDeleteCookie { get; set; }
15+
}
16+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using Microsoft.AspNet.Http;
5+
6+
namespace Microsoft.AspNet.CookiePolicy
7+
{
8+
public class DeleteCookieContext
9+
{
10+
public DeleteCookieContext(HttpContext context, CookieOptions options, string name)
11+
{
12+
Context = context;
13+
CookieOptions = options;
14+
CookieName = name;
15+
}
16+
17+
public HttpContext Context { get; }
18+
public CookieOptions CookieOptions { get; }
19+
public string CookieName { get; set; }
20+
}
21+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace Microsoft.AspNet.CookiePolicy
5+
{
6+
public enum HttpOnlyPolicy
7+
{
8+
None,
9+
Always
10+
}
11+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup>
4+
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
5+
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
6+
</PropertyGroup>
7+
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
8+
<PropertyGroup Label="Globals">
9+
<ProjectGuid>86183dc3-02a8-4a68-8b60-71ecec066e79</ProjectGuid>
10+
<RootNamespace>Microsoft.AspNet.CookiePolicy</RootNamespace>
11+
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
12+
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
13+
</PropertyGroup>
14+
15+
<PropertyGroup>
16+
<SchemaVersion>2.0</SchemaVersion>
17+
</PropertyGroup>
18+
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
19+
</Project>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Reflection;
5+
using System.Resources;
6+
7+
[assembly: AssemblyMetadata("Serviceable", "True")]
8+
[assembly: NeutralResourcesLanguage("en-us")]
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace Microsoft.AspNet.CookiePolicy
5+
{
6+
public enum SecurePolicy
7+
{
8+
None,
9+
Always,
10+
SameAsRequest
11+
}
12+
}

0 commit comments

Comments
 (0)