Esempio n. 1
0
 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)
Esempio n. 2
0
 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)
Esempio n. 3
0
 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)
Esempio n. 4
0
 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)
Esempio n. 5
0
 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"'])
Esempio n. 6
0
 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"'])
Esempio n. 7
0
 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)
Esempio n. 8
0
 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'])
Esempio n. 9
0
    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