PageRenderTime 41ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/src/test.py

https://bitbucket.org/lukeivers/cwdapache
Python | 314 lines | 304 code | 8 blank | 2 comment | 20 complexity | f34df53b69cfc09f8324552b67616ce0 MD5 | raw file
  1. #! /usr/bin/env python
  2. import BaseHTTPServer
  3. import cookielib
  4. import errno
  5. import os
  6. import urllib2
  7. import subprocess
  8. import threading
  9. import time
  10. httpd = None
  11. base_url = 'http://httpd.atlassian.test:8080'
  12. def assert_exits(process):
  13. timeout = 5
  14. while process.poll() is None:
  15. assert timeout > 0
  16. timeout -= 1
  17. time.sleep(1)
  18. def http_get(username, password, relative_url = '/', cookie_jar = None, forwarded_for = None):
  19. url = base_url + relative_url
  20. if username is None:
  21. auth_handler = None
  22. else:
  23. auth_handler = urllib2.HTTPBasicAuthHandler()
  24. auth_handler.add_password('test', url, username, password)
  25. if cookie_jar is None:
  26. opener = urllib2.build_opener(auth_handler)
  27. else:
  28. if auth_handler is None:
  29. opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie_jar))
  30. else:
  31. opener = urllib2.build_opener(auth_handler, urllib2.HTTPCookieProcessor(cookie_jar))
  32. if forwarded_for is None:
  33. opener.open(url)
  34. else:
  35. opener.open(urllib2.Request(url, headers = {'X-Forwarded-For': forwarded_for}))
  36. def start_httpd(config_file = 'conf/httpd.conf'):
  37. global httpd
  38. httpd = subprocess.Popen([apache_bin_dir + '/httpd', '-X', '-d', 'httpd', '-e', 'debug', '-f', config_file], stdout = subprocess.PIPE)
  39. def terminate_httpd():
  40. httpd.kill()
  41. httpd.wait()
  42. def wait_for_httpd_startup(expect_authentication = True):
  43. # Test that authentication is required. Repeat until the server starts.
  44. timeout = 5
  45. while True:
  46. try:
  47. urllib2.urlopen(base_url + '/')
  48. assert not expect_authentication, 'Authentication was not requested.'
  49. break
  50. except urllib2.HTTPError as exception:
  51. assert expect_authentication and exception.code == 401, exception.code
  52. break
  53. except urllib2.URLError as exception:
  54. assert timeout > 0
  55. timeout -= 1
  56. time.sleep(1)
  57. continue
  58. def start_mock_crowd(request_handler):
  59. mock_crowd = BaseHTTPServer.HTTPServer(('', 8096), request_handler)
  60. threading.Thread(target = mock_crowd.serve_forever).start()
  61. return mock_crowd
  62. def svn_command(user, password, command):
  63. command_line = ['svn', '--non-interactive', '--no-auth-cache']
  64. if not user is None:
  65. command_line += ['--username', user, '--password', password]
  66. command_line += command
  67. return subprocess.call(command_line) == 0
  68. def svn_can_read(user = None, password = None, path=''):
  69. return svn_command(user, password, ['ls', base_url + path + '/'])
  70. def svn_can_write(user = None, password = None, path = ''):
  71. if svn_command(user, password, ['mkdir', '-m', '', base_url + path + '/newdir']):
  72. svn_command(user, password, ['rm', '-m', '', base_url + path + '/newdir'])
  73. return True
  74. return False
  75. apache_bin_dir = os.environ['APACHE_BIN_DIR']
  76. print apache_bin_dir
  77. # Install mod_authnz_crowd module.
  78. subprocess.check_call([apache_bin_dir + '/apxs', '-S', 'LIBEXECDIR=' + os.getcwd() + '/httpd/modules', '-i', 'mod_authnz_crowd.la', 'svn/mod_authz_svn_crowd.la'])
  79. # Start httpd with missing configuration parameter.
  80. start_httpd('conf/httpd_missing.conf')
  81. assert_exits(httpd)
  82. # Start httpd with duplicated configuration parameter.
  83. start_httpd('conf/httpd_duplicate.conf')
  84. assert_exits(httpd)
  85. # Start httpd with valid configuration.
  86. start_httpd()
  87. try:
  88. wait_for_httpd_startup()
  89. # Test that authentication succeeds with valid credentials.
  90. http_get('httpd_test', 'httpd_password')
  91. # Test that authentication succeeds with valid credentials containing XML entity.
  92. http_get('httpd_>', 'httpd_>')
  93. # Test that authentication succeeds with valid credentials containing <.
  94. http_get('httpd_<', 'httpd_<')
  95. # Test that authentication succeeds with valid credentials containing reserved URL characters.
  96. http_get('httpd_;?@=&', 'httpd_;?@=&')
  97. # Test that authentication succeeds with valid credentials containing CDATA terminators.
  98. http_get('httpd_<![CDATA[]]>', 'httpd_<![CDATA[]]>')
  99. # Test that authentication succeeds with valid credentials with UTF-8 encoding.
  100. http_get('httpd_\xc3\xa5\xc3\xa9\xc3\xae\xc3\xb8\xc3\xbc', 'httpd_\xc3\xa5\xc3\xa9\xc3\xae\xc3\xb8\xc3\xbc')
  101. # Test that authentication succeeds with valid credentials with ISO-8859-1 encoding.
  102. http_get('httpd_\xe5\xe9\xee\xf8\xfc', 'httpd_\xe5\xe9\xee\xf8\xfc')
  103. # Test that authentication fails with incorrect password.
  104. try:
  105. http_get('httpd_test', 'incorrect')
  106. assert False, 'Authentication succeeded with incorrect password.'
  107. except urllib2.URLError as exception:
  108. assert exception.code == 401, exception.code
  109. # Test that authentication fails with unknown username.
  110. try:
  111. http_get('httpd_iamnobody', 'incorrect')
  112. assert False, 'Authentication succeeded with unknown user.'
  113. except urllib2.URLError as exception:
  114. assert exception.code == 401, exception.code
  115. # Test that authorisation is granted with specific user requirement.
  116. http_get('httpd_superuser', 'httpd_superuser', relative_url = '/superuser_only/')
  117. # Test that authorisation is denied due to specific user requirement.
  118. try:
  119. http_get('httpd_test', 'httpd_password', relative_url = '/superuser_only/')
  120. assert False, 'Authorisation granted to incorrect user.'
  121. except urllib2.URLError as exception:
  122. assert exception.code == 401, exception.code
  123. # Test that authorisation is granted with specific group requirement.
  124. http_get('httpd_supergroupmember', 'httpd_supergroupmember', relative_url = '/supergroup_only/')
  125. # Test that authorisation is granted with specific group requirement, based on a nested group.
  126. http_get('httpd_nestedgroupmember', 'httpd_nestedgroupmember', relative_url = '/supergroup_only/')
  127. # Test that authorisation is denied due to specific group requirement.
  128. try:
  129. http_get('httpd_test', 'httpd_password', relative_url = '/supergroup_only/')
  130. assert False, 'Authorisation granted to non-member of group.'
  131. except urllib2.URLError as exception:
  132. assert exception.code == 401, exception.code
  133. # Test SSO
  134. cookie_jar = cookielib.CookieJar()
  135. http_get('httpd_test', 'httpd_password', cookie_jar = cookie_jar)
  136. http_get(None, None, cookie_jar = cookie_jar)
  137. # Test SSO via proxy
  138. cookie_jar = cookielib.CookieJar()
  139. http_get('httpd_test', 'httpd_password', cookie_jar = cookie_jar, forwarded_for = '10.0.1.1')
  140. http_get(None, None, cookie_jar = cookie_jar, forwarded_for = '10.0.1.1')
  141. try:
  142. http_get(None, None, cookie_jar = cookie_jar, forwarded_for = '10.0.1.2')
  143. assert False, 'Authentication succeeded when forwarded for different client.'
  144. except urllib2.URLError as exception:
  145. assert exception.code == 401, exception.code
  146. # Test behaviour when Crowd is not running.
  147. terminate_httpd()
  148. httpd = subprocess.Popen([apache_bin_dir + '/httpd', '-X', '-d', 'httpd', '-e', 'debug', '-f', 'conf/httpd_mock_crowd.conf'])
  149. wait_for_httpd_startup()
  150. try:
  151. http_get('httpd_test', 'httpd_password')
  152. assert False, 'Authentication succeeded with Crowd not running.'
  153. except urllib2.URLError as exception:
  154. assert exception.code == 500, exception.code
  155. # Test behaviour when response from Crowd is not valid HTTP.
  156. class MockCrowd_invalidHTTP(BaseHTTPServer.BaseHTTPRequestHandler):
  157. def do_POST(self):
  158. self.wfile.write('This is not valid HTTP\r\n\r\n')
  159. self.wfile.close()
  160. mock_crowd = start_mock_crowd(MockCrowd_invalidHTTP)
  161. try:
  162. http_get('httpd_test', 'httpd_password')
  163. assert False, 'Authentication succeeded with non-HTTP response.'
  164. except urllib2.URLError as exception:
  165. assert exception.code == 500, exception.code
  166. finally:
  167. mock_crowd.shutdown()
  168. mock_crowd.socket.close()
  169. # Test behaviour when response from Crowd has a body that is not valid XML.
  170. class MockCrowd_invalidXML(BaseHTTPServer.BaseHTTPRequestHandler):
  171. def do_POST(self):
  172. self.wfile.write('HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 18\r\n\r\nThis is not XML.\r\n')
  173. self.wfile.close()
  174. mock_crowd = start_mock_crowd(MockCrowd_invalidXML)
  175. try:
  176. http_get('httpd_test', 'httpd_password')
  177. assert False, 'Authentication succeeded with non-XML response.'
  178. except urllib2.URLError as exception:
  179. assert exception.code == 500, exception.code
  180. finally:
  181. mock_crowd.shutdown()
  182. mock_crowd.socket.close()
  183. # Test behaviour when response from Crowd is not received within timeout.
  184. class MockCrowd_timeout(BaseHTTPServer.BaseHTTPRequestHandler):
  185. def do_POST(self):
  186. time.sleep(4)
  187. self.wfile.write('HTTP/1.0 200 OK\r\nContent-Type: application/xml\r\nContent-Length: 9\r\n\r\n<user/>\r\n')
  188. self.wfile.close()
  189. mock_crowd = start_mock_crowd(MockCrowd_timeout)
  190. try:
  191. http_get('httpd_test', 'httpd_password')
  192. assert False, 'Authentication succeeded after timeout expired.'
  193. except urllib2.URLError as exception:
  194. assert exception.code == 500, exception.code
  195. finally:
  196. mock_crowd.shutdown()
  197. mock_crowd.socket.close()
  198. # Test behaviour when a large response is received from Crowd.
  199. class MockCrowd_largeResponse(BaseHTTPServer.BaseHTTPRequestHandler):
  200. def do_POST(self):
  201. self.wfile.write('HTTP/1.0 200 OK\r\nContent-Type: application/xml\r\nContent-Length: 9\r\n\r\n<user/>\r\n')
  202. self.wfile.close()
  203. def do_GET(self):
  204. self.wfile.write('HTTP/1.1 200 OK\r\nServer: Apache-Coyote/1.1\r\nX-Embedded-Crowd-Version: 2.1.0\r\nSet-Cookie: JSESSIONID=E04DBF0AEAE4AE218D7B4C700841618B; Path=/crowd\r\nContent-Type: application/xml\r\nContent-Length: 546\r\nDate: Mon, 13 Dec 2010 02:57:21 GMT\r\n\r\n<?xml version="1.0" encoding="UTF-8" standalone="yes"?><groups expand="group"><group name="bamboo-user"><link rel="self" href="http://localhost:8011/crowd/rest/usermanagement/1/group?groupname=bamboo-user"/></group><group name="mauswerks-web-developer"><link rel="self" href="http://localhost:8011/crowd/rest/usermanagement/1/group?groupname=mauswerks-web-developer"/></group><group name="tweetmech-web-developer"><link rel="self" href="http://localhost:8011/crowd/rest/usermanagement/1/group?groupname=tweetmech-web-developer"/></group></groups>')
  205. self.wfile.close()
  206. mock_crowd = start_mock_crowd(MockCrowd_largeResponse)
  207. try:
  208. http_get('httpd_test', 'httpd_password')
  209. finally:
  210. mock_crowd.shutdown()
  211. mock_crowd.socket.close()
  212. finally:
  213. terminate_httpd()
  214. # Start httpd with valid Subversion configuration.
  215. start_httpd('conf/httpd_svn.conf')
  216. try:
  217. wait_for_httpd_startup(expect_authentication = False)
  218. # Test that anonymous user can read but not write root.
  219. assert svn_can_read()
  220. assert not svn_can_write()
  221. # Test that permitted users can read and write root, when the correct password is supplied.
  222. assert svn_can_read('svn_superuser', 'svn_superuser')
  223. assert svn_can_write('svn_superuser', 'svn_superuser')
  224. assert not svn_can_write('svn_superuser', 'wrong')
  225. assert svn_can_read('svn_developer', 'svn_developer')
  226. assert svn_can_write('svn_developer', 'svn_developer')
  227. assert not svn_can_write('svn_developer', 'wrong')
  228. assert svn_can_read('svn_user', 'svn_user')
  229. assert not svn_can_write('svn_user', 'svn_user')
  230. assert not svn_can_write('svn_user', 'wrong')
  231. # Test a directory without anonymous access.
  232. assert not svn_can_read(path = '/developers_only')
  233. assert not svn_can_write(path = '/developers_only')
  234. assert svn_can_read('svn_superuser', 'svn_superuser', '/developers_only')
  235. assert not svn_can_read('svn_superuser', 'wrong', '/developers_only')
  236. assert svn_can_write('svn_superuser', 'svn_superuser', '/developers_only')
  237. assert not svn_can_write('svn_superuser', 'wrong', '/developers_only')
  238. assert svn_can_read('svn_developer', 'svn_developer', '/developers_only')
  239. assert not svn_can_read('svn_developer', 'wrong', '/developers_only')
  240. assert svn_can_write('svn_developer', 'svn_developer', '/developers_only')
  241. assert not svn_can_write('svn_developer', 'wrong', '/developers_only')
  242. assert not svn_can_read('svn_user', 'svn_user', '/developers_only')
  243. assert not svn_can_read('svn_user', 'wrong', '/developers_only')
  244. assert not svn_can_write('svn_user', 'svn_user', '/developers_only')
  245. assert not svn_can_write('svn_user', 'wrong', '/developers_only')
  246. # Test a directory with anonymous write access.
  247. assert svn_can_read(path = '/public_sandbox')
  248. assert svn_can_write(path = '/public_sandbox')
  249. assert svn_can_read('svn_user', 'svn_user', '/public_sandbox')
  250. assert svn_can_write('svn_user', 'svn_user', '/public_sandbox')
  251. # Test a directory with read-only access.
  252. assert svn_can_read(path = '/read_only')
  253. assert not svn_can_write(path = '/read_only')
  254. assert svn_can_read('svn_superuser', 'svn_superuser', '/read_only')
  255. assert not svn_can_write('svn_superuser', 'svn_superuser', '/read_only')
  256. assert not svn_can_write('svn_superuser', 'wrong', '/read_only')
  257. assert svn_can_read('svn_developer', 'svn_developer', '/read_only')
  258. assert not svn_can_write('svn_developer', 'svn_developer', '/read_only')
  259. assert not svn_can_write('svn_developer', 'wrong', '/read_only')
  260. assert svn_can_read('svn_user', 'svn_user', '/read_only')
  261. assert not svn_can_write('svn_user', 'svn_user', '/read_only')
  262. assert not svn_can_write('svn_user', 'wrong', '/read_only')
  263. finally:
  264. terminate_httpd()