Add a test, add missing imports. refs #2388
authorDaira Hopwood <daira@jacaranda.org>
Tue, 24 Mar 2015 17:10:00 +0000 (17:10 +0000)
committerDaira Hopwood <daira@jacaranda.org>
Tue, 24 Mar 2015 17:10:00 +0000 (17:10 +0000)
This tests ftpd, but not sftpd. Doing this sort of test on sftpd
requires the creation of a valid pubkey/privkey file pair, which is more
work than I want to do right now.

init_ftp/init_sftp were changed to interpret the configured
accounts.file as relative to the node's basedir, with
abspath_expanduser_unicode(accountfile, base=self.basedir).
This would happen naturally in a real node, since it os.chdir()s
to the basedir before doing anything. But tests don't do that.

Author: Brian Warner <warner@lothar.com>
Author: Daira Hopwood <daira@jacaranda.org>
Signed-off-by: Daira Hopwood <daira@jacaranda.org>
src/allmydata/client.py
src/allmydata/frontends/ftpd.py
src/allmydata/frontends/sftpd.py
src/allmydata/test/test_client.py

index b67c78b039d670399267fbf24f7c6b6a6bc72480..bb6dce23096d4d0af7b89973af4e08394a0a460b 100644 (file)
@@ -15,7 +15,8 @@ from allmydata.immutable.offloaded import Helper
 from allmydata.control import ControlServer
 from allmydata.introducer.client import IntroducerClient
 from allmydata.util import hashutil, base32, pollmixin, log, keyutil, idlib
-from allmydata.util.encodingutil import get_filesystem_encoding
+from allmydata.util.encodingutil import get_filesystem_encoding, \
+     from_utf8_or_none
 from allmydata.util.fileutil import abspath_expanduser_unicode
 from allmydata.util.abbreviate import parse_abbreviated_size
 from allmydata.util.time_format import parse_duration, parse_date
@@ -458,7 +459,10 @@ class Client(node.Node, pollmixin.PollMixin):
 
     def init_ftp_server(self):
         if self.get_config("ftpd", "enabled", False, boolean=True):
-            accountfile = from_utf8_or_none(self.get_config("ftpd", "accounts.file", None))
+            accountfile = from_utf8_or_none(
+                self.get_config("ftpd", "accounts.file", None))
+            if accountfile:
+                accountfile = abspath_expanduser_unicode(accountfile, base=self.basedir)
             accounturl = self.get_config("ftpd", "accounts.url", None)
             ftp_portstr = self.get_config("ftpd", "port", "8021")
 
@@ -468,7 +472,10 @@ class Client(node.Node, pollmixin.PollMixin):
 
     def init_sftp_server(self):
         if self.get_config("sftpd", "enabled", False, boolean=True):
-            accountfile = from_utf8_or_none(self.get_config("sftpd", "accounts.file", None))
+            accountfile = from_utf8_or_none(
+                self.get_config("sftpd", "accounts.file", None))
+            if accountfile:
+                accountfile = abspath_expanduser_unicode(accountfile, base=self.basedir)
             accounturl = self.get_config("sftpd", "accounts.url", None)
             sftp_portstr = self.get_config("sftpd", "port", "8022")
             pubkey_file = from_utf8_or_none(self.get_config("sftpd", "host_pubkey_file"))
index c625f2ac21ccbc646eb0528b3487c3e6484ec0cb..9922a86ad8b38429c1626af65b770f5eea80f364 100644 (file)
@@ -1,4 +1,6 @@
 
+from types import NoneType
+
 from zope.interface import implements
 from twisted.application import service, strports
 from twisted.internet import defer
@@ -10,6 +12,7 @@ from allmydata.interfaces import IDirectoryNode, ExistingChildError, \
      NoSuchChildError
 from allmydata.immutable.upload import FileHandle
 from allmydata.util.fileutil import EncryptedTemporaryFile
+from allmydata.util.assertutil import precondition
 
 class ReadFile:
     implements(ftp.IReadFile)
@@ -288,7 +291,7 @@ class Dispatcher:
 
 class FTPServer(service.MultiService):
     def __init__(self, client, accountfile, accounturl, ftp_portstr):
-        precondition(isinstance(accountfile, unicode), accountfile)
+        precondition(isinstance(accountfile, (unicode, NoneType)), accountfile)
         service.MultiService.__init__(self)
 
         r = Dispatcher(client)
index a18af9c4e1350df96118b03a1ffad8adcb241719..f4a39cb9b14ccff8b8a7c94745ebadc4d741871a 100644 (file)
@@ -28,6 +28,7 @@ from allmydata.util import deferredutil
 
 from allmydata.util.assertutil import _assert, precondition
 from allmydata.util.consumer import download_to_data
+from allmydata.util.encodingutil import get_filesystem_encoding
 from allmydata.interfaces import IFileNode, IDirectoryNode, ExistingChildError, \
      NoSuchChildError, ChildOfWrongTypeError
 from allmydata.mutable.common import NotWriteableError
@@ -1979,7 +1980,7 @@ class Dispatcher:
 class SFTPServer(service.MultiService):
     def __init__(self, client, accountfile, accounturl,
                  sftp_portstr, pubkey_file, privkey_file):
-        precondition(isinstance(accountfile, unicode), accountfile)
+        precondition(isinstance(accountfile, (unicode, NoneType)), accountfile)
         precondition(isinstance(pubkey_file, unicode), pubkey_file)
         precondition(isinstance(privkey_file, unicode), privkey_file)
         service.MultiService.__init__(self)
index 94bfbdf536556eae9b59c8735eba53400b837242..d6cd7d0d45e35a0e77e88693535182875440ecd4 100644 (file)
@@ -4,6 +4,7 @@ from twisted.application import service
 
 import allmydata
 from allmydata.node import Node, OldConfigError, OldConfigOptionError, MissingConfigEntry, UnescapedHashError
+from allmydata.frontends.auth import NeedRootcapLookupScheme
 from allmydata import client
 from allmydata.storage_client import StorageFarmBroker
 from allmydata.manhole import AuthorizedKeysManhole
@@ -203,6 +204,44 @@ class Basic(testutil.ReallyEqualMixin, unittest.TestCase):
         expected = fileutil.abspath_expanduser_unicode(u"relative", abs_basedir)
         self.failUnlessReallyEqual(m.keyfile, expected)
 
+    # TODO: also test config options for SFTP.
+
+    def test_ftp_auth_keyfile(self):
+        basedir = u"client.Basic.test_ftp_auth_keyfile"
+        os.mkdir(basedir)
+        fileutil.write(os.path.join(basedir, "tahoe.cfg"),
+                       (BASECONFIG +
+                        "[ftpd]\n"
+                        "enabled = true\n"
+                        "port = tcp:0:interface=127.0.0.1\n"
+                        "accounts.file = private/accounts\n"))
+        os.mkdir(os.path.join(basedir, "private"))
+        fileutil.write(os.path.join(basedir, "private", "accounts"), "\n")
+        c = client.Client(basedir) # just make sure it can be instantiated
+        del c
+
+    def test_ftp_auth_url(self):
+        basedir = u"client.Basic.test_ftp_auth_url"
+        os.mkdir(basedir)
+        fileutil.write(os.path.join(basedir, "tahoe.cfg"),
+                       (BASECONFIG +
+                        "[ftpd]\n"
+                        "enabled = true\n"
+                        "port = tcp:0:interface=127.0.0.1\n"
+                        "accounts.url = http://0.0.0.0/\n"))
+        c = client.Client(basedir) # just make sure it can be instantiated
+        del c
+
+    def test_ftp_auth_no_accountfile_or_url(self):
+        basedir = u"client.Basic.test_ftp_auth_no_accountfile_or_url"
+        os.mkdir(basedir)
+        fileutil.write(os.path.join(basedir, "tahoe.cfg"),
+                       (BASECONFIG +
+                        "[ftpd]\n"
+                        "enabled = true\n"
+                        "port = tcp:0:interface=127.0.0.1\n"))
+        self.failUnlessRaises(NeedRootcapLookupScheme, client.Client, basedir)
+
     def _permute(self, sb, key):
         return [ s.get_longname() for s in sb.get_servers_for_psi(key) ]