This commit is contained in:
Mai Gillmann
2019-12-17 14:09:10 +01:00
parent 66e908fc8a
commit 4791d00a43
2122 changed files with 423791 additions and 0 deletions
@@ -0,0 +1,178 @@
###############################################################################
#
# The MIT License (MIT)
#
# Copyright (c) Crossbar.io Technologies GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
###############################################################################
from __future__ import absolute_import
from zope.interface import implementer
from twisted.plugin import IPlugin
from twisted.internet.interfaces import IStreamServerEndpointStringParser, \
IStreamServerEndpoint, \
IStreamClientEndpoint
try:
from twisted.internet.interfaces import IStreamClientEndpointStringParserWithReactor
_HAS_REACTOR_ARG = True
except ImportError:
_HAS_REACTOR_ARG = False
from twisted.internet.interfaces import IStreamClientEndpointStringParser as \
IStreamClientEndpointStringParserWithReactor
from twisted.internet.endpoints import serverFromString, clientFromString
from autobahn.twisted.websocket import WrappingWebSocketServerFactory, \
WrappingWebSocketClientFactory
def _parseOptions(options):
opts = {}
if 'url' not in options:
raise Exception("URL needed")
else:
opts['url'] = options['url']
if 'compression' in options:
value = options['compression'].lower().strip()
if value == 'true':
opts['enableCompression'] = True
elif value == 'false':
opts['enableCompression'] = False
else:
raise Exception("invalid value '{0}' for compression".format(value))
if 'autofrag' in options:
try:
value = int(options['autofrag'])
except:
raise Exception("invalid value '{0}' for autofrag".format(options['autofrag']))
if value < 0:
raise Exception("negative value '{0}' for autofrag".format(value))
opts['autoFragmentSize'] = value
if 'subprotocol' in options:
value = options['subprotocol'].lower().strip()
opts['subprotocol'] = value
if 'debug' in options:
value = options['debug'].lower().strip()
if value == 'true':
opts['debug'] = True
elif value == 'false':
opts['debug'] = False
else:
raise Exception("invalid value '{0}' for debug".format(value))
return opts
@implementer(IPlugin)
@implementer(IStreamServerEndpointStringParser)
class AutobahnServerParser(object):
prefix = "autobahn"
def parseStreamServer(self, reactor, description, **options):
# The present endpoint plugin is intended to be used as in the
# following for running a streaming protocol over WebSocket over
# an underlying stream transport.
#
# endpoint = serverFromString(reactor,
# "autobahn:tcp\:9000\:interface\=0.0.0.0:url=ws\://localhost\:9000:compress=false"
#
# This will result in `parseStreamServer` to be called will
#
# description == tcp:9000:interface=0.0.0.0
#
# and
#
# options == {'url': 'ws://localhost:9000', 'compress': 'false'}
#
# Essentially, we are using the `\:` escape to coerce the endpoint descriptor
# of the underlying stream transport into one (first) positional argument.
#
# Note that the `\:` within "url" is another form of escaping!
#
opts = _parseOptions(options)
endpoint = serverFromString(reactor, description)
return AutobahnServerEndpoint(reactor, endpoint, opts)
@implementer(IPlugin)
@implementer(IStreamServerEndpoint)
class AutobahnServerEndpoint(object):
def __init__(self, reactor, endpoint, options):
self._reactor = reactor
self._endpoint = endpoint
self._options = options
def listen(self, protocolFactory):
return self._endpoint.listen(WrappingWebSocketServerFactory(protocolFactory, reactor=self._reactor, **self._options))
# note that for older Twisted before the WithReactor variant, we
# import it under that name so we can share (most of) this
# implementation...
@implementer(IPlugin)
@implementer(IStreamClientEndpointStringParserWithReactor)
class AutobahnClientParser(object):
prefix = "autobahn"
def parseStreamClient(self, *args, **options):
if _HAS_REACTOR_ARG:
reactor = args[0]
if len(args) != 2:
raise RuntimeError("autobahn: client plugin takes exactly one positional argument")
description = args[1]
else:
from twisted.internet import reactor
if len(args) != 1:
raise RuntimeError("autobahn: client plugin takes exactly one positional argument")
description = args[0]
opts = _parseOptions(options)
endpoint = clientFromString(reactor, description)
return AutobahnClientEndpoint(reactor, endpoint, opts)
@implementer(IPlugin)
@implementer(IStreamClientEndpoint)
class AutobahnClientEndpoint(object):
def __init__(self, reactor, endpoint, options):
self._reactor = reactor
self._endpoint = endpoint
self._options = options
def connect(self, protocolFactory):
return self._endpoint.connect(WrappingWebSocketClientFactory(protocolFactory, reactor=self._reactor, **self._options))
autobahnServerParser = AutobahnServerParser()
autobahnClientParser = AutobahnClientParser()
@@ -0,0 +1,61 @@
# -*- test-case-name: twisted.test.test_strcred -*-
#
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Cred plugin for a file of the format 'username:password'.
"""
from __future__ import absolute_import, division
import sys
from zope.interface import implementer
from twisted import plugin
from twisted.cred.checkers import FilePasswordDB
from twisted.cred.strcred import ICheckerFactory
from twisted.cred.credentials import IUsernamePassword, IUsernameHashedPassword
fileCheckerFactoryHelp = """
This checker expects to receive the location of a file that
conforms to the FilePasswordDB format. Each line in the file
should be of the format 'username:password', in plain text.
"""
invalidFileWarning = 'Warning: not a valid file'
@implementer(ICheckerFactory, plugin.IPlugin)
class FileCheckerFactory(object):
"""
A factory for instances of L{FilePasswordDB}.
"""
authType = 'file'
authHelp = fileCheckerFactoryHelp
argStringFormat = 'Location of a FilePasswordDB-formatted file.'
# Explicitly defined here because FilePasswordDB doesn't do it for us
credentialInterfaces = (IUsernamePassword, IUsernameHashedPassword)
errorOutput = sys.stderr
def generateChecker(self, argstring):
"""
This checker factory expects to get the location of a file.
The file should conform to the format required by
L{FilePasswordDB} (using defaults for all
initialization parameters).
"""
from twisted.python.filepath import FilePath
if not argstring.strip():
raise ValueError('%r requires a filename' % self.authType)
elif not FilePath(argstring).isfile():
self.errorOutput.write('%s: %s\n' % (invalidFileWarning, argstring))
return FilePasswordDB(argstring)
theFileCheckerFactory = FileCheckerFactory()
@@ -0,0 +1,185 @@
# -*- test-case-name: twisted.test.test_strcred -*-
#
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Cred plugin for UNIX user accounts.
"""
from __future__ import absolute_import, division
from zope.interface import implementer
from twisted import plugin
from twisted.cred.strcred import ICheckerFactory
from twisted.cred.checkers import ICredentialsChecker
from twisted.cred.credentials import IUsernamePassword
from twisted.cred.error import UnauthorizedLogin
from twisted.internet import defer
from twisted.python.compat import StringType
def verifyCryptedPassword(crypted, pw):
"""
Use L{crypt.crypt} to Verify that an unencrypted
password matches the encrypted password.
@param crypted: The encrypted password, obtained from
the Unix password database or Unix shadow
password database.
@param pw: The unencrypted password.
@return: L{True} if there is successful match, else L{False}.
@rtype: L{bool}
"""
try:
import crypt
except ImportError:
crypt = None
if crypt is None:
raise NotImplementedError("cred_unix not supported on this platform")
if not isinstance(pw, StringType):
pw = pw.decode('utf-8')
if not isinstance(crypted, StringType):
crypted = crypted.decode('utf-8')
return crypt.crypt(pw, crypted) == crypted
@implementer(ICredentialsChecker)
class UNIXChecker(object):
"""
A credentials checker for a UNIX server. This will check that
an authenticating username/password is a valid user on the system.
Does not work on Windows.
Right now this supports Python's pwd and spwd modules, if they are
installed. It does not support PAM.
"""
credentialInterfaces = (IUsernamePassword,)
def checkPwd(self, pwd, username, password):
"""
Obtain the encrypted password for C{username} from the Unix password
database using L{pwd.getpwnam}, and see if it it matches it matches
C{password}.
@param pwd: Module which provides functions which
access to the Unix password database.
@type pwd: C{module}
@param username: The user to look up in the Unix password database.
@type username: L{unicode}/L{str} or L{bytes}
@param password: The password to compare.
@type username: L{unicode}/L{str} or L{bytes}
"""
try:
if not isinstance(username, StringType):
username = username.decode('utf-8')
cryptedPass = pwd.getpwnam(username).pw_passwd
except KeyError:
return defer.fail(UnauthorizedLogin())
else:
if cryptedPass in ('*', 'x'):
# Allow checkSpwd to take over
return None
elif verifyCryptedPassword(cryptedPass, password):
return defer.succeed(username)
def checkSpwd(self, spwd, username, password):
"""
Obtain the encrypted password for C{username} from the
Unix shadow password database using L{spwd.getspnam},
and see if it it matches it matches C{password}.
@param spwd: Module which provides functions which
access to the Unix shadow password database.
@type pwd: C{module}
@param username: The user to look up in the Unix password database.
@type username: L{unicode}/L{str} or L{bytes}
@param password: The password to compare.
@type username: L{unicode}/L{str} or L{bytes}
"""
try:
if not isinstance(username, StringType):
username = username.decode('utf-8')
if getattr(spwd.struct_spwd, "sp_pwdp", None):
# Python 3
cryptedPass = spwd.getspnam(username).sp_pwdp
else:
# Python 2
cryptedPass = spwd.getspnam(username).sp_pwd
except KeyError:
return defer.fail(UnauthorizedLogin())
else:
if verifyCryptedPassword(cryptedPass, password):
return defer.succeed(username)
def requestAvatarId(self, credentials):
username, password = credentials.username, credentials.password
try:
import pwd
except ImportError:
pwd = None
if pwd is not None:
checked = self.checkPwd(pwd, username, password)
if checked is not None:
return checked
try:
import spwd
except ImportError:
spwd = None
if spwd is not None:
checked = self.checkSpwd(spwd, username, password)
if checked is not None:
return checked
# TODO: check_pam?
# TODO: check_shadow?
return defer.fail(UnauthorizedLogin())
unixCheckerFactoryHelp = """
This checker will attempt to use every resource available to
authenticate against the list of users on the local UNIX system.
(This does not support Windows servers for very obvious reasons.)
Right now, this includes support for:
* Python's pwd module (which checks /etc/passwd)
* Python's spwd module (which checks /etc/shadow)
Future versions may include support for PAM authentication.
"""
@implementer(ICheckerFactory, plugin.IPlugin)
class UNIXCheckerFactory(object):
"""
A factory for L{UNIXChecker}.
"""
authType = 'unix'
authHelp = unixCheckerFactoryHelp
argStringFormat = 'No argstring required.'
credentialInterfaces = UNIXChecker.credentialInterfaces
def generateChecker(self, argstring):
"""
This checker factory ignores the argument string. Everything
needed to generate a user database is pulled out of the local
UNIX environment.
"""
return UNIXChecker()
theUnixCheckerFactory = UNIXCheckerFactory()
@@ -0,0 +1,24 @@
import socket
from twisted.internet import endpoints
from twisted.internet.interfaces import IStreamServerEndpointStringParser
from twisted.plugin import IPlugin
from zope.interface import implementer
@implementer(IPlugin, IStreamServerEndpointStringParser)
class _FDParser(object):
prefix = "fd"
def _parseServer(self, reactor, fileno, domain=socket.AF_INET):
fileno = int(fileno)
return endpoints.AdoptedStreamServerEndpoint(reactor, fileno, domain)
def parseStreamServer(self, reactor, *args, **kwargs):
# Delegate to another function with a sane signature. This function has
# an insane signature to trick zope.interface into believing the
# interface is correctly implemented.
return self._parseServer(reactor, *args, **kwargs)
parser = _FDParser()
@@ -0,0 +1,18 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
from __future__ import absolute_import, division
from twisted.internet.endpoints import (
_SystemdParser, _TCP6ServerParser, _StandardIOParser,
_TLSClientEndpointParser)
from twisted.protocols.haproxy._parser import (
HAProxyServerParser as _HAProxyServerParser
)
systemdEndpointParser = _SystemdParser()
tcp6ServerEndpointParser = _TCP6ServerParser()
stdioEndpointParser = _StandardIOParser()
tlsClientEndpointParser = _TLSClientEndpointParser()
_haProxyServerEndpointParser = _HAProxyServerParser()
@@ -0,0 +1,10 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
from twisted.application.service import ServiceMaker
TwistedNames = ServiceMaker(
"Twisted DNS Server",
"twisted.names.tap",
"A domain name server.",
"dns")
@@ -0,0 +1,47 @@
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
from zope.interface import provider
from twisted.plugin import IPlugin
from twisted.application.service import ServiceMaker
from twisted.words import iwords
NewTwistedWords = ServiceMaker(
"New Twisted Words",
"twisted.words.tap",
"A modern words server",
"words")
TwistedXMPPRouter = ServiceMaker(
"XMPP Router",
"twisted.words.xmpproutertap",
"An XMPP Router server",
"xmpp-router")
@provider(IPlugin, iwords.IProtocolPlugin)
class RelayChatInterface(object):
name = 'irc'
def getFactory(cls, realm, portal):
from twisted.words import service
return service.IRCFactory(realm, portal)
getFactory = classmethod(getFactory)
@provider(IPlugin, iwords.IProtocolPlugin)
class PBChatInterface(object):
name = 'pb'
def getFactory(cls, realm, portal):
from twisted.spread import pb
return pb.PBServerFactory(portal, True)
getFactory = classmethod(getFactory)