1#!/usr/bin/env python
2#
3#  mod_authz_svn_tests.py:  testing mod_authz_svn
4#
5#  Subversion is a tool for revision control.
6#  See http://subversion.apache.org for more information.
7#
8# ====================================================================
9#    Licensed to the Apache Software Foundation (ASF) under one
10#    or more contributor license agreements.  See the NOTICE file
11#    distributed with this work for additional information
12#    regarding copyright ownership.  The ASF licenses this file
13#    to you under the Apache License, Version 2.0 (the
14#    "License"); you may not use this file except in compliance
15#    with the License.  You may obtain a copy of the License at
16#
17#      http://www.apache.org/licenses/LICENSE-2.0
18#
19#    Unless required by applicable law or agreed to in writing,
20#    software distributed under the License is distributed on an
21#    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
22#    KIND, either express or implied.  See the License for the
23#    specific language governing permissions and limitations
24#    under the License.
25######################################################################
26
27# General modules
28import os, re, logging
29
30logger = logging.getLogger()
31
32# Our testing module
33import svntest
34
35# (abbreviation)
36Skip = svntest.testcase.Skip_deco
37SkipUnless = svntest.testcase.SkipUnless_deco
38XFail = svntest.testcase.XFail_deco
39Issues = svntest.testcase.Issues_deco
40Issue = svntest.testcase.Issue_deco
41Wimp = svntest.testcase.Wimp_deco
42
43ls_of_D_no_H = '''<html><head><title>repos - Revision 1: /A/D</title></head>
44<body>
45 <h2>repos - Revision 1: /A/D</h2>
46 <ul>
47  <li><a href="../">..</a></li>
48  <li><a href="G/">G/</a></li>
49  <li><a href="gamma">gamma</a></li>
50 </ul>
51</body></html>'''
52
53ls_of_D_H = '''<html><head><title>repos - Revision 1: /A/D</title></head>
54<body>
55 <h2>repos - Revision 1: /A/D</h2>
56 <ul>
57  <li><a href="../">..</a></li>
58  <li><a href="G/">G/</a></li>
59  <li><a href="H/">H/</a></li>
60  <li><a href="gamma">gamma</a></li>
61 </ul>
62</body></html>'''
63
64ls_of_H = '''<html><head><title>repos - Revision 1: /A/D/H</title></head>
65<body>
66 <h2>repos - Revision 1: /A/D/H</h2>
67 <ul>
68  <li><a href="../">..</a></li>
69  <li><a href="chi">chi</a></li>
70  <li><a href="omega">omega</a></li>
71  <li><a href="psi">psi</a></li>
72 </ul>
73</body></html>'''
74
75user1 = svntest.main.wc_author
76user1_upper = user1.upper()
77user1_pass = svntest.main.wc_passwd
78user1_badpass = 'XXX'
79assert user1_pass != user1_badpass, "Passwords can't match"
80user2 = svntest.main.wc_author2
81user2_upper = user2.upper()
82user2_pass = svntest.main.wc_passwd
83user2_badpass = 'XXX'
84assert user2_pass != user2_badpass, "Passwords can't match"
85
86def write_authz_file(sbox):
87    svntest.main.write_authz_file(sbox, {
88                                          '/':  '$anonymous = r\n' +
89                                                'jrandom = rw\n' +
90                                                'jconstant = rw',
91                                          '/A/D/H': '$anonymous =\n' +
92                                                    '$authenticated =\n' +
93                                                    'jrandom = rw'
94                                        })
95
96def write_authz_file_groups(sbox):
97    authz_name = sbox.authz_name()
98    svntest.main.write_authz_file(sbox,{
99                                         '/':  '* =',
100                                       })
101
102def verify_get(test_area_url, path, user, pw,
103               expected_status, expected_body, headers):
104  import base64
105
106  req_url = test_area_url + path
107
108  h = svntest.main.create_http_connection(req_url, 0)
109
110  if headers is None:
111    headers = {}
112
113  if user and pw:
114      auth_info = user + ':' + pw
115      user_pw = base64.b64encode(auth_info.encode()).decode()
116      headers['Authorization'] = 'Basic ' + user_pw
117  else:
118      auth_info = "anonymous"
119
120  h.request('GET', req_url, None, headers)
121
122  r = h.getresponse()
123
124  actual_status = r.status
125  if expected_status and expected_status != actual_status:
126
127      logger.warn("Expected status '" + str(expected_status) +
128                  "' but got '" + str(actual_status) +
129                  "' on url '" + req_url + "' (" +
130                  auth_info + ").")
131      raise svntest.Failure
132
133  if expected_body:
134      actual_body = r.read()
135      if isinstance(expected_body, str) and not isinstance(actual_body, str):
136        actual_body = actual_body.decode()
137      if expected_body != actual_body:
138        logger.warn("Expected body:")
139        logger.warn(expected_body)
140        logger.warn("But got:")
141        logger.warn(actual_body)
142        logger.warn("on url '" + req_url + "' (" + auth_info + ").")
143        raise svntest.Failure
144
145def verify_gets(test_area_url, tests):
146  for test in tests:
147      verify_get(test_area_url, test['path'], test.get('user'), test.get('pw'),
148                 test['status'], test.get('body'), test.get('headers'))
149
150
151######################################################################
152# Tests
153#
154#   Each test must return on success or raise on failure.
155
156
157#----------------------------------------------------------------------
158
159
160@SkipUnless(svntest.main.is_ra_type_dav)
161def anon(sbox):
162  "test anonymous access"
163  sbox.build(read_only = True, create_wc = False)
164
165  test_area_url = sbox.repo_url.replace('/svn-test-work/local_tmp/repos',
166                                        '/authz-test-work/anon')
167
168  write_authz_file(sbox)
169
170  anon_tests = (
171                 { 'path': '', 'status': 301 },
172                 { 'path': '/', 'status': 200 },
173                 { 'path': '/repos', 'status': 301 },
174                 { 'path': '/repos/', 'status': 200 },
175                 { 'path': '/repos/A', 'status': 301 },
176                 { 'path': '/repos/A/', 'status': 200 },
177                 { 'path': '/repos/A/D', 'status': 301 },
178                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_no_H },
179                 { 'path': '/repos/A/D/gamma', 'status': 200 },
180                 { 'path': '/repos/A/D/H', 'status': 403 },
181                 { 'path': '/repos/A/D/H/', 'status': 403 },
182                 { 'path': '/repos/A/D/H/chi', 'status': 403 },
183                 # auth isn't configured so nothing should change when passing
184                 # authn details
185                 { 'path': '', 'status': 301, 'user': user1, 'pw': user1_pass},
186                 { 'path': '/', 'status': 200, 'user': user1, 'pw': user1_pass},
187                 { 'path': '/repos', 'status': 301, 'user': user1, 'pw': user1_pass},
188                 { 'path': '/repos/', 'status': 200, 'user': user1, 'pw': user1_pass},
189                 { 'path': '/repos/A', 'status': 301, 'user': user1, 'pw': user1_pass},
190                 { 'path': '/repos/A/', 'status': 200, 'user': user1, 'pw': user1_pass},
191                 { 'path': '/repos/A/D', 'status': 301, 'user': user1, 'pw': user1_pass},
192                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_no_H,
193                   'user': user1, 'pw': user1_pass},
194                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user1, 'pw': user1_pass},
195                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user1, 'pw': user1_pass},
196                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user1, 'pw': user1_pass},
197                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user1, 'pw': user1_pass},
198                 { 'path': '', 'status': 301, 'user': user1, 'pw': user1_badpass},
199                 { 'path': '/', 'status': 200, 'user': user1, 'pw': user1_badpass},
200                 { 'path': '/repos', 'status': 301, 'user': user1, 'pw': user1_badpass},
201                 { 'path': '/repos/', 'status': 200, 'user': user1, 'pw': user1_badpass},
202                 { 'path': '/repos/A', 'status': 301, 'user': user1, 'pw': user1_badpass},
203                 { 'path': '/repos/A/', 'status': 200, 'user': user1, 'pw': user1_badpass},
204                 { 'path': '/repos/A/D', 'status': 301, 'user': user1, 'pw': user1_badpass},
205                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_no_H,
206                   'user': user1, 'pw': user1_badpass},
207                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user1, 'pw': user1_badpass},
208                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user1, 'pw': user1_badpass},
209                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user1, 'pw': user1_badpass},
210                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user1, 'pw': user1_badpass},
211                 { 'path': '', 'status': 301, 'user': user2, 'pw': user1_pass},
212                 { 'path': '/', 'status': 200, 'user': user2, 'pw': user1_pass},
213                 { 'path': '/repos', 'status': 301, 'user': user2, 'pw': user1_pass},
214                 { 'path': '/repos/', 'status': 200, 'user': user2, 'pw': user1_pass},
215                 { 'path': '/repos/A', 'status': 301, 'user': user2, 'pw': user1_pass},
216                 { 'path': '/repos/A/', 'status': 200, 'user': user2, 'pw': user1_pass},
217                 { 'path': '/repos/A/D', 'status': 301, 'user': user2, 'pw': user1_pass},
218                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_no_H,
219                   'user': user2, 'pw': user1_pass},
220                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user2, 'pw': user2_pass},
221                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user2, 'pw': user2_pass},
222                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user2, 'pw': user2_pass},
223                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user2, 'pw': user2_pass},
224                 { 'path': '', 'status': 301, 'user': user2, 'pw': user2_badpass},
225                 { 'path': '/', 'status': 200, 'user': user2, 'pw': user2_badpass},
226                 { 'path': '/repos', 'status': 301, 'user': user2, 'pw': user2_badpass},
227                 { 'path': '/repos/', 'status': 200, 'user': user2, 'pw': user2_badpass},
228                 { 'path': '/repos/A', 'status': 301, 'user': user2, 'pw': user2_badpass},
229                 { 'path': '/repos/A/', 'status': 200, 'user': user2, 'pw': user2_badpass},
230                 { 'path': '/repos/A/D', 'status': 301, 'user': user2, 'pw': user2_badpass},
231                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_no_H,
232                   'user': user2, 'pw': user2_badpass},
233                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user2, 'pw': user2_badpass},
234                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user2, 'pw': user2_badpass},
235                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user2, 'pw': user2_badpass},
236                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user2, 'pw': user2_badpass},
237               )
238
239  verify_gets(test_area_url, anon_tests)
240
241
242@SkipUnless(svntest.main.is_ra_type_dav)
243def mixed(sbox):
244  "test mixed anonymous and authenticated access"
245  sbox.build(read_only = True, create_wc = False)
246
247  test_area_url = sbox.repo_url.replace('/svn-test-work/local_tmp/repos',
248                                        '/authz-test-work/mixed')
249
250  write_authz_file(sbox)
251
252  mixed_tests = (
253                 { 'path': '', 'status': 301,  },
254                 { 'path': '/', 'status': 200,  },
255                 { 'path': '/repos', 'status': 301,  },
256                 { 'path': '/repos/', 'status': 200,  },
257                 { 'path': '/repos/A', 'status': 301,  },
258                 { 'path': '/repos/A/', 'status': 200,  },
259                 { 'path': '/repos/A/D', 'status': 301,  },
260                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_no_H,
261                   },
262                 { 'path': '/repos/A/D/gamma', 'status': 200, },
263                 { 'path': '/repos/A/D/H', 'status': 401, },
264                 { 'path': '/repos/A/D/H/', 'status': 401, },
265                 { 'path': '/repos/A/D/H/chi', 'status': 401, },
266                 # auth is configured and user1 is allowed access to H
267                 { 'path': '', 'status': 301, 'user': user1, 'pw': user1_pass},
268                 { 'path': '/', 'status': 200, 'user': user1, 'pw': user1_pass},
269                 { 'path': '/repos', 'status': 301, 'user': user1, 'pw': user1_pass},
270                 { 'path': '/repos/', 'status': 200, 'user': user1, 'pw': user1_pass},
271                 { 'path': '/repos/A', 'status': 301, 'user': user1, 'pw': user1_pass},
272                 { 'path': '/repos/A/', 'status': 200, 'user': user1, 'pw': user1_pass},
273                 { 'path': '/repos/A/D', 'status': 301, 'user': user1, 'pw': user1_pass},
274                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_H,
275                   'user': user1, 'pw': user1_pass},
276                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user1, 'pw': user1_pass},
277                 { 'path': '/repos/A/D/H', 'status': 301, 'user': user1, 'pw': user1_pass},
278                 { 'path': '/repos/A/D/H/', 'status': 200, 'body': ls_of_H, 'user': user1, 'pw': user1_pass},
279                 { 'path': '/repos/A/D/H/chi', 'status': 200, 'user': user1, 'pw': user1_pass},
280                 # try with the wrong password for user1
281                 { 'path': '', 'status': 401, 'user': user1, 'pw': user1_badpass},
282                 { 'path': '/', 'status': 401, 'user': user1, 'pw': user1_badpass},
283                 { 'path': '/repos', 'status': 401, 'user': user1, 'pw': user1_badpass},
284                 { 'path': '/repos/', 'status': 401, 'user': user1, 'pw': user1_badpass},
285                 { 'path': '/repos/A', 'status': 401, 'user': user1, 'pw': user1_badpass},
286                 { 'path': '/repos/A/', 'status': 401, 'user': user1, 'pw': user1_badpass},
287                 { 'path': '/repos/A/D', 'status': 401, 'user': user1, 'pw': user1_badpass},
288                 { 'path': '/repos/A/D/', 'status': 401, 'user': user1, 'pw': user1_badpass},
289                 { 'path': '/repos/A/D/gamma', 'status': 401, 'user': user1, 'pw': user1_badpass},
290                 { 'path': '/repos/A/D/H', 'status': 401, 'user': user1, 'pw': user1_badpass},
291                 { 'path': '/repos/A/D/H/', 'status': 401, 'user': user1, 'pw': user1_badpass},
292                 { 'path': '/repos/A/D/H/chi', 'status': 401, 'user': user1, 'pw': user1_badpass},
293                 # auth is configured and user2 is not allowed access to H
294                 { 'path': '', 'status': 301, 'user': user2, 'pw': user2_pass},
295                 { 'path': '/', 'status': 200, 'user': user2, 'pw': user2_pass},
296                 { 'path': '/repos', 'status': 301, 'user': user2, 'pw': user2_pass},
297                 { 'path': '/repos/', 'status': 200, 'user': user2, 'pw': user2_pass},
298                 { 'path': '/repos/A', 'status': 301, 'user': user2, 'pw': user2_pass},
299                 { 'path': '/repos/A/', 'status': 200, 'user': user2, 'pw': user2_pass},
300                 { 'path': '/repos/A/D', 'status': 301, 'user': user2, 'pw': user2_pass},
301                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_no_H,
302                   'user': user2, 'pw': user2_pass},
303                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user2, 'pw': user2_pass},
304                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user2, 'pw': user2_pass},
305                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user2, 'pw': user2_pass},
306                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user2, 'pw': user2_pass},
307                 # try with the wrong password for user2
308                 { 'path': '', 'status': 401, 'user': user2, 'pw': user2_badpass},
309                 { 'path': '/', 'status': 401, 'user': user2, 'pw': user2_badpass},
310                 { 'path': '/repos', 'status': 401, 'user': user2, 'pw': user2_badpass},
311                 { 'path': '/repos/', 'status': 401, 'user': user2, 'pw': user2_badpass},
312                 { 'path': '/repos/A', 'status': 401, 'user': user2, 'pw': user2_badpass},
313                 { 'path': '/repos/A/', 'status': 401, 'user': user2, 'pw': user2_badpass},
314                 { 'path': '/repos/A/D', 'status': 401, 'user': user2, 'pw': user2_badpass},
315                 { 'path': '/repos/A/D/', 'status': 401, 'user': user2, 'pw': user2_badpass},
316                 { 'path': '/repos/A/D/gamma', 'status': 401, 'user': user2, 'pw': user2_badpass},
317                 { 'path': '/repos/A/D/H', 'status': 401, 'user': user2, 'pw': user2_badpass},
318                 { 'path': '/repos/A/D/H/', 'status': 401, 'user': user2, 'pw': user2_badpass},
319                 { 'path': '/repos/A/D/H/chi', 'status': 401, 'user': user2, 'pw': user2_badpass},
320                 )
321
322  verify_gets(test_area_url, mixed_tests)
323
324@SkipUnless(svntest.main.is_ra_type_dav)
325@XFail(svntest.main.is_httpd_authz_provider_enabled)
326# uses the AuthzSVNNoAuthWhenAnonymousAllowed On directive
327# this is broken with httpd 2.3.x+ since it requires the auth system to accept
328# r->user == NULL and there is a test for this in server/request.c now.  It
329# was intended as a workaround for the lack of Satisfy Any in 2.3.x+ which
330# was resolved by httpd with mod_access_compat in 2.3.x+.
331def mixed_noauthwhenanon(sbox):
332  "test mixed with noauthwhenanon directive"
333  sbox.build(read_only = True, create_wc = False)
334
335  test_area_url = sbox.repo_url.replace('/svn-test-work/local_tmp/repos',
336                                        '/authz-test-work/mixed-noauthwhenanon')
337
338  write_authz_file(sbox)
339
340  noauthwhenanon_tests = (
341                 { 'path': '', 'status': 301,  },
342                 { 'path': '/', 'status': 200,  },
343                 { 'path': '/repos', 'status': 301,  },
344                 { 'path': '/repos/', 'status': 200,  },
345                 { 'path': '/repos/A', 'status': 301,  },
346                 { 'path': '/repos/A/', 'status': 200,  },
347                 { 'path': '/repos/A/D', 'status': 301,  },
348                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_no_H,
349                   },
350                 { 'path': '/repos/A/D/gamma', 'status': 200, },
351                 { 'path': '/repos/A/D/H', 'status': 401, },
352                 { 'path': '/repos/A/D/H/', 'status': 401, },
353                 { 'path': '/repos/A/D/H/chi', 'status': 401, },
354                 # auth is configured and user1 is allowed access to H
355                 { 'path': '', 'status': 301, 'user': user1, 'pw': user1_pass},
356                 { 'path': '/', 'status': 200, 'user': user1, 'pw': user1_pass},
357                 { 'path': '/repos', 'status': 301, 'user': user1, 'pw': user1_pass},
358                 { 'path': '/repos/', 'status': 200, 'user': user1, 'pw': user1_pass},
359                 { 'path': '/repos/A', 'status': 301, 'user': user1, 'pw': user1_pass},
360                 { 'path': '/repos/A/', 'status': 200, 'user': user1, 'pw': user1_pass},
361                 { 'path': '/repos/A/D', 'status': 301, 'user': user1, 'pw': user1_pass},
362                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_H,
363                   'user': user1, 'pw': user1_pass},
364                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user1, 'pw': user1_pass},
365                 { 'path': '/repos/A/D/H', 'status': 301, 'user': user1, 'pw': user1_pass},
366                 { 'path': '/repos/A/D/H/', 'status': 200, 'body': ls_of_H, 'user': user1, 'pw': user1_pass},
367                 { 'path': '/repos/A/D/H/chi', 'status': 200, 'user': user1, 'pw': user1_pass},
368                 # try with the wrong password for user1
369                 # note that unlike doing this with Satisfy Any this case
370                 # actually provides anon access when provided with an invalid
371                 # password
372                 { 'path': '', 'status': 301, 'user': user1, 'pw': user1_badpass},
373                 { 'path': '/', 'status': 200, 'user': user1, 'pw': user1_badpass},
374                 { 'path': '/repos', 'status': 301, 'user': user1, 'pw': user1_badpass},
375                 { 'path': '/repos/', 'status': 200, 'user': user1, 'pw': user1_badpass},
376                 { 'path': '/repos/A', 'status': 301, 'user': user1, 'pw': user1_badpass},
377                 { 'path': '/repos/A/', 'status': 200, 'user': user1, 'pw': user1_badpass},
378                 { 'path': '/repos/A/D', 'status': 301, 'user': user1, 'pw': user1_badpass},
379                 { 'path': '/repos/A/D/', 'status': 200, 'user': user1, 'pw': user1_badpass},
380                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user1, 'pw': user1_badpass},
381                 { 'path': '/repos/A/D/H', 'status': 401, 'user': user1, 'pw': user1_badpass},
382                 { 'path': '/repos/A/D/H/', 'status': 401, 'user': user1, 'pw': user1_badpass},
383                 { 'path': '/repos/A/D/H/chi', 'status': 401, 'user': user1, 'pw': user1_badpass},
384                 # auth is configured and user2 is not allowed access to H
385                 { 'path': '', 'status': 301, 'user': user2, 'pw': user2_pass},
386                 { 'path': '/', 'status': 200, 'user': user2, 'pw': user2_pass},
387                 { 'path': '/repos', 'status': 301, 'user': user2, 'pw': user2_pass},
388                 { 'path': '/repos/', 'status': 200, 'user': user2, 'pw': user2_pass},
389                 { 'path': '/repos/A', 'status': 301, 'user': user2, 'pw': user2_pass},
390                 { 'path': '/repos/A/', 'status': 200, 'user': user2, 'pw': user2_pass},
391                 { 'path': '/repos/A/D', 'status': 301, 'user': user2, 'pw': user2_pass},
392                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_no_H,
393                   'user': user2, 'pw': user2_pass},
394                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user2, 'pw': user2_pass},
395                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user2, 'pw': user2_pass},
396                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user2, 'pw': user2_pass},
397                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user2, 'pw': user2_pass},
398                 # try with the wrong password for user2
399                 { 'path': '', 'status': 301, 'user': user2, 'pw': user2_badpass},
400                 { 'path': '/', 'status': 200, 'user': user2, 'pw': user2_badpass},
401                 { 'path': '/repos', 'status': 301, 'user': user2, 'pw': user2_badpass},
402                 { 'path': '/repos/', 'status': 200, 'user': user2, 'pw': user2_badpass},
403                 { 'path': '/repos/A', 'status': 301, 'user': user2, 'pw': user2_badpass},
404                 { 'path': '/repos/A/', 'status': 200, 'user': user2, 'pw': user2_badpass},
405                 { 'path': '/repos/A/D', 'status': 301, 'user': user2, 'pw': user2_badpass},
406                 { 'path': '/repos/A/D/', 'status': 200, 'user': user2, 'pw': user2_badpass},
407                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user2, 'pw': user2_badpass},
408                 { 'path': '/repos/A/D/H', 'status': 401, 'user': user2, 'pw': user2_badpass},
409                 { 'path': '/repos/A/D/H/', 'status': 401, 'user': user2, 'pw': user2_badpass},
410                 { 'path': '/repos/A/D/H/chi', 'status': 401, 'user': user2, 'pw': user2_badpass},
411                 )
412
413  verify_gets(test_area_url, noauthwhenanon_tests)
414
415
416@SkipUnless(svntest.main.is_ra_type_dav)
417def authn(sbox):
418  "test authenticated only access"
419  sbox.build(read_only = True, create_wc = False)
420
421  test_area_url = sbox.repo_url.replace('/svn-test-work/local_tmp/repos',
422                                        '/authz-test-work/authn')
423
424  write_authz_file(sbox)
425
426  authn_tests = (
427                 { 'path': '', 'status': 401,  },
428                 { 'path': '/', 'status': 401,  },
429                 { 'path': '/repos', 'status': 401,  },
430                 { 'path': '/repos/', 'status': 401,  },
431                 { 'path': '/repos/A', 'status': 401,  },
432                 { 'path': '/repos/A/', 'status': 401,  },
433                 { 'path': '/repos/A/D', 'status': 401,  },
434                 { 'path': '/repos/A/D/', 'status': 401, },
435                 { 'path': '/repos/A/D/gamma', 'status': 401, },
436                 { 'path': '/repos/A/D/H', 'status': 401, },
437                 { 'path': '/repos/A/D/H/', 'status': 401, },
438                 { 'path': '/repos/A/D/H/chi', 'status': 401, },
439                 # auth is configured and user1 is allowed access to H
440                 { 'path': '', 'status': 301, 'user': user1, 'pw': user1_pass},
441                 { 'path': '/', 'status': 200, 'user': user1, 'pw': user1_pass},
442                 { 'path': '/repos', 'status': 301, 'user': user1, 'pw': user1_pass},
443                 { 'path': '/repos/', 'status': 200, 'user': user1, 'pw': user1_pass},
444                 { 'path': '/repos/A', 'status': 301, 'user': user1, 'pw': user1_pass},
445                 { 'path': '/repos/A/', 'status': 200, 'user': user1, 'pw': user1_pass},
446                 { 'path': '/repos/A/D', 'status': 301, 'user': user1, 'pw': user1_pass},
447                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_H,
448                   'user': user1, 'pw': user1_pass},
449                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user1, 'pw': user1_pass},
450                 { 'path': '/repos/A/D/H', 'status': 301, 'user': user1, 'pw': user1_pass},
451                 { 'path': '/repos/A/D/H/', 'status': 200, 'body': ls_of_H, 'user': user1, 'pw': user1_pass},
452                 { 'path': '/repos/A/D/H/chi', 'status': 200, 'user': user1, 'pw': user1_pass},
453                 # try with upper case username for user1
454                 { 'path': '', 'status': 301, 'user': user1_upper, 'pw': user1_pass},
455                 { 'path': '/', 'status': 200, 'user': user1_upper, 'pw': user1_pass},
456                 { 'path': '/repos', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
457                 { 'path': '/repos/', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
458                 { 'path': '/repos/A', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
459                 { 'path': '/repos/A/', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
460                 { 'path': '/repos/A/D', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
461                 { 'path': '/repos/A/D/', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
462                 { 'path': '/repos/A/D/gamma', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
463                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
464                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
465                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
466                 # try with the wrong password for user1
467                 { 'path': '', 'status': 401, 'user': user1, 'pw': user1_badpass},
468                 { 'path': '/', 'status': 401, 'user': user1, 'pw': user1_badpass},
469                 { 'path': '/repos', 'status': 401, 'user': user1, 'pw': user1_badpass},
470                 { 'path': '/repos/', 'status': 401, 'user': user1, 'pw': user1_badpass},
471                 { 'path': '/repos/A', 'status': 401, 'user': user1, 'pw': user1_badpass},
472                 { 'path': '/repos/A/', 'status': 401, 'user': user1, 'pw': user1_badpass},
473                 { 'path': '/repos/A/D', 'status': 401, 'user': user1, 'pw': user1_badpass},
474                 { 'path': '/repos/A/D/', 'status': 401, 'user': user1, 'pw': user1_badpass},
475                 { 'path': '/repos/A/D/gamma', 'status': 401, 'user': user1, 'pw': user1_badpass},
476                 { 'path': '/repos/A/D/H', 'status': 401, 'user': user1, 'pw': user1_badpass},
477                 { 'path': '/repos/A/D/H/', 'status': 401, 'user': user1, 'pw': user1_badpass},
478                 { 'path': '/repos/A/D/H/chi', 'status': 401, 'user': user1, 'pw': user1_badpass},
479                 # auth is configured and user2 is not allowed access to H
480                 { 'path': '', 'status': 301, 'user': user2, 'pw': user2_pass},
481                 { 'path': '/', 'status': 200, 'user': user2, 'pw': user2_pass},
482                 { 'path': '/repos', 'status': 301, 'user': user2, 'pw': user2_pass},
483                 { 'path': '/repos/', 'status': 200, 'user': user2, 'pw': user2_pass},
484                 { 'path': '/repos/A', 'status': 301, 'user': user2, 'pw': user2_pass},
485                 { 'path': '/repos/A/', 'status': 200, 'user': user2, 'pw': user2_pass},
486                 { 'path': '/repos/A/D', 'status': 301, 'user': user2, 'pw': user2_pass},
487                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_no_H,
488                   'user': user2, 'pw': user2_pass},
489                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user2, 'pw': user2_pass},
490                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user2, 'pw': user2_pass},
491                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user2, 'pw': user2_pass},
492                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user2, 'pw': user2_pass},
493                 # try with upper case username for user2
494                 { 'path': '', 'status': 301, 'user': user2_upper, 'pw': user2_pass},
495                 { 'path': '/', 'status': 200, 'user': user2_upper, 'pw': user2_pass},
496                 { 'path': '/repos', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
497                 { 'path': '/repos/', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
498                 { 'path': '/repos/A', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
499                 { 'path': '/repos/A/', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
500                 { 'path': '/repos/A/D', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
501                 { 'path': '/repos/A/D/', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
502                 { 'path': '/repos/A/D/gamma', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
503                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
504                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
505                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
506                 # try with the wrong password for user2
507                 { 'path': '', 'status': 401, 'user': user2, 'pw': user2_badpass},
508                 { 'path': '/', 'status': 401, 'user': user2, 'pw': user2_badpass},
509                 { 'path': '/repos', 'status': 401, 'user': user2, 'pw': user2_badpass},
510                 { 'path': '/repos/', 'status': 401, 'user': user2, 'pw': user2_badpass},
511                 { 'path': '/repos/A', 'status': 401, 'user': user2, 'pw': user2_badpass},
512                 { 'path': '/repos/A/', 'status': 401, 'user': user2, 'pw': user2_badpass},
513                 { 'path': '/repos/A/D', 'status': 401, 'user': user2, 'pw': user2_badpass},
514                 { 'path': '/repos/A/D/', 'status': 401, 'user': user2, 'pw': user2_badpass},
515                 { 'path': '/repos/A/D/gamma', 'status': 401, 'user': user2, 'pw': user2_badpass},
516                 { 'path': '/repos/A/D/H', 'status': 401, 'user': user2, 'pw': user2_badpass},
517                 { 'path': '/repos/A/D/H/', 'status': 401, 'user': user2, 'pw': user2_badpass},
518                 { 'path': '/repos/A/D/H/chi', 'status': 401, 'user': user2, 'pw': user2_badpass},
519                 )
520
521  verify_gets(test_area_url, authn_tests)
522
523@SkipUnless(svntest.main.is_ra_type_dav)
524def authn_anonoff(sbox):
525  "test authenticated only access with anonoff"
526  sbox.build(read_only = True, create_wc = False)
527
528  test_area_url = sbox.repo_url.replace('/svn-test-work/local_tmp/repos',
529                                        '/authz-test-work/authn-anonoff')
530
531  write_authz_file(sbox)
532
533  anonoff_tests = (
534                 { 'path': '', 'status': 401,  },
535                 { 'path': '/', 'status': 401,  },
536                 { 'path': '/repos', 'status': 401,  },
537                 { 'path': '/repos/', 'status': 401,  },
538                 { 'path': '/repos/A', 'status': 401,  },
539                 { 'path': '/repos/A/', 'status': 401,  },
540                 { 'path': '/repos/A/D', 'status': 401,  },
541                 { 'path': '/repos/A/D/', 'status': 401, },
542                 { 'path': '/repos/A/D/gamma', 'status': 401, },
543                 { 'path': '/repos/A/D/H', 'status': 401, },
544                 { 'path': '/repos/A/D/H/', 'status': 401, },
545                 { 'path': '/repos/A/D/H/chi', 'status': 401, },
546                 # auth is configured and user1 is allowed access to H
547                 { 'path': '', 'status': 301, 'user': user1, 'pw': user1_pass},
548                 { 'path': '/', 'status': 200, 'user': user1, 'pw': user1_pass},
549                 { 'path': '/repos', 'status': 301, 'user': user1, 'pw': user1_pass},
550                 { 'path': '/repos/', 'status': 200, 'user': user1, 'pw': user1_pass},
551                 { 'path': '/repos/A', 'status': 301, 'user': user1, 'pw': user1_pass},
552                 { 'path': '/repos/A/', 'status': 200, 'user': user1, 'pw': user1_pass},
553                 { 'path': '/repos/A/D', 'status': 301, 'user': user1, 'pw': user1_pass},
554                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_H,
555                   'user': user1, 'pw': user1_pass},
556                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user1, 'pw': user1_pass},
557                 { 'path': '/repos/A/D/H', 'status': 301, 'user': user1, 'pw': user1_pass},
558                 { 'path': '/repos/A/D/H/', 'status': 200, 'body': ls_of_H, 'user': user1, 'pw': user1_pass},
559                 { 'path': '/repos/A/D/H/chi', 'status': 200, 'user': user1, 'pw': user1_pass},
560                 # try with upper case username for user1
561                 { 'path': '', 'status': 301, 'user': user1_upper, 'pw': user1_pass},
562                 { 'path': '/', 'status': 200, 'user': user1_upper, 'pw': user1_pass},
563                 { 'path': '/repos', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
564                 { 'path': '/repos/', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
565                 { 'path': '/repos/A', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
566                 { 'path': '/repos/A/', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
567                 { 'path': '/repos/A/D', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
568                 { 'path': '/repos/A/D/', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
569                 { 'path': '/repos/A/D/gamma', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
570                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
571                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
572                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user1_upper, 'pw': user1_pass},
573                 # try with the wrong password for user1
574                 { 'path': '', 'status': 401, 'user': user1, 'pw': user1_badpass},
575                 { 'path': '/', 'status': 401, 'user': user1, 'pw': user1_badpass},
576                 { 'path': '/repos', 'status': 401, 'user': user1, 'pw': user1_badpass},
577                 { 'path': '/repos/', 'status': 401, 'user': user1, 'pw': user1_badpass},
578                 { 'path': '/repos/A', 'status': 401, 'user': user1, 'pw': user1_badpass},
579                 { 'path': '/repos/A/', 'status': 401, 'user': user1, 'pw': user1_badpass},
580                 { 'path': '/repos/A/D', 'status': 401, 'user': user1, 'pw': user1_badpass},
581                 { 'path': '/repos/A/D/', 'status': 401, 'user': user1, 'pw': user1_badpass},
582                 { 'path': '/repos/A/D/gamma', 'status': 401, 'user': user1, 'pw': user1_badpass},
583                 { 'path': '/repos/A/D/H', 'status': 401, 'user': user1, 'pw': user1_badpass},
584                 { 'path': '/repos/A/D/H/', 'status': 401, 'user': user1, 'pw': user1_badpass},
585                 { 'path': '/repos/A/D/H/chi', 'status': 401, 'user': user1, 'pw': user1_badpass},
586                 # auth is configured and user2 is not allowed access to H
587                 { 'path': '', 'status': 301, 'user': user2, 'pw': user2_pass},
588                 { 'path': '/', 'status': 200, 'user': user2, 'pw': user2_pass},
589                 { 'path': '/repos', 'status': 301, 'user': user2, 'pw': user2_pass},
590                 { 'path': '/repos/', 'status': 200, 'user': user2, 'pw': user2_pass},
591                 { 'path': '/repos/A', 'status': 301, 'user': user2, 'pw': user2_pass},
592                 { 'path': '/repos/A/', 'status': 200, 'user': user2, 'pw': user2_pass},
593                 { 'path': '/repos/A/D', 'status': 301, 'user': user2, 'pw': user2_pass},
594                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_no_H,
595                   'user': user2, 'pw': user2_pass},
596                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user2, 'pw': user2_pass},
597                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user2, 'pw': user2_pass},
598                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user2, 'pw': user2_pass},
599                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user2, 'pw': user2_pass},
600                 # try with upper case username for user2
601                 { 'path': '', 'status': 301, 'user': user2_upper, 'pw': user2_pass},
602                 { 'path': '/', 'status': 200, 'user': user2_upper, 'pw': user2_pass},
603                 { 'path': '/repos', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
604                 { 'path': '/repos/', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
605                 { 'path': '/repos/A', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
606                 { 'path': '/repos/A/', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
607                 { 'path': '/repos/A/D', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
608                 { 'path': '/repos/A/D/', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
609                 { 'path': '/repos/A/D/gamma', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
610                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
611                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
612                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
613                 # try with the wrong password for user2
614                 { 'path': '', 'status': 401, 'user': user2, 'pw': user2_badpass},
615                 { 'path': '/', 'status': 401, 'user': user2, 'pw': user2_badpass},
616                 { 'path': '/repos', 'status': 401, 'user': user2, 'pw': user2_badpass},
617                 { 'path': '/repos/', 'status': 401, 'user': user2, 'pw': user2_badpass},
618                 { 'path': '/repos/A', 'status': 401, 'user': user2, 'pw': user2_badpass},
619                 { 'path': '/repos/A/', 'status': 401, 'user': user2, 'pw': user2_badpass},
620                 { 'path': '/repos/A/D', 'status': 401, 'user': user2, 'pw': user2_badpass},
621                 { 'path': '/repos/A/D/', 'status': 401, 'user': user2, 'pw': user2_badpass},
622                 { 'path': '/repos/A/D/gamma', 'status': 401, 'user': user2, 'pw': user2_badpass},
623                 { 'path': '/repos/A/D/H', 'status': 401, 'user': user2, 'pw': user2_badpass},
624                 { 'path': '/repos/A/D/H/', 'status': 401, 'user': user2, 'pw': user2_badpass},
625                 { 'path': '/repos/A/D/H/chi', 'status': 401, 'user': user2, 'pw': user2_badpass},
626                 )
627
628  verify_gets(test_area_url, anonoff_tests)
629
630@SkipUnless(svntest.main.is_ra_type_dav)
631def authn_lcuser(sbox):
632  "test authenticated only access with lcuser"
633  sbox.build(read_only = True, create_wc = False)
634
635  test_area_url = sbox.repo_url.replace('/svn-test-work/local_tmp/repos',
636                                        '/authz-test-work/authn-lcuser')
637
638  write_authz_file(sbox)
639
640  lcuser_tests = (
641                 # try with upper case username for user1 (works due to lcuser option)
642                 { 'path': '', 'status': 301, 'user': user1_upper, 'pw': user1_pass},
643                 { 'path': '/', 'status': 200, 'user': user1_upper, 'pw': user1_pass},
644                 { 'path': '/repos', 'status': 301, 'user': user1_upper, 'pw': user1_pass},
645                 { 'path': '/repos/', 'status': 200, 'user': user1_upper, 'pw': user1_pass},
646                 { 'path': '/repos/A', 'status': 301, 'user': user1_upper, 'pw': user1_pass},
647                 { 'path': '/repos/A/', 'status': 200, 'user': user1_upper, 'pw': user1_pass},
648                 { 'path': '/repos/A/D', 'status': 301, 'user': user1_upper, 'pw': user1_pass},
649                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_H,
650                   'user': user1_upper, 'pw': user1_pass},
651                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user1_upper, 'pw': user1_pass},
652                 { 'path': '/repos/A/D/H', 'status': 301, 'user': user1_upper, 'pw': user1_pass},
653                 { 'path': '/repos/A/D/H/', 'status': 200, 'body': ls_of_H, 'user': user1_upper, 'pw': user1_pass},
654                 { 'path': '/repos/A/D/H/chi', 'status': 200, 'user': user1_upper, 'pw': user1_pass},
655                 # try with upper case username for user2 (works due to lcuser option)
656                 { 'path': '', 'status': 301, 'user': user2_upper, 'pw': user2_pass},
657                 { 'path': '/', 'status': 200, 'user': user2_upper, 'pw': user2_pass},
658                 { 'path': '/repos', 'status': 301, 'user': user2_upper, 'pw': user2_pass},
659                 { 'path': '/repos/', 'status': 200, 'user': user2_upper, 'pw': user2_pass},
660                 { 'path': '/repos/A', 'status': 301, 'user': user2_upper, 'pw': user2_pass},
661                 { 'path': '/repos/A/', 'status': 200, 'user': user2_upper, 'pw': user2_pass},
662                 { 'path': '/repos/A/D', 'status': 301, 'user': user2_upper, 'pw': user2_pass},
663                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_no_H,
664                   'user': user2_upper, 'pw': user2_pass},
665                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user2_upper, 'pw': user2_pass},
666                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
667                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
668                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user2_upper, 'pw': user2_pass},
669                 )
670
671  verify_gets(test_area_url, lcuser_tests)
672
673# authenticated access only by group - a excuse to use AuthzSVNAuthoritative Off
674# this is terribly messed up, Require group runs after mod_authz_svn.
675# so if mod_authz_svn grants the access then it doesn't matter what the group
676# requirement says.  If we reject the access then you can use the AuthzSVNAuthoritative Off
677# directive to fall through to the group check.  Overall the behavior of setups like this
678# is almost guaranteed to not be what users expect.
679@SkipUnless(svntest.main.is_ra_type_dav)
680def authn_group(sbox):
681  "test authenticated only access via groups"
682  sbox.build(read_only = True, create_wc = False)
683
684  test_area_url = sbox.repo_url.replace('/svn-test-work/local_tmp/repos',
685                                        '/authz-test-work/authn-group')
686
687  # Can't use write_authz_file() as most tests because we want to deny all
688  # access with mod_authz_svn so the tests fall through to the group handling
689  authz_name = sbox.authz_name()
690  svntest.main.write_authz_file(sbox, {
691                                        '/':  '* =',
692                                      })
693
694  group_tests = (
695                 { 'path': '', 'status': 401, },
696                 { 'path': '/', 'status': 401, },
697                 { 'path': '/repos', 'status': 401, },
698                 { 'path': '/repos/', 'status': 401, },
699                 { 'path': '/repos/A', 'status': 401, },
700                 { 'path': '/repos/A/', 'status': 401, },
701                 { 'path': '/repos/A/D', 'status': 401, },
702                 { 'path': '/repos/A/D/', 'status': 401, },
703                 { 'path': '/repos/A/D/gamma', 'status': 401, },
704                 { 'path': '/repos/A/D/H', 'status': 401, },
705                 { 'path': '/repos/A/D/H/', 'status': 401, },
706                 { 'path': '/repos/A/D/H/chi', 'status': 401, },
707                 # auth is configured and user1 is allowed access repo including H
708                 { 'path': '', 'status': 301, 'user': user1, 'pw': user1_pass},
709                 { 'path': '/', 'status': 200, 'user': user1, 'pw': user1_pass},
710                 { 'path': '/repos', 'status': 301, 'user': user1, 'pw': user1_pass},
711                 { 'path': '/repos/', 'status': 200, 'user': user1, 'pw': user1_pass},
712                 { 'path': '/repos/A', 'status': 301, 'user': user1, 'pw': user1_pass},
713                 { 'path': '/repos/A/', 'status': 200, 'user': user1, 'pw': user1_pass},
714                 { 'path': '/repos/A/D', 'status': 301, 'user': user1, 'pw': user1_pass},
715                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_H,
716                   'user': user1, 'pw': user1_pass},
717                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user1, 'pw': user1_pass},
718                 { 'path': '/repos/A/D/H', 'status': 301, 'user': user1, 'pw': user1_pass},
719                 { 'path': '/repos/A/D/H/', 'status': 200, 'body': ls_of_H, 'user': user1, 'pw': user1_pass},
720                 { 'path': '/repos/A/D/H/chi', 'status': 200, 'user': user1, 'pw': user1_pass},
721                 )
722
723  verify_gets(test_area_url, group_tests)
724
725# This test exists to validate our behavior when used with the new authz
726# provider system introduced in httpd 2.3.x.  The Satisfy directive
727# determines how older authz hooks are combined and the RequireA(ll|ny)
728# blocks handles how new authz providers are combined.  The overall results of
729# all the authz providers (combined per the Require* blocks) are then
730# combined with the other authz hooks via the Satisfy directive.
731# Meaning this test requires that mod_authz_svn says yes and there is
732# either a valid user or the ALLOW header is 1.  The header may seem
733# like a silly test but it's easier to excercise than say a host directive
734# in a repeatable test.
735@SkipUnless(svntest.main.is_httpd_authz_provider_enabled)
736def authn_sallrany(sbox):
737  "test satisfy all require any config"
738  sbox.build(read_only = True, create_wc = False)
739
740  test_area_url = sbox.repo_url.replace('/svn-test-work/local_tmp/repos',
741                                        '/authz-test-work/sallrany')
742
743  write_authz_file(sbox)
744
745  allow_header = { 'ALLOW': '1' }
746
747  sallrany_tests = (
748                 #anon access isn't allowed without ALLOW header
749                 { 'path': '', 'status': 401, },
750                 { 'path': '/', 'status': 401, },
751                 { 'path': '/repos', 'status': 401, },
752                 { 'path': '/repos/', 'status': 401, },
753                 { 'path': '/repos/A', 'status': 401, },
754                 { 'path': '/repos/A/', 'status': 401, },
755                 { 'path': '/repos/A/D', 'status': 401, },
756                 { 'path': '/repos/A/D/', 'status': 401, },
757                 { 'path': '/repos/A/D/gamma', 'status': 401, },
758                 { 'path': '/repos/A/D/H', 'status': 401, },
759                 { 'path': '/repos/A/D/H/', 'status': 401, },
760                 { 'path': '/repos/A/D/H/chi', 'status': 401, },
761                 # auth is configured and user1 is allowed access repo including H
762                 { 'path': '', 'status': 301, 'user': user1, 'pw': user1_pass},
763                 { 'path': '/', 'status': 200, 'user': user1, 'pw': user1_pass},
764                 { 'path': '/repos', 'status': 301, 'user': user1, 'pw': user1_pass},
765                 { 'path': '/repos/', 'status': 200, 'user': user1, 'pw': user1_pass},
766                 { 'path': '/repos/A', 'status': 301, 'user': user1, 'pw': user1_pass},
767                 { 'path': '/repos/A/', 'status': 200, 'user': user1, 'pw': user1_pass},
768                 { 'path': '/repos/A/D', 'status': 301, 'user': user1, 'pw': user1_pass},
769                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_H,
770                   'user': user1, 'pw': user1_pass},
771                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user1, 'pw': user1_pass},
772                 { 'path': '/repos/A/D/H', 'status': 301, 'user': user1, 'pw': user1_pass},
773                 { 'path': '/repos/A/D/H/', 'status': 200, 'body': ls_of_H, 'user': user1, 'pw': user1_pass},
774                 { 'path': '/repos/A/D/H/chi', 'status': 200, 'user': user1, 'pw': user1_pass},
775                 # try with the wrong password for user1
776                 { 'path': '', 'status': 401, 'user': user1, 'pw': user1_badpass},
777                 { 'path': '/', 'status': 401, 'user': user1, 'pw': user1_badpass},
778                 { 'path': '/repos', 'status': 401, 'user': user1, 'pw': user1_badpass},
779                 { 'path': '/repos/', 'status': 401, 'user': user1, 'pw': user1_badpass},
780                 { 'path': '/repos/A', 'status': 401, 'user': user1, 'pw': user1_badpass},
781                 { 'path': '/repos/A/', 'status': 401, 'user': user1, 'pw': user1_badpass},
782                 { 'path': '/repos/A/D', 'status': 401, 'user': user1, 'pw': user1_badpass},
783                 { 'path': '/repos/A/D/', 'status': 401, 'user': user1, 'pw': user1_badpass},
784                 { 'path': '/repos/A/D/gamma', 'status': 401, 'user': user1, 'pw': user1_badpass},
785                 { 'path': '/repos/A/D/H', 'status': 401, 'user': user1, 'pw': user1_badpass},
786                 { 'path': '/repos/A/D/H/', 'status': 401, 'user': user1, 'pw': user1_badpass},
787                 { 'path': '/repos/A/D/H/chi', 'status': 401, 'user': user1, 'pw': user1_badpass},
788                 # auth is configured and user2 is not allowed access to H
789                 { 'path': '', 'status': 301, 'user': user2, 'pw': user2_pass},
790                 { 'path': '/', 'status': 200, 'user': user2, 'pw': user2_pass},
791                 { 'path': '/repos', 'status': 301, 'user': user2, 'pw': user2_pass},
792                 { 'path': '/repos/', 'status': 200, 'user': user2, 'pw': user2_pass},
793                 { 'path': '/repos/A', 'status': 301, 'user': user2, 'pw': user2_pass},
794                 { 'path': '/repos/A/', 'status': 200, 'user': user2, 'pw': user2_pass},
795                 { 'path': '/repos/A/D', 'status': 301, 'user': user2, 'pw': user2_pass},
796                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_no_H,
797                   'user': user2, 'pw': user2_pass},
798                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user2, 'pw': user2_pass},
799                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user2, 'pw': user2_pass},
800                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user2, 'pw': user2_pass},
801                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user2, 'pw': user2_pass},
802                 # try with the wrong password for user2
803                 { 'path': '', 'status': 401, 'user': user2, 'pw': user2_badpass},
804                 { 'path': '/', 'status': 401, 'user': user2, 'pw': user2_badpass},
805                 { 'path': '/repos', 'status': 401, 'user': user2, 'pw': user2_badpass},
806                 { 'path': '/repos/', 'status': 401, 'user': user2, 'pw': user2_badpass},
807                 { 'path': '/repos/A', 'status': 401, 'user': user2, 'pw': user2_badpass},
808                 { 'path': '/repos/A/', 'status': 401, 'user': user2, 'pw': user2_badpass},
809                 { 'path': '/repos/A/D', 'status': 401, 'user': user2, 'pw': user2_badpass},
810                 { 'path': '/repos/A/D/', 'status': 401, 'user': user2, 'pw': user2_badpass},
811                 { 'path': '/repos/A/D/gamma', 'status': 401, 'user': user2, 'pw': user2_badpass},
812                 { 'path': '/repos/A/D/H', 'status': 401, 'user': user2, 'pw': user2_badpass},
813                 { 'path': '/repos/A/D/H/', 'status': 401, 'user': user2, 'pw': user2_badpass},
814                 { 'path': '/repos/A/D/H/chi', 'status': 401, 'user': user2, 'pw': user2_badpass},
815                 # anon is allowed with the ALLOW header
816                 { 'path': '', 'status': 301, 'headers': allow_header },
817                 { 'path': '/', 'status': 200, 'headers': allow_header },
818                 { 'path': '/repos', 'status': 301, 'headers': allow_header },
819                 { 'path': '/repos/', 'status': 200, 'headers': allow_header },
820                 { 'path': '/repos/A', 'status': 301, 'headers': allow_header },
821                 { 'path': '/repos/A/', 'status': 200, 'headers': allow_header },
822                 { 'path': '/repos/A/D', 'status': 301, 'headers': allow_header },
823                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_no_H, 'headers': allow_header },
824                 { 'path': '/repos/A/D/gamma', 'status': 200, 'headers': allow_header },
825                 # these 3 tests return 403 instead of 401 becasue the config allows
826                 # the anon user with the ALLOW header without any auth and the old hook
827                 # system has no way of knowing it should return 401 since authentication is
828                 # configured and can change the behavior.  It could decide to return 401 just on
829                 # the basis of authentication being configured but then that leaks info in other
830                 # cases so it's better for this case to be "broken".
831                 { 'path': '/repos/A/D/H', 'status': 403, 'headers': allow_header },
832                 { 'path': '/repos/A/D/H/', 'status': 403, 'headers': allow_header },
833                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'headers': allow_header },
834                 # auth is configured and user1 is allowed access repo including H
835                 { 'path': '', 'status': 301, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
836                 { 'path': '/', 'status': 200, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
837                 { 'path': '/repos', 'status': 301, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
838                 { 'path': '/repos/', 'status': 200, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
839                 { 'path': '/repos/A', 'status': 301, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
840                 { 'path': '/repos/A/', 'status': 200, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
841                 { 'path': '/repos/A/D', 'status': 301, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
842                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_H,
843                   'user': user1, 'pw': user1_pass, 'headers': allow_header },
844                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
845                 { 'path': '/repos/A/D/H', 'status': 301, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
846                 { 'path': '/repos/A/D/H/', 'status': 200, 'body': ls_of_H, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
847                 { 'path': '/repos/A/D/H/chi', 'status': 200, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
848                 # try with the wrong password for user1
849                 { 'path': '', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
850                 { 'path': '/', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
851                 { 'path': '/repos', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
852                 { 'path': '/repos/', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
853                 { 'path': '/repos/A', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
854                 { 'path': '/repos/A/', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
855                 { 'path': '/repos/A/D', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
856                 { 'path': '/repos/A/D/', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
857                 { 'path': '/repos/A/D/gamma', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
858                 { 'path': '/repos/A/D/H', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
859                 { 'path': '/repos/A/D/H/', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
860                 { 'path': '/repos/A/D/H/chi', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
861                 # auth is configured and user2 is not allowed access to H
862                 { 'path': '', 'status': 301, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
863                 { 'path': '/', 'status': 200, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
864                 { 'path': '/repos', 'status': 301, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
865                 { 'path': '/repos/', 'status': 200, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
866                 { 'path': '/repos/A', 'status': 301, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
867                 { 'path': '/repos/A/', 'status': 200, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
868                 { 'path': '/repos/A/D', 'status': 301, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
869                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_no_H,
870                   'user': user2, 'pw': user2_pass, 'headers': allow_header },
871                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
872                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
873                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
874                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
875                 # try with the wrong password for user2
876                 { 'path': '', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
877                 { 'path': '/', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
878                 { 'path': '/repos', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
879                 { 'path': '/repos/', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
880                 { 'path': '/repos/A', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
881                 { 'path': '/repos/A/', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
882                 { 'path': '/repos/A/D', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
883                 { 'path': '/repos/A/D/', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
884                 { 'path': '/repos/A/D/gamma', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
885                 { 'path': '/repos/A/D/H', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
886                 { 'path': '/repos/A/D/H/', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
887                 { 'path': '/repos/A/D/H/chi', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
888
889                 )
890
891  verify_gets(test_area_url, sallrany_tests)
892
893# See comments on authn_sallrany test for some background on the interaction
894# of Satisfy Any and the newer Require blocks.
895@SkipUnless(svntest.main.is_httpd_authz_provider_enabled)
896def authn_sallrall(sbox):
897  "test satisfy all require all config"
898  sbox.build(read_only = True, create_wc = False)
899
900  test_area_url = sbox.repo_url.replace('/svn-test-work/local_tmp/repos',
901                                        '/authz-test-work/sallrall')
902
903  write_authz_file(sbox)
904
905  allow_header = { 'ALLOW': '1' }
906
907  sallrall_tests = (
908                 #anon access isn't allowed without ALLOW header
909                 { 'path': '', 'status': 403, },
910                 { 'path': '/', 'status': 403, },
911                 { 'path': '/repos', 'status': 403, },
912                 { 'path': '/repos/', 'status': 403, },
913                 { 'path': '/repos/A', 'status': 403, },
914                 { 'path': '/repos/A/', 'status': 403, },
915                 { 'path': '/repos/A/D', 'status': 403, },
916                 { 'path': '/repos/A/D/', 'status': 403, },
917                 { 'path': '/repos/A/D/gamma', 'status': 403, },
918                 { 'path': '/repos/A/D/H', 'status': 403, },
919                 { 'path': '/repos/A/D/H/', 'status': 403, },
920                 { 'path': '/repos/A/D/H/chi', 'status': 403, },
921                 # auth is configured but no access is allowed without the ALLOW header
922                 { 'path': '', 'status': 403, 'user': user1, 'pw': user1_pass},
923                 { 'path': '/', 'status': 403, 'user': user1, 'pw': user1_pass},
924                 { 'path': '/repos', 'status': 403, 'user': user1, 'pw': user1_pass},
925                 { 'path': '/repos/', 'status': 403, 'user': user1, 'pw': user1_pass},
926                 { 'path': '/repos/A', 'status': 403, 'user': user1, 'pw': user1_pass},
927                 { 'path': '/repos/A/', 'status': 403, 'user': user1, 'pw': user1_pass},
928                 { 'path': '/repos/A/D', 'status': 403, 'user': user1, 'pw': user1_pass},
929                 { 'path': '/repos/A/D/', 'status': 403, 'user': user1, 'pw': user1_pass},
930                 { 'path': '/repos/A/D/gamma', 'status': 403, 'user': user1, 'pw': user1_pass},
931                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user1, 'pw': user1_pass},
932                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user1, 'pw': user1_pass},
933                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user1, 'pw': user1_pass},
934                 # try with the wrong password for user1
935                 { 'path': '', 'status': 403, 'user': user1, 'pw': user1_badpass},
936                 { 'path': '/', 'status': 403, 'user': user1, 'pw': user1_badpass},
937                 { 'path': '/repos', 'status': 403, 'user': user1, 'pw': user1_badpass},
938                 { 'path': '/repos/', 'status': 403, 'user': user1, 'pw': user1_badpass},
939                 { 'path': '/repos/A', 'status': 403, 'user': user1, 'pw': user1_badpass},
940                 { 'path': '/repos/A/', 'status': 403, 'user': user1, 'pw': user1_badpass},
941                 { 'path': '/repos/A/D', 'status': 403, 'user': user1, 'pw': user1_badpass},
942                 { 'path': '/repos/A/D/', 'status': 403, 'user': user1, 'pw': user1_badpass},
943                 { 'path': '/repos/A/D/gamma', 'status': 403, 'user': user1, 'pw': user1_badpass},
944                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user1, 'pw': user1_badpass},
945                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user1, 'pw': user1_badpass},
946                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user1, 'pw': user1_badpass},
947                 # auth is configured but no access is allowed without the ALLOW header
948                 { 'path': '', 'status': 403, 'user': user2, 'pw': user2_pass},
949                 { 'path': '/', 'status': 403, 'user': user2, 'pw': user2_pass},
950                 { 'path': '/repos', 'status': 403, 'user': user2, 'pw': user2_pass},
951                 { 'path': '/repos/', 'status': 403, 'user': user2, 'pw': user2_pass},
952                 { 'path': '/repos/A', 'status': 403, 'user': user2, 'pw': user2_pass},
953                 { 'path': '/repos/A/', 'status': 403, 'user': user2, 'pw': user2_pass},
954                 { 'path': '/repos/A/D', 'status': 403, 'user': user2, 'pw': user2_pass},
955                 { 'path': '/repos/A/D/', 'status': 403, 'user': user2, 'pw': user2_pass},
956                 { 'path': '/repos/A/D/gamma', 'status': 403, 'user': user2, 'pw': user2_pass},
957                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user2, 'pw': user2_pass},
958                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user2, 'pw': user2_pass},
959                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user2, 'pw': user2_pass},
960                 # try with the wrong password for user2
961                 { 'path': '', 'status': 403, 'user': user2, 'pw': user2_badpass},
962                 { 'path': '/', 'status': 403, 'user': user2, 'pw': user2_badpass},
963                 { 'path': '/repos', 'status': 403, 'user': user2, 'pw': user2_badpass},
964                 { 'path': '/repos/', 'status': 403, 'user': user2, 'pw': user2_badpass},
965                 { 'path': '/repos/A', 'status': 403, 'user': user2, 'pw': user2_badpass},
966                 { 'path': '/repos/A/', 'status': 403, 'user': user2, 'pw': user2_badpass},
967                 { 'path': '/repos/A/D', 'status': 403, 'user': user2, 'pw': user2_badpass},
968                 { 'path': '/repos/A/D/', 'status': 403, 'user': user2, 'pw': user2_badpass},
969                 { 'path': '/repos/A/D/gamma', 'status': 403, 'user': user2, 'pw': user2_badpass},
970                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user2, 'pw': user2_badpass},
971                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user2, 'pw': user2_badpass},
972                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user2, 'pw': user2_badpass},
973                 # anon is not allowed even with ALLOW header
974                 { 'path': '', 'status': 401, 'headers': allow_header },
975                 { 'path': '/', 'status': 401, 'headers': allow_header },
976                 { 'path': '/repos', 'status': 401, 'headers': allow_header },
977                 { 'path': '/repos/', 'status': 401, 'headers': allow_header },
978                 { 'path': '/repos/A', 'status': 401, 'headers': allow_header },
979                 { 'path': '/repos/A/', 'status': 401, 'headers': allow_header },
980                 { 'path': '/repos/A/D', 'status': 401, 'headers': allow_header },
981                 { 'path': '/repos/A/D/', 'status': 401, 'headers': allow_header },
982                 { 'path': '/repos/A/D/gamma', 'status': 401, 'headers': allow_header },
983                 { 'path': '/repos/A/D/H', 'status': 401, 'headers': allow_header },
984                 { 'path': '/repos/A/D/H/', 'status': 401, 'headers': allow_header },
985                 { 'path': '/repos/A/D/H/chi', 'status': 401, 'headers': allow_header },
986                 # auth is configured and user1 is allowed access repo including H
987                 { 'path': '', 'status': 301, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
988                 { 'path': '/', 'status': 200, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
989                 { 'path': '/repos', 'status': 301, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
990                 { 'path': '/repos/', 'status': 200, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
991                 { 'path': '/repos/A', 'status': 301, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
992                 { 'path': '/repos/A/', 'status': 200, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
993                 { 'path': '/repos/A/D', 'status': 301, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
994                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_H,
995                   'user': user1, 'pw': user1_pass, 'headers': allow_header },
996                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
997                 { 'path': '/repos/A/D/H', 'status': 301, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
998                 { 'path': '/repos/A/D/H/', 'status': 200, 'body': ls_of_H, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
999                 { 'path': '/repos/A/D/H/chi', 'status': 200, 'user': user1, 'pw': user1_pass, 'headers': allow_header },
1000                 # try with the wrong password for user1
1001                 { 'path': '', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
1002                 { 'path': '/', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
1003                 { 'path': '/repos', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
1004                 { 'path': '/repos/', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
1005                 { 'path': '/repos/A', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
1006                 { 'path': '/repos/A/', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
1007                 { 'path': '/repos/A/D', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
1008                 { 'path': '/repos/A/D/', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
1009                 { 'path': '/repos/A/D/gamma', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
1010                 { 'path': '/repos/A/D/H', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
1011                 { 'path': '/repos/A/D/H/', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
1012                 { 'path': '/repos/A/D/H/chi', 'status': 401, 'user': user1, 'pw': user1_badpass, 'headers': allow_header },
1013                 # auth is configured and user2 is not allowed access to H
1014                 { 'path': '', 'status': 301, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
1015                 { 'path': '/', 'status': 200, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
1016                 { 'path': '/repos', 'status': 301, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
1017                 { 'path': '/repos/', 'status': 200, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
1018                 { 'path': '/repos/A', 'status': 301, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
1019                 { 'path': '/repos/A/', 'status': 200, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
1020                 { 'path': '/repos/A/D', 'status': 301, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
1021                 { 'path': '/repos/A/D/', 'status': 200, 'body': ls_of_D_no_H,
1022                   'user': user2, 'pw': user2_pass, 'headers': allow_header },
1023                 { 'path': '/repos/A/D/gamma', 'status': 200, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
1024                 { 'path': '/repos/A/D/H', 'status': 403, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
1025                 { 'path': '/repos/A/D/H/', 'status': 403, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
1026                 { 'path': '/repos/A/D/H/chi', 'status': 403, 'user': user2, 'pw': user2_pass, 'headers': allow_header },
1027                 # try with the wrong password for user2
1028                 { 'path': '', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
1029                 { 'path': '/', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
1030                 { 'path': '/repos', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
1031                 { 'path': '/repos/', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
1032                 { 'path': '/repos/A', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
1033                 { 'path': '/repos/A/', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
1034                 { 'path': '/repos/A/D', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
1035                 { 'path': '/repos/A/D/', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
1036                 { 'path': '/repos/A/D/gamma', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
1037                 { 'path': '/repos/A/D/H', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
1038                 { 'path': '/repos/A/D/H/', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
1039                 { 'path': '/repos/A/D/H/chi', 'status': 401, 'user': user2, 'pw': user2_badpass, 'headers': allow_header },
1040
1041                 )
1042
1043  verify_gets(test_area_url, sallrall_tests)
1044
1045
1046########################################################################
1047# Run the tests
1048
1049
1050# list all tests here, starting with None:
1051test_list = [ None,
1052              anon,
1053              mixed,
1054              mixed_noauthwhenanon,
1055              authn,
1056              authn_anonoff,
1057              authn_lcuser,
1058              authn_group,
1059              authn_sallrany,
1060              authn_sallrall,
1061             ]
1062serial_only = True
1063
1064if __name__ == '__main__':
1065  svntest.main.run_tests(test_list)
1066  # NOTREACHED
1067
1068
1069### End of file.
1070