def test_getChildWithDefault(self): """ An L{UnauthorizedResource} is every child of itself. """ resource = UnauthorizedResource([]) self.assertIdentical(resource.getChildWithDefault("foo", None), resource) self.assertIdentical(resource.getChildWithDefault("bar", None), resource)
def test_getChildWithDefault(self): """ An L{UnauthorizedResource} is every child of itself. """ resource = UnauthorizedResource([]) self.assertIdentical( resource.getChildWithDefault("foo", None), resource) self.assertIdentical( resource.getChildWithDefault("bar", None), resource)
def _loginFailed(self, result): if result.check(error.Unauthorized, error.LoginFailed): return UnauthorizedResource(self._credentialFactories) else: log.err( result, "HTTPAuthSessionWrapper.getChildWithDefault encountered " "unexpected error") return ErrorPage(500, None, None)
def test_renderQuotesDigest(self): """ The digest value must be correctly quoted. It is a byte string in python3, so we must make sure the proper conversion is done """ resource = UnauthorizedResource([ digest.DigestCredentialFactory(b'md5', b'example\\"foo')]) request = DummyRequest([b'']) request.render(resource) auth_header = request.responseHeaders.getRawHeaders(b'www-authenticate')[0] self.assertIn(b'realm="example\\\\\\"foo"', auth_header) self.assertIn(b'hm="md5', auth_header)
def test_renderQuotesRealm(self): """ The realm value included in the I{WWW-Authenticate} header set in the response when L{UnauthorizedResounrce} is rendered has quotes and backslashes escaped. """ resource = UnauthorizedResource( [BasicCredentialFactory('example\\"foo')]) request = self.makeRequest() request.render(resource) self.assertEqual( request.responseHeaders.getRawHeaders(b'www-authenticate'), [b'basic realm="example\\\\\\"foo"'])
def _unauthorizedRenderTest(self, request): """ Render L{UnauthorizedResource} for the given request object and verify that the response code is I{Unauthorized} and that a I{WWW-Authenticate} header is set in the response containing a challenge. """ resource = UnauthorizedResource( [BasicCredentialFactory('example.com')]) request.render(resource) self.assertEqual(request.responseCode, 401) self.assertEqual( request.responseHeaders.getRawHeaders(b'www-authenticate'), [b'basic realm="example.com"'])
def test_renderQuotesDigest(self): """ The digest value included in the I{WWW-Authenticate} header set in the response when L{UnauthorizedResource} is rendered has quotes and backslashes escaped. """ resource = UnauthorizedResource( [digest.DigestCredentialFactory(b'md5', b'example\\"foo')]) request = self.makeRequest() request.render(resource) authHeader = request.responseHeaders.getRawHeaders( b'www-authenticate')[0] self.assertIn(b'realm="example\\\\\\"foo"', authHeader) self.assertIn(b'hm="md5', authHeader)
def test_render(self): """ L{UnauthorizedResource} renders with a 401 response code and a I{WWW-Authenticate} header and puts a simple unauthorized message into the response body. """ resource = UnauthorizedResource([ BasicCredentialFactory('example.com')]) request = DummyRequest(['']) render(resource, request) self.assertEqual(request.responseCode, 401) self.assertEqual( request.responseHeaders.getRawHeaders('www-authenticate'), ['basic realm="example.com"']) self.assertEqual(request.written, ['Unauthorized'])
def getChild(self, path, request): """Find the appropriate child resource depending on request type Possible URLs: - /foo/bar/info/refs -> info refs (file / SmartHTTP hybrid) - /foo/bar/git-upload-pack -> SmartHTTP RPC - /foo/bar/git-receive-pack -> SmartHTTP RPC - /foo/bar/HEAD -> file (dumb http) - /foo/bar/objects/* -> file (dumb http) """ path = request.path # alternatively use path + request.postpath pathparts = path.split('/') writerequired = False script_name = '/' new_path = path resource = NoResource() # Path lookup / translation path_info = self.git_configuration.path_lookup(path, protocol_hint='http') if path_info is None: log.msg('User %s tried to access %s ' 'but the lookup failed' % (self.username, path)) return resource log.msg('Lookup of %s gave %r' % (path, path_info)) if (path_info['repository_fs_path'] is None and path_info['repository_base_fs_path'] is None): log.msg('Neither a repository base nor a repository were returned') return resource # split script_name / new_path according to path info if path_info['repository_base_url_path'] is not None: script_name = '/' script_name += path_info['repository_base_url_path'].strip('/') new_path = path[len(script_name.rstrip('/')):] # since pretty much everything needs read access, check for it now if not self.authnz.can_read(self.username, path_info): if self.username is None: return UnauthorizedResource(self.credentialFactories) else: return ForbiddenResource("You don't have read access") # Smart HTTP requests # /info/refs if (len(pathparts) >= 2 and pathparts[-2] == 'info' and pathparts[-1] == 'refs'): writerequired = ('service' in request.args and request.args['service'][0] == 'git-receive-pack') resource = InfoRefs(path_info['repository_fs_path']) # /git-upload-pack (client pull) elif len(pathparts) >= 1 and pathparts[-1] == 'git-upload-pack': cmd = 'git' args = [ os.path.basename(cmd), 'upload-pack', '--stateless-rpc', path_info['repository_fs_path'] ] resource = GitCommand(cmd, args) request.setHeader('Content-Type', 'application/x-git-upload-pack-result') # /git-receive-pack (client push) elif len(pathparts) >= 1 and pathparts[-1] == 'git-receive-pack': writerequired = True cmd = 'git' args = [ os.path.basename(cmd), 'receive-pack', '--stateless-rpc', path_info['repository_fs_path'] ] resource = GitCommand(cmd, args) request.setHeader('Content-Type', 'application/x-git-receive-pack-result') # static files as specified in file_headers or fallback webfrontend else: # determine the headers for this file filename, headers = None, None for matcher, get_headers in file_headers.items(): m = matcher.match(path) if m: filename = m.group(1) headers = get_headers() break if filename is not None: for key, val in headers.items(): request.setHeader(key, val) log.msg( "Returning file %s" % os.path.join(path_info['repository_fs_path'], filename)) resource = File( os.path.join(path_info['repository_fs_path'], filename), headers['Content-Type']) resource.isLeaf = True # static file -> it is a leaf else: # No match -> fallback to git viewer if script_name is not None: # patch pre/post path of request according to # script_name and path request.prepath = script_name.strip('/').split('/') if request.prepath == ['']: request.prepath = [] request.postpath = new_path.lstrip('/').split('/') log.msg("pre and post: %r %r" % (request.prepath, request.postpath)) # If the resource has a withEnviron function, it's # probably our own flavour of WSGIResource that # supports passing further args for the environ if hasattr(self.git_viewer, "withEnviron"): # set wsgirouting args routing_args = { 'repository_path': path_info['repository_fs_path'], 'repository_base': path_info['repository_base_fs_path'] } if 'repository_clone_urls' in path_info: routing_args['repository_clone_urls'] = path_info[ 'repository_clone_urls'] resource = self.git_viewer.withEnviron( {'wsgiorg.routing_args': ([], routing_args)}) else: resource = self.git_viewer # before returning the resource, check if write access is required # and enforce privileges accordingly # anonymous (username = None) will never be granted write access if writerequired and ( self.username is None or not self.authnz.can_write(self.username, path_info)): if self.username is None: return UnauthorizedResource(self.credentialFactories) else: return ForbiddenResource("You don't have write access") return resource