mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-22 06:17:50 +00:00
Remove AccountURLChecker, the code that relies on it, associated tests, and docs.
This commit is contained in:
parent
19a3481e5f
commit
1b46f981c6
@ -78,33 +78,6 @@ start with "ssh-".
|
||||
Now add an ``accounts.file`` directive to your ``tahoe.cfg`` file, as described in
|
||||
the next sections.
|
||||
|
||||
Running An Account Server (accounts.url)
|
||||
========================================
|
||||
|
||||
The accounts.url directive allows access requests to be controlled by an
|
||||
HTTP-based login service, useful for centralized deployments. This was used
|
||||
by AllMyData to provide web-based file access, where the service used a
|
||||
simple PHP script and database lookups to map an account email address and
|
||||
password to a Tahoe-LAFS directory cap. The service will receive a
|
||||
multipart/form-data POST, just like one created with a <form> and <input>
|
||||
fields, with three parameters:
|
||||
|
||||
• action: "authenticate" (this is a static string)
|
||||
• email: USERNAME (Tahoe-LAFS has no notion of email addresses, but the
|
||||
authentication service uses them as account names, so the interface
|
||||
presents this argument as "email" rather than "username").
|
||||
• passwd: PASSWORD
|
||||
|
||||
It should return a single string that either contains a Tahoe-LAFS directory
|
||||
cap (URI:DIR2:...), or "0" to indicate a login failure.
|
||||
|
||||
Tahoe-LAFS recommends the service be secure, preferably localhost-only. This
|
||||
makes it harder for attackers to brute force the password or use DNS
|
||||
poisoning to cause the Tahoe-LAFS gateway to talk with the wrong server,
|
||||
thereby revealing the usernames and passwords.
|
||||
|
||||
Public key authentication is not supported when an account server is used.
|
||||
|
||||
Configuring SFTP Access
|
||||
=======================
|
||||
|
||||
|
1
newsfragments/3652.removed
Normal file
1
newsfragments/3652.removed
Normal file
@ -0,0 +1 @@
|
||||
Removed support for the Account Server frontend authentication type.
|
@ -116,7 +116,6 @@ _client_config = configutil.ValidConfiguration(
|
||||
),
|
||||
"sftpd": (
|
||||
"accounts.file",
|
||||
"accounts.url",
|
||||
"enabled",
|
||||
"host_privkey_file",
|
||||
"host_pubkey_file",
|
||||
@ -1042,13 +1041,12 @@ class _Client(node.Node, pollmixin.PollMixin):
|
||||
accountfile = self.config.get_config("sftpd", "accounts.file", None)
|
||||
if accountfile:
|
||||
accountfile = self.config.get_config_path(accountfile)
|
||||
accounturl = self.config.get_config("sftpd", "accounts.url", None)
|
||||
sftp_portstr = self.config.get_config("sftpd", "port", "tcp:8022")
|
||||
pubkey_file = self.config.get_config("sftpd", "host_pubkey_file")
|
||||
privkey_file = self.config.get_config("sftpd", "host_privkey_file")
|
||||
|
||||
from allmydata.frontends import sftpd
|
||||
s = sftpd.SFTPServer(self, accountfile, accounturl,
|
||||
s = sftpd.SFTPServer(self, accountfile,
|
||||
sftp_portstr, pubkey_file, privkey_file)
|
||||
s.setServiceParent(self)
|
||||
|
||||
|
@ -1,14 +1,10 @@
|
||||
import os
|
||||
|
||||
from zope.interface import implementer
|
||||
from twisted.web.client import getPage
|
||||
from twisted.internet import defer
|
||||
from twisted.cred import error, checkers, credentials
|
||||
from twisted.conch.ssh import keys
|
||||
from twisted.conch.checkers import SSHPublicKeyChecker, InMemorySSHKeyDB
|
||||
|
||||
from allmydata.util.dictutil import BytesKeyDict
|
||||
from allmydata.util import base32
|
||||
from allmydata.util.fileutil import abspath_expanduser_unicode
|
||||
|
||||
|
||||
@ -86,54 +82,3 @@ class AccountFileChecker(object):
|
||||
d = defer.maybeDeferred(creds.checkPassword, correct)
|
||||
d.addCallback(self._cbPasswordMatch, str(creds.username))
|
||||
return d
|
||||
|
||||
|
||||
@implementer(checkers.ICredentialsChecker)
|
||||
class AccountURLChecker(object):
|
||||
credentialInterfaces = (credentials.IUsernamePassword,)
|
||||
|
||||
def __init__(self, client, auth_url):
|
||||
self.client = client
|
||||
self.auth_url = auth_url
|
||||
|
||||
def _cbPasswordMatch(self, rootcap, username):
|
||||
return FTPAvatarID(username, rootcap)
|
||||
|
||||
def post_form(self, username, password):
|
||||
sepbase = base32.b2a(os.urandom(4))
|
||||
sep = "--" + sepbase
|
||||
form = []
|
||||
form.append(sep)
|
||||
fields = {"action": "authenticate",
|
||||
"email": username,
|
||||
"passwd": password,
|
||||
}
|
||||
for name, value in fields.iteritems():
|
||||
form.append('Content-Disposition: form-data; name="%s"' % name)
|
||||
form.append('')
|
||||
assert isinstance(value, str)
|
||||
form.append(value)
|
||||
form.append(sep)
|
||||
form[-1] += "--"
|
||||
body = "\r\n".join(form) + "\r\n"
|
||||
headers = {"content-type": "multipart/form-data; boundary=%s" % sepbase,
|
||||
}
|
||||
return getPage(self.auth_url, method="POST",
|
||||
postdata=body, headers=headers,
|
||||
followRedirect=True, timeout=30)
|
||||
|
||||
def _parse_response(self, res):
|
||||
rootcap = res.strip()
|
||||
if rootcap == "0":
|
||||
raise error.UnauthorizedLogin
|
||||
return rootcap
|
||||
|
||||
def requestAvatarId(self, credentials):
|
||||
# construct a POST to the login form. While this could theoretically
|
||||
# be done with something like the stdlib 'email' package, I can't
|
||||
# figure out how, so we just slam together a form manually.
|
||||
d = self.post_form(credentials.username, credentials.password)
|
||||
d.addCallback(self._parse_response)
|
||||
d.addCallback(self._cbPasswordMatch, str(credentials.username))
|
||||
return d
|
||||
|
||||
|
@ -1983,7 +1983,7 @@ class ShellSession(PrefixingLogMixin):
|
||||
components.registerAdapter(ShellSession, SFTPUserHandler, ISession)
|
||||
|
||||
|
||||
from allmydata.frontends.auth import AccountURLChecker, AccountFileChecker, NeedRootcapLookupScheme
|
||||
from allmydata.frontends.auth import AccountFileChecker, NeedRootcapLookupScheme
|
||||
|
||||
@implementer(portal.IRealm)
|
||||
class Dispatcher(object):
|
||||
@ -2000,7 +2000,7 @@ class Dispatcher(object):
|
||||
class SFTPServer(service.MultiService):
|
||||
name = "frontend:sftp"
|
||||
|
||||
def __init__(self, client, accountfile, accounturl,
|
||||
def __init__(self, client, accountfile,
|
||||
sftp_portstr, pubkey_file, privkey_file):
|
||||
precondition(isinstance(accountfile, (str, type(None))), accountfile)
|
||||
precondition(isinstance(pubkey_file, str), pubkey_file)
|
||||
@ -2013,12 +2013,9 @@ class SFTPServer(service.MultiService):
|
||||
if accountfile:
|
||||
c = AccountFileChecker(self, accountfile)
|
||||
p.registerChecker(c)
|
||||
if accounturl:
|
||||
c = AccountURLChecker(self, accounturl)
|
||||
p.registerChecker(c)
|
||||
if not accountfile and not accounturl:
|
||||
if not accountfile:
|
||||
# we could leave this anonymous, with just the /uri/CAP form
|
||||
raise NeedRootcapLookupScheme("must provide an account file or URL")
|
||||
raise NeedRootcapLookupScheme("must provide an account file")
|
||||
|
||||
pubkey = keys.Key.fromFile(pubkey_file.encode(get_filesystem_encoding()))
|
||||
privkey = keys.Key.fromFile(privkey_file.encode(get_filesystem_encoding()))
|
||||
|
Loading…
Reference in New Issue
Block a user