22// See LICENSE for more details.
33
44using System ;
5- using System . Collections . Generic ;
65using System . Security . Claims ;
7- using System . Threading . Tasks ;
86using Microsoft . AspNetCore . Authorization ;
97using Microsoft . AspNetCore . Http ;
108using Microsoft . Extensions . Primitives ;
@@ -35,7 +33,7 @@ public class ContentPermissionsQueryStringHandlerTests
3533 public async Task Node_Id_From_Requirement_With_Permission_Is_Authorized ( )
3634 {
3735 var authHandlerContext = CreateAuthorizationHandlerContext ( NodeId ) ;
38- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( ) ;
36+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( ) ;
3937 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "A" } ) ;
4038
4139 await sut . HandleAsync ( authHandlerContext ) ;
@@ -47,7 +45,7 @@ public async Task Node_Id_From_Requirement_With_Permission_Is_Authorized()
4745 public async Task Node_Id_From_Requirement_Without_Permission_Is_Not_Authorized ( )
4846 {
4947 var authHandlerContext = CreateAuthorizationHandlerContext ( NodeId ) ;
50- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( ) ;
48+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( ) ;
5149 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "B" } ) ;
5250
5351 await sut . HandleAsync ( authHandlerContext ) ;
@@ -60,7 +58,7 @@ public async Task Node_Id_From_Requirement_Without_Permission_Is_Not_Authorized(
6058 public async Task Node_Id_Missing_From_Requirement_And_QueryString_Is_Authorized ( )
6159 {
6260 var authHandlerContext = CreateAuthorizationHandlerContext ( ) ;
63- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( "xxx" ) ;
61+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( "xxx" ) ;
6462 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "A" } ) ;
6563
6664 await sut . HandleAsync ( authHandlerContext ) ;
@@ -72,7 +70,7 @@ public async Task Node_Id_Missing_From_Requirement_And_QueryString_Is_Authorized
7270 public async Task Node_Integer_Id_From_QueryString_With_Permission_Is_Authorized ( )
7371 {
7472 var authHandlerContext = CreateAuthorizationHandlerContext ( ) ;
75- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( queryStringValue : NodeId . ToString ( ) ) ;
73+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( queryStringValue : NodeId . ToString ( ) ) ;
7674 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "A" } ) ;
7775
7876 await sut . HandleAsync ( authHandlerContext ) ;
@@ -85,7 +83,21 @@ public async Task Node_Integer_Id_From_QueryString_With_Permission_Is_Authorized
8583 public async Task Node_Integer_Id_From_QueryString_Without_Permission_Is_Not_Authorized ( )
8684 {
8785 var authHandlerContext = CreateAuthorizationHandlerContext ( ) ;
88- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( queryStringValue : NodeId . ToString ( ) ) ;
86+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( queryStringValue : NodeId . ToString ( ) ) ;
87+ var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "B" } ) ;
88+
89+ await sut . HandleAsync ( authHandlerContext ) ;
90+
91+ Assert . IsFalse ( authHandlerContext . HasSucceeded ) ;
92+ AssertContentCached ( mockHttpContextAccessor ) ;
93+ }
94+
95+ [ Test ]
96+ public async Task Node_Integer_Id_From_QueryString_Without_Permission_Is_Not_Authorized_Even_When_Additional_Parameter_For_Id_With_Permission_Is_Provided ( )
97+ {
98+ // Provides initially failing test and verifies fix for advisory https://github.com/umbraco/Umbraco-CMS/security/advisories/GHSA-wx5h-wqfq-v698
99+ var authHandlerContext = CreateAuthorizationHandlerContext ( ) ;
100+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValues ( queryStringValues : new [ ] { NodeId . ToString ( ) , 1001 . ToString ( ) } ) ;
89101 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "B" } ) ;
90102
91103 await sut . HandleAsync ( authHandlerContext ) ;
@@ -98,7 +110,7 @@ public async Task Node_Integer_Id_From_QueryString_Without_Permission_Is_Not_Aut
98110 public async Task Node_Udi_Id_From_QueryString_With_Permission_Is_Authorized ( )
99111 {
100112 var authHandlerContext = CreateAuthorizationHandlerContext ( ) ;
101- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( queryStringValue : s_nodeUdi . ToString ( ) ) ;
113+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( queryStringValue : s_nodeUdi . ToString ( ) ) ;
102114 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "A" } ) ;
103115
104116 await sut . HandleAsync ( authHandlerContext ) ;
@@ -111,7 +123,7 @@ public async Task Node_Udi_Id_From_QueryString_With_Permission_Is_Authorized()
111123 public async Task Node_Udi_Id_From_QueryString_Without_Permission_Is_Not_Authorized ( )
112124 {
113125 var authHandlerContext = CreateAuthorizationHandlerContext ( ) ;
114- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( queryStringValue : s_nodeUdi . ToString ( ) ) ;
126+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( queryStringValue : s_nodeUdi . ToString ( ) ) ;
115127 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "B" } ) ;
116128
117129 await sut . HandleAsync ( authHandlerContext ) ;
@@ -124,7 +136,7 @@ public async Task Node_Udi_Id_From_QueryString_Without_Permission_Is_Not_Authori
124136 public async Task Node_Guid_Id_From_QueryString_With_Permission_Is_Authorized ( )
125137 {
126138 var authHandlerContext = CreateAuthorizationHandlerContext ( ) ;
127- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( queryStringValue : s_nodeGuid . ToString ( ) ) ;
139+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( queryStringValue : s_nodeGuid . ToString ( ) ) ;
128140 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "A" } ) ;
129141
130142 await sut . HandleAsync ( authHandlerContext ) ;
@@ -137,7 +149,7 @@ public async Task Node_Guid_Id_From_QueryString_With_Permission_Is_Authorized()
137149 public async Task Node_Guid_Id_From_QueryString_Without_Permission_Is_Not_Authorized ( )
138150 {
139151 var authHandlerContext = CreateAuthorizationHandlerContext ( ) ;
140- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( queryStringValue : s_nodeGuid . ToString ( ) ) ;
152+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( queryStringValue : s_nodeGuid . ToString ( ) ) ;
141153 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "B" } ) ;
142154
143155 await sut . HandleAsync ( authHandlerContext ) ;
@@ -150,7 +162,7 @@ public async Task Node_Guid_Id_From_QueryString_Without_Permission_Is_Not_Author
150162 public async Task Node_Invalid_Id_From_QueryString_Is_Authorized ( )
151163 {
152164 var authHandlerContext = CreateAuthorizationHandlerContext ( ) ;
153- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( queryStringValue : "invalid" ) ;
165+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( queryStringValue : "invalid" ) ;
154166 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "A" } ) ;
155167
156168 await sut . HandleAsync ( authHandlerContext ) ;
@@ -169,14 +181,20 @@ private static AuthorizationHandlerContext CreateAuthorizationHandlerContext(int
169181 return new AuthorizationHandlerContext ( new List < IAuthorizationRequirement > { requirement } , user , resource ) ;
170182 }
171183
172- private static Mock < IHttpContextAccessor > CreateMockHttpContextAccessor (
184+ private static Mock < IHttpContextAccessor > CreateMockHttpContextAccessorWithQueryStringValue (
173185 string queryStringName = QueryStringName ,
174186 string queryStringValue = "" )
187+ => CreateMockHttpContextAccessorWithQueryStringValues ( queryStringName , new [ ] { queryStringValue } ) ;
188+
189+ private static Mock < IHttpContextAccessor > CreateMockHttpContextAccessorWithQueryStringValues (
190+ string queryStringName = QueryStringName ,
191+ string [ ] ? queryStringValues = null )
175192 {
193+ queryStringValues ??= Array . Empty < string > ( ) ;
176194 var mockHttpContextAccessor = new Mock < IHttpContextAccessor > ( ) ;
177195 var mockHttpContext = new Mock < HttpContext > ( ) ;
178196 var mockHttpRequest = new Mock < HttpRequest > ( ) ;
179- var queryParams = new Dictionary < string , StringValues > { { queryStringName , queryStringValue } } ;
197+ var queryParams = new Dictionary < string , StringValues > { { queryStringName , new StringValues ( queryStringValues ) } } ;
180198 mockHttpRequest . SetupGet ( x => x . Query ) . Returns ( new QueryCollection ( queryParams ) ) ;
181199 mockHttpContext . SetupGet ( x => x . Request ) . Returns ( mockHttpRequest . Object ) ;
182200 mockHttpContext . SetupGet ( x => x . Items ) . Returns ( new Dictionary < object , object > ( ) ) ;
0 commit comments