11// Copyright (c) Umbraco.
22// See LICENSE for more details.
33
4- using System . Collections . Generic ;
54using System . Security . Claims ;
6- using System . Threading . Tasks ;
75using Microsoft . AspNetCore . Authorization ;
86using Microsoft . AspNetCore . Http ;
97using Microsoft . Extensions . Primitives ;
@@ -34,7 +32,7 @@ public class ContentPermissionsQueryStringHandlerTests
3432 public async Task Node_Id_From_Requirement_With_Permission_Is_Authorized ( )
3533 {
3634 var authHandlerContext = CreateAuthorizationHandlerContext ( NodeId ) ;
37- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( ) ;
35+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( ) ;
3836 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "A" } ) ;
3937
4038 await sut . HandleAsync ( authHandlerContext ) ;
@@ -46,7 +44,7 @@ public async Task Node_Id_From_Requirement_With_Permission_Is_Authorized()
4644 public async Task Node_Id_From_Requirement_Without_Permission_Is_Not_Authorized ( )
4745 {
4846 var authHandlerContext = CreateAuthorizationHandlerContext ( NodeId ) ;
49- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( ) ;
47+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( ) ;
5048 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "B" } ) ;
5149
5250 await sut . HandleAsync ( authHandlerContext ) ;
@@ -59,7 +57,7 @@ public async Task Node_Id_From_Requirement_Without_Permission_Is_Not_Authorized(
5957 public async Task Node_Id_Missing_From_Requirement_And_QueryString_Is_Authorized ( )
6058 {
6159 var authHandlerContext = CreateAuthorizationHandlerContext ( ) ;
62- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( "xxx" ) ;
60+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( "xxx" ) ;
6361 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "A" } ) ;
6462
6563 await sut . HandleAsync ( authHandlerContext ) ;
@@ -71,7 +69,7 @@ public async Task Node_Id_Missing_From_Requirement_And_QueryString_Is_Authorized
7169 public async Task Node_Integer_Id_From_QueryString_With_Permission_Is_Authorized ( )
7270 {
7371 var authHandlerContext = CreateAuthorizationHandlerContext ( ) ;
74- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( queryStringValue : NodeId . ToString ( ) ) ;
72+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( queryStringValue : NodeId . ToString ( ) ) ;
7573 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "A" } ) ;
7674
7775 await sut . HandleAsync ( authHandlerContext ) ;
@@ -84,7 +82,21 @@ public async Task Node_Integer_Id_From_QueryString_With_Permission_Is_Authorized
8482 public async Task Node_Integer_Id_From_QueryString_Without_Permission_Is_Not_Authorized ( )
8583 {
8684 var authHandlerContext = CreateAuthorizationHandlerContext ( ) ;
87- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( queryStringValue : NodeId . ToString ( ) ) ;
85+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( queryStringValue : NodeId . ToString ( ) ) ;
86+ var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "B" } ) ;
87+
88+ await sut . HandleAsync ( authHandlerContext ) ;
89+
90+ Assert . IsFalse ( authHandlerContext . HasSucceeded ) ;
91+ AssertContentCached ( mockHttpContextAccessor ) ;
92+ }
93+
94+ [ Test ]
95+ public async Task Node_Integer_Id_From_QueryString_Without_Permission_Is_Not_Authorized_Even_When_Additional_Parameter_For_Id_With_Permission_Is_Provided ( )
96+ {
97+ // Provides initially failing test and verifies fix for advisory https://github.com/umbraco/Umbraco-CMS/security/advisories/GHSA-wx5h-wqfq-v698
98+ var authHandlerContext = CreateAuthorizationHandlerContext ( ) ;
99+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValues ( queryStringValues : [ NodeId . ToString ( ) , 1001 . ToString ( ) ] ) ;
88100 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "B" } ) ;
89101
90102 await sut . HandleAsync ( authHandlerContext ) ;
@@ -97,7 +109,7 @@ public async Task Node_Integer_Id_From_QueryString_Without_Permission_Is_Not_Aut
97109 public async Task Node_Udi_Id_From_QueryString_With_Permission_Is_Authorized ( )
98110 {
99111 var authHandlerContext = CreateAuthorizationHandlerContext ( ) ;
100- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( queryStringValue : s_nodeUdi . ToString ( ) ) ;
112+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( queryStringValue : s_nodeUdi . ToString ( ) ) ;
101113 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "A" } ) ;
102114
103115 await sut . HandleAsync ( authHandlerContext ) ;
@@ -110,7 +122,7 @@ public async Task Node_Udi_Id_From_QueryString_With_Permission_Is_Authorized()
110122 public async Task Node_Udi_Id_From_QueryString_Without_Permission_Is_Not_Authorized ( )
111123 {
112124 var authHandlerContext = CreateAuthorizationHandlerContext ( ) ;
113- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( queryStringValue : s_nodeUdi . ToString ( ) ) ;
125+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( queryStringValue : s_nodeUdi . ToString ( ) ) ;
114126 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "B" } ) ;
115127
116128 await sut . HandleAsync ( authHandlerContext ) ;
@@ -123,7 +135,7 @@ public async Task Node_Udi_Id_From_QueryString_Without_Permission_Is_Not_Authori
123135 public async Task Node_Guid_Id_From_QueryString_With_Permission_Is_Authorized ( )
124136 {
125137 var authHandlerContext = CreateAuthorizationHandlerContext ( ) ;
126- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( queryStringValue : s_nodeGuid . ToString ( ) ) ;
138+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( queryStringValue : s_nodeGuid . ToString ( ) ) ;
127139 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "A" } ) ;
128140
129141 await sut . HandleAsync ( authHandlerContext ) ;
@@ -136,7 +148,7 @@ public async Task Node_Guid_Id_From_QueryString_With_Permission_Is_Authorized()
136148 public async Task Node_Guid_Id_From_QueryString_Without_Permission_Is_Not_Authorized ( )
137149 {
138150 var authHandlerContext = CreateAuthorizationHandlerContext ( ) ;
139- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( queryStringValue : s_nodeGuid . ToString ( ) ) ;
151+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( queryStringValue : s_nodeGuid . ToString ( ) ) ;
140152 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "B" } ) ;
141153
142154 await sut . HandleAsync ( authHandlerContext ) ;
@@ -149,7 +161,7 @@ public async Task Node_Guid_Id_From_QueryString_Without_Permission_Is_Not_Author
149161 public async Task Node_Invalid_Id_From_QueryString_Is_Authorized ( )
150162 {
151163 var authHandlerContext = CreateAuthorizationHandlerContext ( ) ;
152- var mockHttpContextAccessor = CreateMockHttpContextAccessor ( queryStringValue : "invalid" ) ;
164+ var mockHttpContextAccessor = CreateMockHttpContextAccessorWithQueryStringValue ( queryStringValue : "invalid" ) ;
153165 var sut = CreateHandler ( mockHttpContextAccessor . Object , NodeId , new [ ] { "A" } ) ;
154166
155167 await sut . HandleAsync ( authHandlerContext ) ;
@@ -168,14 +180,20 @@ private static AuthorizationHandlerContext CreateAuthorizationHandlerContext(int
168180 return new AuthorizationHandlerContext ( new List < IAuthorizationRequirement > { requirement } , user , resource ) ;
169181 }
170182
171- private static Mock < IHttpContextAccessor > CreateMockHttpContextAccessor (
183+ private static Mock < IHttpContextAccessor > CreateMockHttpContextAccessorWithQueryStringValue (
172184 string queryStringName = QueryStringName ,
173185 string queryStringValue = "" )
186+ => CreateMockHttpContextAccessorWithQueryStringValues ( queryStringName , [ queryStringValue ] ) ;
187+
188+ private static Mock < IHttpContextAccessor > CreateMockHttpContextAccessorWithQueryStringValues (
189+ string queryStringName = QueryStringName ,
190+ string [ ] ? queryStringValues = null )
174191 {
192+ queryStringValues ??= [ ] ;
175193 var mockHttpContextAccessor = new Mock < IHttpContextAccessor > ( ) ;
176194 var mockHttpContext = new Mock < HttpContext > ( ) ;
177195 var mockHttpRequest = new Mock < HttpRequest > ( ) ;
178- var queryParams = new Dictionary < string , StringValues > { { queryStringName , queryStringValue } } ;
196+ var queryParams = new Dictionary < string , StringValues > { { queryStringName , new StringValues ( queryStringValues ) } } ;
179197 mockHttpRequest . SetupGet ( x => x . Query ) . Returns ( new QueryCollection ( queryParams ) ) ;
180198 mockHttpContext . SetupGet ( x => x . Request ) . Returns ( mockHttpRequest . Object ) ;
181199 mockHttpContext . SetupGet ( x => x . Items ) . Returns ( new Dictionary < object , object > ( ) ) ;
0 commit comments