From ff61a43031735f743da37b8619781079b222ce1d Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Mon, 23 Sep 2019 16:06:43 -0700 Subject: [PATCH 01/26] Merge branches --- Directory.Build.props | 7 ++++++- packageIcon.png | Bin 0 -> 7006 bytes .../src/Microsoft.AspNetCore.Analyzers.csproj | 1 + .../src/Microsoft.AspNetCore.Analyzers.nuspec | 1 + .../src/Microsoft.AspNetCore.Blazor.Build.csproj | 1 + .../src/Microsoft.AspNetCore.Blazor.Build.nuspec | 1 + .../Microsoft.AspNetCore.Blazor.DevServer.csproj | 1 + .../Microsoft.AspNetCore.Blazor.DevServer.nuspec | 1 + .../Microsoft.AspNetCore.Blazor.Templates.csproj | 4 ++++ .../Microsoft.AspNetCore.Blazor.Templates.nuspec | 1 + .../src/Microsoft.AspNetCore.Components.csproj | 1 + ...soft.AspNetCore.Components.multitarget.nuspec | 1 + ...ft.AspNetCore.Components.netcoreapp3.0.nuspec | 1 + .../SharedFramework/SharedFramework.wixproj | 4 ++++ .../SharedFrameworkPackage.nuspec | 1 + .../Windows/TargetingPack/TargetingPack.wixproj | 4 ++++ .../TargetingPack/TargetingPackPackage.nuspec | 1 + .../Microsoft.AspNetCore.Mvc.Analyzers.csproj | 1 + .../Microsoft.AspNetCore.Mvc.Analyzers.nuspec | 1 + ...Microsoft.AspNetCore.Mvc.Api.Analyzers.csproj | 1 + ...Microsoft.AspNetCore.Mvc.Api.Analyzers.nuspec | 1 + src/ProjectTemplates/TemplateProjects.props | 4 ++++ src/ProjectTemplates/templates.nuspec | 1 + ...osoft.Extensions.ApiDescription.Client.csproj | 1 + ...osoft.Extensions.ApiDescription.Client.nuspec | 1 + ...osoft.Extensions.ApiDescription.Server.csproj | 1 + ...osoft.Extensions.ApiDescription.Server.nuspec | 1 + 27 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 packageIcon.png diff --git a/Directory.Build.props b/Directory.Build.props index 66e5b316b1..e1bf86d4e1 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -46,7 +46,8 @@ nugetaspnet@microsoft.com - https://go.microsoft.com/fwlink/?LinkID=288859 + packageIcon.png + $(MSBuildThisFileDirectory)packageIcon.png https://asp.net $(MSBuildProjectDirectory) @@ -55,6 +56,10 @@ netcoreapp$(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion) + + + + true diff --git a/packageIcon.png b/packageIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..a0f1fdbf4d5eae0e561018cccee74f6a454cdb9c GIT binary patch literal 7006 zcmeHMXH-+`n%)#eMU;C)kZw7O2nvFLpcE@A^-u+AN(mh$UH*JD5Jjm{4}uUR zs5C(zdURn*zrcHqdVxK)P)7322TAMVbNR4HRzo3_~zdgjvf?Ot98@H{LHdy zK*)TM=g&B9f}+9IKfm=aF5e3_{PQJ$ zY4?9DHvtd+Y14o8TQs=)&+P)Wjb3|LIT@*NDqyYm#gu^q*EFSow<%yKVx`_Ka)!0 z2YAaQr%LYyQ%n$Rjx)e%JeM5_ov70FUMveJTS(J+%C4(L)~h*MQ8!wJtf_X{`Ol?k z;{27%#**2uiR&R6-eaRK1Mdgl2xHQ=uS(~VqsTVrsUnQhc zRIK5>@(05w3gHYdsI0;;sOO66pUEl)DGyD(D4>$7drUDFZ|uxx;-nWj7d|rj=u+D@ z-HU+mLOInrsXdSL1Z6nVB&D z@>f4!yq=_B+16+qw5k=4o#*tf;6Oe*F;`&L!)bT{U7Wc3YmG2;NRxb%woCt~*Yr2E zfwiUdS=7SK&5>df-aqY8lp~SEUG*ziXGvHMLp_#vgvVMQ*&{+d@(a>v4;7p_%Jte0Ga5zNbUI28WAgY5f?FX^;q`1WTw2~t|P54N&e^@=nFqDj}W#o z_-kZBWDQ%($YJH43Y7YrbjfsUrAEjla>?j0;YLdXxjK}P@xDGc%r&c)6`t?XW=*{r z%Z^p)?6*7obKU_;NZK_ejh9n&?qzO0#(}Uo+KSm|e}q1+f$wM!G8>lLvKK1UK^uz5 zDk&5(DuUnzQy{aQ8%b~*_4Ri`TOj}Dd{0OCls}^VD8=qDC%Q9tSSt5LZoxd!|ai3oGtf&cOy(`^W9zMNR;bII|OS+Pe(-9=f!m6}w zV>f(mH^BYE-=Wl=)Q2s2TF*j&tRkN0KOu3-(VN?4?-v|?W^Xj)@u4^bNB%bN+f|D= z?r1ey$UbahYv!qISaxV8>+1Mnz!M&S1o+~titx|65MA`iQMjscL!+LOGjZ?p>}x6d z4`FiZV9i-E6F8c|Fq37-TTTtJOdIZ9<*YrJU86UuQr6dipNC%AxT?lXa9U=`iq+2= zOT!CFUlJM1&INj~InR!=@x@{Z8BnvgL~_>nN)y@!r<0$uGCJ<0B-q!vZn@~#5^Ig8B}}g&dYBee=x50Wv$R^^f%aTE~g_a7&8Y(5L>! zkYgCl@1ZVqFSwkH(ns-EtYbOFLrarf#r6W9#x8rO<<_6h33faYV{<&_gBahO#ga9j z$|}=ea)vEm|Hb`E%L9Gn#Osxg( z&sxXz7lsse+_i@<_LUl@8$916h*m6!R?~zr_ZQU^H3F(aC1is#I$VP$GO(s!pT&Y# z85JYcwQqu6Ja6sje&x*)nOdx;bt1hNMTSwSikFeKE)+MRrW?mg=8mp^AR_kz{C%e* z32H_>c600^d$9)ob+$yzpyxHa+k0Sz7GG41I0A59bKJf?X}E6mX$pU~Wc%_?$2w1s zZEbk$svZ4U+WH;XPEb^-IqhGQX1U|z8KWp8&jVlWFPP+7Um6;oMy?>TFU`cMT5bYx z;7_~MfZ(sumPQHg++U)9PT=+=zxu+qmP==xJ&oI%XgD8=YZo%*rGq2U_J^D4d%7H`}jau-;<_^n?THcf9*rKD^J#%p%l zA8DILPr+wPY^MpxQbxGXG2f0xcjxSw;wjl53EsXe0poYHgfc(T;v5J;H$neUhElxe zrX0NdQ4e#4L4e-JmsN$%C+#BKX8TYA1YlhN`|QyqnlH{Igil*i0?NrD9qi2Fw_&~eMSk3UGyWzcay4oPaWE~nJ{R}-u+%oE z^4pk7G%~M66x6$a(@21!KD)Us1JG?!Xn4Zb;NYOn2SGc%JK!@mQv*PGMGxMb{#a4F z_#t!~GhhJR9)$w;fi20azFx86@7j4yB zpC7-bK<170rK@aOPg zDv69Iy;oMY0yq-ORy`~=Y8>ZQ_}+6m=ElBFD(BO@q9)h-K%)s9-^rh(;7T`vu={0p zCzf*G!~Iex?wWwWS?rOOYx{i!_Lh~OXJ7gYPR(bWfke`)l(GCjjtT06t7+0hHGHhh zA9y}JSM5#_xw|dqtlV?PVqZwGRm*pM)dvDj|LAzkF?4x}RLkCA#>G3V21ZLIt^gG< zQI&0O8}Rf;Def0;ZbweV+|x(R-?(Vnj5F9~eOT)4!nDr7Yq-5!y1bz1t;HjQSLn-A zt1qf%FzvKZ`+#!ufUYj;;FE!eL$>Pcse)qp0BW@>*U{2zo_CWHpgvHpnGofD&KYKY z+!}avbdRD^hZQf zU#$@f{W=^JvL7g)bcEZ<)O9tw4?Dxp&lksZ;$I_{?{l;o=>&}=tF-5MU&27^*rhJT zcd0DiLPxBSPJ<5cx}JGQAds^*(&j4-nHoTwx>dVUGJHkMM7w*nPbN5n_W)JJ zoSF~F)URWm1xS-QkhpAB(#}xq`0?;AQ=#^xj8iv{-*?l`8a;)kpuatAQXeVT+=;#A zT0rvGu`_`{>KMvxzgLkb$EeCy`RyvAx+nC!D381cssru;3nBjt{S>AGvQAs(kxLO{ zIp*xXImIAQJ>kiL&b~R(P_(nAu2z<~Dc*-_c3=C`sjCz@AZVOwgE5s@G#uy{iQNJ} z*pY1bjnx4K{yik#93ftw2}MI#Dt>w>)q5vp~-G zX7!=BUrYpB-3#04(mvmC$-Y!WY8${8gcraWB}q}i z(|PAS*SoXp)9`8tTYTuy7`=#uWFoR#J2(AVcxr-9uF+7kB$GxNkA$Vfoz}l40*Ydo zXReR;i`X4$Te~{&2?RE~^39WlS?>E>my@CS3|paiTe-zGjS$iwI*YbAHOwW*PD@wI z=Nl-L-*Y(4b+hX{-tb98arKb!Q^EK+RA0Lfp4`cv&x7o<`~ghNZ#@Z$`B6O*2R6%R z+kg>9tGG(TtYgVXWD_X)ySeq_3Tq2*GEPMlF@o;BBxfbxC%!xOuwUa+?wXac%Dce> z+d&$P_VsrSw*$bMY#z8~U%K$AIc8vOosw2D4`XdBe5NKVuc+s10x-cw)v;&2Yd`@# z6UL-Y1G;FY$G$?{@cwL6zaRL5p_lTzugeI5PB@eSk^x^LJ=N!qHsScr*=1fnx>1;L zY5eqB8dlecz6GSs<7{=#sl?FWEY66Ejk>f}1odw~P?}i0yH&4d%vKKZ@hTi7-IW8%;{(vI`&L;i z@`wN4O!SHFV&u%JzXt*g%E%4J$^z@6FOtA7Yc(*Rz2%_90Exxp+}r^Vb|pF?C;F8w zu&f+_Jsvg^Wp?I6!+uV$Bi#fzohClm^T{PdQzz%Nn}GENT0zaz{xqo+NWJ!QdLYKf zBHdX|LMnBh5jXZ;>OoAWv*rOX&O8Sbzjyl*y-%<2V2oE_*lEG(1GlpzBZ6aoOp%y8 ze&=uJp63A7*h}C9j-sY70bc4bHQr`@q#!@&!5LxUu`)c;-&WVK?$9+vP%D`7v^_`5 zrOcY7w(+sWUl!hkCI>q|qg_*OZ$os^0Fsg`di5ki_Tzr$8gh}#WNKHtX|hlAupfW6 zk_ZWVB&Hjb9ZbLk!Ie1lMyGd?qhgq8>{#iC>Kg^*taLx^YuW+VQG;}IK{6+Y@0i7& z6iRAQBlI8*LwK}P>x0;cL*en^{8^OvUg%KTXIa~~>xA%u_2)y{h_+YQ?tpDgX9rIe zOo3t5%oVK)PzXFaqN#F2^qJbgB3HzT`{nJcFO`#ATLWNBXfYU5CYHs&PnH^f*Wl6k z?<0KM*e@M?auAvtBi}A#6V#ej{yvSOE8v?4^Jb8y4~i{ zSIC{Kc9#!&HhKqJI9L>s*NbwiwWXI+w-X6TM}&3$PlPOE+G8HP8Hi(#UMtyKy= zLo(ZOb7qTQ^r{NHBg^h=C`gbboZigk0*;z5+XW@P;EzUwQZv5|SZ6W0tBbATVDt$& z4th!!{t_tBc>V9qZE^8&@=VbaMh;!ivCF~IC28PzN2Z{@`)H;y3+{?j%eQl6gP|I9 z-agi;Y>P($m>0yG48Z>=AC0W_h5((46THSuk)X||?u=A_N-{J)`M9Q^WnUMh84VTQ zIvQlFtG4Z5X~3!o0K!K+^E@{TZ;5W3XkNzy z*j?DZB4J)s(LK@K0K1T4u&xvPHDTX zs$=NfQalJo9RXF+0@j1~t~aK@*DAWgsI@Sl{8AP8%T`P`Vu~Tv_%ZmbJz^#V>NJZl-TbST^RMK5DlNOs$kegkbICLYRJk-}g{l-Wn^Vya`SL3T1tiIw^Z zm~h)cx+UimpKrqQ=$a*_BCrvMGi%5Nr5qU)hq|P1Tjp!gLgpIqRRIs`qsDGjcel*OH-c~&6W812bsUI z>umkx8_8Ottu&n?L`^t@;63h8!Nb19V4*G1v2?3e;$WrvvX7%#JaxH?R) zN@KLmgq3q$NONDrj=7c`8~kK5VTf>xS$Q2C8@T{(7ygTX1N^6hZ&3*F7Z@!5FaMz+ n@b3Qu^xx$8Uk}h2jH{d|uJ4jrSC|P(2)ca1@;v^m$K8JeR7TPQ literal 0 HcmV?d00001 diff --git a/src/Analyzers/Analyzers/src/Microsoft.AspNetCore.Analyzers.csproj b/src/Analyzers/Analyzers/src/Microsoft.AspNetCore.Analyzers.csproj index feec3324be..cc4201ca79 100644 --- a/src/Analyzers/Analyzers/src/Microsoft.AspNetCore.Analyzers.csproj +++ b/src/Analyzers/Analyzers/src/Microsoft.AspNetCore.Analyzers.csproj @@ -25,6 +25,7 @@ + diff --git a/src/Analyzers/Analyzers/src/Microsoft.AspNetCore.Analyzers.nuspec b/src/Analyzers/Analyzers/src/Microsoft.AspNetCore.Analyzers.nuspec index f906ece217..0780ae588d 100644 --- a/src/Analyzers/Analyzers/src/Microsoft.AspNetCore.Analyzers.nuspec +++ b/src/Analyzers/Analyzers/src/Microsoft.AspNetCore.Analyzers.nuspec @@ -7,5 +7,6 @@ + diff --git a/src/Components/Blazor/Build/src/Microsoft.AspNetCore.Blazor.Build.csproj b/src/Components/Blazor/Build/src/Microsoft.AspNetCore.Blazor.Build.csproj index adfa71ef6b..aa5a484bf5 100644 --- a/src/Components/Blazor/Build/src/Microsoft.AspNetCore.Blazor.Build.csproj +++ b/src/Components/Blazor/Build/src/Microsoft.AspNetCore.Blazor.Build.csproj @@ -23,6 +23,7 @@ + diff --git a/src/Components/Blazor/Build/src/Microsoft.AspNetCore.Blazor.Build.nuspec b/src/Components/Blazor/Build/src/Microsoft.AspNetCore.Blazor.Build.nuspec index ab73599f0b..56fee600d3 100644 --- a/src/Components/Blazor/Build/src/Microsoft.AspNetCore.Blazor.Build.nuspec +++ b/src/Components/Blazor/Build/src/Microsoft.AspNetCore.Blazor.Build.nuspec @@ -12,5 +12,6 @@ + diff --git a/src/Components/Blazor/DevServer/src/Microsoft.AspNetCore.Blazor.DevServer.csproj b/src/Components/Blazor/DevServer/src/Microsoft.AspNetCore.Blazor.DevServer.csproj index b12f55ef82..3862555a0e 100644 --- a/src/Components/Blazor/DevServer/src/Microsoft.AspNetCore.Blazor.DevServer.csproj +++ b/src/Components/Blazor/DevServer/src/Microsoft.AspNetCore.Blazor.DevServer.csproj @@ -33,6 +33,7 @@ + diff --git a/src/Components/Blazor/DevServer/src/Microsoft.AspNetCore.Blazor.DevServer.nuspec b/src/Components/Blazor/DevServer/src/Microsoft.AspNetCore.Blazor.DevServer.nuspec index 5142ba2080..48e4e8b238 100644 --- a/src/Components/Blazor/DevServer/src/Microsoft.AspNetCore.Blazor.DevServer.nuspec +++ b/src/Components/Blazor/DevServer/src/Microsoft.AspNetCore.Blazor.DevServer.nuspec @@ -7,5 +7,6 @@ + diff --git a/src/Components/Blazor/Templates/src/Microsoft.AspNetCore.Blazor.Templates.csproj b/src/Components/Blazor/Templates/src/Microsoft.AspNetCore.Blazor.Templates.csproj index c91a32128d..640d8f21d0 100644 --- a/src/Components/Blazor/Templates/src/Microsoft.AspNetCore.Blazor.Templates.csproj +++ b/src/Components/Blazor/Templates/src/Microsoft.AspNetCore.Blazor.Templates.csproj @@ -15,6 +15,10 @@ false + + + + diff --git a/src/Components/Blazor/Templates/src/Microsoft.AspNetCore.Blazor.Templates.nuspec b/src/Components/Blazor/Templates/src/Microsoft.AspNetCore.Blazor.Templates.nuspec index 70b93d7253..babb09b520 100644 --- a/src/Components/Blazor/Templates/src/Microsoft.AspNetCore.Blazor.Templates.nuspec +++ b/src/Components/Blazor/Templates/src/Microsoft.AspNetCore.Blazor.Templates.nuspec @@ -11,5 +11,6 @@ src="content/**" exclude="**/bin/**;**/obj/**;**/.template.config.src/**;content/Directory.Build.props;content/Directory.Build.targets;" target="Content" /> + diff --git a/src/Components/Components/src/Microsoft.AspNetCore.Components.csproj b/src/Components/Components/src/Microsoft.AspNetCore.Components.csproj index a7ad3493c9..8d5bf5328e 100644 --- a/src/Components/Components/src/Microsoft.AspNetCore.Components.csproj +++ b/src/Components/Components/src/Microsoft.AspNetCore.Components.csproj @@ -48,6 +48,7 @@ + diff --git a/src/Components/Components/src/Microsoft.AspNetCore.Components.multitarget.nuspec b/src/Components/Components/src/Microsoft.AspNetCore.Components.multitarget.nuspec index 6324ea3136..14934a1d76 100644 --- a/src/Components/Components/src/Microsoft.AspNetCore.Components.multitarget.nuspec +++ b/src/Components/Components/src/Microsoft.AspNetCore.Components.multitarget.nuspec @@ -20,6 +20,7 @@ + diff --git a/src/Components/Components/src/Microsoft.AspNetCore.Components.netcoreapp3.0.nuspec b/src/Components/Components/src/Microsoft.AspNetCore.Components.netcoreapp3.0.nuspec index 8dec24f270..615d24fbdc 100644 --- a/src/Components/Components/src/Microsoft.AspNetCore.Components.netcoreapp3.0.nuspec +++ b/src/Components/Components/src/Microsoft.AspNetCore.Components.netcoreapp3.0.nuspec @@ -14,6 +14,7 @@ + diff --git a/src/Installers/Windows/SharedFramework/SharedFramework.wixproj b/src/Installers/Windows/SharedFramework/SharedFramework.wixproj index 4752953ec2..afb754e2dd 100644 --- a/src/Installers/Windows/SharedFramework/SharedFramework.wixproj +++ b/src/Installers/Windows/SharedFramework/SharedFramework.wixproj @@ -24,6 +24,10 @@ $(RepoRoot)\src\Installers\Windows\SharedFramework\SharedFrameworkPackage.nuspec + + + + $(WixExtDir)\WixDependencyExtension.dll diff --git a/src/Installers/Windows/SharedFramework/SharedFrameworkPackage.nuspec b/src/Installers/Windows/SharedFramework/SharedFrameworkPackage.nuspec index b5b8c43d9e..ecbdf5d60c 100644 --- a/src/Installers/Windows/SharedFramework/SharedFrameworkPackage.nuspec +++ b/src/Installers/Windows/SharedFramework/SharedFrameworkPackage.nuspec @@ -15,5 +15,6 @@ + diff --git a/src/Installers/Windows/TargetingPack/TargetingPack.wixproj b/src/Installers/Windows/TargetingPack/TargetingPack.wixproj index d8b2b051af..80065cb692 100644 --- a/src/Installers/Windows/TargetingPack/TargetingPack.wixproj +++ b/src/Installers/Windows/TargetingPack/TargetingPack.wixproj @@ -22,6 +22,10 @@ $(RepoRoot)\src\Installers\Windows\TargetingPack\TargetingPackPackage.nuspec + + + + $(WixExtDir)\WixDependencyExtension.dll diff --git a/src/Installers/Windows/TargetingPack/TargetingPackPackage.nuspec b/src/Installers/Windows/TargetingPack/TargetingPackPackage.nuspec index d5ef9a2069..10301e289f 100644 --- a/src/Installers/Windows/TargetingPack/TargetingPackPackage.nuspec +++ b/src/Installers/Windows/TargetingPack/TargetingPackPackage.nuspec @@ -14,5 +14,6 @@ + diff --git a/src/Mvc/Mvc.Analyzers/src/Microsoft.AspNetCore.Mvc.Analyzers.csproj b/src/Mvc/Mvc.Analyzers/src/Microsoft.AspNetCore.Mvc.Analyzers.csproj index 2ece75d8d8..b098c7cad2 100644 --- a/src/Mvc/Mvc.Analyzers/src/Microsoft.AspNetCore.Mvc.Analyzers.csproj +++ b/src/Mvc/Mvc.Analyzers/src/Microsoft.AspNetCore.Mvc.Analyzers.csproj @@ -19,6 +19,7 @@ + diff --git a/src/Mvc/Mvc.Analyzers/src/Microsoft.AspNetCore.Mvc.Analyzers.nuspec b/src/Mvc/Mvc.Analyzers/src/Microsoft.AspNetCore.Mvc.Analyzers.nuspec index f906ece217..0780ae588d 100644 --- a/src/Mvc/Mvc.Analyzers/src/Microsoft.AspNetCore.Mvc.Analyzers.nuspec +++ b/src/Mvc/Mvc.Analyzers/src/Microsoft.AspNetCore.Mvc.Analyzers.nuspec @@ -7,5 +7,6 @@ + diff --git a/src/Mvc/Mvc.Api.Analyzers/src/Microsoft.AspNetCore.Mvc.Api.Analyzers.csproj b/src/Mvc/Mvc.Api.Analyzers/src/Microsoft.AspNetCore.Mvc.Api.Analyzers.csproj index d3a6e138f1..0ae605cb69 100644 --- a/src/Mvc/Mvc.Api.Analyzers/src/Microsoft.AspNetCore.Mvc.Api.Analyzers.csproj +++ b/src/Mvc/Mvc.Api.Analyzers/src/Microsoft.AspNetCore.Mvc.Api.Analyzers.csproj @@ -24,6 +24,7 @@ + diff --git a/src/Mvc/Mvc.Api.Analyzers/src/Microsoft.AspNetCore.Mvc.Api.Analyzers.nuspec b/src/Mvc/Mvc.Api.Analyzers/src/Microsoft.AspNetCore.Mvc.Api.Analyzers.nuspec index f906ece217..0780ae588d 100644 --- a/src/Mvc/Mvc.Api.Analyzers/src/Microsoft.AspNetCore.Mvc.Api.Analyzers.nuspec +++ b/src/Mvc/Mvc.Api.Analyzers/src/Microsoft.AspNetCore.Mvc.Api.Analyzers.nuspec @@ -7,5 +7,6 @@ + diff --git a/src/ProjectTemplates/TemplateProjects.props b/src/ProjectTemplates/TemplateProjects.props index 8cfab01c93..fd6dc06fe4 100644 --- a/src/ProjectTemplates/TemplateProjects.props +++ b/src/ProjectTemplates/TemplateProjects.props @@ -21,4 +21,8 @@ + + + + diff --git a/src/ProjectTemplates/templates.nuspec b/src/ProjectTemplates/templates.nuspec index 8e85ee528c..f603e4757c 100644 --- a/src/ProjectTemplates/templates.nuspec +++ b/src/ProjectTemplates/templates.nuspec @@ -11,5 +11,6 @@ src="content/**" exclude="**/node_modules/**;**/bin/**;**/obj/**;**/.vs/**;**/.vscode/**;**/ClientApp/dist/**;**/wwwroot/dist/**;content/Directory.Build.*" target="" /> + diff --git a/src/Tools/Extensions.ApiDescription.Client/src/Microsoft.Extensions.ApiDescription.Client.csproj b/src/Tools/Extensions.ApiDescription.Client/src/Microsoft.Extensions.ApiDescription.Client.csproj index c50a0115fa..cef31805db 100644 --- a/src/Tools/Extensions.ApiDescription.Client/src/Microsoft.Extensions.ApiDescription.Client.csproj +++ b/src/Tools/Extensions.ApiDescription.Client/src/Microsoft.Extensions.ApiDescription.Client.csproj @@ -21,5 +21,6 @@ + diff --git a/src/Tools/Extensions.ApiDescription.Client/src/Microsoft.Extensions.ApiDescription.Client.nuspec b/src/Tools/Extensions.ApiDescription.Client/src/Microsoft.Extensions.ApiDescription.Client.nuspec index 23d654d168..20e8384e0c 100644 --- a/src/Tools/Extensions.ApiDescription.Client/src/Microsoft.Extensions.ApiDescription.Client.nuspec +++ b/src/Tools/Extensions.ApiDescription.Client/src/Microsoft.Extensions.ApiDescription.Client.nuspec @@ -8,5 +8,6 @@ + diff --git a/src/Tools/Extensions.ApiDescription.Server/src/Microsoft.Extensions.ApiDescription.Server.csproj b/src/Tools/Extensions.ApiDescription.Server/src/Microsoft.Extensions.ApiDescription.Server.csproj index e0d39cff01..c4c5f3aa7f 100644 --- a/src/Tools/Extensions.ApiDescription.Server/src/Microsoft.Extensions.ApiDescription.Server.csproj +++ b/src/Tools/Extensions.ApiDescription.Server/src/Microsoft.Extensions.ApiDescription.Server.csproj @@ -30,6 +30,7 @@ + diff --git a/src/Tools/Extensions.ApiDescription.Server/src/Microsoft.Extensions.ApiDescription.Server.nuspec b/src/Tools/Extensions.ApiDescription.Server/src/Microsoft.Extensions.ApiDescription.Server.nuspec index 2ffc3b4f87..7fe0e38e93 100644 --- a/src/Tools/Extensions.ApiDescription.Server/src/Microsoft.Extensions.ApiDescription.Server.nuspec +++ b/src/Tools/Extensions.ApiDescription.Server/src/Microsoft.Extensions.ApiDescription.Server.nuspec @@ -11,5 +11,6 @@ + From 8c49f8937dfa60a10bad4b327b9a3de57a0527ef Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Tue, 24 Sep 2019 13:31:51 -0700 Subject: [PATCH 02/26] Add icon metadata to manually generated .nuspecs --- .../Analyzers/src/Microsoft.AspNetCore.Analyzers.nuspec | 1 + .../Blazor/Build/src/Microsoft.AspNetCore.Blazor.Build.nuspec | 1 + .../DevServer/src/Microsoft.AspNetCore.Blazor.DevServer.nuspec | 1 + .../Templates/src/Microsoft.AspNetCore.Blazor.Templates.nuspec | 1 + .../src/Microsoft.AspNetCore.Components.multitarget.nuspec | 1 + .../src/Microsoft.AspNetCore.Components.netcoreapp3.0.nuspec | 1 + .../Windows/SharedFramework/SharedFrameworkPackage.nuspec | 1 + src/Installers/Windows/TargetingPack/TargetingPackPackage.nuspec | 1 + .../Mvc.Analyzers/src/Microsoft.AspNetCore.Mvc.Analyzers.nuspec | 1 + .../src/Microsoft.AspNetCore.Mvc.Api.Analyzers.nuspec | 1 + src/ProjectTemplates/templates.nuspec | 1 + .../src/Microsoft.Extensions.ApiDescription.Client.nuspec | 1 + .../src/Microsoft.Extensions.ApiDescription.Server.nuspec | 1 + 13 files changed, 13 insertions(+) diff --git a/src/Analyzers/Analyzers/src/Microsoft.AspNetCore.Analyzers.nuspec b/src/Analyzers/Analyzers/src/Microsoft.AspNetCore.Analyzers.nuspec index 0780ae588d..106615a7da 100644 --- a/src/Analyzers/Analyzers/src/Microsoft.AspNetCore.Analyzers.nuspec +++ b/src/Analyzers/Analyzers/src/Microsoft.AspNetCore.Analyzers.nuspec @@ -2,6 +2,7 @@ $CommonMetadataElements$ + packageIcon.png diff --git a/src/Components/Blazor/Build/src/Microsoft.AspNetCore.Blazor.Build.nuspec b/src/Components/Blazor/Build/src/Microsoft.AspNetCore.Blazor.Build.nuspec index 56fee600d3..feffe95c50 100644 --- a/src/Components/Blazor/Build/src/Microsoft.AspNetCore.Blazor.Build.nuspec +++ b/src/Components/Blazor/Build/src/Microsoft.AspNetCore.Blazor.Build.nuspec @@ -5,6 +5,7 @@ + packageIcon.png diff --git a/src/Components/Blazor/DevServer/src/Microsoft.AspNetCore.Blazor.DevServer.nuspec b/src/Components/Blazor/DevServer/src/Microsoft.AspNetCore.Blazor.DevServer.nuspec index 48e4e8b238..b59725fc14 100644 --- a/src/Components/Blazor/DevServer/src/Microsoft.AspNetCore.Blazor.DevServer.nuspec +++ b/src/Components/Blazor/DevServer/src/Microsoft.AspNetCore.Blazor.DevServer.nuspec @@ -2,6 +2,7 @@ $CommonMetadataElements$ + packageIcon.png diff --git a/src/Components/Blazor/Templates/src/Microsoft.AspNetCore.Blazor.Templates.nuspec b/src/Components/Blazor/Templates/src/Microsoft.AspNetCore.Blazor.Templates.nuspec index babb09b520..cde7bc4c1f 100644 --- a/src/Components/Blazor/Templates/src/Microsoft.AspNetCore.Blazor.Templates.nuspec +++ b/src/Components/Blazor/Templates/src/Microsoft.AspNetCore.Blazor.Templates.nuspec @@ -5,6 +5,7 @@ + packageIcon.png + packageIcon.png diff --git a/src/Components/Components/src/Microsoft.AspNetCore.Components.netcoreapp3.0.nuspec b/src/Components/Components/src/Microsoft.AspNetCore.Components.netcoreapp3.0.nuspec index 615d24fbdc..d218582bba 100644 --- a/src/Components/Components/src/Microsoft.AspNetCore.Components.netcoreapp3.0.nuspec +++ b/src/Components/Components/src/Microsoft.AspNetCore.Components.netcoreapp3.0.nuspec @@ -9,6 +9,7 @@ + packageIcon.png diff --git a/src/Installers/Windows/SharedFramework/SharedFrameworkPackage.nuspec b/src/Installers/Windows/SharedFramework/SharedFrameworkPackage.nuspec index ecbdf5d60c..e0deb1cb9f 100644 --- a/src/Installers/Windows/SharedFramework/SharedFrameworkPackage.nuspec +++ b/src/Installers/Windows/SharedFramework/SharedFrameworkPackage.nuspec @@ -8,6 +8,7 @@ Microsoft https://www.microsoft.com/net/dotnet_library_license.htm https://github.com/aspnet/aspnetcore + packageIcon.png true $MAJOR$.$MINOR$ ASP.NET Core TargetingPack ($ARCH$) Windows Installer MSI as a .nupkg for internal Visual Studio build consumption © Microsoft Corporation. All rights reserved. diff --git a/src/Installers/Windows/TargetingPack/TargetingPackPackage.nuspec b/src/Installers/Windows/TargetingPack/TargetingPackPackage.nuspec index 10301e289f..c1b74d2689 100644 --- a/src/Installers/Windows/TargetingPack/TargetingPackPackage.nuspec +++ b/src/Installers/Windows/TargetingPack/TargetingPackPackage.nuspec @@ -8,6 +8,7 @@ Microsoft https://www.microsoft.com/net/dotnet_library_license.htm https://github.com/aspnet/aspnetcore + packageIcon.png true $MAJOR$.$MINOR$ ASP.NET Core TargetingPack ($ARCH$) Windows Installer MSI as a .nupkg for internal Visual Studio build consumption © Microsoft Corporation. All rights reserved. diff --git a/src/Mvc/Mvc.Analyzers/src/Microsoft.AspNetCore.Mvc.Analyzers.nuspec b/src/Mvc/Mvc.Analyzers/src/Microsoft.AspNetCore.Mvc.Analyzers.nuspec index 0780ae588d..106615a7da 100644 --- a/src/Mvc/Mvc.Analyzers/src/Microsoft.AspNetCore.Mvc.Analyzers.nuspec +++ b/src/Mvc/Mvc.Analyzers/src/Microsoft.AspNetCore.Mvc.Analyzers.nuspec @@ -2,6 +2,7 @@ $CommonMetadataElements$ + packageIcon.png diff --git a/src/Mvc/Mvc.Api.Analyzers/src/Microsoft.AspNetCore.Mvc.Api.Analyzers.nuspec b/src/Mvc/Mvc.Api.Analyzers/src/Microsoft.AspNetCore.Mvc.Api.Analyzers.nuspec index 0780ae588d..106615a7da 100644 --- a/src/Mvc/Mvc.Api.Analyzers/src/Microsoft.AspNetCore.Mvc.Api.Analyzers.nuspec +++ b/src/Mvc/Mvc.Api.Analyzers/src/Microsoft.AspNetCore.Mvc.Api.Analyzers.nuspec @@ -2,6 +2,7 @@ $CommonMetadataElements$ + packageIcon.png diff --git a/src/ProjectTemplates/templates.nuspec b/src/ProjectTemplates/templates.nuspec index f603e4757c..49a1d320ec 100644 --- a/src/ProjectTemplates/templates.nuspec +++ b/src/ProjectTemplates/templates.nuspec @@ -5,6 +5,7 @@ + packageIcon.png $CommonMetadataElements$ + packageIcon.png diff --git a/src/Tools/Extensions.ApiDescription.Server/src/Microsoft.Extensions.ApiDescription.Server.nuspec b/src/Tools/Extensions.ApiDescription.Server/src/Microsoft.Extensions.ApiDescription.Server.nuspec index 7fe0e38e93..2839a1d0b2 100644 --- a/src/Tools/Extensions.ApiDescription.Server/src/Microsoft.Extensions.ApiDescription.Server.nuspec +++ b/src/Tools/Extensions.ApiDescription.Server/src/Microsoft.Extensions.ApiDescription.Server.nuspec @@ -2,6 +2,7 @@ $CommonMetadataElements$ + packageIcon.png From 4e72e6692ad6cecf6e2e5e2218b250bd663c4bd1 Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Tue, 24 Sep 2019 15:59:26 -0700 Subject: [PATCH 03/26] Update to GA SDK --- global.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global.json b/global.json index dcba24801f..80ff5760c4 100644 --- a/global.json +++ b/global.json @@ -1,9 +1,9 @@ { "sdk": { - "version": "3.0.100-preview8-013656" + "version": "3.0.100" }, "tools": { - "dotnet": "3.0.100-preview8-013656", + "dotnet": "3.0.100", "runtimes": { "dotnet/x64": [ "$(MicrosoftNETCoreAppRuntimeVersion)" From f20a4143de1877d0a98c0d831480e6d9ca6b1d4a Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Wed, 25 Sep 2019 15:55:47 -0700 Subject: [PATCH 04/26] Update to stable SDK in source build --- .azure/pipelines/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.azure/pipelines/ci.yml b/.azure/pipelines/ci.yml index ca0ef63a15..01b3300006 100644 --- a/.azure/pipelines/ci.yml +++ b/.azure/pipelines/ci.yml @@ -535,7 +535,7 @@ stages: # For the purpose of building Linux distros, we can't depend on features of the SDK # which may not exist in pre-built versions of the SDK # Pinning to preview 8 since preview 9 has breaking changes - version: 3.0.100-preview8-013656 + version: 3.0.100 installationPath: $(DotNetCoreSdkDir) includePreviewVersions: true - script: ./eng/scripts/ci-source-build.sh --ci --configuration Release /p:BuildManaged=true /p:BuildNodeJs=false From 86e9b45aa00da85094de2bf35f6af8a5d786496d Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Thu, 26 Sep 2019 12:53:59 -0700 Subject: [PATCH 05/26] Use up-to-date nuget versions --- eng/tools/RepoTasks/RepoTasks.csproj | 2 +- src/Installers/Windows/GenerateNugetPackageWithMsi.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/tools/RepoTasks/RepoTasks.csproj b/eng/tools/RepoTasks/RepoTasks.csproj index 0bf6be98ae..6e0baa292f 100644 --- a/eng/tools/RepoTasks/RepoTasks.csproj +++ b/eng/tools/RepoTasks/RepoTasks.csproj @@ -12,7 +12,7 @@ - + diff --git a/src/Installers/Windows/GenerateNugetPackageWithMsi.ps1 b/src/Installers/Windows/GenerateNugetPackageWithMsi.ps1 index f4171751f6..4c1c4970dc 100644 --- a/src/Installers/Windows/GenerateNugetPackageWithMsi.ps1 +++ b/src/Installers/Windows/GenerateNugetPackageWithMsi.ps1 @@ -24,7 +24,7 @@ if (-not (Test-Path $NuGetDir)) { if (-not (Test-Path $NuGetExe)) { # Using 3.5.0 to workaround https://github.com/NuGet/Home/issues/5016 Write-Output "Downloading nuget.exe to $NuGetExe" - wget https://dist.nuget.org/win-x86-commandline/v3.5.0/nuget.exe -OutFile $NuGetExe + wget https://dist.nuget.org/win-x86-commandline/latest/nuget.exe -OutFile $NuGetExe } & $NuGetExe pack $NuspecFile -Version $PackageVersion -OutputDirectory $OutputDirectory -NoDefaultExcludes -NoPackageAnalysis -Properties ASPNETCORE_RUNTIME_MSI=$MsiPath`;ASPNETCORE_CAB_FILE=$CabPath`;ARCH=$Architecture`;MAJOR=$MajorVersion`;MINOR=$MinorVersion`; From ac691731677064e31bf4011c692fc492e4a123c0 Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Thu, 26 Sep 2019 13:36:19 -0700 Subject: [PATCH 06/26] Update MSBuild deps --- eng/tools/RepoTasks/RepoTasks.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/tools/RepoTasks/RepoTasks.csproj b/eng/tools/RepoTasks/RepoTasks.csproj index 6e0baa292f..48c529fdd8 100644 --- a/eng/tools/RepoTasks/RepoTasks.csproj +++ b/eng/tools/RepoTasks/RepoTasks.csproj @@ -17,9 +17,9 @@ - - - + + + From 14eb9e3325894d6413102220b15ef565a0757097 Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Fri, 27 Sep 2019 11:10:52 -0700 Subject: [PATCH 07/26] Temporarily try usi a preview9 sdk --- global.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global.json b/global.json index 80ff5760c4..b8e9d668a9 100644 --- a/global.json +++ b/global.json @@ -1,9 +1,9 @@ { "sdk": { - "version": "3.0.100" + "version": "3.0.100-preview9-013918" }, "tools": { - "dotnet": "3.0.100", + "dotnet": "3.0.100-preview9-013918", "runtimes": { "dotnet/x64": [ "$(MicrosoftNETCoreAppRuntimeVersion)" From cad19885729d8efd29b2cde4b6db2be4336fdd16 Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Fri, 27 Sep 2019 12:49:10 -0700 Subject: [PATCH 08/26] Newer SDK --- global.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global.json b/global.json index b8e9d668a9..321b11a5ca 100644 --- a/global.json +++ b/global.json @@ -1,9 +1,9 @@ { "sdk": { - "version": "3.0.100-preview9-013918" + "version": "3.0.100-preview9-014000" }, "tools": { - "dotnet": "3.0.100-preview9-013918", + "dotnet": "3.0.100-preview9-014000", "runtimes": { "dotnet/x64": [ "$(MicrosoftNETCoreAppRuntimeVersion)" From fa21e53dd9fa7f2dba385a0490fe7f17ef662572 Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Tue, 1 Oct 2019 11:01:22 -0700 Subject: [PATCH 09/26] Revert to GA SDK --- global.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global.json b/global.json index 321b11a5ca..80ff5760c4 100644 --- a/global.json +++ b/global.json @@ -1,9 +1,9 @@ { "sdk": { - "version": "3.0.100-preview9-014000" + "version": "3.0.100" }, "tools": { - "dotnet": "3.0.100-preview9-014000", + "dotnet": "3.0.100", "runtimes": { "dotnet/x64": [ "$(MicrosoftNETCoreAppRuntimeVersion)" From ac261d878930870cabc9adde497c7213e4e257b9 Mon Sep 17 00:00:00 2001 From: Brennan Date: Thu, 3 Oct 2019 08:27:41 -0700 Subject: [PATCH 10/26] Don't call close if connect does not succeed (#14114) - small comment - patch config - fix assert --- eng/PatchConfig.props | 1 + .../ts/signalr/src/WebSocketTransport.ts | 20 +++++++++++++- .../tests/ServerSentEventsTransport.test.ts | 21 +++++++++++++++ .../signalr/tests/WebSocketTransport.test.ts | 27 +++++++++++++++++++ 4 files changed, 68 insertions(+), 1 deletion(-) diff --git a/eng/PatchConfig.props b/eng/PatchConfig.props index c139969aa4..1dfe2a7fc8 100644 --- a/eng/PatchConfig.props +++ b/eng/PatchConfig.props @@ -16,6 +16,7 @@ Directory.Build.props checks this property using the following condition: Microsoft.AspNetCore.DataProtection.EntityFrameworkCore; + @microsoft/signalr; diff --git a/src/SignalR/clients/ts/signalr/src/WebSocketTransport.ts b/src/SignalR/clients/ts/signalr/src/WebSocketTransport.ts index b7e842e3ec..418c306055 100644 --- a/src/SignalR/clients/ts/signalr/src/WebSocketTransport.ts +++ b/src/SignalR/clients/ts/signalr/src/WebSocketTransport.ts @@ -49,6 +49,7 @@ export class WebSocketTransport implements ITransport { url = url.replace(/^http/, "ws"); let webSocket: WebSocket | undefined; const cookies = this.httpClient.getCookieString(url); + let opened = false; if (Platform.isNode && cookies) { // Only pass cookies when in non-browser environments @@ -72,6 +73,7 @@ export class WebSocketTransport implements ITransport { webSocket.onopen = (_event: Event) => { this.logger.log(LogLevel.Information, `WebSocket connected to ${url}.`); this.webSocket = webSocket; + opened = true; resolve(); }; @@ -94,7 +96,23 @@ export class WebSocketTransport implements ITransport { } }; - webSocket.onclose = (event: CloseEvent) => this.close(event); + webSocket.onclose = (event: CloseEvent) => { + // Don't call close handler if connection was never established + // We'll reject the connect call instead + if (opened) { + this.close(event); + } else { + let error: any = null; + // ErrorEvent is a browser only type we need to check if the type exists before using it + if (typeof ErrorEvent !== "undefined" && event instanceof ErrorEvent) { + error = event.error; + } else { + error = new Error("There was an error with the transport."); + } + + reject(error); + } + }; }); } diff --git a/src/SignalR/clients/ts/signalr/tests/ServerSentEventsTransport.test.ts b/src/SignalR/clients/ts/signalr/tests/ServerSentEventsTransport.test.ts index 0f017adace..bad6a9fb3a 100644 --- a/src/SignalR/clients/ts/signalr/tests/ServerSentEventsTransport.test.ts +++ b/src/SignalR/clients/ts/signalr/tests/ServerSentEventsTransport.test.ts @@ -45,6 +45,27 @@ describe("ServerSentEventsTransport", () => { }); }); + it("connect failure does not call onclose handler", async () => { + await VerifyLogger.run(async (logger) => { + const sse = new ServerSentEventsTransport(new TestHttpClient(), undefined, logger, true, TestEventSource); + let closeCalled = false; + sse.onclose = () => closeCalled = true; + + const connectPromise = (async () => { + await sse.connect("http://example.com", TransferFormat.Text); + })(); + + await TestEventSource.eventSource.openSet; + + TestEventSource.eventSource.onerror(new TestMessageEvent()); + + await expect(connectPromise) + .rejects + .toEqual(new Error("Error occurred")); + expect(closeCalled).toBe(false); + }); + }); + [["http://example.com", "http://example.com?access_token=secretToken"], ["http://example.com?value=null", "http://example.com?value=null&access_token=secretToken"]] .forEach(([input, expected]) => { diff --git a/src/SignalR/clients/ts/signalr/tests/WebSocketTransport.test.ts b/src/SignalR/clients/ts/signalr/tests/WebSocketTransport.test.ts index 28277df11a..e26eaa86a3 100644 --- a/src/SignalR/clients/ts/signalr/tests/WebSocketTransport.test.ts +++ b/src/SignalR/clients/ts/signalr/tests/WebSocketTransport.test.ts @@ -66,6 +66,33 @@ describe("WebSocketTransport", () => { }); }); + it("connect failure does not call onclose handler", async () => { + await VerifyLogger.run(async (logger) => { + (global as any).ErrorEvent = TestErrorEvent; + const webSocket = new WebSocketTransport(new TestHttpClient(), undefined, logger, true, TestWebSocket); + let closeCalled = false; + webSocket.onclose = () => closeCalled = true; + + let connectComplete: boolean = false; + const connectPromise = (async () => { + await webSocket.connect("http://example.com", TransferFormat.Text); + connectComplete = true; + })(); + + await TestWebSocket.webSocket.closeSet; + + expect(connectComplete).toBe(false); + + TestWebSocket.webSocket.onclose(new TestEvent()); + + await expect(connectPromise) + .rejects + .toThrow("There was an error with the transport."); + expect(connectComplete).toBe(false); + expect(closeCalled).toBe(false); + }); + }); + [["http://example.com", "ws://example.com?access_token=secretToken"], ["http://example.com?value=null", "ws://example.com?value=null&access_token=secretToken"], ["https://example.com?value=null", "wss://example.com?value=null&access_token=secretToken"]] From c36b12bd5f139bb6b363557efdd25a19651bf642 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Tue, 24 Sep 2019 15:12:47 +1200 Subject: [PATCH 11/26] Update gRPC package version to 2.23.2 --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index a0c39b7f4e..c7f31b506f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -242,7 +242,7 @@ 4.2.1 4.2.1 3.8.0 - 2.23.1 + 2.23.2 3.0.0 3.0.0 3.0.0 From a9fb7f4a6d290c21351be79c6b1a29f527dc0215 Mon Sep 17 00:00:00 2001 From: Doug Bunting <6431421+dougbu@users.noreply.github.com> Date: Thu, 3 Oct 2019 12:32:34 -0700 Subject: [PATCH 12/26] Get latest from EntityFrameworkCore for 2.1.14 --- build/submodules.props | 2 +- modules/EntityFrameworkCore | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/submodules.props b/build/submodules.props index 4370c412c7..a088430493 100644 --- a/build/submodules.props +++ b/build/submodules.props @@ -37,6 +37,6 @@ - + diff --git a/modules/EntityFrameworkCore b/modules/EntityFrameworkCore index 688198bcdd..b8ba7191e9 160000 --- a/modules/EntityFrameworkCore +++ b/modules/EntityFrameworkCore @@ -1 +1 @@ -Subproject commit 688198bcdd754273fc3ebb63bbd75931f5841e14 +Subproject commit b8ba7191e9c39642bb340fd2b79fbf3df0f6c71c From f198e559f87d113b99a0f693dffc1baaab1b782c Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 3 Oct 2019 14:37:24 -0700 Subject: [PATCH 13/26] [2.1] Re-implement SameSite for 2019 (#13746) * Re-implement SameSite for 2019 #12125 * Rename compat flag * Use Microsoft.AspNetCore.SuppressSameSiteNone compat key * Backport CookiePolicy quirk and sample * Patch config --- eng/PatchConfig.props | 2 + src/Http/Headers/src/SetCookieHeaderValue.cs | 71 ++++++++-- .../Headers/test/SetCookieHeaderValueTest.cs | 124 +++++++++++++++++- .../OpenIdConnectSample.csproj | 4 +- .../samples/OpenIdConnectSample/Startup.cs | 30 +++++ .../Authentication/test/CookieTests.cs | 2 +- ...soft.AspNetCore.Authentication.Test.csproj | 3 +- .../OpenIdConnectChallengeTests.cs | 3 +- .../CookiePolicy/src/CookiePolicyOptions.cs | 14 +- .../src/ResponseCookiesWrapper.cs | 29 +--- .../CookiePolicy/test/CookiePolicyTests.cs | 32 ++++- ...rosoft.AspNetCore.CookiePolicy.Test.csproj | 3 +- src/Security/Security.sln | 7 + 13 files changed, 271 insertions(+), 53 deletions(-) diff --git a/eng/PatchConfig.props b/eng/PatchConfig.props index 71ff8312fd..3ba7babc57 100644 --- a/eng/PatchConfig.props +++ b/eng/PatchConfig.props @@ -40,6 +40,8 @@ Later on, this will be checked using this condition: + Microsoft.Net.Http.Headers; + Microsoft.AspNetCore.CookiePolicy; diff --git a/src/Http/Headers/src/SetCookieHeaderValue.cs b/src/Http/Headers/src/SetCookieHeaderValue.cs index f3477648de..e72f02b048 100644 --- a/src/Http/Headers/src/SetCookieHeaderValue.cs +++ b/src/Http/Headers/src/SetCookieHeaderValue.cs @@ -19,8 +19,14 @@ namespace Microsoft.Net.Http.Headers private const string SecureToken = "secure"; // RFC Draft: https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 private const string SameSiteToken = "samesite"; + private static readonly string SameSiteNoneToken = SameSiteMode.None.ToString().ToLower(); private static readonly string SameSiteLaxToken = SameSiteMode.Lax.ToString().ToLower(); private static readonly string SameSiteStrictToken = SameSiteMode.Strict.ToString().ToLower(); + + // True (old): https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-3.1 + // False (new): https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.1 + internal static bool SuppressSameSiteNone; + private const string HttpOnlyToken = "httponly"; private const string SeparatorToken = "; "; private const string EqualsToken = "="; @@ -34,6 +40,14 @@ namespace Microsoft.Net.Http.Headers private StringSegment _name; private StringSegment _value; + static SetCookieHeaderValue() + { + if (AppContext.TryGetSwitch("Microsoft.AspNetCore.SuppressSameSiteNone", out var enabled)) + { + SuppressSameSiteNone = enabled; + } + } + private SetCookieHeaderValue() { // Used by the parser to create a new instance of this type. @@ -90,11 +104,11 @@ namespace Microsoft.Net.Http.Headers public bool Secure { get; set; } - public SameSiteMode SameSite { get; set; } + public SameSiteMode SameSite { get; set; } = SuppressSameSiteNone ? SameSiteMode.None : (SameSiteMode)(-1); // Unspecified public bool HttpOnly { get; set; } - // name="value"; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={Strict|Lax}; httponly + // name="value"; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={strict|lax|none}; httponly public override string ToString() { var length = _name.Length + EqualsToken.Length + _value.Length; @@ -130,9 +144,20 @@ namespace Microsoft.Net.Http.Headers length += SeparatorToken.Length + SecureToken.Length; } - if (SameSite != SameSiteMode.None) + // Allow for Unspecified (-1) to skip SameSite + if (SameSite == SameSiteMode.None && !SuppressSameSiteNone) { - sameSite = SameSite == SameSiteMode.Lax ? SameSiteLaxToken : SameSiteStrictToken; + sameSite = SameSiteNoneToken; + length += SeparatorToken.Length + SameSiteToken.Length + EqualsToken.Length + sameSite.Length; + } + else if (SameSite == SameSiteMode.Lax) + { + sameSite = SameSiteLaxToken; + length += SeparatorToken.Length + SameSiteToken.Length + EqualsToken.Length + sameSite.Length; + } + else if (SameSite == SameSiteMode.Strict) + { + sameSite = SameSiteStrictToken; length += SeparatorToken.Length + SameSiteToken.Length + EqualsToken.Length + sameSite.Length; } @@ -172,7 +197,7 @@ namespace Microsoft.Net.Http.Headers AppendSegment(ref sb, SecureToken, null); } - if (SameSite != SameSiteMode.None) + if (sameSite != null) { AppendSegment(ref sb, SameSiteToken, sameSite); } @@ -235,9 +260,18 @@ namespace Microsoft.Net.Http.Headers AppendSegment(builder, SecureToken, null); } - if (SameSite != SameSiteMode.None) + // Allow for Unspecified (-1) to skip SameSite + if (SameSite == SameSiteMode.None && !SuppressSameSiteNone) { - AppendSegment(builder, SameSiteToken, SameSite == SameSiteMode.Lax ? SameSiteLaxToken : SameSiteStrictToken); + AppendSegment(builder, SameSiteToken, SameSiteNoneToken); + } + else if (SameSite == SameSiteMode.Lax) + { + AppendSegment(builder, SameSiteToken, SameSiteLaxToken); + } + else if (SameSite == SameSiteMode.Strict) + { + AppendSegment(builder, SameSiteToken, SameSiteStrictToken); } if (HttpOnly) @@ -289,7 +323,7 @@ namespace Microsoft.Net.Http.Headers return MultipleValueParser.TryParseStrictValues(inputs, out parsedValues); } - // name=value; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={Strict|Lax}; httponly + // name=value; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={Strict|Lax|None}; httponly private static int GetSetCookieLength(StringSegment input, int startIndex, out SetCookieHeaderValue parsedValue) { Contract.Requires(startIndex >= 0); @@ -424,25 +458,34 @@ namespace Microsoft.Net.Http.Headers { result.Secure = true; } - // samesite-av = "SameSite" / "SameSite=" samesite-value - // samesite-value = "Strict" / "Lax" + // samesite-av = "SameSite=" samesite-value + // samesite-value = "Strict" / "Lax" / "None" else if (StringSegment.Equals(token, SameSiteToken, StringComparison.OrdinalIgnoreCase)) { if (!ReadEqualsSign(input, ref offset)) { - result.SameSite = SameSiteMode.Strict; + result.SameSite = SuppressSameSiteNone ? SameSiteMode.Strict : (SameSiteMode)(-1); // Unspecified } else { var enforcementMode = ReadToSemicolonOrEnd(input, ref offset); - if (StringSegment.Equals(enforcementMode, SameSiteLaxToken, StringComparison.OrdinalIgnoreCase)) + if (StringSegment.Equals(enforcementMode, SameSiteStrictToken, StringComparison.OrdinalIgnoreCase)) + { + result.SameSite = SameSiteMode.Strict; + } + else if (StringSegment.Equals(enforcementMode, SameSiteLaxToken, StringComparison.OrdinalIgnoreCase)) { result.SameSite = SameSiteMode.Lax; } + else if (!SuppressSameSiteNone + && StringSegment.Equals(enforcementMode, SameSiteNoneToken, StringComparison.OrdinalIgnoreCase)) + { + result.SameSite = SameSiteMode.None; + } else { - result.SameSite = SameSiteMode.Strict; + result.SameSite = SuppressSameSiteNone ? SameSiteMode.Strict : (SameSiteMode)(-1); // Unspecified } } } @@ -520,4 +563,4 @@ namespace Microsoft.Net.Http.Headers ^ HttpOnly.GetHashCode(); } } -} \ No newline at end of file +} diff --git a/src/Http/Headers/test/SetCookieHeaderValueTest.cs b/src/Http/Headers/test/SetCookieHeaderValueTest.cs index e7e8bf045a..32424363dd 100644 --- a/src/Http/Headers/test/SetCookieHeaderValueTest.cs +++ b/src/Http/Headers/test/SetCookieHeaderValueTest.cs @@ -57,7 +57,7 @@ namespace Microsoft.Net.Http.Headers { SameSite = SameSiteMode.None, }; - dataset.Add(header7, "name7=value7"); + dataset.Add(header7, "name7=value7; samesite=none"); return dataset; @@ -155,9 +155,20 @@ namespace Microsoft.Net.Http.Headers { SameSite = SameSiteMode.Strict }; - var string6a = "name6=value6; samesite"; - var string6b = "name6=value6; samesite=Strict"; - var string6c = "name6=value6; samesite=invalid"; + var string6 = "name6=value6; samesite=Strict"; + + var header7 = new SetCookieHeaderValue("name7", "value7") + { + SameSite = SameSiteMode.None + }; + var string7 = "name7=value7; samesite=None"; + + var header8 = new SetCookieHeaderValue("name8", "value8") + { + SameSite = (SameSiteMode)(-1) // Unspecified + }; + var string8a = "name8=value8; samesite"; + var string8b = "name8=value8; samesite=invalid"; dataset.Add(new[] { header1 }.ToList(), new[] { string1 }); dataset.Add(new[] { header1, header1 }.ToList(), new[] { string1, string1 }); @@ -170,9 +181,10 @@ namespace Microsoft.Net.Http.Headers dataset.Add(new[] { header1, header2, header3, header4 }.ToList(), new[] { string.Join(",", string1, string2, string3, string4) }); dataset.Add(new[] { header5 }.ToList(), new[] { string5a }); dataset.Add(new[] { header5 }.ToList(), new[] { string5b }); - dataset.Add(new[] { header6 }.ToList(), new[] { string6a }); - dataset.Add(new[] { header6 }.ToList(), new[] { string6b }); - dataset.Add(new[] { header6 }.ToList(), new[] { string6c }); + dataset.Add(new[] { header6 }.ToList(), new[] { string6 }); + dataset.Add(new[] { header7 }.ToList(), new[] { string7 }); + dataset.Add(new[] { header8 }.ToList(), new[] { string8a }); + dataset.Add(new[] { header8 }.ToList(), new[] { string8b }); return dataset; } @@ -301,6 +313,28 @@ namespace Microsoft.Net.Http.Headers Assert.Equal(expectedValue, input.ToString()); } + [Fact] + public void SetCookieHeaderValue_ToString_SameSiteNoneCompat() + { + SetCookieHeaderValue.SuppressSameSiteNone = true; + + var input = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.None, + }; + + Assert.Equal("name=value", input.ToString()); + + SetCookieHeaderValue.SuppressSameSiteNone = false; + + var input2 = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.None, + }; + + Assert.Equal("name=value; samesite=none", input2.ToString()); + } + [Theory] [MemberData(nameof(SetCookieHeaderDataSet))] public void SetCookieHeaderValue_AppendToStringBuilder(SetCookieHeaderValue input, string expectedValue) @@ -312,6 +346,32 @@ namespace Microsoft.Net.Http.Headers Assert.Equal(expectedValue, builder.ToString()); } + [Fact] + public void SetCookieHeaderValue_AppendToStringBuilder_SameSiteNoneCompat() + { + SetCookieHeaderValue.SuppressSameSiteNone = true; + + var builder = new StringBuilder(); + var input = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.None, + }; + + input.AppendToStringBuilder(builder); + Assert.Equal("name=value", builder.ToString()); + + SetCookieHeaderValue.SuppressSameSiteNone = false; + + var builder2 = new StringBuilder(); + var input2 = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.None, + }; + + input2.AppendToStringBuilder(builder2); + Assert.Equal("name=value; samesite=none", builder2.ToString()); + } + [Theory] [MemberData(nameof(SetCookieHeaderDataSet))] public void SetCookieHeaderValue_Parse_AcceptsValidValues(SetCookieHeaderValue cookie, string expectedValue) @@ -322,6 +382,31 @@ namespace Microsoft.Net.Http.Headers Assert.Equal(expectedValue, header.ToString()); } + [Fact] + public void SetCookieHeaderValue_Parse_AcceptsValidValues_SameSiteNoneCompat() + { + SetCookieHeaderValue.SuppressSameSiteNone = true; + var header = SetCookieHeaderValue.Parse("name=value; samesite=none"); + + var cookie = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.Strict, + }; + + Assert.Equal(cookie, header); + Assert.Equal("name=value; samesite=strict", header.ToString()); + SetCookieHeaderValue.SuppressSameSiteNone = false; + + var header2 = SetCookieHeaderValue.Parse("name=value; samesite=none"); + + var cookie2 = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.None, + }; + Assert.Equal(cookie2, header2); + Assert.Equal("name=value; samesite=none", header2.ToString()); + } + [Theory] [MemberData(nameof(SetCookieHeaderDataSet))] public void SetCookieHeaderValue_TryParse_AcceptsValidValues(SetCookieHeaderValue cookie, string expectedValue) @@ -332,6 +417,31 @@ namespace Microsoft.Net.Http.Headers Assert.Equal(expectedValue, header.ToString()); } + [Fact] + public void SetCookieHeaderValue_TryParse_AcceptsValidValues_SameSiteNoneCompat() + { + SetCookieHeaderValue.SuppressSameSiteNone = true; + Assert.True(SetCookieHeaderValue.TryParse("name=value; samesite=none", out var header)); + var cookie = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.Strict, + }; + + Assert.Equal(cookie, header); + Assert.Equal("name=value; samesite=strict", header.ToString()); + + SetCookieHeaderValue.SuppressSameSiteNone = false; + + Assert.True(SetCookieHeaderValue.TryParse("name=value; samesite=none", out var header2)); + var cookie2 = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.None, + }; + + Assert.Equal(cookie2, header2); + Assert.Equal("name=value; samesite=none", header2.ToString()); + } + [Theory] [MemberData(nameof(InvalidSetCookieHeaderDataSet))] public void SetCookieHeaderValue_Parse_RejectsInvalidValues(string value) diff --git a/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/OpenIdConnectSample.csproj b/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/OpenIdConnectSample.csproj index 6b34fabc6c..9fb07fe38f 100644 --- a/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/OpenIdConnectSample.csproj +++ b/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/OpenIdConnectSample.csproj @@ -1,4 +1,4 @@ - + net461;netcoreapp2.1 @@ -12,6 +12,7 @@ + @@ -21,6 +22,7 @@ + diff --git a/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/Startup.cs b/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/Startup.cs index 1aa7625cb0..638a6050d7 100644 --- a/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/Startup.cs +++ b/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/Startup.cs @@ -43,10 +43,33 @@ namespace OpenIdConnectSample public IHostingEnvironment Environment { get; set; } + private void CheckSameSite(HttpContext httpContext, CookieOptions options) + { + if (options.SameSite > (SameSiteMode)(-1)) + { + var userAgent = httpContext.Request.Headers["User-Agent"].ToString(); + // TODO: Use your User Agent library of choice here. + if (userAgent.Contains("CPU iPhone OS 12") // Also covers iPod touch + || userAgent.Contains("iPad; CPU OS 12") + // Safari 12 and 13 are both broken on Mojave + || userAgent.Contains("Macintosh; Intel Mac OS X 10_14")) + { + options.SameSite = (SameSiteMode)(-1); + } + } + } + public void ConfigureServices(IServiceCollection services) { JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + services.Configure(options => + { + options.MinimumSameSitePolicy = (SameSiteMode)(-1); + options.OnAppendCookie = cookieContext => CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); + options.OnDeleteCookie = cookieContext => CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); + }); + services.AddAuthentication(sharedOptions => { sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; @@ -56,9 +79,15 @@ namespace OpenIdConnectSample .AddCookie() .AddOpenIdConnect(o => { + /* o.ClientId = Configuration["oidc:clientid"]; o.ClientSecret = Configuration["oidc:clientsecret"]; // for code flow o.Authority = Configuration["oidc:authority"]; + */ + // https://github.com/IdentityServer/IdentityServer4.Demo/blob/master/src/IdentityServer4Demo/Config.cs + o.ClientId = "server.hybrid"; + o.ClientSecret = "secret"; // for code flow + o.Authority = "https://demo.identityserver.io/"; o.ResponseType = OpenIdConnectResponseType.CodeIdToken; o.SaveTokens = true; @@ -88,6 +117,7 @@ namespace OpenIdConnectSample public void Configure(IApplicationBuilder app, IOptionsMonitor optionsMonitor) { app.UseDeveloperExceptionPage(); + app.UseCookiePolicy(); // Before UseAuthentication or anything else that writes cookies. app.UseAuthentication(); app.Run(async context => diff --git a/src/Security/Authentication/test/CookieTests.cs b/src/Security/Authentication/test/CookieTests.cs index 766d1e2e53..c2445d747c 100644 --- a/src/Security/Authentication/test/CookieTests.cs +++ b/src/Security/Authentication/test/CookieTests.cs @@ -649,7 +649,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies Assert.Contains(" path=/foo", setCookie1); Assert.Contains(" domain=another.com", setCookie1); Assert.Contains(" secure", setCookie1); - Assert.DoesNotContain(" samesite", setCookie1); + Assert.Contains(" samesite=none", setCookie1); Assert.Contains(" httponly", setCookie1); var server2 = CreateServer(o => diff --git a/src/Security/Authentication/test/Microsoft.AspNetCore.Authentication.Test.csproj b/src/Security/Authentication/test/Microsoft.AspNetCore.Authentication.Test.csproj index d008f35ffd..94e3ae739d 100644 --- a/src/Security/Authentication/test/Microsoft.AspNetCore.Authentication.Test.csproj +++ b/src/Security/Authentication/test/Microsoft.AspNetCore.Authentication.Test.csproj @@ -1,4 +1,4 @@ - + netcoreapp2.1;net461 @@ -39,6 +39,7 @@ + diff --git a/src/Security/Authentication/test/OpenIdConnect/OpenIdConnectChallengeTests.cs b/src/Security/Authentication/test/OpenIdConnect/OpenIdConnectChallengeTests.cs index cbafc46223..9e2c47a7a7 100644 --- a/src/Security/Authentication/test/OpenIdConnect/OpenIdConnectChallengeTests.cs +++ b/src/Security/Authentication/test/OpenIdConnect/OpenIdConnectChallengeTests.cs @@ -376,6 +376,7 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect var server = settings.CreateTestServer(); var transaction = await server.SendAsync(ChallengeEndpoint); + Assert.Contains("samesite=none", transaction.SetCookie.First()); var challengeCookies = SetCookieHeaderValue.ParseList(transaction.SetCookie); var nonceCookie = challengeCookies.Where(cookie => cookie.Name.StartsWith(OpenIdConnectDefaults.CookieNoncePrefix, StringComparison.Ordinal)).Single(); Assert.True(nonceCookie.Expires.HasValue); @@ -613,4 +614,4 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect Assert.Contains("max_age=1234", res.Headers.Location.Query); } } -} \ No newline at end of file +} diff --git a/src/Security/CookiePolicy/src/CookiePolicyOptions.cs b/src/Security/CookiePolicy/src/CookiePolicyOptions.cs index 32d047297a..dda970a511 100644 --- a/src/Security/CookiePolicy/src/CookiePolicyOptions.cs +++ b/src/Security/CookiePolicy/src/CookiePolicyOptions.cs @@ -12,6 +12,18 @@ namespace Microsoft.AspNetCore.Builder /// public class CookiePolicyOptions { + // True (old): https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-3.1 + // False (new): https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.1 + internal static bool SuppressSameSiteNone; + + static CookiePolicyOptions() + { + if (AppContext.TryGetSwitch("Microsoft.AspNetCore.SuppressSameSiteNone", out var enabled)) + { + SuppressSameSiteNone = enabled; + } + } + /// /// Affects the cookie's same site attribute. /// @@ -49,4 +61,4 @@ namespace Microsoft.AspNetCore.Builder /// public Action OnDeleteCookie { get; set; } } -} \ No newline at end of file +} diff --git a/src/Security/CookiePolicy/src/ResponseCookiesWrapper.cs b/src/Security/CookiePolicy/src/ResponseCookiesWrapper.cs index 126c4d7bd5..1db77125f6 100644 --- a/src/Security/CookiePolicy/src/ResponseCookiesWrapper.cs +++ b/src/Security/CookiePolicy/src/ResponseCookiesWrapper.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -115,7 +115,8 @@ namespace Microsoft.AspNetCore.CookiePolicy private bool CheckPolicyRequired() { return !CanTrack - || Options.MinimumSameSitePolicy != SameSiteMode.None + || (CookiePolicyOptions.SuppressSameSiteNone && Options.MinimumSameSitePolicy != SameSiteMode.None) + || (!CookiePolicyOptions.SuppressSameSiteNone && Options.MinimumSameSitePolicy != (SameSiteMode)(-1)) || Options.HttpOnly != HttpOnlyPolicy.None || Options.Secure != CookieSecurePolicy.None; } @@ -241,26 +242,10 @@ namespace Microsoft.AspNetCore.CookiePolicy default: throw new InvalidOperationException(); } - switch (Options.MinimumSameSitePolicy) + if (options.SameSite < Options.MinimumSameSitePolicy) { - case SameSiteMode.None: - break; - case SameSiteMode.Lax: - if (options.SameSite == SameSiteMode.None) - { - options.SameSite = SameSiteMode.Lax; - _logger.CookieSameSiteUpgraded(key, "lax"); - } - break; - case SameSiteMode.Strict: - if (options.SameSite != SameSiteMode.Strict) - { - options.SameSite = SameSiteMode.Strict; - _logger.CookieSameSiteUpgraded(key, "strict"); - } - break; - default: - throw new InvalidOperationException($"Unrecognized {nameof(SameSiteMode)} value {Options.MinimumSameSitePolicy.ToString()}"); + options.SameSite = Options.MinimumSameSitePolicy; + _logger.CookieSameSiteUpgraded(key, Options.MinimumSameSitePolicy.ToString()); } switch (Options.HttpOnly) { @@ -278,4 +263,4 @@ namespace Microsoft.AspNetCore.CookiePolicy } } } -} \ No newline at end of file +} diff --git a/src/Security/CookiePolicy/test/CookiePolicyTests.cs b/src/Security/CookiePolicy/test/CookiePolicyTests.cs index a2592e5575..2eec9e7b6c 100644 --- a/src/Security/CookiePolicy/test/CookiePolicyTests.cs +++ b/src/Security/CookiePolicy/test/CookiePolicyTests.cs @@ -43,6 +43,7 @@ namespace Microsoft.AspNetCore.CookiePolicy.Test context.Response.Cookies.Append("C", "C", new CookieOptions()); context.Response.Cookies.Append("D", "D", new CookieOptions { SameSite = Http.SameSiteMode.Lax }); context.Response.Cookies.Append("E", "E", new CookieOptions { SameSite = Http.SameSiteMode.Strict }); + context.Response.Cookies.Append("F", "F", new CookieOptions { SameSite = (Http.SameSiteMode)(-1) }); return Task.FromResult(0); }; @@ -198,7 +199,7 @@ namespace Microsoft.AspNetCore.CookiePolicy.Test } [Fact] - public async Task SameSiteNoneLeavesItAlone() + public async Task SameSiteNoneSetsItAlways() { await RunTest("/sameSiteNone", new CookiePolicyOptions @@ -210,11 +211,34 @@ namespace Microsoft.AspNetCore.CookiePolicy.Test transaction => { Assert.NotNull(transaction.SetCookie); - Assert.Equal("A=A; path=/", transaction.SetCookie[0]); - Assert.Equal("B=B; path=/", transaction.SetCookie[1]); + Assert.Equal("A=A; path=/; samesite=lax", transaction.SetCookie[0]); + Assert.Equal("B=B; path=/; samesite=none", transaction.SetCookie[1]); Assert.Equal("C=C; path=/; samesite=lax", transaction.SetCookie[2]); Assert.Equal("D=D; path=/; samesite=lax", transaction.SetCookie[3]); Assert.Equal("E=E; path=/; samesite=strict", transaction.SetCookie[4]); + Assert.Equal("F=F; path=/; samesite=none", transaction.SetCookie[5]); + })); + } + + [Fact] + public async Task SameSiteUnspecifiedLeavesItAlone() + { + await RunTest("/sameSiteNone", + new CookiePolicyOptions + { + MinimumSameSitePolicy = (Http.SameSiteMode)(-1) + }, + SameSiteCookieAppends, + new RequestTest("http://example.com/sameSiteNone", + transaction => + { + Assert.NotNull(transaction.SetCookie); + Assert.Equal("A=A; path=/", transaction.SetCookie[0]); + Assert.Equal("B=B; path=/; samesite=none", transaction.SetCookie[1]); + Assert.Equal("C=C; path=/; samesite=lax", transaction.SetCookie[2]); + Assert.Equal("D=D; path=/; samesite=lax", transaction.SetCookie[3]); + Assert.Equal("E=E; path=/; samesite=strict", transaction.SetCookie[4]); + Assert.Equal("F=F; path=/", transaction.SetCookie[5]); })); } @@ -468,4 +492,4 @@ namespace Microsoft.AspNetCore.CookiePolicy.Test } } } -} \ No newline at end of file +} diff --git a/src/Security/CookiePolicy/test/Microsoft.AspNetCore.CookiePolicy.Test.csproj b/src/Security/CookiePolicy/test/Microsoft.AspNetCore.CookiePolicy.Test.csproj index cf7016dd3d..6d4c6c8535 100644 --- a/src/Security/CookiePolicy/test/Microsoft.AspNetCore.CookiePolicy.Test.csproj +++ b/src/Security/CookiePolicy/test/Microsoft.AspNetCore.CookiePolicy.Test.csproj @@ -1,4 +1,4 @@ - + netcoreapp2.1;net461 @@ -13,6 +13,7 @@ + diff --git a/src/Security/Security.sln b/src/Security/Security.sln index 3d36597db9..557b68ac83 100644 --- a/src/Security/Security.sln +++ b/src/Security/Security.sln @@ -102,6 +102,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.IISIntegration", "..\Servers\IIS\IISIntegration\src\Microsoft.AspNetCore.Server.IISIntegration.csproj", "{81D0E81F-4711-4C7B-BBD4-E168102D0D7D}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Net.Http.Headers", "..\Http\Headers\src\Microsoft.Net.Http.Headers.csproj", "{4BB8D7D7-E111-4A86-B6E5-C1201E0DA8CE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -248,6 +250,10 @@ Global {81D0E81F-4711-4C7B-BBD4-E168102D0D7D}.Debug|Any CPU.Build.0 = Debug|Any CPU {81D0E81F-4711-4C7B-BBD4-E168102D0D7D}.Release|Any CPU.ActiveCfg = Release|Any CPU {81D0E81F-4711-4C7B-BBD4-E168102D0D7D}.Release|Any CPU.Build.0 = Release|Any CPU + {4BB8D7D7-E111-4A86-B6E5-C1201E0DA8CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4BB8D7D7-E111-4A86-B6E5-C1201E0DA8CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4BB8D7D7-E111-4A86-B6E5-C1201E0DA8CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4BB8D7D7-E111-4A86-B6E5-C1201E0DA8CE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -298,6 +304,7 @@ Global {707CBFB4-4D35-479E-9BAF-39B4DA9782DE} = {A3766414-EB5C-40F7-B031-121804ED5D0A} {AFE880E8-2E9E-46FD-BE87-DFC8192E7B2D} = {A3766414-EB5C-40F7-B031-121804ED5D0A} {81D0E81F-4711-4C7B-BBD4-E168102D0D7D} = {A3766414-EB5C-40F7-B031-121804ED5D0A} + {4BB8D7D7-E111-4A86-B6E5-C1201E0DA8CE} = {A3766414-EB5C-40F7-B031-121804ED5D0A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {ABF8089E-43D0-4010-84A7-7A9DCFE49357} From bae8fe9399c5bc1110638743816f27f055be3385 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Thu, 3 Oct 2019 14:37:36 -0700 Subject: [PATCH 14/26] [2.2] Re-implement SameSite for 2019 (#13858) * Re-implement SameSite for 2019 #12125 * Rename compat flag * References * Use Microsoft.AspNetCore.SuppressSameSiteNone compat key * Patchconfig * Port CookiePolicy fix --- eng/PatchConfig.props | 2 + src/Http/Headers/src/SetCookieHeaderValue.cs | 71 ++++++++-- .../Headers/test/SetCookieHeaderValueTest.cs | 124 +++++++++++++++++- .../OpenIdConnectSample.csproj | 4 +- .../samples/OpenIdConnectSample/Startup.cs | 30 +++++ .../samples/WsFedSample/WsFedSample.csproj | 3 +- .../samples/SocialSample/SocialSample.csproj | 3 +- .../Authentication/test/CookieTests.cs | 2 +- ...soft.AspNetCore.Authentication.Test.csproj | 3 +- .../OpenIdConnectChallengeTests.cs | 3 +- .../CookiePolicy/src/CookiePolicyOptions.cs | 14 +- .../src/ResponseCookiesWrapper.cs | 29 +--- .../CookiePolicy/test/CookiePolicyTests.cs | 32 ++++- ...rosoft.AspNetCore.CookiePolicy.Test.csproj | 3 +- src/Security/Security.sln | 7 + 15 files changed, 275 insertions(+), 55 deletions(-) diff --git a/eng/PatchConfig.props b/eng/PatchConfig.props index dc15b2cbe0..47b5678703 100644 --- a/eng/PatchConfig.props +++ b/eng/PatchConfig.props @@ -78,6 +78,8 @@ Later on, this will be checked using this condition: + Microsoft.Net.Http.Headers; + Microsoft.AspNetCore.CookiePolicy; Microsoft.AspNetCore.DataProtection.EntityFrameworkCore; diff --git a/src/Http/Headers/src/SetCookieHeaderValue.cs b/src/Http/Headers/src/SetCookieHeaderValue.cs index f3477648de..e72f02b048 100644 --- a/src/Http/Headers/src/SetCookieHeaderValue.cs +++ b/src/Http/Headers/src/SetCookieHeaderValue.cs @@ -19,8 +19,14 @@ namespace Microsoft.Net.Http.Headers private const string SecureToken = "secure"; // RFC Draft: https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 private const string SameSiteToken = "samesite"; + private static readonly string SameSiteNoneToken = SameSiteMode.None.ToString().ToLower(); private static readonly string SameSiteLaxToken = SameSiteMode.Lax.ToString().ToLower(); private static readonly string SameSiteStrictToken = SameSiteMode.Strict.ToString().ToLower(); + + // True (old): https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-3.1 + // False (new): https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.1 + internal static bool SuppressSameSiteNone; + private const string HttpOnlyToken = "httponly"; private const string SeparatorToken = "; "; private const string EqualsToken = "="; @@ -34,6 +40,14 @@ namespace Microsoft.Net.Http.Headers private StringSegment _name; private StringSegment _value; + static SetCookieHeaderValue() + { + if (AppContext.TryGetSwitch("Microsoft.AspNetCore.SuppressSameSiteNone", out var enabled)) + { + SuppressSameSiteNone = enabled; + } + } + private SetCookieHeaderValue() { // Used by the parser to create a new instance of this type. @@ -90,11 +104,11 @@ namespace Microsoft.Net.Http.Headers public bool Secure { get; set; } - public SameSiteMode SameSite { get; set; } + public SameSiteMode SameSite { get; set; } = SuppressSameSiteNone ? SameSiteMode.None : (SameSiteMode)(-1); // Unspecified public bool HttpOnly { get; set; } - // name="value"; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={Strict|Lax}; httponly + // name="value"; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={strict|lax|none}; httponly public override string ToString() { var length = _name.Length + EqualsToken.Length + _value.Length; @@ -130,9 +144,20 @@ namespace Microsoft.Net.Http.Headers length += SeparatorToken.Length + SecureToken.Length; } - if (SameSite != SameSiteMode.None) + // Allow for Unspecified (-1) to skip SameSite + if (SameSite == SameSiteMode.None && !SuppressSameSiteNone) { - sameSite = SameSite == SameSiteMode.Lax ? SameSiteLaxToken : SameSiteStrictToken; + sameSite = SameSiteNoneToken; + length += SeparatorToken.Length + SameSiteToken.Length + EqualsToken.Length + sameSite.Length; + } + else if (SameSite == SameSiteMode.Lax) + { + sameSite = SameSiteLaxToken; + length += SeparatorToken.Length + SameSiteToken.Length + EqualsToken.Length + sameSite.Length; + } + else if (SameSite == SameSiteMode.Strict) + { + sameSite = SameSiteStrictToken; length += SeparatorToken.Length + SameSiteToken.Length + EqualsToken.Length + sameSite.Length; } @@ -172,7 +197,7 @@ namespace Microsoft.Net.Http.Headers AppendSegment(ref sb, SecureToken, null); } - if (SameSite != SameSiteMode.None) + if (sameSite != null) { AppendSegment(ref sb, SameSiteToken, sameSite); } @@ -235,9 +260,18 @@ namespace Microsoft.Net.Http.Headers AppendSegment(builder, SecureToken, null); } - if (SameSite != SameSiteMode.None) + // Allow for Unspecified (-1) to skip SameSite + if (SameSite == SameSiteMode.None && !SuppressSameSiteNone) { - AppendSegment(builder, SameSiteToken, SameSite == SameSiteMode.Lax ? SameSiteLaxToken : SameSiteStrictToken); + AppendSegment(builder, SameSiteToken, SameSiteNoneToken); + } + else if (SameSite == SameSiteMode.Lax) + { + AppendSegment(builder, SameSiteToken, SameSiteLaxToken); + } + else if (SameSite == SameSiteMode.Strict) + { + AppendSegment(builder, SameSiteToken, SameSiteStrictToken); } if (HttpOnly) @@ -289,7 +323,7 @@ namespace Microsoft.Net.Http.Headers return MultipleValueParser.TryParseStrictValues(inputs, out parsedValues); } - // name=value; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={Strict|Lax}; httponly + // name=value; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={Strict|Lax|None}; httponly private static int GetSetCookieLength(StringSegment input, int startIndex, out SetCookieHeaderValue parsedValue) { Contract.Requires(startIndex >= 0); @@ -424,25 +458,34 @@ namespace Microsoft.Net.Http.Headers { result.Secure = true; } - // samesite-av = "SameSite" / "SameSite=" samesite-value - // samesite-value = "Strict" / "Lax" + // samesite-av = "SameSite=" samesite-value + // samesite-value = "Strict" / "Lax" / "None" else if (StringSegment.Equals(token, SameSiteToken, StringComparison.OrdinalIgnoreCase)) { if (!ReadEqualsSign(input, ref offset)) { - result.SameSite = SameSiteMode.Strict; + result.SameSite = SuppressSameSiteNone ? SameSiteMode.Strict : (SameSiteMode)(-1); // Unspecified } else { var enforcementMode = ReadToSemicolonOrEnd(input, ref offset); - if (StringSegment.Equals(enforcementMode, SameSiteLaxToken, StringComparison.OrdinalIgnoreCase)) + if (StringSegment.Equals(enforcementMode, SameSiteStrictToken, StringComparison.OrdinalIgnoreCase)) + { + result.SameSite = SameSiteMode.Strict; + } + else if (StringSegment.Equals(enforcementMode, SameSiteLaxToken, StringComparison.OrdinalIgnoreCase)) { result.SameSite = SameSiteMode.Lax; } + else if (!SuppressSameSiteNone + && StringSegment.Equals(enforcementMode, SameSiteNoneToken, StringComparison.OrdinalIgnoreCase)) + { + result.SameSite = SameSiteMode.None; + } else { - result.SameSite = SameSiteMode.Strict; + result.SameSite = SuppressSameSiteNone ? SameSiteMode.Strict : (SameSiteMode)(-1); // Unspecified } } } @@ -520,4 +563,4 @@ namespace Microsoft.Net.Http.Headers ^ HttpOnly.GetHashCode(); } } -} \ No newline at end of file +} diff --git a/src/Http/Headers/test/SetCookieHeaderValueTest.cs b/src/Http/Headers/test/SetCookieHeaderValueTest.cs index 9a920f40d0..3bd2dde3aa 100644 --- a/src/Http/Headers/test/SetCookieHeaderValueTest.cs +++ b/src/Http/Headers/test/SetCookieHeaderValueTest.cs @@ -57,7 +57,7 @@ namespace Microsoft.Net.Http.Headers { SameSite = SameSiteMode.None, }; - dataset.Add(header7, "name7=value7"); + dataset.Add(header7, "name7=value7; samesite=none"); return dataset; @@ -155,9 +155,20 @@ namespace Microsoft.Net.Http.Headers { SameSite = SameSiteMode.Strict }; - var string6a = "name6=value6; samesite"; - var string6b = "name6=value6; samesite=Strict"; - var string6c = "name6=value6; samesite=invalid"; + var string6 = "name6=value6; samesite=Strict"; + + var header7 = new SetCookieHeaderValue("name7", "value7") + { + SameSite = SameSiteMode.None + }; + var string7 = "name7=value7; samesite=None"; + + var header8 = new SetCookieHeaderValue("name8", "value8") + { + SameSite = (SameSiteMode)(-1) // Unspecified + }; + var string8a = "name8=value8; samesite"; + var string8b = "name8=value8; samesite=invalid"; dataset.Add(new[] { header1 }.ToList(), new[] { string1 }); dataset.Add(new[] { header1, header1 }.ToList(), new[] { string1, string1 }); @@ -170,9 +181,10 @@ namespace Microsoft.Net.Http.Headers dataset.Add(new[] { header1, header2, header3, header4 }.ToList(), new[] { string.Join(",", string1, string2, string3, string4) }); dataset.Add(new[] { header5 }.ToList(), new[] { string5a }); dataset.Add(new[] { header5 }.ToList(), new[] { string5b }); - dataset.Add(new[] { header6 }.ToList(), new[] { string6a }); - dataset.Add(new[] { header6 }.ToList(), new[] { string6b }); - dataset.Add(new[] { header6 }.ToList(), new[] { string6c }); + dataset.Add(new[] { header6 }.ToList(), new[] { string6 }); + dataset.Add(new[] { header7 }.ToList(), new[] { string7 }); + dataset.Add(new[] { header8 }.ToList(), new[] { string8a }); + dataset.Add(new[] { header8 }.ToList(), new[] { string8b }); return dataset; } @@ -301,6 +313,28 @@ namespace Microsoft.Net.Http.Headers Assert.Equal(expectedValue, input.ToString()); } + [Fact] + public void SetCookieHeaderValue_ToString_SameSiteNoneCompat() + { + SetCookieHeaderValue.SuppressSameSiteNone = true; + + var input = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.None, + }; + + Assert.Equal("name=value", input.ToString()); + + SetCookieHeaderValue.SuppressSameSiteNone = false; + + var input2 = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.None, + }; + + Assert.Equal("name=value; samesite=none", input2.ToString()); + } + [Theory] [MemberData(nameof(SetCookieHeaderDataSet))] public void SetCookieHeaderValue_AppendToStringBuilder(SetCookieHeaderValue input, string expectedValue) @@ -312,6 +346,32 @@ namespace Microsoft.Net.Http.Headers Assert.Equal(expectedValue, builder.ToString()); } + [Fact] + public void SetCookieHeaderValue_AppendToStringBuilder_SameSiteNoneCompat() + { + SetCookieHeaderValue.SuppressSameSiteNone = true; + + var builder = new StringBuilder(); + var input = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.None, + }; + + input.AppendToStringBuilder(builder); + Assert.Equal("name=value", builder.ToString()); + + SetCookieHeaderValue.SuppressSameSiteNone = false; + + var builder2 = new StringBuilder(); + var input2 = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.None, + }; + + input2.AppendToStringBuilder(builder2); + Assert.Equal("name=value; samesite=none", builder2.ToString()); + } + [Theory] [MemberData(nameof(SetCookieHeaderDataSet))] public void SetCookieHeaderValue_Parse_AcceptsValidValues(SetCookieHeaderValue cookie, string expectedValue) @@ -322,6 +382,31 @@ namespace Microsoft.Net.Http.Headers Assert.Equal(expectedValue, header.ToString()); } + [Fact] + public void SetCookieHeaderValue_Parse_AcceptsValidValues_SameSiteNoneCompat() + { + SetCookieHeaderValue.SuppressSameSiteNone = true; + var header = SetCookieHeaderValue.Parse("name=value; samesite=none"); + + var cookie = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.Strict, + }; + + Assert.Equal(cookie, header); + Assert.Equal("name=value; samesite=strict", header.ToString()); + SetCookieHeaderValue.SuppressSameSiteNone = false; + + var header2 = SetCookieHeaderValue.Parse("name=value; samesite=none"); + + var cookie2 = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.None, + }; + Assert.Equal(cookie2, header2); + Assert.Equal("name=value; samesite=none", header2.ToString()); + } + [Theory] [MemberData(nameof(SetCookieHeaderDataSet))] public void SetCookieHeaderValue_TryParse_AcceptsValidValues(SetCookieHeaderValue cookie, string expectedValue) @@ -332,6 +417,31 @@ namespace Microsoft.Net.Http.Headers Assert.Equal(expectedValue, header.ToString()); } + [Fact] + public void SetCookieHeaderValue_TryParse_AcceptsValidValues_SameSiteNoneCompat() + { + SetCookieHeaderValue.SuppressSameSiteNone = true; + Assert.True(SetCookieHeaderValue.TryParse("name=value; samesite=none", out var header)); + var cookie = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.Strict, + }; + + Assert.Equal(cookie, header); + Assert.Equal("name=value; samesite=strict", header.ToString()); + + SetCookieHeaderValue.SuppressSameSiteNone = false; + + Assert.True(SetCookieHeaderValue.TryParse("name=value; samesite=none", out var header2)); + var cookie2 = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.None, + }; + + Assert.Equal(cookie2, header2); + Assert.Equal("name=value; samesite=none", header2.ToString()); + } + [Theory] [MemberData(nameof(InvalidSetCookieHeaderDataSet))] public void SetCookieHeaderValue_Parse_RejectsInvalidValues(string value) diff --git a/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/OpenIdConnectSample.csproj b/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/OpenIdConnectSample.csproj index 39d1a8055c..5111e9ac70 100644 --- a/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/OpenIdConnectSample.csproj +++ b/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/OpenIdConnectSample.csproj @@ -1,4 +1,4 @@ - + net461;netcoreapp2.2 @@ -12,6 +12,7 @@ + @@ -21,6 +22,7 @@ + diff --git a/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/Startup.cs b/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/Startup.cs index 1aa7625cb0..638a6050d7 100644 --- a/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/Startup.cs +++ b/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/Startup.cs @@ -43,10 +43,33 @@ namespace OpenIdConnectSample public IHostingEnvironment Environment { get; set; } + private void CheckSameSite(HttpContext httpContext, CookieOptions options) + { + if (options.SameSite > (SameSiteMode)(-1)) + { + var userAgent = httpContext.Request.Headers["User-Agent"].ToString(); + // TODO: Use your User Agent library of choice here. + if (userAgent.Contains("CPU iPhone OS 12") // Also covers iPod touch + || userAgent.Contains("iPad; CPU OS 12") + // Safari 12 and 13 are both broken on Mojave + || userAgent.Contains("Macintosh; Intel Mac OS X 10_14")) + { + options.SameSite = (SameSiteMode)(-1); + } + } + } + public void ConfigureServices(IServiceCollection services) { JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + services.Configure(options => + { + options.MinimumSameSitePolicy = (SameSiteMode)(-1); + options.OnAppendCookie = cookieContext => CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); + options.OnDeleteCookie = cookieContext => CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); + }); + services.AddAuthentication(sharedOptions => { sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; @@ -56,9 +79,15 @@ namespace OpenIdConnectSample .AddCookie() .AddOpenIdConnect(o => { + /* o.ClientId = Configuration["oidc:clientid"]; o.ClientSecret = Configuration["oidc:clientsecret"]; // for code flow o.Authority = Configuration["oidc:authority"]; + */ + // https://github.com/IdentityServer/IdentityServer4.Demo/blob/master/src/IdentityServer4Demo/Config.cs + o.ClientId = "server.hybrid"; + o.ClientSecret = "secret"; // for code flow + o.Authority = "https://demo.identityserver.io/"; o.ResponseType = OpenIdConnectResponseType.CodeIdToken; o.SaveTokens = true; @@ -88,6 +117,7 @@ namespace OpenIdConnectSample public void Configure(IApplicationBuilder app, IOptionsMonitor optionsMonitor) { app.UseDeveloperExceptionPage(); + app.UseCookiePolicy(); // Before UseAuthentication or anything else that writes cookies. app.UseAuthentication(); app.Run(async context => diff --git a/src/Security/Authentication/WsFederation/samples/WsFedSample/WsFedSample.csproj b/src/Security/Authentication/WsFederation/samples/WsFedSample/WsFedSample.csproj index 26f51963cd..6a68d49c8e 100644 --- a/src/Security/Authentication/WsFederation/samples/WsFedSample/WsFedSample.csproj +++ b/src/Security/Authentication/WsFederation/samples/WsFedSample/WsFedSample.csproj @@ -1,4 +1,4 @@ - + net461;netcoreapp2.2 @@ -15,6 +15,7 @@ + diff --git a/src/Security/Authentication/samples/SocialSample/SocialSample.csproj b/src/Security/Authentication/samples/SocialSample/SocialSample.csproj index cce4675916..2081b5cf34 100644 --- a/src/Security/Authentication/samples/SocialSample/SocialSample.csproj +++ b/src/Security/Authentication/samples/SocialSample/SocialSample.csproj @@ -1,4 +1,4 @@ - + net461;netcoreapp2.2 @@ -28,6 +28,7 @@ + diff --git a/src/Security/Authentication/test/CookieTests.cs b/src/Security/Authentication/test/CookieTests.cs index 766d1e2e53..c2445d747c 100644 --- a/src/Security/Authentication/test/CookieTests.cs +++ b/src/Security/Authentication/test/CookieTests.cs @@ -649,7 +649,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies Assert.Contains(" path=/foo", setCookie1); Assert.Contains(" domain=another.com", setCookie1); Assert.Contains(" secure", setCookie1); - Assert.DoesNotContain(" samesite", setCookie1); + Assert.Contains(" samesite=none", setCookie1); Assert.Contains(" httponly", setCookie1); var server2 = CreateServer(o => diff --git a/src/Security/Authentication/test/Microsoft.AspNetCore.Authentication.Test.csproj b/src/Security/Authentication/test/Microsoft.AspNetCore.Authentication.Test.csproj index 922a7843e5..35cea7283a 100644 --- a/src/Security/Authentication/test/Microsoft.AspNetCore.Authentication.Test.csproj +++ b/src/Security/Authentication/test/Microsoft.AspNetCore.Authentication.Test.csproj @@ -1,4 +1,4 @@ - + netcoreapp2.2;net461 @@ -39,6 +39,7 @@ + diff --git a/src/Security/Authentication/test/OpenIdConnect/OpenIdConnectChallengeTests.cs b/src/Security/Authentication/test/OpenIdConnect/OpenIdConnectChallengeTests.cs index cbafc46223..9e2c47a7a7 100644 --- a/src/Security/Authentication/test/OpenIdConnect/OpenIdConnectChallengeTests.cs +++ b/src/Security/Authentication/test/OpenIdConnect/OpenIdConnectChallengeTests.cs @@ -376,6 +376,7 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect var server = settings.CreateTestServer(); var transaction = await server.SendAsync(ChallengeEndpoint); + Assert.Contains("samesite=none", transaction.SetCookie.First()); var challengeCookies = SetCookieHeaderValue.ParseList(transaction.SetCookie); var nonceCookie = challengeCookies.Where(cookie => cookie.Name.StartsWith(OpenIdConnectDefaults.CookieNoncePrefix, StringComparison.Ordinal)).Single(); Assert.True(nonceCookie.Expires.HasValue); @@ -613,4 +614,4 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect Assert.Contains("max_age=1234", res.Headers.Location.Query); } } -} \ No newline at end of file +} diff --git a/src/Security/CookiePolicy/src/CookiePolicyOptions.cs b/src/Security/CookiePolicy/src/CookiePolicyOptions.cs index 32d047297a..dda970a511 100644 --- a/src/Security/CookiePolicy/src/CookiePolicyOptions.cs +++ b/src/Security/CookiePolicy/src/CookiePolicyOptions.cs @@ -12,6 +12,18 @@ namespace Microsoft.AspNetCore.Builder /// public class CookiePolicyOptions { + // True (old): https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-3.1 + // False (new): https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.1 + internal static bool SuppressSameSiteNone; + + static CookiePolicyOptions() + { + if (AppContext.TryGetSwitch("Microsoft.AspNetCore.SuppressSameSiteNone", out var enabled)) + { + SuppressSameSiteNone = enabled; + } + } + /// /// Affects the cookie's same site attribute. /// @@ -49,4 +61,4 @@ namespace Microsoft.AspNetCore.Builder /// public Action OnDeleteCookie { get; set; } } -} \ No newline at end of file +} diff --git a/src/Security/CookiePolicy/src/ResponseCookiesWrapper.cs b/src/Security/CookiePolicy/src/ResponseCookiesWrapper.cs index 126c4d7bd5..1db77125f6 100644 --- a/src/Security/CookiePolicy/src/ResponseCookiesWrapper.cs +++ b/src/Security/CookiePolicy/src/ResponseCookiesWrapper.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -115,7 +115,8 @@ namespace Microsoft.AspNetCore.CookiePolicy private bool CheckPolicyRequired() { return !CanTrack - || Options.MinimumSameSitePolicy != SameSiteMode.None + || (CookiePolicyOptions.SuppressSameSiteNone && Options.MinimumSameSitePolicy != SameSiteMode.None) + || (!CookiePolicyOptions.SuppressSameSiteNone && Options.MinimumSameSitePolicy != (SameSiteMode)(-1)) || Options.HttpOnly != HttpOnlyPolicy.None || Options.Secure != CookieSecurePolicy.None; } @@ -241,26 +242,10 @@ namespace Microsoft.AspNetCore.CookiePolicy default: throw new InvalidOperationException(); } - switch (Options.MinimumSameSitePolicy) + if (options.SameSite < Options.MinimumSameSitePolicy) { - case SameSiteMode.None: - break; - case SameSiteMode.Lax: - if (options.SameSite == SameSiteMode.None) - { - options.SameSite = SameSiteMode.Lax; - _logger.CookieSameSiteUpgraded(key, "lax"); - } - break; - case SameSiteMode.Strict: - if (options.SameSite != SameSiteMode.Strict) - { - options.SameSite = SameSiteMode.Strict; - _logger.CookieSameSiteUpgraded(key, "strict"); - } - break; - default: - throw new InvalidOperationException($"Unrecognized {nameof(SameSiteMode)} value {Options.MinimumSameSitePolicy.ToString()}"); + options.SameSite = Options.MinimumSameSitePolicy; + _logger.CookieSameSiteUpgraded(key, Options.MinimumSameSitePolicy.ToString()); } switch (Options.HttpOnly) { @@ -278,4 +263,4 @@ namespace Microsoft.AspNetCore.CookiePolicy } } } -} \ No newline at end of file +} diff --git a/src/Security/CookiePolicy/test/CookiePolicyTests.cs b/src/Security/CookiePolicy/test/CookiePolicyTests.cs index a2592e5575..2eec9e7b6c 100644 --- a/src/Security/CookiePolicy/test/CookiePolicyTests.cs +++ b/src/Security/CookiePolicy/test/CookiePolicyTests.cs @@ -43,6 +43,7 @@ namespace Microsoft.AspNetCore.CookiePolicy.Test context.Response.Cookies.Append("C", "C", new CookieOptions()); context.Response.Cookies.Append("D", "D", new CookieOptions { SameSite = Http.SameSiteMode.Lax }); context.Response.Cookies.Append("E", "E", new CookieOptions { SameSite = Http.SameSiteMode.Strict }); + context.Response.Cookies.Append("F", "F", new CookieOptions { SameSite = (Http.SameSiteMode)(-1) }); return Task.FromResult(0); }; @@ -198,7 +199,7 @@ namespace Microsoft.AspNetCore.CookiePolicy.Test } [Fact] - public async Task SameSiteNoneLeavesItAlone() + public async Task SameSiteNoneSetsItAlways() { await RunTest("/sameSiteNone", new CookiePolicyOptions @@ -210,11 +211,34 @@ namespace Microsoft.AspNetCore.CookiePolicy.Test transaction => { Assert.NotNull(transaction.SetCookie); - Assert.Equal("A=A; path=/", transaction.SetCookie[0]); - Assert.Equal("B=B; path=/", transaction.SetCookie[1]); + Assert.Equal("A=A; path=/; samesite=lax", transaction.SetCookie[0]); + Assert.Equal("B=B; path=/; samesite=none", transaction.SetCookie[1]); Assert.Equal("C=C; path=/; samesite=lax", transaction.SetCookie[2]); Assert.Equal("D=D; path=/; samesite=lax", transaction.SetCookie[3]); Assert.Equal("E=E; path=/; samesite=strict", transaction.SetCookie[4]); + Assert.Equal("F=F; path=/; samesite=none", transaction.SetCookie[5]); + })); + } + + [Fact] + public async Task SameSiteUnspecifiedLeavesItAlone() + { + await RunTest("/sameSiteNone", + new CookiePolicyOptions + { + MinimumSameSitePolicy = (Http.SameSiteMode)(-1) + }, + SameSiteCookieAppends, + new RequestTest("http://example.com/sameSiteNone", + transaction => + { + Assert.NotNull(transaction.SetCookie); + Assert.Equal("A=A; path=/", transaction.SetCookie[0]); + Assert.Equal("B=B; path=/; samesite=none", transaction.SetCookie[1]); + Assert.Equal("C=C; path=/; samesite=lax", transaction.SetCookie[2]); + Assert.Equal("D=D; path=/; samesite=lax", transaction.SetCookie[3]); + Assert.Equal("E=E; path=/; samesite=strict", transaction.SetCookie[4]); + Assert.Equal("F=F; path=/", transaction.SetCookie[5]); })); } @@ -468,4 +492,4 @@ namespace Microsoft.AspNetCore.CookiePolicy.Test } } } -} \ No newline at end of file +} diff --git a/src/Security/CookiePolicy/test/Microsoft.AspNetCore.CookiePolicy.Test.csproj b/src/Security/CookiePolicy/test/Microsoft.AspNetCore.CookiePolicy.Test.csproj index 0eb3303ede..e8b2d1d106 100644 --- a/src/Security/CookiePolicy/test/Microsoft.AspNetCore.CookiePolicy.Test.csproj +++ b/src/Security/CookiePolicy/test/Microsoft.AspNetCore.CookiePolicy.Test.csproj @@ -1,4 +1,4 @@ - + netcoreapp2.2;net461 @@ -13,6 +13,7 @@ + diff --git a/src/Security/Security.sln b/src/Security/Security.sln index 3d36597db9..557b68ac83 100644 --- a/src/Security/Security.sln +++ b/src/Security/Security.sln @@ -102,6 +102,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.IISIntegration", "..\Servers\IIS\IISIntegration\src\Microsoft.AspNetCore.Server.IISIntegration.csproj", "{81D0E81F-4711-4C7B-BBD4-E168102D0D7D}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Net.Http.Headers", "..\Http\Headers\src\Microsoft.Net.Http.Headers.csproj", "{4BB8D7D7-E111-4A86-B6E5-C1201E0DA8CE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -248,6 +250,10 @@ Global {81D0E81F-4711-4C7B-BBD4-E168102D0D7D}.Debug|Any CPU.Build.0 = Debug|Any CPU {81D0E81F-4711-4C7B-BBD4-E168102D0D7D}.Release|Any CPU.ActiveCfg = Release|Any CPU {81D0E81F-4711-4C7B-BBD4-E168102D0D7D}.Release|Any CPU.Build.0 = Release|Any CPU + {4BB8D7D7-E111-4A86-B6E5-C1201E0DA8CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4BB8D7D7-E111-4A86-B6E5-C1201E0DA8CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4BB8D7D7-E111-4A86-B6E5-C1201E0DA8CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4BB8D7D7-E111-4A86-B6E5-C1201E0DA8CE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -298,6 +304,7 @@ Global {707CBFB4-4D35-479E-9BAF-39B4DA9782DE} = {A3766414-EB5C-40F7-B031-121804ED5D0A} {AFE880E8-2E9E-46FD-BE87-DFC8192E7B2D} = {A3766414-EB5C-40F7-B031-121804ED5D0A} {81D0E81F-4711-4C7B-BBD4-E168102D0D7D} = {A3766414-EB5C-40F7-B031-121804ED5D0A} + {4BB8D7D7-E111-4A86-B6E5-C1201E0DA8CE} = {A3766414-EB5C-40F7-B031-121804ED5D0A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {ABF8089E-43D0-4010-84A7-7A9DCFE49357} From 354d859d50f252526be5a6264434d1765df86450 Mon Sep 17 00:00:00 2001 From: John Luo Date: Mon, 7 Oct 2019 21:00:34 -0700 Subject: [PATCH 15/26] Manually add TypeForwardedTo in ref assemblies (#14538) * Manually add TypeForwardedTo in ref assemblies * Pin ref assembly version to Major.Minor.0.0 * Disable MSB3243 warning * Pin pinning implementation assembly version * Use nuget.exe v5.3.0 which support icon metadata * Fixup nuspec packing --- Directory.Build.targets | 6 +++++ eng/targets/ReferenceAssembly.targets | 9 ++++++- .../Microsoft.AspNetCore.Components.csproj | 5 ++-- ...t.AspNetCore.Components.multitarget.nuspec | 6 ++--- ...AspNetCore.Components.netcoreapp3.0.nuspec | 6 ++--- .../ref/Microsoft.AspNetCore.App.Ref.csproj | 26 +++++++++++++++++-- .../Microsoft.AspNetCore.App.UnitTests.csproj | 12 +++++++++ src/Framework/test/TargetingPackTests.cs | 9 ++++++- src/Framework/test/TestData.cs | 2 ++ ....AspNetCore.Routing.Abstractions.Manual.cs | 13 ++++++++++ ...oft.AspNetCore.Routing.Abstractions.csproj | 1 + .../Windows/GenerateNugetPackageWithMsi.ps1 | 7 ++--- .../SharedFramework/SharedFramework.wixproj | 3 ++- .../SharedFrameworkPackage.nuspec | 2 +- .../TargetingPack/TargetingPack.wixproj | 3 ++- .../TargetingPack/TargetingPackPackage.nuspec | 2 +- ...osoft.AspNetCore.Mvc.ApiExplorer.Manual.cs | 13 ++++++++++ ...icrosoft.AspNetCore.Mvc.ApiExplorer.csproj | 1 + .../Microsoft.AspNetCore.Mvc.Core.Manual.cs | 7 +++++ .../ref/Microsoft.AspNetCore.Mvc.Core.csproj | 1 + ...t.AspNetCore.Mvc.Formatters.Json.Manual.cs | 7 +++++ ...soft.AspNetCore.Mvc.Formatters.Json.csproj | 1 + ...crosoft.AspNetCore.Razor.Runtime.Manual.cs | 23 ++++++++++++++++ .../Microsoft.AspNetCore.Razor.Runtime.csproj | 1 + ...crosoft.AspNetCore.Authorization.Manual.cs | 10 +++++++ .../Microsoft.AspNetCore.Authorization.csproj | 2 ++ .../Microsoft.AspNetCore.Server.IIS.Manual.cs | 8 ++++++ .../Microsoft.AspNetCore.Server.IIS.csproj | 1 + 28 files changed, 167 insertions(+), 20 deletions(-) create mode 100644 src/Http/Routing.Abstractions/ref/Microsoft.AspNetCore.Routing.Abstractions.Manual.cs create mode 100644 src/Mvc/Mvc.ApiExplorer/ref/Microsoft.AspNetCore.Mvc.ApiExplorer.Manual.cs create mode 100644 src/Mvc/Mvc.Core/ref/Microsoft.AspNetCore.Mvc.Core.Manual.cs create mode 100644 src/Mvc/Mvc.Formatters.Json/ref/Microsoft.AspNetCore.Mvc.Formatters.Json.Manual.cs create mode 100644 src/Razor/Razor.Runtime/ref/Microsoft.AspNetCore.Razor.Runtime.Manual.cs create mode 100644 src/Security/Authorization/Core/ref/Microsoft.AspNetCore.Authorization.Manual.cs create mode 100644 src/Servers/IIS/IIS/ref/Microsoft.AspNetCore.Server.IIS.Manual.cs diff --git a/Directory.Build.targets b/Directory.Build.targets index 0bbb16aa49..db3cea59f1 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -105,6 +105,12 @@ + + + + $(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion).0.0 + + diff --git a/eng/targets/ReferenceAssembly.targets b/eng/targets/ReferenceAssembly.targets index bb6230e633..74cbf583e3 100644 --- a/eng/targets/ReferenceAssembly.targets +++ b/eng/targets/ReferenceAssembly.targets @@ -47,6 +47,7 @@ <_RefSourceOutputPath>$([System.IO.Directory]::GetParent('$(MSBuildProjectDirectory)'))/ref/ <_RefSourceFileName>$(AssemblyName).$(TargetFramework).cs + <_ManualRefSourceFileName>$(AssemblyName).Manual.cs <_RefSourceFileOutputPath>$(_RefSourceOutputPath)$(_RefSourceFileName) @@ -76,10 +77,16 @@ + <_ManualReferenceAssemblyContent /> + <_ManualReferenceAssemblyContent Condition="Exists('$(_RefSourceOutputPath)$(_ManualRefSourceFileName)')"> + ]]> + + - + ]]>$(_ManualReferenceAssemblyContent)'', '%0A ') ]]> diff --git a/src/Components/Components/src/Microsoft.AspNetCore.Components.csproj b/src/Components/Components/src/Microsoft.AspNetCore.Components.csproj index f4cc80aad5..bffd047457 100644 --- a/src/Components/Components/src/Microsoft.AspNetCore.Components.csproj +++ b/src/Components/Components/src/Microsoft.AspNetCore.Components.csproj @@ -53,9 +53,8 @@ - - - + + diff --git a/src/Components/Components/src/Microsoft.AspNetCore.Components.multitarget.nuspec b/src/Components/Components/src/Microsoft.AspNetCore.Components.multitarget.nuspec index 941b82323b..585e6ed49c 100644 --- a/src/Components/Components/src/Microsoft.AspNetCore.Components.multitarget.nuspec +++ b/src/Components/Components/src/Microsoft.AspNetCore.Components.multitarget.nuspec @@ -18,9 +18,9 @@ packageIcon.png - - - + + + diff --git a/src/Components/Components/src/Microsoft.AspNetCore.Components.netcoreapp3.0.nuspec b/src/Components/Components/src/Microsoft.AspNetCore.Components.netcoreapp3.0.nuspec index d218582bba..239e775650 100644 --- a/src/Components/Components/src/Microsoft.AspNetCore.Components.netcoreapp3.0.nuspec +++ b/src/Components/Components/src/Microsoft.AspNetCore.Components.netcoreapp3.0.nuspec @@ -12,9 +12,9 @@ packageIcon.png - - - + + + diff --git a/src/Framework/ref/Microsoft.AspNetCore.App.Ref.csproj b/src/Framework/ref/Microsoft.AspNetCore.App.Ref.csproj index ff5fa19191..c8c23952f8 100644 --- a/src/Framework/ref/Microsoft.AspNetCore.App.Ref.csproj +++ b/src/Framework/ref/Microsoft.AspNetCore.App.Ref.csproj @@ -36,10 +36,17 @@ This package is an internal implementation of the .NET Core SDK and is not meant true + + MSB3243 FrameworkList.xml $(ArtifactsObjDir)$(FrameworkListFileName) + + + $(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion).0 + $(ReferencePackSharedFxVersion)-$(VersionSuffix) + $(ArtifactsObjDir)ref\PlatformManifest.txt @@ -93,6 +100,7 @@ This package is an internal implementation of the .NET Core SDK and is not meant @@ -109,6 +117,7 @@ This package is an internal implementation of the .NET Core SDK and is not meant Exclude=" @(_SelectedExtensionsRefAssemblies); @(ReferencePathWithRefAssemblies->WithMetadataValue('NuGetPackageId', 'Microsoft.NETCore.App.Ref')); + @(ReferencePathWithRefAssemblies->WithMetadataValue('IsReferenceAssembly', 'false')); @(ReferencePathWithRefAssemblies->WithMetadataValue('ReferenceGrouping', 'Microsoft.NETCore.App'));" /> + + + + - + @@ -128,9 +149,10 @@ This package is an internal implementation of the .NET Core SDK and is not meant DependsOnTargets="ResolveReferences" Inputs="$(MSBuildAllProjects)" Outputs="$(TargetDir)$(PackageConflictManifestFileName)"> + <_AspNetCoreAppPackageOverrides Include="@(ReferencePath->'%(NuGetPackageId)|%(NuGetPackageVersion)')" Condition=" '%(ReferencePath.NuGetPackageId)' != 'Microsoft.NETCore.App' AND '%(ReferencePath.NuGetSourceType)' == 'Package' " /> - <_AspNetCoreAppPackageOverrides Include="@(ReferencePath->'%(FileName)|$(SharedFxVersion)')" Condition=" '%(ReferencePath.ReferenceSourceTarget)' == 'ProjectReference' " /> + <_AspNetCoreAppPackageOverrides Include="@(ReferencePath->'%(FileName)|$(ReferencePackSharedFxVersion)')" Condition=" '%(ReferencePath.ReferenceSourceTarget)' == 'ProjectReference' AND '%(ReferencePath.IsReferenceAssembly)' == 'true' " /> + + + + + + + <_Parameter1>TargetingPackDependencies + <_Parameter2>@(_TargetingPackDependencies) + + <_Parameter1>RepositoryCommit <_Parameter2>$(SourceRevisionId) diff --git a/src/Framework/test/TargetingPackTests.cs b/src/Framework/test/TargetingPackTests.cs index 8222092260..8a2625b99d 100644 --- a/src/Framework/test/TargetingPackTests.cs +++ b/src/Framework/test/TargetingPackTests.cs @@ -59,8 +59,15 @@ namespace Microsoft.AspNetCore public void PlatformManifestListsAllFiles() { var platformManifestPath = Path.Combine(_targetingPackRoot, "data", "PlatformManifest.txt"); - var expectedAssemblies = TestData.GetSharedFxDependencies() + var expectedAssemblies = TestData.GetTargetingPackDependencies() .Split(';', StringSplitOptions.RemoveEmptyEntries) + .Select(i => + { + var fileName = Path.GetFileName(i); + return fileName.EndsWith(".dll", StringComparison.Ordinal) + ? fileName.Substring(0, fileName.Length - 4) + : fileName; + }) .ToHashSet(); _output.WriteLine("==== file contents ===="); diff --git a/src/Framework/test/TestData.cs b/src/Framework/test/TestData.cs index ede8565f85..594f7693a4 100644 --- a/src/Framework/test/TestData.cs +++ b/src/Framework/test/TestData.cs @@ -18,6 +18,8 @@ namespace Microsoft.AspNetCore public static string GetSharedFxDependencies() => GetTestDataValue("SharedFxDependencies"); + public static string GetTargetingPackDependencies() => GetTestDataValue("TargetingPackDependencies"); + public static string GetTestDataValue(string key) => typeof(TestData).Assembly.GetCustomAttributes().Single(d => d.Key == key).Value; } diff --git a/src/Http/Routing.Abstractions/ref/Microsoft.AspNetCore.Routing.Abstractions.Manual.cs b/src/Http/Routing.Abstractions/ref/Microsoft.AspNetCore.Routing.Abstractions.Manual.cs new file mode 100644 index 0000000000..9a0e3418cf --- /dev/null +++ b/src/Http/Routing.Abstractions/ref/Microsoft.AspNetCore.Routing.Abstractions.Manual.cs @@ -0,0 +1,13 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Runtime.CompilerServices; +using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; + +[assembly: TypeForwardedTo(typeof(IEndpointFeature))] +[assembly: TypeForwardedTo(typeof(IRouteValuesFeature))] +[assembly: TypeForwardedTo(typeof(Endpoint))] +[assembly: TypeForwardedTo(typeof(EndpointMetadataCollection))] +[assembly: TypeForwardedTo(typeof(RouteValueDictionary))] diff --git a/src/Http/Routing.Abstractions/ref/Microsoft.AspNetCore.Routing.Abstractions.csproj b/src/Http/Routing.Abstractions/ref/Microsoft.AspNetCore.Routing.Abstractions.csproj index 909f00e6e0..fe6fa231aa 100644 --- a/src/Http/Routing.Abstractions/ref/Microsoft.AspNetCore.Routing.Abstractions.csproj +++ b/src/Http/Routing.Abstractions/ref/Microsoft.AspNetCore.Routing.Abstractions.csproj @@ -5,6 +5,7 @@ + diff --git a/src/Installers/Windows/GenerateNugetPackageWithMsi.ps1 b/src/Installers/Windows/GenerateNugetPackageWithMsi.ps1 index 4c1c4970dc..b0c497b985 100644 --- a/src/Installers/Windows/GenerateNugetPackageWithMsi.ps1 +++ b/src/Installers/Windows/GenerateNugetPackageWithMsi.ps1 @@ -11,7 +11,8 @@ param( [Parameter(Mandatory=$true)][string]$PackageVersion, [Parameter(Mandatory=$true)][string]$RepoRoot, [Parameter(Mandatory=$true)][string]$MajorVersion, - [Parameter(Mandatory=$true)][string]$MinorVersion + [Parameter(Mandatory=$true)][string]$MinorVersion, + [Parameter(Mandatory=$true)][string]$PackageIconPath ) $NuGetDir = Join-Path $RepoRoot "artifacts\Tools\nuget\$Name\$Architecture" @@ -24,8 +25,8 @@ if (-not (Test-Path $NuGetDir)) { if (-not (Test-Path $NuGetExe)) { # Using 3.5.0 to workaround https://github.com/NuGet/Home/issues/5016 Write-Output "Downloading nuget.exe to $NuGetExe" - wget https://dist.nuget.org/win-x86-commandline/latest/nuget.exe -OutFile $NuGetExe + wget https://dist.nuget.org/win-x86-commandline/v5.3.0/nuget.exe -OutFile $NuGetExe } -& $NuGetExe pack $NuspecFile -Version $PackageVersion -OutputDirectory $OutputDirectory -NoDefaultExcludes -NoPackageAnalysis -Properties ASPNETCORE_RUNTIME_MSI=$MsiPath`;ASPNETCORE_CAB_FILE=$CabPath`;ARCH=$Architecture`;MAJOR=$MajorVersion`;MINOR=$MinorVersion`; +& $NuGetExe pack $NuspecFile -Version $PackageVersion -OutputDirectory $OutputDirectory -NoDefaultExcludes -NoPackageAnalysis -Properties ASPNETCORE_RUNTIME_MSI=$MsiPath`;ASPNETCORE_CAB_FILE=$CabPath`;ARCH=$Architecture`;MAJOR=$MajorVersion`;MINOR=$MinorVersion`;PACKAGE_ICON_PATH=$PackageIconPath`; Exit $LastExitCode \ No newline at end of file diff --git a/src/Installers/Windows/SharedFramework/SharedFramework.wixproj b/src/Installers/Windows/SharedFramework/SharedFramework.wixproj index afb754e2dd..4404e17ce7 100644 --- a/src/Installers/Windows/SharedFramework/SharedFramework.wixproj +++ b/src/Installers/Windows/SharedFramework/SharedFramework.wixproj @@ -106,6 +106,7 @@ '$(_GeneratedPackageVersion)' ^ '$(RepoRoot)' ^ '$(AspNetCoreMajorVersion)' ^ - '$(AspNetCoreMinorVersion)'" /> + '$(AspNetCoreMinorVersion)' ^ + '$(PackageIconFullPath)'" /> diff --git a/src/Installers/Windows/SharedFramework/SharedFrameworkPackage.nuspec b/src/Installers/Windows/SharedFramework/SharedFrameworkPackage.nuspec index e0deb1cb9f..66e9055af4 100644 --- a/src/Installers/Windows/SharedFramework/SharedFrameworkPackage.nuspec +++ b/src/Installers/Windows/SharedFramework/SharedFrameworkPackage.nuspec @@ -16,6 +16,6 @@ - + diff --git a/src/Installers/Windows/TargetingPack/TargetingPack.wixproj b/src/Installers/Windows/TargetingPack/TargetingPack.wixproj index 80065cb692..0bf3a72d58 100644 --- a/src/Installers/Windows/TargetingPack/TargetingPack.wixproj +++ b/src/Installers/Windows/TargetingPack/TargetingPack.wixproj @@ -101,6 +101,7 @@ '$(_GeneratedPackageVersion)' ^ '$(RepoRoot)' ^ '$(AspNetCoreMajorVersion)' ^ - '$(AspNetCoreMinorVersion)'" /> + '$(AspNetCoreMinorVersion)' ^ + '$(PackageIconFullPath)'" /> diff --git a/src/Installers/Windows/TargetingPack/TargetingPackPackage.nuspec b/src/Installers/Windows/TargetingPack/TargetingPackPackage.nuspec index c1b74d2689..5c85b569ba 100644 --- a/src/Installers/Windows/TargetingPack/TargetingPackPackage.nuspec +++ b/src/Installers/Windows/TargetingPack/TargetingPackPackage.nuspec @@ -15,6 +15,6 @@ - + diff --git a/src/Mvc/Mvc.ApiExplorer/ref/Microsoft.AspNetCore.Mvc.ApiExplorer.Manual.cs b/src/Mvc/Mvc.ApiExplorer/ref/Microsoft.AspNetCore.Mvc.ApiExplorer.Manual.cs new file mode 100644 index 0000000000..55c1e57727 --- /dev/null +++ b/src/Mvc/Mvc.ApiExplorer/ref/Microsoft.AspNetCore.Mvc.ApiExplorer.Manual.cs @@ -0,0 +1,13 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Runtime.CompilerServices; + +[assembly: TypeForwardedTo(typeof(Microsoft.AspNetCore.Mvc.ApiExplorer.IApiDescriptionProvider))] +[assembly: TypeForwardedTo(typeof(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription))] +[assembly: TypeForwardedTo(typeof(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescriptionProviderContext))] +[assembly: TypeForwardedTo(typeof(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterDescription))] +[assembly: TypeForwardedTo(typeof(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterRouteInfo))] +[assembly: TypeForwardedTo(typeof(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiRequestFormat))] +[assembly: TypeForwardedTo(typeof(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiResponseFormat))] +[assembly: TypeForwardedTo(typeof(Microsoft.AspNetCore.Mvc.ApiExplorer.ApiResponseType))] diff --git a/src/Mvc/Mvc.ApiExplorer/ref/Microsoft.AspNetCore.Mvc.ApiExplorer.csproj b/src/Mvc/Mvc.ApiExplorer/ref/Microsoft.AspNetCore.Mvc.ApiExplorer.csproj index 791b79a913..10680b3401 100644 --- a/src/Mvc/Mvc.ApiExplorer/ref/Microsoft.AspNetCore.Mvc.ApiExplorer.csproj +++ b/src/Mvc/Mvc.ApiExplorer/ref/Microsoft.AspNetCore.Mvc.ApiExplorer.csproj @@ -5,6 +5,7 @@ + diff --git a/src/Mvc/Mvc.Core/ref/Microsoft.AspNetCore.Mvc.Core.Manual.cs b/src/Mvc/Mvc.Core/ref/Microsoft.AspNetCore.Mvc.Core.Manual.cs new file mode 100644 index 0000000000..d3e44fb471 --- /dev/null +++ b/src/Mvc/Mvc.Core/ref/Microsoft.AspNetCore.Mvc.Core.Manual.cs @@ -0,0 +1,7 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Runtime.CompilerServices; +using Microsoft.AspNetCore.Mvc.Formatters; + +[assembly: TypeForwardedTo(typeof(InputFormatterException))] diff --git a/src/Mvc/Mvc.Core/ref/Microsoft.AspNetCore.Mvc.Core.csproj b/src/Mvc/Mvc.Core/ref/Microsoft.AspNetCore.Mvc.Core.csproj index d319a85c95..e6b5b968a8 100644 --- a/src/Mvc/Mvc.Core/ref/Microsoft.AspNetCore.Mvc.Core.csproj +++ b/src/Mvc/Mvc.Core/ref/Microsoft.AspNetCore.Mvc.Core.csproj @@ -5,6 +5,7 @@ + diff --git a/src/Mvc/Mvc.Formatters.Json/ref/Microsoft.AspNetCore.Mvc.Formatters.Json.Manual.cs b/src/Mvc/Mvc.Formatters.Json/ref/Microsoft.AspNetCore.Mvc.Formatters.Json.Manual.cs new file mode 100644 index 0000000000..039f419cd4 --- /dev/null +++ b/src/Mvc/Mvc.Formatters.Json/ref/Microsoft.AspNetCore.Mvc.Formatters.Json.Manual.cs @@ -0,0 +1,7 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Runtime.CompilerServices; +using Microsoft.AspNetCore.Mvc; + +[assembly: TypeForwardedTo(typeof(JsonResult))] diff --git a/src/Mvc/Mvc.Formatters.Json/ref/Microsoft.AspNetCore.Mvc.Formatters.Json.csproj b/src/Mvc/Mvc.Formatters.Json/ref/Microsoft.AspNetCore.Mvc.Formatters.Json.csproj index c32a9966a4..520d3abb20 100644 --- a/src/Mvc/Mvc.Formatters.Json/ref/Microsoft.AspNetCore.Mvc.Formatters.Json.csproj +++ b/src/Mvc/Mvc.Formatters.Json/ref/Microsoft.AspNetCore.Mvc.Formatters.Json.csproj @@ -5,6 +5,7 @@ + diff --git a/src/Razor/Razor.Runtime/ref/Microsoft.AspNetCore.Razor.Runtime.Manual.cs b/src/Razor/Razor.Runtime/ref/Microsoft.AspNetCore.Razor.Runtime.Manual.cs new file mode 100644 index 0000000000..8549a23cd4 --- /dev/null +++ b/src/Razor/Razor.Runtime/ref/Microsoft.AspNetCore.Razor.Runtime.Manual.cs @@ -0,0 +1,23 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Runtime.CompilerServices; +using Microsoft.AspNetCore.Razor.TagHelpers; + +[assembly: TypeForwardedTo(typeof(DefaultTagHelperContent))] +[assembly: TypeForwardedTo(typeof(HtmlAttributeNameAttribute))] +[assembly: TypeForwardedTo(typeof(HtmlAttributeNotBoundAttribute))] +[assembly: TypeForwardedTo(typeof(HtmlTargetElementAttribute))] +[assembly: TypeForwardedTo(typeof(ITagHelper))] +[assembly: TypeForwardedTo(typeof(ITagHelperComponent))] +[assembly: TypeForwardedTo(typeof(NullHtmlEncoder))] +[assembly: TypeForwardedTo(typeof(OutputElementHintAttribute))] +[assembly: TypeForwardedTo(typeof(ReadOnlyTagHelperAttributeList))] +[assembly: TypeForwardedTo(typeof(RestrictChildrenAttribute))] +[assembly: TypeForwardedTo(typeof(TagHelper))] +[assembly: TypeForwardedTo(typeof(TagHelperAttribute))] +[assembly: TypeForwardedTo(typeof(TagHelperAttributeList))] +[assembly: TypeForwardedTo(typeof(TagHelperComponent))] +[assembly: TypeForwardedTo(typeof(TagHelperContent))] +[assembly: TypeForwardedTo(typeof(TagHelperContext))] +[assembly: TypeForwardedTo(typeof(TagHelperOutput))] \ No newline at end of file diff --git a/src/Razor/Razor.Runtime/ref/Microsoft.AspNetCore.Razor.Runtime.csproj b/src/Razor/Razor.Runtime/ref/Microsoft.AspNetCore.Razor.Runtime.csproj index 54f42c224a..8f18b18879 100644 --- a/src/Razor/Razor.Runtime/ref/Microsoft.AspNetCore.Razor.Runtime.csproj +++ b/src/Razor/Razor.Runtime/ref/Microsoft.AspNetCore.Razor.Runtime.csproj @@ -5,6 +5,7 @@ + diff --git a/src/Security/Authorization/Core/ref/Microsoft.AspNetCore.Authorization.Manual.cs b/src/Security/Authorization/Core/ref/Microsoft.AspNetCore.Authorization.Manual.cs new file mode 100644 index 0000000000..84fc42f7ab --- /dev/null +++ b/src/Security/Authorization/Core/ref/Microsoft.AspNetCore.Authorization.Manual.cs @@ -0,0 +1,10 @@ + +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Runtime.CompilerServices; +using Microsoft.AspNetCore.Authorization; + +// Microsoft.AspNetCore.Metadata +[assembly: TypeForwardedTo(typeof(IAuthorizeData))] +[assembly: TypeForwardedTo(typeof(IAllowAnonymous))] diff --git a/src/Security/Authorization/Core/ref/Microsoft.AspNetCore.Authorization.csproj b/src/Security/Authorization/Core/ref/Microsoft.AspNetCore.Authorization.csproj index 64c2d6f679..6b81f7e2ca 100644 --- a/src/Security/Authorization/Core/ref/Microsoft.AspNetCore.Authorization.csproj +++ b/src/Security/Authorization/Core/ref/Microsoft.AspNetCore.Authorization.csproj @@ -5,12 +5,14 @@ + + diff --git a/src/Servers/IIS/IIS/ref/Microsoft.AspNetCore.Server.IIS.Manual.cs b/src/Servers/IIS/IIS/ref/Microsoft.AspNetCore.Server.IIS.Manual.cs new file mode 100644 index 0000000000..ab9860b033 --- /dev/null +++ b/src/Servers/IIS/IIS/ref/Microsoft.AspNetCore.Server.IIS.Manual.cs @@ -0,0 +1,8 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Runtime.CompilerServices; +using Microsoft.AspNetCore.Http.Features; + +[assembly: TypeForwardedTo(typeof(IServerVariablesFeature))] + diff --git a/src/Servers/IIS/IIS/ref/Microsoft.AspNetCore.Server.IIS.csproj b/src/Servers/IIS/IIS/ref/Microsoft.AspNetCore.Server.IIS.csproj index 72d9c85999..371f23089c 100644 --- a/src/Servers/IIS/IIS/ref/Microsoft.AspNetCore.Server.IIS.csproj +++ b/src/Servers/IIS/IIS/ref/Microsoft.AspNetCore.Server.IIS.csproj @@ -5,6 +5,7 @@ + From 6fc778af6a9327930cb6842d4aeafd5e0625aa9c Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Thu, 3 Oct 2019 13:31:44 -0700 Subject: [PATCH 16/26] disable building Microsoft.AspNetCore.App.Ref package in 3.0 --- src/Framework/ref/Microsoft.AspNetCore.App.Ref.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Framework/ref/Microsoft.AspNetCore.App.Ref.csproj b/src/Framework/ref/Microsoft.AspNetCore.App.Ref.csproj index c8c23952f8..9fc826b1ab 100644 --- a/src/Framework/ref/Microsoft.AspNetCore.App.Ref.csproj +++ b/src/Framework/ref/Microsoft.AspNetCore.App.Ref.csproj @@ -85,7 +85,7 @@ This package is an internal implementation of the .NET Core SDK and is not meant - + From 527b4e1c58cded4f72484901aad47aed7d3c485a Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Fri, 4 Oct 2019 15:50:40 -0700 Subject: [PATCH 17/26] Update condition for targetingPackBuilding --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 1d002b3001..440c9d79a8 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -91,7 +91,7 @@ aspnetcore-targeting-pack - false + false - + $(PackageId)_$(DebPackageVersion)-$(PackageRevision)_$(DebianPackageArch).deb diff --git a/src/Installers/Windows/TargetingPack/TargetingPack.wixproj b/src/Installers/Windows/TargetingPack/TargetingPack.wixproj index 0bf3a72d58..e7cbb1f2ce 100644 --- a/src/Installers/Windows/TargetingPack/TargetingPack.wixproj +++ b/src/Installers/Windows/TargetingPack/TargetingPack.wixproj @@ -9,6 +9,7 @@ $(Name)-$(Platform) Package true + true 0AC34F1B-8056-4FFB-A398-E6BB7D67B48D true 5150;5151 diff --git a/src/Installers/Windows/Wix.targets b/src/Installers/Windows/Wix.targets index f7323ee110..a6c7224a84 100644 --- a/src/Installers/Windows/Wix.targets +++ b/src/Installers/Windows/Wix.targets @@ -63,7 +63,7 @@ From dd13c8737adb1f955ba8a48d21217313d4d16b96 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Sat, 5 Oct 2019 00:03:05 -0700 Subject: [PATCH 19/26] Update src/Framework/ref/Microsoft.AspNetCore.App.Ref.csproj Co-Authored-By: Doug Bunting <6431421+dougbu@users.noreply.github.com> --- src/Framework/ref/Microsoft.AspNetCore.App.Ref.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Framework/ref/Microsoft.AspNetCore.App.Ref.csproj b/src/Framework/ref/Microsoft.AspNetCore.App.Ref.csproj index 9fc826b1ab..4f34f355d5 100644 --- a/src/Framework/ref/Microsoft.AspNetCore.App.Ref.csproj +++ b/src/Framework/ref/Microsoft.AspNetCore.App.Ref.csproj @@ -85,7 +85,7 @@ This package is an internal implementation of the .NET Core SDK and is not meant - + From b89103fd5fba0ac879e3fa0cd9c9e17c60b54f0c Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Tue, 8 Oct 2019 11:18:37 -0700 Subject: [PATCH 20/26] Fix Xunit skip attribute --- src/Framework/test/TargetingPackTests.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Framework/test/TargetingPackTests.cs b/src/Framework/test/TargetingPackTests.cs index 4d47e7894c..5e715f2e8f 100644 --- a/src/Framework/test/TargetingPackTests.cs +++ b/src/Framework/test/TargetingPackTests.cs @@ -55,8 +55,7 @@ namespace Microsoft.AspNetCore }); } - [Fact] - [Skip] + [Fact(Skip="https://github.com/aspnet/AspNetCore/issues/14832")] public void PlatformManifestListsAllFiles() { var platformManifestPath = Path.Combine(_targetingPackRoot, "data", "PlatformManifest.txt"); From 5e2e1cdfd3c540f2b165ed4feb06b7baa884b7e3 Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Tue, 8 Oct 2019 12:32:37 -0700 Subject: [PATCH 21/26] disable other targeting pack test --- src/Framework/test/TargetingPackTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Framework/test/TargetingPackTests.cs b/src/Framework/test/TargetingPackTests.cs index 5e715f2e8f..ec8a646f48 100644 --- a/src/Framework/test/TargetingPackTests.cs +++ b/src/Framework/test/TargetingPackTests.cs @@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore _targetingPackRoot = Path.Combine(TestData.GetTestDataValue("TargetingPackLayoutRoot"), "packs", "Microsoft.AspNetCore.App.Ref", TestData.GetTestDataValue("TargetingPackVersion")); } - [Fact] + [Fact(Skip="https://github.com/aspnet/AspNetCore/issues/14832")] public void AssembliesAreReferenceAssemblies() { IEnumerable dlls = Directory.GetFiles(_targetingPackRoot, "*.dll", SearchOption.AllDirectories); From c0a7f04370054e3625f93350237596046fa9534b Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Wed, 9 Oct 2019 14:19:33 -0700 Subject: [PATCH 22/26] [3.0 patch] Re-implement SameSite for 2019 (#13870) --- eng/PatchConfig.props | 4 + src/Http/Headers/src/SetCookieHeaderValue.cs | 76 ++++++++--- .../Headers/test/SetCookieHeaderValueTest.cs | 124 +++++++++++++++++- .../Http.Abstractions/src/CookieBuilder.cs | 16 ++- src/Http/Http.Features/src/CookieOptions.cs | 16 ++- .../OpenIdConnectSample.csproj | 2 + .../samples/OpenIdConnectSample/Startup.cs | 24 ++++ .../samples/WsFedSample/WsFedSample.csproj | 1 + .../Authentication/test/CookieTests.cs | 2 +- ...soft.AspNetCore.Authentication.Test.csproj | 1 + .../OpenIdConnectChallengeTests.cs | 1 + .../CookiePolicy/src/CookiePolicyOptions.cs | 14 +- .../src/ResponseCookiesWrapper.cs | 31 ++--- .../CookiePolicy/test/CookieConsentTests.cs | 12 +- .../CookiePolicy/test/CookiePolicyTests.cs | 29 +++- ...rosoft.AspNetCore.CookiePolicy.Test.csproj | 1 + 16 files changed, 293 insertions(+), 61 deletions(-) diff --git a/eng/PatchConfig.props b/eng/PatchConfig.props index 1dfe2a7fc8..e19b7d39d5 100644 --- a/eng/PatchConfig.props +++ b/eng/PatchConfig.props @@ -17,6 +17,10 @@ Directory.Build.props checks this property using the following condition: Microsoft.AspNetCore.DataProtection.EntityFrameworkCore; @microsoft/signalr; + Microsoft.Net.Http.Headers; + Microsoft.AspNetCore.Http.Abstractions; + Microsoft.AspNetCore.Http.Features; + Microsoft.AspNetCore.CookiePolicy; diff --git a/src/Http/Headers/src/SetCookieHeaderValue.cs b/src/Http/Headers/src/SetCookieHeaderValue.cs index 8529593486..0f23b10fd8 100644 --- a/src/Http/Headers/src/SetCookieHeaderValue.cs +++ b/src/Http/Headers/src/SetCookieHeaderValue.cs @@ -20,8 +20,14 @@ namespace Microsoft.Net.Http.Headers private const string SecureToken = "secure"; // RFC Draft: https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 private const string SameSiteToken = "samesite"; + private static readonly string SameSiteNoneToken = SameSiteMode.None.ToString().ToLower(); private static readonly string SameSiteLaxToken = SameSiteMode.Lax.ToString().ToLower(); private static readonly string SameSiteStrictToken = SameSiteMode.Strict.ToString().ToLower(); + + // True (old): https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-3.1 + // False (new): https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.1 + internal static bool SuppressSameSiteNone; + private const string HttpOnlyToken = "httponly"; private const string SeparatorToken = "; "; private const string EqualsToken = "="; @@ -36,6 +42,14 @@ namespace Microsoft.Net.Http.Headers private StringSegment _name; private StringSegment _value; + static SetCookieHeaderValue() + { + if (AppContext.TryGetSwitch("Microsoft.AspNetCore.SuppressSameSiteNone", out var enabled)) + { + SuppressSameSiteNone = enabled; + } + } + private SetCookieHeaderValue() { // Used by the parser to create a new instance of this type. @@ -92,16 +106,17 @@ namespace Microsoft.Net.Http.Headers public bool Secure { get; set; } - public SameSiteMode SameSite { get; set; } + public SameSiteMode SameSite { get; set; } = SuppressSameSiteNone ? SameSiteMode.None : (SameSiteMode)(-1); // Unspecified public bool HttpOnly { get; set; } - // name="value"; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={Strict|Lax}; httponly + // name="value"; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={strict|lax|none}; httponly public override string ToString() { var length = _name.Length + EqualsToken.Length + _value.Length; string maxAge = null; + string sameSite = null; if (Expires.HasValue) { @@ -129,9 +144,20 @@ namespace Microsoft.Net.Http.Headers length += SeparatorToken.Length + SecureToken.Length; } - if (SameSite != SameSiteMode.None) + // Allow for Unspecified (-1) to skip SameSite + if (SameSite == SameSiteMode.None && !SuppressSameSiteNone) { - var sameSite = SameSite == SameSiteMode.Lax ? SameSiteLaxToken : SameSiteStrictToken; + sameSite = SameSiteNoneToken; + length += SeparatorToken.Length + SameSiteToken.Length + EqualsToken.Length + sameSite.Length; + } + else if (SameSite == SameSiteMode.Lax) + { + sameSite = SameSiteLaxToken; + length += SeparatorToken.Length + SameSiteToken.Length + EqualsToken.Length + sameSite.Length; + } + else if (SameSite == SameSiteMode.Strict) + { + sameSite = SameSiteStrictToken; length += SeparatorToken.Length + SameSiteToken.Length + EqualsToken.Length + sameSite.Length; } @@ -140,9 +166,9 @@ namespace Microsoft.Net.Http.Headers length += SeparatorToken.Length + HttpOnlyToken.Length; } - return string.Create(length, (this, maxAge), (span, tuple) => + return string.Create(length, (this, maxAge, sameSite), (span, tuple) => { - var (headerValue, maxAgeValue) = tuple; + var (headerValue, maxAgeValue, sameSite) = tuple; Append(ref span, headerValue._name); Append(ref span, EqualsToken); @@ -180,9 +206,9 @@ namespace Microsoft.Net.Http.Headers AppendSegment(ref span, SecureToken, null); } - if (headerValue.SameSite != SameSiteMode.None) + if (sameSite != null) { - AppendSegment(ref span, SameSiteToken, headerValue.SameSite == SameSiteMode.Lax ? SameSiteLaxToken : SameSiteStrictToken); + AppendSegment(ref span, SameSiteToken, sameSite); } if (headerValue.HttpOnly) @@ -248,9 +274,18 @@ namespace Microsoft.Net.Http.Headers AppendSegment(builder, SecureToken, null); } - if (SameSite != SameSiteMode.None) + // Allow for Unspecified (-1) to skip SameSite + if (SameSite == SameSiteMode.None && !SuppressSameSiteNone) { - AppendSegment(builder, SameSiteToken, SameSite == SameSiteMode.Lax ? SameSiteLaxToken : SameSiteStrictToken); + AppendSegment(builder, SameSiteToken, SameSiteNoneToken); + } + else if (SameSite == SameSiteMode.Lax) + { + AppendSegment(builder, SameSiteToken, SameSiteLaxToken); + } + else if (SameSite == SameSiteMode.Strict) + { + AppendSegment(builder, SameSiteToken, SameSiteStrictToken); } if (HttpOnly) @@ -302,7 +337,7 @@ namespace Microsoft.Net.Http.Headers return MultipleValueParser.TryParseStrictValues(inputs, out parsedValues); } - // name=value; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={Strict|Lax}; httponly + // name=value; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={Strict|Lax|None}; httponly private static int GetSetCookieLength(StringSegment input, int startIndex, out SetCookieHeaderValue parsedValue) { Contract.Requires(startIndex >= 0); @@ -437,25 +472,34 @@ namespace Microsoft.Net.Http.Headers { result.Secure = true; } - // samesite-av = "SameSite" / "SameSite=" samesite-value - // samesite-value = "Strict" / "Lax" + // samesite-av = "SameSite=" samesite-value + // samesite-value = "Strict" / "Lax" / "None" else if (StringSegment.Equals(token, SameSiteToken, StringComparison.OrdinalIgnoreCase)) { if (!ReadEqualsSign(input, ref offset)) { - result.SameSite = SameSiteMode.Strict; + result.SameSite = SuppressSameSiteNone ? SameSiteMode.Strict : (SameSiteMode)(-1); // Unspecified } else { var enforcementMode = ReadToSemicolonOrEnd(input, ref offset); - if (StringSegment.Equals(enforcementMode, SameSiteLaxToken, StringComparison.OrdinalIgnoreCase)) + if (StringSegment.Equals(enforcementMode, SameSiteStrictToken, StringComparison.OrdinalIgnoreCase)) + { + result.SameSite = SameSiteMode.Strict; + } + else if (StringSegment.Equals(enforcementMode, SameSiteLaxToken, StringComparison.OrdinalIgnoreCase)) { result.SameSite = SameSiteMode.Lax; } + else if (!SuppressSameSiteNone + && StringSegment.Equals(enforcementMode, SameSiteNoneToken, StringComparison.OrdinalIgnoreCase)) + { + result.SameSite = SameSiteMode.None; + } else { - result.SameSite = SameSiteMode.Strict; + result.SameSite = SuppressSameSiteNone ? SameSiteMode.Strict : (SameSiteMode)(-1); // Unspecified } } } diff --git a/src/Http/Headers/test/SetCookieHeaderValueTest.cs b/src/Http/Headers/test/SetCookieHeaderValueTest.cs index 058f8d4bd9..b86e2821ba 100644 --- a/src/Http/Headers/test/SetCookieHeaderValueTest.cs +++ b/src/Http/Headers/test/SetCookieHeaderValueTest.cs @@ -57,7 +57,7 @@ namespace Microsoft.Net.Http.Headers { SameSite = SameSiteMode.None, }; - dataset.Add(header7, "name7=value7"); + dataset.Add(header7, "name7=value7; samesite=none"); return dataset; @@ -155,9 +155,20 @@ namespace Microsoft.Net.Http.Headers { SameSite = SameSiteMode.Strict }; - var string6a = "name6=value6; samesite"; - var string6b = "name6=value6; samesite=Strict"; - var string6c = "name6=value6; samesite=invalid"; + var string6 = "name6=value6; samesite=Strict"; + + var header7 = new SetCookieHeaderValue("name7", "value7") + { + SameSite = SameSiteMode.None + }; + var string7 = "name7=value7; samesite=None"; + + var header8 = new SetCookieHeaderValue("name8", "value8") + { + SameSite = (SameSiteMode)(-1) // Unspecified + }; + var string8a = "name8=value8; samesite"; + var string8b = "name8=value8; samesite=invalid"; dataset.Add(new[] { header1 }.ToList(), new[] { string1 }); dataset.Add(new[] { header1, header1 }.ToList(), new[] { string1, string1 }); @@ -170,9 +181,10 @@ namespace Microsoft.Net.Http.Headers dataset.Add(new[] { header1, header2, header3, header4 }.ToList(), new[] { string.Join(",", string1, string2, string3, string4) }); dataset.Add(new[] { header5 }.ToList(), new[] { string5a }); dataset.Add(new[] { header5 }.ToList(), new[] { string5b }); - dataset.Add(new[] { header6 }.ToList(), new[] { string6a }); - dataset.Add(new[] { header6 }.ToList(), new[] { string6b }); - dataset.Add(new[] { header6 }.ToList(), new[] { string6c }); + dataset.Add(new[] { header6 }.ToList(), new[] { string6 }); + dataset.Add(new[] { header7 }.ToList(), new[] { string7 }); + dataset.Add(new[] { header8 }.ToList(), new[] { string8a }); + dataset.Add(new[] { header8 }.ToList(), new[] { string8b }); return dataset; } @@ -301,6 +313,28 @@ namespace Microsoft.Net.Http.Headers Assert.Equal(expectedValue, input.ToString()); } + [Fact] + public void SetCookieHeaderValue_ToString_SameSiteNoneCompat() + { + SetCookieHeaderValue.SuppressSameSiteNone = true; + + var input = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.None, + }; + + Assert.Equal("name=value", input.ToString()); + + SetCookieHeaderValue.SuppressSameSiteNone = false; + + var input2 = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.None, + }; + + Assert.Equal("name=value; samesite=none", input2.ToString()); + } + [Theory] [MemberData(nameof(SetCookieHeaderDataSet))] public void SetCookieHeaderValue_AppendToStringBuilder(SetCookieHeaderValue input, string expectedValue) @@ -312,6 +346,32 @@ namespace Microsoft.Net.Http.Headers Assert.Equal(expectedValue, builder.ToString()); } + [Fact] + public void SetCookieHeaderValue_AppendToStringBuilder_SameSiteNoneCompat() + { + SetCookieHeaderValue.SuppressSameSiteNone = true; + + var builder = new StringBuilder(); + var input = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.None, + }; + + input.AppendToStringBuilder(builder); + Assert.Equal("name=value", builder.ToString()); + + SetCookieHeaderValue.SuppressSameSiteNone = false; + + var builder2 = new StringBuilder(); + var input2 = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.None, + }; + + input2.AppendToStringBuilder(builder2); + Assert.Equal("name=value; samesite=none", builder2.ToString()); + } + [Theory] [MemberData(nameof(SetCookieHeaderDataSet))] public void SetCookieHeaderValue_Parse_AcceptsValidValues(SetCookieHeaderValue cookie, string expectedValue) @@ -322,6 +382,31 @@ namespace Microsoft.Net.Http.Headers Assert.Equal(expectedValue, header.ToString()); } + [Fact] + public void SetCookieHeaderValue_Parse_AcceptsValidValues_SameSiteNoneCompat() + { + SetCookieHeaderValue.SuppressSameSiteNone = true; + var header = SetCookieHeaderValue.Parse("name=value; samesite=none"); + + var cookie = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.Strict, + }; + + Assert.Equal(cookie, header); + Assert.Equal("name=value; samesite=strict", header.ToString()); + SetCookieHeaderValue.SuppressSameSiteNone = false; + + var header2 = SetCookieHeaderValue.Parse("name=value; samesite=none"); + + var cookie2 = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.None, + }; + Assert.Equal(cookie2, header2); + Assert.Equal("name=value; samesite=none", header2.ToString()); + } + [Theory] [MemberData(nameof(SetCookieHeaderDataSet))] public void SetCookieHeaderValue_TryParse_AcceptsValidValues(SetCookieHeaderValue cookie, string expectedValue) @@ -332,6 +417,31 @@ namespace Microsoft.Net.Http.Headers Assert.Equal(expectedValue, header.ToString()); } + [Fact] + public void SetCookieHeaderValue_TryParse_AcceptsValidValues_SameSiteNoneCompat() + { + SetCookieHeaderValue.SuppressSameSiteNone = true; + Assert.True(SetCookieHeaderValue.TryParse("name=value; samesite=none", out var header)); + var cookie = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.Strict, + }; + + Assert.Equal(cookie, header); + Assert.Equal("name=value; samesite=strict", header.ToString()); + + SetCookieHeaderValue.SuppressSameSiteNone = false; + + Assert.True(SetCookieHeaderValue.TryParse("name=value; samesite=none", out var header2)); + var cookie2 = new SetCookieHeaderValue("name", "value") + { + SameSite = SameSiteMode.None, + }; + + Assert.Equal(cookie2, header2); + Assert.Equal("name=value; samesite=none", header2.ToString()); + } + [Theory] [MemberData(nameof(InvalidSetCookieHeaderDataSet))] public void SetCookieHeaderValue_Parse_RejectsInvalidValues(string value) diff --git a/src/Http/Http.Abstractions/src/CookieBuilder.cs b/src/Http/Http.Abstractions/src/CookieBuilder.cs index bbaaf07d1f..6230288ba1 100644 --- a/src/Http/Http.Abstractions/src/CookieBuilder.cs +++ b/src/Http/Http.Abstractions/src/CookieBuilder.cs @@ -11,8 +11,20 @@ namespace Microsoft.AspNetCore.Http /// public class CookieBuilder { + // True (old): https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-3.1 + // False (new): https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.1 + internal static bool SuppressSameSiteNone; + private string _name; + static CookieBuilder() + { + if (AppContext.TryGetSwitch("Microsoft.AspNetCore.SuppressSameSiteNone", out var enabled)) + { + SuppressSameSiteNone = enabled; + } + } + /// /// The name of the cookie. /// @@ -49,12 +61,12 @@ namespace Microsoft.AspNetCore.Http public virtual bool HttpOnly { get; set; } /// - /// The SameSite attribute of the cookie. The default value is + /// The SameSite attribute of the cookie. The default value is -1 (Unspecified) /// /// /// Determines the value that will set on . /// - public virtual SameSiteMode SameSite { get; set; } = SameSiteMode.None; + public virtual SameSiteMode SameSite { get; set; } = SuppressSameSiteNone ? SameSiteMode.None : (SameSiteMode)(-1); /// /// The policy that will be used to determine . diff --git a/src/Http/Http.Features/src/CookieOptions.cs b/src/Http/Http.Features/src/CookieOptions.cs index 81e883bd56..42bf1beae5 100644 --- a/src/Http/Http.Features/src/CookieOptions.cs +++ b/src/Http/Http.Features/src/CookieOptions.cs @@ -10,6 +10,18 @@ namespace Microsoft.AspNetCore.Http /// public class CookieOptions { + // True (old): https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-3.1 + // False (new): https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.1 + internal static bool SuppressSameSiteNone; + + static CookieOptions() + { + if (AppContext.TryGetSwitch("Microsoft.AspNetCore.SuppressSameSiteNone", out var enabled)) + { + SuppressSameSiteNone = enabled; + } + } + /// /// Creates a default cookie with a path of '/'. /// @@ -43,10 +55,10 @@ namespace Microsoft.AspNetCore.Http public bool Secure { get; set; } /// - /// Gets or sets the value for the SameSite attribute of the cookie. The default value is + /// Gets or sets the value for the SameSite attribute of the cookie. The default value is -1 (Unspecified) /// /// The representing the enforcement mode of the cookie. - public SameSiteMode SameSite { get; set; } = SameSiteMode.None; + public SameSiteMode SameSite { get; set; } = SuppressSameSiteNone ? SameSiteMode.None : (SameSiteMode)(-1); /// /// Gets or sets a value that indicates whether a cookie is accessible by client-side script. diff --git a/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/OpenIdConnectSample.csproj b/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/OpenIdConnectSample.csproj index 18db419418..0c06ca81ea 100644 --- a/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/OpenIdConnectSample.csproj +++ b/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/OpenIdConnectSample.csproj @@ -14,7 +14,9 @@ + + diff --git a/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/Startup.cs b/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/Startup.cs index b30f479b8c..7107bbe397 100644 --- a/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/Startup.cs +++ b/src/Security/Authentication/OpenIdConnect/samples/OpenIdConnectSample/Startup.cs @@ -32,10 +32,33 @@ namespace OpenIdConnectSample public IConfiguration Configuration { get; set; } public IWebHostEnvironment Environment { get; } + private void CheckSameSite(HttpContext httpContext, CookieOptions options) + { + if (options.SameSite > (SameSiteMode)(-1)) + { + var userAgent = httpContext.Request.Headers["User-Agent"].ToString(); + // TODO: Use your User Agent library of choice here. + if (userAgent.Contains("CPU iPhone OS 12") // Also covers iPod touch + || userAgent.Contains("iPad; CPU OS 12") + // Safari 12 and 13 are both broken on Mojave + || userAgent.Contains("Macintosh; Intel Mac OS X 10_14")) + { + options.SameSite = (SameSiteMode)(-1); + } + } + } + public void ConfigureServices(IServiceCollection services) { JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + services.Configure(options => + { + options.MinimumSameSitePolicy = (SameSiteMode)(-1); + options.OnAppendCookie = cookieContext => CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); + options.OnDeleteCookie = cookieContext => CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); + }); + services.AddAuthentication(sharedOptions => { sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; @@ -84,6 +107,7 @@ namespace OpenIdConnectSample public void Configure(IApplicationBuilder app, IOptionsMonitor optionsMonitor) { app.UseDeveloperExceptionPage(); + app.UseCookiePolicy(); // Before UseAuthentication or anything else that writes cookies. app.UseAuthentication(); app.Run(async context => diff --git a/src/Security/Authentication/WsFederation/samples/WsFedSample/WsFedSample.csproj b/src/Security/Authentication/WsFederation/samples/WsFedSample/WsFedSample.csproj index 5a2186f3df..20a6b1ecef 100644 --- a/src/Security/Authentication/WsFederation/samples/WsFedSample/WsFedSample.csproj +++ b/src/Security/Authentication/WsFederation/samples/WsFedSample/WsFedSample.csproj @@ -2,6 +2,7 @@ netcoreapp3.0 + OutOfProcess diff --git a/src/Security/Authentication/test/CookieTests.cs b/src/Security/Authentication/test/CookieTests.cs index 439c2cccc4..4477518712 100644 --- a/src/Security/Authentication/test/CookieTests.cs +++ b/src/Security/Authentication/test/CookieTests.cs @@ -229,7 +229,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies Assert.Contains(" path=/foo", setCookie1); Assert.Contains(" domain=another.com", setCookie1); Assert.Contains(" secure", setCookie1); - Assert.DoesNotContain(" samesite", setCookie1); + Assert.Contains(" samesite=none", setCookie1); Assert.Contains(" httponly", setCookie1); var server2 = CreateServer(o => diff --git a/src/Security/Authentication/test/Microsoft.AspNetCore.Authentication.Test.csproj b/src/Security/Authentication/test/Microsoft.AspNetCore.Authentication.Test.csproj index fd033a9169..1a39e4008d 100644 --- a/src/Security/Authentication/test/Microsoft.AspNetCore.Authentication.Test.csproj +++ b/src/Security/Authentication/test/Microsoft.AspNetCore.Authentication.Test.csproj @@ -49,6 +49,7 @@ + diff --git a/src/Security/Authentication/test/OpenIdConnect/OpenIdConnectChallengeTests.cs b/src/Security/Authentication/test/OpenIdConnect/OpenIdConnectChallengeTests.cs index d683659118..2220f9be78 100644 --- a/src/Security/Authentication/test/OpenIdConnect/OpenIdConnectChallengeTests.cs +++ b/src/Security/Authentication/test/OpenIdConnect/OpenIdConnectChallengeTests.cs @@ -437,6 +437,7 @@ namespace Microsoft.AspNetCore.Authentication.Test.OpenIdConnect var server = settings.CreateTestServer(); var transaction = await server.SendAsync(ChallengeEndpoint); + Assert.Contains("samesite=none", transaction.SetCookie.First()); var challengeCookies = SetCookieHeaderValue.ParseList(transaction.SetCookie); var nonceCookie = challengeCookies.Where(cookie => cookie.Name.StartsWith(OpenIdConnectDefaults.CookieNoncePrefix, StringComparison.Ordinal)).Single(); Assert.True(nonceCookie.Expires.HasValue); diff --git a/src/Security/CookiePolicy/src/CookiePolicyOptions.cs b/src/Security/CookiePolicy/src/CookiePolicyOptions.cs index 4f0806c46c..15ea44b088 100644 --- a/src/Security/CookiePolicy/src/CookiePolicyOptions.cs +++ b/src/Security/CookiePolicy/src/CookiePolicyOptions.cs @@ -12,10 +12,22 @@ namespace Microsoft.AspNetCore.Builder /// public class CookiePolicyOptions { + // True (old): https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-3.1 + // False (new): https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.1 + internal static bool SuppressSameSiteNone; + + static CookiePolicyOptions() + { + if (AppContext.TryGetSwitch("Microsoft.AspNetCore.SuppressSameSiteNone", out var enabled)) + { + SuppressSameSiteNone = enabled; + } + } + /// /// Affects the cookie's same site attribute. /// - public SameSiteMode MinimumSameSitePolicy { get; set; } = SameSiteMode.None; + public SameSiteMode MinimumSameSitePolicy { get; set; } = SuppressSameSiteNone ? SameSiteMode.None : (SameSiteMode)(-1); /// /// Affects whether cookies must be HttpOnly. diff --git a/src/Security/CookiePolicy/src/ResponseCookiesWrapper.cs b/src/Security/CookiePolicy/src/ResponseCookiesWrapper.cs index 126c4d7bd5..0dbd9057c0 100644 --- a/src/Security/CookiePolicy/src/ResponseCookiesWrapper.cs +++ b/src/Security/CookiePolicy/src/ResponseCookiesWrapper.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -115,7 +115,8 @@ namespace Microsoft.AspNetCore.CookiePolicy private bool CheckPolicyRequired() { return !CanTrack - || Options.MinimumSameSitePolicy != SameSiteMode.None + || (CookiePolicyOptions.SuppressSameSiteNone && Options.MinimumSameSitePolicy != SameSiteMode.None) + || (!CookiePolicyOptions.SuppressSameSiteNone && Options.MinimumSameSitePolicy != (SameSiteMode)(-1)) // Unspecified || Options.HttpOnly != HttpOnlyPolicy.None || Options.Secure != CookieSecurePolicy.None; } @@ -241,27 +242,13 @@ namespace Microsoft.AspNetCore.CookiePolicy default: throw new InvalidOperationException(); } - switch (Options.MinimumSameSitePolicy) + + if (options.SameSite < Options.MinimumSameSitePolicy) { - case SameSiteMode.None: - break; - case SameSiteMode.Lax: - if (options.SameSite == SameSiteMode.None) - { - options.SameSite = SameSiteMode.Lax; - _logger.CookieSameSiteUpgraded(key, "lax"); - } - break; - case SameSiteMode.Strict: - if (options.SameSite != SameSiteMode.Strict) - { - options.SameSite = SameSiteMode.Strict; - _logger.CookieSameSiteUpgraded(key, "strict"); - } - break; - default: - throw new InvalidOperationException($"Unrecognized {nameof(SameSiteMode)} value {Options.MinimumSameSitePolicy.ToString()}"); + options.SameSite = Options.MinimumSameSitePolicy; + _logger.CookieSameSiteUpgraded(key, Options.MinimumSameSitePolicy.ToString()); } + switch (Options.HttpOnly) { case HttpOnlyPolicy.Always: @@ -278,4 +265,4 @@ namespace Microsoft.AspNetCore.CookiePolicy } } } -} \ No newline at end of file +} diff --git a/src/Security/CookiePolicy/test/CookieConsentTests.cs b/src/Security/CookiePolicy/test/CookieConsentTests.cs index ffe8c30619..de4771d724 100644 --- a/src/Security/CookiePolicy/test/CookieConsentTests.cs +++ b/src/Security/CookiePolicy/test/CookieConsentTests.cs @@ -223,12 +223,12 @@ namespace Microsoft.AspNetCore.CookiePolicy.Test Assert.Equal("yes", consentCookie.Value); Assert.True(consentCookie.Expires.HasValue); Assert.True(consentCookie.Expires.Value > DateTimeOffset.Now + TimeSpan.FromDays(364)); - Assert.Equal(Net.Http.Headers.SameSiteMode.None, consentCookie.SameSite); + Assert.Equal((Net.Http.Headers.SameSiteMode)(-1), consentCookie.SameSite); Assert.NotNull(consentCookie.Expires); var testCookie = cookies[1]; Assert.Equal("Test", testCookie.Name); Assert.Equal("Value", testCookie.Value); - Assert.Equal(Net.Http.Headers.SameSiteMode.None, testCookie.SameSite); + Assert.Equal((Net.Http.Headers.SameSiteMode)(-1), testCookie.SameSite); Assert.Null(testCookie.Expires); } @@ -400,12 +400,12 @@ namespace Microsoft.AspNetCore.CookiePolicy.Test var testCookie = cookies[0]; Assert.Equal("Test", testCookie.Name); Assert.Equal("Value1", testCookie.Value); - Assert.Equal(Net.Http.Headers.SameSiteMode.None, testCookie.SameSite); + Assert.Equal((Net.Http.Headers.SameSiteMode)(-1), testCookie.SameSite); Assert.Null(testCookie.Expires); var consentCookie = cookies[1]; Assert.Equal(".AspNet.Consent", consentCookie.Name); Assert.Equal("", consentCookie.Value); - Assert.Equal(Net.Http.Headers.SameSiteMode.None, consentCookie.SameSite); + Assert.Equal((Net.Http.Headers.SameSiteMode)(-1), consentCookie.SameSite); Assert.NotNull(consentCookie.Expires); } @@ -512,7 +512,7 @@ namespace Microsoft.AspNetCore.CookiePolicy.Test var testCookie = cookies[0]; Assert.Equal("Test", testCookie.Name); Assert.Equal("", testCookie.Value); - Assert.Equal(Net.Http.Headers.SameSiteMode.None, testCookie.SameSite); + Assert.Equal((Net.Http.Headers.SameSiteMode)(-1), testCookie.SameSite); Assert.NotNull(testCookie.Expires); } @@ -576,7 +576,7 @@ namespace Microsoft.AspNetCore.CookiePolicy.Test var consentCookie = cookies[0]; Assert.Equal(".AspNet.Consent", consentCookie.Name); Assert.Equal("yes", consentCookie.Value); - Assert.Equal(Net.Http.Headers.SameSiteMode.None, consentCookie.SameSite); + Assert.Equal((Net.Http.Headers.SameSiteMode)(-1), consentCookie.SameSite); Assert.NotNull(consentCookie.Expires); cookies = SetCookieHeaderValue.ParseList(httpContext.Response.Headers["ManualCookie"]); diff --git a/src/Security/CookiePolicy/test/CookiePolicyTests.cs b/src/Security/CookiePolicy/test/CookiePolicyTests.cs index cf233360fa..dbe2826c40 100644 --- a/src/Security/CookiePolicy/test/CookiePolicyTests.cs +++ b/src/Security/CookiePolicy/test/CookiePolicyTests.cs @@ -39,8 +39,8 @@ namespace Microsoft.AspNetCore.CookiePolicy.Test private RequestDelegate SameSiteCookieAppends = context => { context.Response.Cookies.Append("A", "A"); - context.Response.Cookies.Append("B", "B", new CookieOptions { SameSite = Http.SameSiteMode.None }); - context.Response.Cookies.Append("C", "C", new CookieOptions()); + context.Response.Cookies.Append("B", "B", new CookieOptions()); + context.Response.Cookies.Append("C", "C", new CookieOptions { SameSite = Http.SameSiteMode.None }); context.Response.Cookies.Append("D", "D", new CookieOptions { SameSite = Http.SameSiteMode.Lax }); context.Response.Cookies.Append("E", "E", new CookieOptions { SameSite = Http.SameSiteMode.Strict }); return Task.FromResult(0); @@ -198,7 +198,7 @@ namespace Microsoft.AspNetCore.CookiePolicy.Test } [Fact] - public async Task SameSiteNoneLeavesItAlone() + public async Task SameSiteNoneSetsItAlways() { await RunTest("/sameSiteNone", new CookiePolicyOptions @@ -208,11 +208,32 @@ namespace Microsoft.AspNetCore.CookiePolicy.Test SameSiteCookieAppends, new RequestTest("http://example.com/sameSiteNone", transaction => + { + Assert.NotNull(transaction.SetCookie); + Assert.Equal("A=A; path=/; samesite=none", transaction.SetCookie[0]); + Assert.Equal("B=B; path=/; samesite=none", transaction.SetCookie[1]); + Assert.Equal("C=C; path=/; samesite=none", transaction.SetCookie[2]); + Assert.Equal("D=D; path=/; samesite=lax", transaction.SetCookie[3]); + Assert.Equal("E=E; path=/; samesite=strict", transaction.SetCookie[4]); + })); + } + + [Fact] + public async Task SameSiteUnspecifiedLeavesItAlone() + { + await RunTest("/sameSiteNone", + new CookiePolicyOptions + { + MinimumSameSitePolicy = (Http.SameSiteMode)(-1) + }, + SameSiteCookieAppends, + new RequestTest("http://example.com/sameSiteNone", + transaction => { Assert.NotNull(transaction.SetCookie); Assert.Equal("A=A; path=/", transaction.SetCookie[0]); Assert.Equal("B=B; path=/", transaction.SetCookie[1]); - Assert.Equal("C=C; path=/", transaction.SetCookie[2]); + Assert.Equal("C=C; path=/; samesite=none", transaction.SetCookie[2]); Assert.Equal("D=D; path=/; samesite=lax", transaction.SetCookie[3]); Assert.Equal("E=E; path=/; samesite=strict", transaction.SetCookie[4]); })); diff --git a/src/Security/CookiePolicy/test/Microsoft.AspNetCore.CookiePolicy.Test.csproj b/src/Security/CookiePolicy/test/Microsoft.AspNetCore.CookiePolicy.Test.csproj index 4da143d92f..b32d448247 100644 --- a/src/Security/CookiePolicy/test/Microsoft.AspNetCore.CookiePolicy.Test.csproj +++ b/src/Security/CookiePolicy/test/Microsoft.AspNetCore.CookiePolicy.Test.csproj @@ -13,6 +13,7 @@ + From a071e40e34c237cfc9a0a76ceebb1b615defad91 Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Thu, 10 Oct 2019 13:41:07 -0700 Subject: [PATCH 23/26] Disable DebBuild when we're not building targetingPack --- src/Installers/Debian/Directory.Build.targets | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Installers/Debian/Directory.Build.targets b/src/Installers/Debian/Directory.Build.targets index 68f3fed93e..571343b359 100644 --- a/src/Installers/Debian/Directory.Build.targets +++ b/src/Installers/Debian/Directory.Build.targets @@ -23,7 +23,7 @@ - + @@ -49,9 +49,7 @@ - + $(PackageId)_$(DebPackageVersion)-$(PackageRevision)_$(DebianPackageArch).deb From 8c39137944717cc4118efe9ee251e86cd16083cd Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 10 Oct 2019 14:14:43 -0700 Subject: [PATCH 24/26] Port Throw when UseAuthorization is incorrectly configured (#14893) * Port Throw when UseAuthorization is incorrectly configured * fixup --- .../test/testassets/TestServer/Startup.cs | 24 +- src/Http/HttpAbstractions.sln | 30 +++ src/Http/Routing/src/EndpointMiddleware.cs | 9 +- .../EndpointRoutingIntegrationTest.cs | 240 ++++++++++++++++++ ....AspNetCore.Routing.FunctionalTests.csproj | 2 + .../test/UnitTests/EndpointMiddlewareTest.cs | 6 +- .../CORS/src/Infrastructure/CorsMiddleware.cs | 25 +- .../test/UnitTests/CorsMiddlewareTests.cs | 29 ++- .../Policy/src/AuthorizationMiddleware.cs | 14 +- 9 files changed, 341 insertions(+), 38 deletions(-) create mode 100644 src/Http/Routing/test/FunctionalTests/EndpointRoutingIntegrationTest.cs diff --git a/src/Components/test/testassets/TestServer/Startup.cs b/src/Components/test/testassets/TestServer/Startup.cs index 4012408864..1e608b39f3 100644 --- a/src/Components/test/testassets/TestServer/Startup.cs +++ b/src/Components/test/testassets/TestServer/Startup.cs @@ -24,7 +24,15 @@ namespace TestServer services.AddMvc().AddNewtonsoftJson(); services.AddCors(options => { - options.AddPolicy("AllowAll", _ => { /* Controlled below */ }); + // It's not enough just to return "Access-Control-Allow-Origin: *", because + // browsers don't allow wildcards in conjunction with credentials. So we must + // specify explicitly which origin we want to allow. + options.AddPolicy("AllowAll", policy => + policy.SetIsOriginAllowed(host => host.StartsWith("http://localhost:") || host.StartsWith("http://127.0.0.1:")) + .AllowAnyHeader() + .WithExposedHeaders("MyCustomHeader") + .AllowAnyMethod() + .AllowCredentials()); }); services.AddServerSideBlazor() .AddCircuitOptions(o => @@ -49,18 +57,6 @@ namespace TestServer app.UseDeveloperExceptionPage(); } - // It's not enough just to return "Access-Control-Allow-Origin: *", because - // browsers don't allow wildcards in conjunction with credentials. So we must - // specify explicitly which origin we want to allow. - app.UseCors(policy => - { - policy.SetIsOriginAllowed(host => host.StartsWith("http://localhost:") || host.StartsWith("http://127.0.0.1:")) - .AllowAnyHeader() - .WithExposedHeaders("MyCustomHeader") - .AllowAnyMethod() - .AllowCredentials(); - }); - app.UseAuthentication(); // Mount the server-side Blazor app on /subdir @@ -119,6 +115,8 @@ namespace TestServer }); app.UseRouting(); + + app.UseCors(); app.UseEndpoints(endpoints => { diff --git a/src/Http/HttpAbstractions.sln b/src/Http/HttpAbstractions.sln index 10cac06923..e2595c4f40 100644 --- a/src/Http/HttpAbstractions.sln +++ b/src/Http/HttpAbstractions.sln @@ -113,6 +113,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebUtilities.Performance", "WebUtilities\perf\Microsoft.AspNetCore.WebUtilities.Performance\Microsoft.AspNetCore.WebUtilities.Performance.csproj", "{21AC56E7-4E77-4B0E-B63E-C8E836E4D14E}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authorization.Policy", "..\Security\Authorization\Policy\src\Microsoft.AspNetCore.Authorization.Policy.csproj", "{8BCAA9EC-0ACD-435C-BF8A-8C843499FF7B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Cors", "..\Middleware\CORS\src\Microsoft.AspNetCore.Cors.csproj", "{09168958-FD5B-4D25-8FBF-75E2C80D903B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -603,6 +607,30 @@ Global {21AC56E7-4E77-4B0E-B63E-C8E836E4D14E}.Release|x64.Build.0 = Release|Any CPU {21AC56E7-4E77-4B0E-B63E-C8E836E4D14E}.Release|x86.ActiveCfg = Release|Any CPU {21AC56E7-4E77-4B0E-B63E-C8E836E4D14E}.Release|x86.Build.0 = Release|Any CPU + {8BCAA9EC-0ACD-435C-BF8A-8C843499FF7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8BCAA9EC-0ACD-435C-BF8A-8C843499FF7B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8BCAA9EC-0ACD-435C-BF8A-8C843499FF7B}.Debug|x64.ActiveCfg = Debug|Any CPU + {8BCAA9EC-0ACD-435C-BF8A-8C843499FF7B}.Debug|x64.Build.0 = Debug|Any CPU + {8BCAA9EC-0ACD-435C-BF8A-8C843499FF7B}.Debug|x86.ActiveCfg = Debug|Any CPU + {8BCAA9EC-0ACD-435C-BF8A-8C843499FF7B}.Debug|x86.Build.0 = Debug|Any CPU + {8BCAA9EC-0ACD-435C-BF8A-8C843499FF7B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8BCAA9EC-0ACD-435C-BF8A-8C843499FF7B}.Release|Any CPU.Build.0 = Release|Any CPU + {8BCAA9EC-0ACD-435C-BF8A-8C843499FF7B}.Release|x64.ActiveCfg = Release|Any CPU + {8BCAA9EC-0ACD-435C-BF8A-8C843499FF7B}.Release|x64.Build.0 = Release|Any CPU + {8BCAA9EC-0ACD-435C-BF8A-8C843499FF7B}.Release|x86.ActiveCfg = Release|Any CPU + {8BCAA9EC-0ACD-435C-BF8A-8C843499FF7B}.Release|x86.Build.0 = Release|Any CPU + {09168958-FD5B-4D25-8FBF-75E2C80D903B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {09168958-FD5B-4D25-8FBF-75E2C80D903B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {09168958-FD5B-4D25-8FBF-75E2C80D903B}.Debug|x64.ActiveCfg = Debug|Any CPU + {09168958-FD5B-4D25-8FBF-75E2C80D903B}.Debug|x64.Build.0 = Debug|Any CPU + {09168958-FD5B-4D25-8FBF-75E2C80D903B}.Debug|x86.ActiveCfg = Debug|Any CPU + {09168958-FD5B-4D25-8FBF-75E2C80D903B}.Debug|x86.Build.0 = Debug|Any CPU + {09168958-FD5B-4D25-8FBF-75E2C80D903B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {09168958-FD5B-4D25-8FBF-75E2C80D903B}.Release|Any CPU.Build.0 = Release|Any CPU + {09168958-FD5B-4D25-8FBF-75E2C80D903B}.Release|x64.ActiveCfg = Release|Any CPU + {09168958-FD5B-4D25-8FBF-75E2C80D903B}.Release|x64.Build.0 = Release|Any CPU + {09168958-FD5B-4D25-8FBF-75E2C80D903B}.Release|x86.ActiveCfg = Release|Any CPU + {09168958-FD5B-4D25-8FBF-75E2C80D903B}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -651,6 +679,8 @@ Global {611794D2-EF3A-422A-A077-23E61C7ADE49} = {793FFE24-138A-4C3D-81AB-18D625E36230} {1062FCDE-E145-40EC-B175-FDBCAA0C59A0} = {793FFE24-138A-4C3D-81AB-18D625E36230} {21AC56E7-4E77-4B0E-B63E-C8E836E4D14E} = {80A090C8-ED02-4DE3-875A-30DCCDBD84BA} + {8BCAA9EC-0ACD-435C-BF8A-8C843499FF7B} = {793FFE24-138A-4C3D-81AB-18D625E36230} + {09168958-FD5B-4D25-8FBF-75E2C80D903B} = {793FFE24-138A-4C3D-81AB-18D625E36230} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {85B5E151-2E9D-419C-83DD-0DDCF446C83A} diff --git a/src/Http/Routing/src/EndpointMiddleware.cs b/src/Http/Routing/src/EndpointMiddleware.cs index a2101c40cd..9b06b673ad 100644 --- a/src/Http/Routing/src/EndpointMiddleware.cs +++ b/src/Http/Routing/src/EndpointMiddleware.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Cors.Infrastructure; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -14,8 +13,8 @@ namespace Microsoft.AspNetCore.Routing { internal sealed class EndpointMiddleware { - internal const string AuthorizationMiddlewareInvokedKey = "__AuthorizationMiddlewareInvoked"; - internal const string CorsMiddlewareInvokedKey = "__CorsMiddlewareInvoked"; + internal const string AuthorizationMiddlewareInvokedKey = "__AuthorizationMiddlewareWithEndpointInvoked"; + internal const string CorsMiddlewareInvokedKey = "__CorsMiddlewareWithEndpointInvoked"; private readonly ILogger _logger; private readonly RequestDelegate _next; @@ -91,7 +90,7 @@ namespace Microsoft.AspNetCore.Routing throw new InvalidOperationException($"Endpoint {endpoint.DisplayName} contains authorization metadata, " + "but a middleware was not found that supports authorization." + Environment.NewLine + - "Configure your application startup by adding app.UseAuthorization() inside the call to Configure(..) in the application startup code."); + "Configure your application startup by adding app.UseAuthorization() inside the call to Configure(..) in the application startup code. The call to app.UseAuthorization() must appear between app.UseRouting() and app.UseEndpoints(...)."); } private static void ThrowMissingCorsMiddlewareException(Endpoint endpoint) @@ -99,7 +98,7 @@ namespace Microsoft.AspNetCore.Routing throw new InvalidOperationException($"Endpoint {endpoint.DisplayName} contains CORS metadata, " + "but a middleware was not found that supports CORS." + Environment.NewLine + - "Configure your application startup by adding app.UseCors() inside the call to Configure(..) in the application startup code."); + "Configure your application startup by adding app.UseCors() inside the call to Configure(..) in the application startup code. The call to app.UseAuthorization() must appear between app.UseRouting() and app.UseEndpoints(...)."); } private static class Log diff --git a/src/Http/Routing/test/FunctionalTests/EndpointRoutingIntegrationTest.cs b/src/Http/Routing/test/FunctionalTests/EndpointRoutingIntegrationTest.cs new file mode 100644 index 0000000000..4b33dcb669 --- /dev/null +++ b/src/Http/Routing/test/FunctionalTests/EndpointRoutingIntegrationTest.cs @@ -0,0 +1,240 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Net; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace Microsoft.AspNetCore.Routing.FunctionalTests +{ + public class EndpointRoutingIntegrationTest + { + private static readonly RequestDelegate TestDelegate = async context => await Task.Yield(); + private static readonly string AuthErrorMessage = "Endpoint / contains authorization metadata, but a middleware was not found that supports authorization." + + Environment.NewLine + + "Configure your application startup by adding app.UseAuthorization() inside the call to Configure(..) in the application startup code. " + + "The call to app.UseAuthorization() must appear between app.UseRouting() and app.UseEndpoints(...)."; + + private static readonly string CORSErrorMessage = "Endpoint / contains CORS metadata, but a middleware was not found that supports CORS." + + Environment.NewLine + + "Configure your application startup by adding app.UseCors() inside the call to Configure(..) in the application startup code. " + + "The call to app.UseAuthorization() must appear between app.UseRouting() and app.UseEndpoints(...)."; + + [Fact] + public async Task AuthorizationMiddleware_WhenNoAuthMetadataIsConfigured() + { + // Arrange + var builder = new WebHostBuilder(); + builder.Configure(app => + { + app.UseRouting(); + app.UseAuthorization(); + app.UseEndpoints(b => b.Map("/", TestDelegate)); + }) + .ConfigureServices(services => + { + services.AddAuthorization(); + services.AddRouting(); + }); + + using var server = new TestServer(builder); + + var response = await server.CreateRequest("/").SendAsync("GET"); + + response.EnsureSuccessStatusCode(); + } + + [Fact] + public async Task AuthorizationMiddleware_WhenEndpointIsNotFound() + { + // Arrange + var builder = new WebHostBuilder(); + builder.Configure(app => + { + app.UseRouting(); + app.UseAuthorization(); + app.UseEndpoints(b => b.Map("/", TestDelegate)); + }) + .ConfigureServices(services => + { + services.AddAuthorization(); + services.AddRouting(); + }); + + using var server = new TestServer(builder); + + var response = await server.CreateRequest("/not-found").SendAsync("GET"); + + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + public async Task AuthorizationMiddleware_WithAuthorizedEndpoint() + { + // Arrange + var builder = new WebHostBuilder(); + builder.Configure(app => + { + app.UseRouting(); + app.UseAuthorization(); + app.UseEndpoints(b => b.Map("/", TestDelegate).RequireAuthorization()); + }) + .ConfigureServices(services => + { + services.AddAuthorization(options => options.DefaultPolicy = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build()); + services.AddRouting(); + }); + + using var server = new TestServer(builder); + + var response = await server.CreateRequest("/").SendAsync("GET"); + + response.EnsureSuccessStatusCode(); + } + + [Fact] + public async Task AuthorizationMiddleware_NotConfigured_Throws() + { + // Arrange + var builder = new WebHostBuilder(); + builder.Configure(app => + { + app.UseRouting(); + app.UseEndpoints(b => b.Map("/", TestDelegate).RequireAuthorization()); + + }) + .ConfigureServices(services => + { + services.AddAuthorization(options => options.DefaultPolicy = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build()); + services.AddRouting(); + }); + + using var server = new TestServer(builder); + + var ex = await Assert.ThrowsAsync(() => server.CreateRequest("/").SendAsync("GET")); + Assert.Equal(AuthErrorMessage, ex.Message); + } + + [Fact] + public async Task AuthorizationMiddleware_NotConfigured_WhenEndpointIsNotFound() + { + // Arrange + var builder = new WebHostBuilder(); + builder.Configure(app => + { + app.UseRouting(); + app.UseEndpoints(b => b.Map("/", TestDelegate).RequireAuthorization()); + }) + .ConfigureServices(services => + { + services.AddRouting(); + }); + + using var server = new TestServer(builder); + + var response = await server.CreateRequest("/not-found").SendAsync("GET"); + + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + public async Task AuthorizationMiddleware_ConfiguredBeforeRouting_Throws() + { + // Arrange + var builder = new WebHostBuilder(); + builder.Configure(app => + { + app.UseAuthorization(); + app.UseRouting(); + app.UseEndpoints(b => b.Map("/", TestDelegate).RequireAuthorization()); + }) + .ConfigureServices(services => + { + services.AddAuthorization(options => options.DefaultPolicy = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build()); + services.AddRouting(); + }); + + using var server = new TestServer(builder); + + var ex = await Assert.ThrowsAsync(() => server.CreateRequest("/").SendAsync("GET")); + Assert.Equal(AuthErrorMessage, ex.Message); + } + + [Fact] + public async Task AuthorizationMiddleware_ConfiguredAfterRouting_Throws() + { + // Arrange + var builder = new WebHostBuilder(); + builder.Configure(app => + { + app.UseRouting(); + app.UseEndpoints(b => b.Map("/", TestDelegate).RequireAuthorization()); + app.UseAuthorization(); + }) + .ConfigureServices(services => + { + services.AddAuthorization(options => options.DefaultPolicy = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build()); + services.AddRouting(); + }); + + using var server = new TestServer(builder); + + var ex = await Assert.ThrowsAsync(() => server.CreateRequest("/").SendAsync("GET")); + Assert.Equal(AuthErrorMessage, ex.Message); + } + + [Fact] + public async Task CorsMiddleware_WithCorsEndpoint() + { + // Arrange + var builder = new WebHostBuilder(); + builder.Configure(app => + { + app.UseRouting(); + app.UseCors(); + app.UseEndpoints(b => b.Map("/", TestDelegate).RequireCors(policy => policy.AllowAnyOrigin())); + }) + .ConfigureServices(services => + { + services.AddCors(); + services.AddRouting(); + }); + + using var server = new TestServer(builder); + + var response = await server.CreateRequest("/").SendAsync("PUT"); + + response.EnsureSuccessStatusCode(); + } + + [Fact] + public async Task CorsMiddleware_ConfiguredBeforeRouting_Throws() + { + // Arrange + var builder = new WebHostBuilder(); + builder.Configure(app => + { + app.UseCors(); + app.UseRouting(); + app.UseEndpoints(b => b.Map("/", TestDelegate).RequireCors(policy => policy.AllowAnyOrigin())); + }) + .ConfigureServices(services => + { + services.AddCors(); + services.AddRouting(); + }); + + using var server = new TestServer(builder); + + var ex = await Assert.ThrowsAsync(() => server.CreateRequest("/").SendAsync("GET")); + Assert.Equal(CORSErrorMessage, ex.Message); + } + } +} \ No newline at end of file diff --git a/src/Http/Routing/test/FunctionalTests/Microsoft.AspNetCore.Routing.FunctionalTests.csproj b/src/Http/Routing/test/FunctionalTests/Microsoft.AspNetCore.Routing.FunctionalTests.csproj index c281194c0c..e0f8b35388 100644 --- a/src/Http/Routing/test/FunctionalTests/Microsoft.AspNetCore.Routing.FunctionalTests.csproj +++ b/src/Http/Routing/test/FunctionalTests/Microsoft.AspNetCore.Routing.FunctionalTests.csproj @@ -10,6 +10,8 @@ + + diff --git a/src/Http/Routing/test/UnitTests/EndpointMiddlewareTest.cs b/src/Http/Routing/test/UnitTests/EndpointMiddlewareTest.cs index 1467425222..7a638e7e8c 100644 --- a/src/Http/Routing/test/UnitTests/EndpointMiddlewareTest.cs +++ b/src/Http/Routing/test/UnitTests/EndpointMiddlewareTest.cs @@ -101,7 +101,8 @@ namespace Microsoft.AspNetCore.Routing // Arrange var expected = "Endpoint Test contains authorization metadata, but a middleware was not found that supports authorization." + Environment.NewLine + - "Configure your application startup by adding app.UseAuthorization() inside the call to Configure(..) in the application startup code."; + "Configure your application startup by adding app.UseAuthorization() inside the call to Configure(..) in the application startup code. " + + "The call to app.UseAuthorization() must appear between app.UseRouting() and app.UseEndpoints(...)."; var httpContext = new DefaultHttpContext { RequestServices = new ServiceProvider() @@ -197,7 +198,8 @@ namespace Microsoft.AspNetCore.Routing // Arrange var expected = "Endpoint Test contains CORS metadata, but a middleware was not found that supports CORS." + Environment.NewLine + - "Configure your application startup by adding app.UseCors() inside the call to Configure(..) in the application startup code."; + "Configure your application startup by adding app.UseCors() inside the call to Configure(..) in the application startup code. " + + "The call to app.UseAuthorization() must appear between app.UseRouting() and app.UseEndpoints(...)."; var httpContext = new DefaultHttpContext { RequestServices = new ServiceProvider() diff --git a/src/Middleware/CORS/src/Infrastructure/CorsMiddleware.cs b/src/Middleware/CORS/src/Infrastructure/CorsMiddleware.cs index ed3f743dfc..02e5c7a0d1 100644 --- a/src/Middleware/CORS/src/Infrastructure/CorsMiddleware.cs +++ b/src/Middleware/CORS/src/Infrastructure/CorsMiddleware.cs @@ -14,8 +14,8 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure public class CorsMiddleware { // Property key is used by other systems, e.g. MVC, to check if CORS middleware has run - private const string CorsMiddlewareInvokedKey = "__CorsMiddlewareInvoked"; - private static readonly object CorsMiddlewareInvokedValue = new object(); + private const string CorsMiddlewareWithEndpointInvokedKey = "__CorsMiddlewareWithEndpointInvoked"; + private static readonly object CorsMiddlewareWithEndpointInvokedValue = new object(); private readonly Func OnResponseStartingDelegate = OnResponseStarting; private readonly RequestDelegate _next; @@ -116,14 +116,6 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure /// public Task Invoke(HttpContext context, ICorsPolicyProvider corsPolicyProvider) { - // Flag to indicate to other systems, that CORS middleware was run for this request - context.Items[CorsMiddlewareInvokedKey] = CorsMiddlewareInvokedValue; - - if (!context.Request.Headers.ContainsKey(CorsConstants.Origin)) - { - return _next(context); - } - // CORS policy resolution rules: // // 1. If there is an endpoint with IDisableCorsAttribute then CORS is not run @@ -131,9 +123,20 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure // there is an endpoint with IEnableCorsAttribute that has a policy name then // fetch policy by name, prioritizing it above policy on middleware // 3. If there is no policy on middleware then use name on middleware - var endpoint = context.GetEndpoint(); + if (endpoint != null) + { + // EndpointRoutingMiddleware uses this flag to check if the CORS middleware processed CORS metadata on the endpoint. + // The CORS middleware can only make this claim if it observes an actual endpoint. + context.Items[CorsMiddlewareWithEndpointInvokedKey] = CorsMiddlewareWithEndpointInvokedValue; + } + + if (!context.Request.Headers.ContainsKey(CorsConstants.Origin)) + { + return _next(context); + } + // Get the most significant CORS metadata for the endpoint // For backwards compatibility reasons this is then downcast to Enable/Disable metadata var corsMetadata = endpoint?.Metadata.GetMetadata(); diff --git a/src/Middleware/CORS/test/UnitTests/CorsMiddlewareTests.cs b/src/Middleware/CORS/test/UnitTests/CorsMiddlewareTests.cs index ebd44aa2d0..4b53a43a5b 100644 --- a/src/Middleware/CORS/test/UnitTests/CorsMiddlewareTests.cs +++ b/src/Middleware/CORS/test/UnitTests/CorsMiddlewareTests.cs @@ -918,7 +918,7 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure await middleware.Invoke(httpContext, mockProvider); // Assert - Assert.Contains(httpContext.Items, item => string.Equals(item.Key as string, "__CorsMiddlewareInvoked")); + Assert.Contains(httpContext.Items, item => string.Equals(item.Key as string, "__CorsMiddlewareWithEndpointInvoked")); } [Fact] @@ -936,12 +936,37 @@ namespace Microsoft.AspNetCore.Cors.Infrastructure "DefaultPolicyName"); var httpContext = new DefaultHttpContext(); + httpContext.SetEndpoint(new Endpoint(c => Task.CompletedTask, new EndpointMetadataCollection(new EnableCorsAttribute("MetadataPolicyName"), new DisableCorsAttribute()), "Test endpoint")); // Act await middleware.Invoke(httpContext, mockProvider); // Assert - Assert.Contains(httpContext.Items, item => string.Equals(item.Key as string, "__CorsMiddlewareInvoked")); + Assert.Contains(httpContext.Items, item => string.Equals(item.Key as string, "__CorsMiddlewareWithEndpointInvoked")); + } + + [Fact] + public async Task Invoke_WithoutEndpoint_InvokeFlagSet() + { + // Arrange + var corsService = Mock.Of(); + var mockProvider = Mock.Of(); + var loggerFactory = NullLoggerFactory.Instance; + + var middleware = new CorsMiddleware( + Mock.Of(), + corsService, + loggerFactory, + "DefaultPolicyName"); + + var httpContext = new DefaultHttpContext(); + httpContext.Request.Headers.Add(CorsConstants.Origin, new[] { "http://example.com" }); + + // Act + await middleware.Invoke(httpContext, mockProvider); + + // Assert + Assert.DoesNotContain(httpContext.Items, item => string.Equals(item.Key as string, "__CorsMiddlewareWithEndpointInvoked")); } } } diff --git a/src/Security/Authorization/Policy/src/AuthorizationMiddleware.cs b/src/Security/Authorization/Policy/src/AuthorizationMiddleware.cs index 184209557a..686374d829 100644 --- a/src/Security/Authorization/Policy/src/AuthorizationMiddleware.cs +++ b/src/Security/Authorization/Policy/src/AuthorizationMiddleware.cs @@ -13,9 +13,9 @@ namespace Microsoft.AspNetCore.Authorization { public class AuthorizationMiddleware { - // Property key is used by other systems, e.g. MVC, to check if authorization middleware has run - private const string AuthorizationMiddlewareInvokedKey = "__AuthorizationMiddlewareInvoked"; - private static readonly object AuthorizationMiddlewareInvokedValue = new object(); + // Property key is used by Endpoint routing to determine if Authorization has run + private const string AuthorizationMiddlewareInvokedWithEndpointKey = "__AuthorizationMiddlewareWithEndpointInvoked"; + private static readonly object AuthorizationMiddlewareWithEndpointInvokedValue = new object(); private readonly RequestDelegate _next; private readonly IAuthorizationPolicyProvider _policyProvider; @@ -35,8 +35,12 @@ namespace Microsoft.AspNetCore.Authorization var endpoint = context.GetEndpoint(); - // Flag to indicate to other systems, e.g. MVC, that authorization middleware was run for this request - context.Items[AuthorizationMiddlewareInvokedKey] = AuthorizationMiddlewareInvokedValue; + if (endpoint != null) + { + // EndpointRoutingMiddleware uses this flag to check if the Authorization middleware processed auth metadata on the endpoint. + // The Authorization middleware can only make this claim if it observes an actual endpoint. + context.Items[AuthorizationMiddlewareInvokedWithEndpointKey] = AuthorizationMiddlewareWithEndpointInvokedValue; + } // IMPORTANT: Changes to authorization logic should be mirrored in MVC's AuthorizeFilter var authorizeData = endpoint?.Metadata.GetOrderedMetadata() ?? Array.Empty(); From d7faa8fc486687dc4116578bf74f3535161cb1fa Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Thu, 10 Oct 2019 14:17:15 -0700 Subject: [PATCH 25/26] Disable RPMBuild if not building RefPack, fix template test RefPack version --- src/Installers/Rpm/Directory.Build.targets | 2 +- .../test/Infrastructure/GenerateTestProps.targets | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Installers/Rpm/Directory.Build.targets b/src/Installers/Rpm/Directory.Build.targets index 9a4eb927b0..3dc3ab8202 100644 --- a/src/Installers/Rpm/Directory.Build.targets +++ b/src/Installers/Rpm/Directory.Build.targets @@ -32,7 +32,7 @@ - + DATE=$([System.DateTime]::UtcNow.ToString(ddd MMM dd yyyy)) diff --git a/src/ProjectTemplates/test/Infrastructure/GenerateTestProps.targets b/src/ProjectTemplates/test/Infrastructure/GenerateTestProps.targets index 4ce37d3f61..51e7e7f883 100644 --- a/src/ProjectTemplates/test/Infrastructure/GenerateTestProps.targets +++ b/src/ProjectTemplates/test/Infrastructure/GenerateTestProps.targets @@ -4,12 +4,20 @@ DependsOnTargets="PrepareForTest" Condition="$(DesignTimeBuild) != true"> + + SkipNonexistentProjects="false" + Condition="'$(IsTargetingPackBuilding)' != 'false'"> + + + @(_TargetingPackVersionInfo->'%(PackageVersion)' + $(AspNetCoreBaselineVersion) + + '%(PackageVersion)'); + MicrosoftAspNetCoreAppRefPackageVersion=$(MicrosoftAspNetCoreAppRefPackageVersion); MicrosoftAspNetCoreAppRuntimePackageVersion=@(_RuntimePackageVersionInfo->'%(PackageVersion)'); SupportedRuntimeIdentifiers=$(SupportedRuntimeIdentifiers); From 62a62fae7dffa007aba64acd78696acd416854ff Mon Sep 17 00:00:00 2001 From: wtgodbe Date: Thu, 10 Oct 2019 14:43:16 -0700 Subject: [PATCH 26/26] Fix item metadata evaluation --- .../test/Infrastructure/GenerateTestProps.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ProjectTemplates/test/Infrastructure/GenerateTestProps.targets b/src/ProjectTemplates/test/Infrastructure/GenerateTestProps.targets index 51e7e7f883..b9b5903ff2 100644 --- a/src/ProjectTemplates/test/Infrastructure/GenerateTestProps.targets +++ b/src/ProjectTemplates/test/Infrastructure/GenerateTestProps.targets @@ -14,7 +14,7 @@ - @(_TargetingPackVersionInfo->'%(PackageVersion)' + @(TargetingPackVersionInfo.PackageVersion) $(AspNetCoreBaselineVersion)