openmedialibrary_platform/Linux/lib/python2.7/site-packages/twisted/cred/strcred.py
2014-05-16 01:20:41 +02:00

270 lines
8.1 KiB
Python

# -*- test-case-name: twisted.test.test_strcred -*-
#
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
#
"""
Support for resolving command-line strings that represent different
checkers available to cred.
Examples:
- passwd:/etc/passwd
- memory:admin:asdf:user:lkj
- unix
"""
import sys
from zope.interface import Interface, Attribute
from twisted.plugin import getPlugins
from twisted.python import usage
class ICheckerFactory(Interface):
"""
A factory for objects which provide
L{twisted.cred.checkers.ICredentialsChecker}.
It's implemented by twistd plugins creating checkers.
"""
authType = Attribute(
'A tag that identifies the authentication method.')
authHelp = Attribute(
'A detailed (potentially multi-line) description of precisely '
'what functionality this CheckerFactory provides.')
argStringFormat = Attribute(
'A short (one-line) description of the argument string format.')
credentialInterfaces = Attribute(
'A list of credentials interfaces that this factory will support.')
def generateChecker(argstring):
"""
Return an L{ICredentialChecker} provider using the supplied
argument string.
"""
class StrcredException(Exception):
"""
Base exception class for strcred.
"""
class InvalidAuthType(StrcredException):
"""
Raised when a user provides an invalid identifier for the
authentication plugin (known as the authType).
"""
class InvalidAuthArgumentString(StrcredException):
"""
Raised by an authentication plugin when the argument string
provided is formatted incorrectly.
"""
class UnsupportedInterfaces(StrcredException):
"""
Raised when an application is given a checker to use that does not
provide any of the application's supported credentials interfaces.
"""
# This will be used to warn the users whenever they view help for an
# authType that is not supported by the application.
notSupportedWarning = ("WARNING: This authType is not supported by "
"this application.")
def findCheckerFactories():
"""
Find all objects that implement L{ICheckerFactory}.
"""
return getPlugins(ICheckerFactory)
def findCheckerFactory(authType):
"""
Find the first checker factory that supports the given authType.
"""
for factory in findCheckerFactories():
if factory.authType == authType:
return factory
raise InvalidAuthType(authType)
def makeChecker(description):
"""
Returns an L{twisted.cred.checkers.ICredentialsChecker} based on the
contents of a descriptive string. Similar to
L{twisted.application.strports}.
"""
if ':' in description:
authType, argstring = description.split(':', 1)
else:
authType = description
argstring = ''
return findCheckerFactory(authType).generateChecker(argstring)
class AuthOptionMixin:
"""
Defines helper methods that can be added on to any
L{usage.Options} subclass that needs authentication.
This mixin implements three new options methods:
The opt_auth method (--auth) will write two new values to the
'self' dictionary: C{credInterfaces} (a dict of lists) and
C{credCheckers} (a list).
The opt_help_auth method (--help-auth) will search for all
available checker plugins and list them for the user; it will exit
when finished.
The opt_help_auth_type method (--help-auth-type) will display
detailed help for a particular checker plugin.
@cvar supportedInterfaces: An iterable object that returns
credential interfaces which this application is able to support.
@cvar authOutput: A writeable object to which this options class
will send all help-related output. Default: L{sys.stdout}
"""
supportedInterfaces = None
authOutput = sys.stdout
def supportsInterface(self, interface):
"""
Returns whether a particular credentials interface is supported.
"""
return (self.supportedInterfaces is None
or interface in self.supportedInterfaces)
def supportsCheckerFactory(self, factory):
"""
Returns whether a checker factory will provide at least one of
the credentials interfaces that we care about.
"""
for interface in factory.credentialInterfaces:
if self.supportsInterface(interface):
return True
return False
def addChecker(self, checker):
"""
Supply a supplied credentials checker to the Options class.
"""
# First figure out which interfaces we're willing to support.
supported = []
if self.supportedInterfaces is None:
supported = checker.credentialInterfaces
else:
for interface in checker.credentialInterfaces:
if self.supportsInterface(interface):
supported.append(interface)
if not supported:
raise UnsupportedInterfaces(checker.credentialInterfaces)
# If we get this far, then we know we can use this checker.
if 'credInterfaces' not in self:
self['credInterfaces'] = {}
if 'credCheckers' not in self:
self['credCheckers'] = []
self['credCheckers'].append(checker)
for interface in supported:
self['credInterfaces'].setdefault(interface, []).append(checker)
def opt_auth(self, description):
"""
Specify an authentication method for the server.
"""
try:
self.addChecker(makeChecker(description))
except UnsupportedInterfaces, e:
raise usage.UsageError(
'Auth plugin not supported: %s' % e.args[0])
except InvalidAuthType, e:
raise usage.UsageError(
'Auth plugin not recognized: %s' % e.args[0])
except Exception, e:
raise usage.UsageError('Unexpected error: %s' % e)
def _checkerFactoriesForOptHelpAuth(self):
"""
Return a list of which authTypes will be displayed by --help-auth.
This makes it a lot easier to test this module.
"""
for factory in findCheckerFactories():
for interface in factory.credentialInterfaces:
if self.supportsInterface(interface):
yield factory
break
def opt_help_auth(self):
"""
Show all authentication methods available.
"""
self.authOutput.write("Usage: --auth AuthType[:ArgString]\n")
self.authOutput.write("For detailed help: --help-auth-type AuthType\n")
self.authOutput.write('\n')
# Figure out the right width for our columns
firstLength = 0
for factory in self._checkerFactoriesForOptHelpAuth():
if len(factory.authType) > firstLength:
firstLength = len(factory.authType)
formatString = ' %%-%is\t%%s\n' % firstLength
self.authOutput.write(formatString % ('AuthType', 'ArgString format'))
self.authOutput.write(formatString % ('========', '================'))
for factory in self._checkerFactoriesForOptHelpAuth():
self.authOutput.write(
formatString % (factory.authType, factory.argStringFormat))
self.authOutput.write('\n')
raise SystemExit(0)
def opt_help_auth_type(self, authType):
"""
Show help for a particular authentication type.
"""
try:
cf = findCheckerFactory(authType)
except InvalidAuthType:
raise usage.UsageError("Invalid auth type: %s" % authType)
self.authOutput.write("Usage: --auth %s[:ArgString]\n" % authType)
self.authOutput.write("ArgString format: %s\n" % cf.argStringFormat)
self.authOutput.write('\n')
for line in cf.authHelp.strip().splitlines():
self.authOutput.write(' %s\n' % line.rstrip())
self.authOutput.write('\n')
if not self.supportsCheckerFactory(cf):
self.authOutput.write(' %s\n' % notSupportedWarning)
self.authOutput.write('\n')
raise SystemExit(0)