From f5173e44ae03227c1defbad89f6053b35f6c89d8 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 19 Jun 2014 13:42:01 -0700 Subject: [PATCH] Expand feature support for OWIN->K. --- .../Microsoft.AspNet.Owin.kproj | 3 +- src/Microsoft.AspNet.Owin/OwinEnvironment.cs | 36 ++------------- .../OwinFeatureCollection.cs | 40 +++++++++++++++-- src/Microsoft.AspNet.Owin/Utilities.cs | 45 +++++++++++++++++++ .../OwinFeatureCollectionTests.cs | 40 ++++++++++++++++- 5 files changed, 125 insertions(+), 39 deletions(-) create mode 100644 src/Microsoft.AspNet.Owin/Utilities.cs diff --git a/src/Microsoft.AspNet.Owin/Microsoft.AspNet.Owin.kproj b/src/Microsoft.AspNet.Owin/Microsoft.AspNet.Owin.kproj index 825f49a06f..ea1daa11aa 100644 --- a/src/Microsoft.AspNet.Owin/Microsoft.AspNet.Owin.kproj +++ b/src/Microsoft.AspNet.Owin/Microsoft.AspNet.Owin.kproj @@ -25,6 +25,7 @@ + - + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Owin/OwinEnvironment.cs b/src/Microsoft.AspNet.Owin/OwinEnvironment.cs index 8f6f9c4951..040def476e 100644 --- a/src/Microsoft.AspNet.Owin/OwinEnvironment.cs +++ b/src/Microsoft.AspNet.Owin/OwinEnvironment.cs @@ -37,8 +37,8 @@ namespace Microsoft.AspNet.Owin { OwinConstants.RequestMethod, new FeatureMap(feature => feature.Method, (feature, value) => feature.Method = Convert.ToString(value)) }, { OwinConstants.RequestPathBase, new FeatureMap(feature => feature.PathBase, (feature, value) => feature.PathBase = Convert.ToString(value)) }, { OwinConstants.RequestPath, new FeatureMap(feature => feature.Path, (feature, value) => feature.Path = Convert.ToString(value)) }, - { OwinConstants.RequestQueryString, new FeatureMap(feature => RemoveQuestionMark(feature.QueryString), - (feature, value) => feature.QueryString = AddQuestionMark(Convert.ToString(value))) }, + { OwinConstants.RequestQueryString, new FeatureMap(feature => Utilities.RemoveQuestionMark(feature.QueryString), + (feature, value) => feature.QueryString = Utilities.AddQuestionMark(Convert.ToString(value))) }, { OwinConstants.RequestHeaders, new FeatureMap(feature => feature.Headers, (feature, value) => feature.Headers = (IDictionary)value) }, { OwinConstants.RequestBody, new FeatureMap(feature => feature.Body, (feature, value) => feature.Body = (Stream)value) }, @@ -62,7 +62,7 @@ namespace Microsoft.AspNet.Owin { OwinConstants.SendFiles.SendAsync, new FeatureMap(feature => new SendFileFunc(feature.SendFileAsync)) }, - { OwinConstants.Security.User, new FeatureMap(feature => feature.User, (feature, value) => feature.User = MakeClaimsPrincipal((IPrincipal)value)) }, + { OwinConstants.Security.User, new FeatureMap(feature => feature.User, (feature, value) => feature.User = Utilities.MakeClaimsPrincipal((IPrincipal)value)) }, }; if (context.Request.IsSecure) @@ -230,36 +230,6 @@ namespace Microsoft.AspNet.Owin throw new NotImplementedException(); } - private string RemoveQuestionMark(string queryString) - { - if (!string.IsNullOrEmpty(queryString)) - { - if (queryString[0] == '?') - { - return queryString.Substring(1); - } - } - return queryString; - } - - private string AddQuestionMark(string queryString) - { - if (!string.IsNullOrEmpty(queryString)) - { - return '?' + queryString; - } - return queryString; - } - - private ClaimsPrincipal MakeClaimsPrincipal(IPrincipal principal) - { - if (principal is ClaimsPrincipal) - { - return principal as ClaimsPrincipal; - } - return new ClaimsPrincipal(principal); - } - public class FeatureMap { public FeatureMap(Type featureInterface, Func getter) diff --git a/src/Microsoft.AspNet.Owin/OwinFeatureCollection.cs b/src/Microsoft.AspNet.Owin/OwinFeatureCollection.cs index f0ebf96365..c7af211b46 100644 --- a/src/Microsoft.AspNet.Owin/OwinFeatureCollection.cs +++ b/src/Microsoft.AspNet.Owin/OwinFeatureCollection.cs @@ -8,10 +8,13 @@ using System.IO; using System.Linq; using System.Net; using System.Reflection; +using System.Security.Claims; using System.Security.Cryptography.X509Certificates; +using System.Security.Principal; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.HttpFeature; +using Microsoft.AspNet.HttpFeature.Security; using Microsoft.AspNet.FeatureModel; namespace Microsoft.AspNet.Owin @@ -25,6 +28,8 @@ namespace Microsoft.AspNet.Owin IHttpConnectionFeature, IHttpSendFileFeature, IHttpClientCertificateFeature, + IHttpRequestLifetimeFeature, + IHttpAuthenticationFeature, IOwinEnvironmentFeature { public IDictionary Environment { get; set; } @@ -81,8 +86,8 @@ namespace Microsoft.AspNet.Owin string IHttpRequestFeature.QueryString { - get { return Prop(OwinConstants.RequestQueryString); } - set { Prop(OwinConstants.RequestQueryString, value); } + get { return Utilities.AddQuestionMark(Prop(OwinConstants.RequestQueryString)); } + set { Prop(OwinConstants.RequestQueryString, Utilities.RemoveQuestionMark(value)); } } IDictionary IHttpRequestFeature.Headers @@ -203,11 +208,38 @@ namespace Microsoft.AspNet.Owin set { Prop(OwinConstants.CommonKeys.ClientCertificate, value); } } - Task IHttpClientCertificateFeature.GetClientCertificateAsync(CancellationToken cancellationToken) + async Task IHttpClientCertificateFeature.GetClientCertificateAsync(CancellationToken cancellationToken) + { + var loadAsync = Prop>(OwinConstants.CommonKeys.LoadClientCertAsync); + if (loadAsync != null) + { + await loadAsync(); + } + return Prop(OwinConstants.CommonKeys.ClientCertificate); + } + + CancellationToken IHttpRequestLifetimeFeature.OnRequestAborted + { + get { return Prop(OwinConstants.CallCancelled); } + } + + void IHttpRequestLifetimeFeature.Abort() { throw new NotImplementedException(); } + ClaimsPrincipal IHttpAuthenticationFeature.User + { + get { return Utilities.MakeClaimsPrincipal(Prop(OwinConstants.Security.User)); } + set { Prop(OwinConstants.Security.User, value); } + } + + IAuthenticationHandler IHttpAuthenticationFeature.Handler + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + public int Revision { get { return 0; } // Not modifiable @@ -249,6 +281,8 @@ namespace Microsoft.AspNet.Owin typeof(IHttpResponseFeature), typeof(IHttpConnectionFeature), typeof(IOwinEnvironmentFeature), + typeof(IHttpRequestLifetimeFeature), + typeof(IHttpAuthenticationFeature), }; if (SupportsSendFile) { diff --git a/src/Microsoft.AspNet.Owin/Utilities.cs b/src/Microsoft.AspNet.Owin/Utilities.cs new file mode 100644 index 0000000000..ba3a4d4180 --- /dev/null +++ b/src/Microsoft.AspNet.Owin/Utilities.cs @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Security.Claims; +using System.Security.Principal; + +namespace Microsoft.AspNet.Owin +{ + internal static class Utilities + { + internal static string RemoveQuestionMark(string queryString) + { + if (!string.IsNullOrEmpty(queryString)) + { + if (queryString[0] == '?') + { + return queryString.Substring(1); + } + } + return queryString; + } + + internal static string AddQuestionMark(string queryString) + { + if (!string.IsNullOrEmpty(queryString)) + { + return '?' + queryString; + } + return queryString; + } + + internal static ClaimsPrincipal MakeClaimsPrincipal(IPrincipal principal) + { + if (principal == null) + { + return null; + } + if (principal is ClaimsPrincipal) + { + return principal as ClaimsPrincipal; + } + return new ClaimsPrincipal(principal); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Owin.Tests/OwinFeatureCollectionTests.cs b/test/Microsoft.AspNet.Owin.Tests/OwinFeatureCollectionTests.cs index ca21c566de..663972150f 100644 --- a/test/Microsoft.AspNet.Owin.Tests/OwinFeatureCollectionTests.cs +++ b/test/Microsoft.AspNet.Owin.Tests/OwinFeatureCollectionTests.cs @@ -16,17 +16,53 @@ namespace Microsoft.AspNet.Owin object value; return features.TryGetValue(typeof(T), out value) ? (T)value : default(T); } + private T Get(IDictionary env, string key) + { + object value; + return env.TryGetValue(key, out value) ? (T)value : default(T); + } [Fact] public void OwinHttpEnvironmentCanBeCreated() { var env = new Dictionary { - {"owin.RequestMethod", "POST"} + { "owin.RequestMethod", "POST" }, + { "owin.RequestPath", "/path" }, + { "owin.RequestPathBase", "/pathBase" }, + { "owin.RequestQueryString", "name=value" }, }; var features = new FeatureObject(new OwinFeatureCollection(env)); - Assert.Equal(Get(features).Method, "POST"); + var requestFeature = Get(features); + Assert.Equal(requestFeature.Method, "POST"); + Assert.Equal(requestFeature.Path, "/path"); + Assert.Equal(requestFeature.PathBase, "/pathBase"); + Assert.Equal(requestFeature.QueryString, "?name=value"); + } + + [Fact] + public void OwinHttpEnvironmentCanBeModified() + { + var env = new Dictionary + { + { "owin.RequestMethod", "POST" }, + { "owin.RequestPath", "/path" }, + { "owin.RequestPathBase", "/pathBase" }, + { "owin.RequestQueryString", "name=value" }, + }; + var features = new FeatureObject(new OwinFeatureCollection(env)); + + var requestFeature = Get(features); + requestFeature.Method = "GET"; + requestFeature.Path = "/path2"; + requestFeature.PathBase = "/pathBase2"; + requestFeature.QueryString = "?name=value2"; + + Assert.Equal("GET", Get(env, "owin.RequestMethod")); + Assert.Equal("/path2", Get(env, "owin.RequestPath")); + Assert.Equal("/pathBase2", Get(env, "owin.RequestPathBase")); + Assert.Equal("name=value2", Get(env, "owin.RequestQueryString")); } [Fact]