1
# -*- test-case-name: twisted.test.test_strcred -*-
3
# Copyright (c) 2007-2008 Twisted Matrix Laboratories.
4
# See LICENSE for details.
8
Support for resolving command-line strings that represent different
9
checkers available to cred.
13
- memory:admin:asdf:user:lkj
19
from zope.interface import Interface, Attribute
21
from twisted.plugin import getPlugins
22
from twisted.python import usage
26
class ICheckerFactory(Interface):
28
A factory for objects which provide
29
L{twisted.cred.checkers.ICredentialsChecker}.
31
It's implemented by twistd plugins creating checkers.
35
'A tag that identifies the authentication method.')
39
'A detailed (potentially multi-line) description of precisely '
40
'what functionality this CheckerFactory provides.')
43
argStringFormat = Attribute(
44
'A short (one-line) description of the argument string format.')
47
credentialInterfaces = Attribute(
48
'A list of credentials interfaces that this factory will support.')
51
def generateChecker(argstring):
53
Return an L{ICredentialChecker} provider using the supplied
59
class StrcredException(Exception):
61
Base exception class for strcred.
66
class InvalidAuthType(StrcredException):
68
Raised when a user provides an invalid identifier for the
69
authentication plugin (known as the authType).
74
class InvalidAuthArgumentString(StrcredException):
76
Raised by an authentication plugin when the argument string
77
provided is formatted incorrectly.
82
class UnsupportedInterfaces(StrcredException):
84
Raised when an application is given a checker to use that does not
85
provide any of the application's supported credentials interfaces.
90
# This will be used to warn the users whenever they view help for an
91
# authType that is not supported by the application.
92
notSupportedWarning = ("WARNING: This authType is not supported by "
97
def findCheckerFactories():
99
Find all objects that implement L{ICheckerFactory}.
101
return getPlugins(ICheckerFactory)
105
def findCheckerFactory(authType):
107
Find the first checker factory that supports the given authType.
109
for factory in findCheckerFactories():
110
if factory.authType == authType:
112
raise InvalidAuthType(authType)
116
def makeChecker(description):
118
Returns an L{twisted.cred.checkers.ICredentialsChecker} based on the
119
contents of a descriptive string. Similar to
120
L{twisted.application.strports}.
122
if ':' in description:
123
authType, argstring = description.split(':', 1)
125
authType = description
127
return findCheckerFactory(authType).generateChecker(argstring)
131
class AuthOptionMixin:
133
Defines helper methods that can be added on to any
134
L{usage.Options} subclass that needs authentication.
136
This mixin implements three new options methods:
138
The opt_auth method (--auth) will write two new values to the
139
'self' dictionary: C{credInterfaces} (a dict of lists) and
140
C{credCheckers} (a list).
142
The opt_help_auth method (--help-auth) will search for all
143
available checker plugins and list them for the user; it will exit
146
The opt_help_auth_type method (--help-auth-type) will display
147
detailed help for a particular checker plugin.
149
@cvar supportedInterfaces: An iterable object that returns
150
credential interfaces which this application is able to support.
152
@cvar authOutput: A writeable object to which this options class
153
will send all help-related output. Default: L{sys.stdout}
156
supportedInterfaces = None
157
authOutput = sys.stdout
160
def supportsInterface(self, interface):
162
Returns whether a particular credentials interface is supported.
164
return (self.supportedInterfaces is None
165
or interface in self.supportedInterfaces)
168
def supportsCheckerFactory(self, factory):
170
Returns whether a checker factory will provide at least one of
171
the credentials interfaces that we care about.
173
for interface in factory.credentialInterfaces:
174
if self.supportsInterface(interface):
179
def addChecker(self, checker):
181
Supply a supplied credentials checker to the Options class.
183
# First figure out which interfaces we're willing to support.
185
if self.supportedInterfaces is None:
186
supported = checker.credentialInterfaces
188
for interface in checker.credentialInterfaces:
189
if self.supportsInterface(interface):
190
supported.append(interface)
192
raise UnsupportedInterfaces(checker.credentialInterfaces)
193
# If we get this far, then we know we can use this checker.
194
if 'credInterfaces' not in self:
195
self['credInterfaces'] = {}
196
if 'credCheckers' not in self:
197
self['credCheckers'] = []
198
self['credCheckers'].append(checker)
199
for interface in supported:
200
self['credInterfaces'].setdefault(interface, []).append(checker)
203
def opt_auth(self, description):
205
Specify an authentication method for the server.
208
self.addChecker(makeChecker(description))
209
except UnsupportedInterfaces, e:
210
raise usage.UsageError(
211
'Auth plugin not supported: %s' % e.args[0])
212
except InvalidAuthType, e:
213
raise usage.UsageError(
214
'Auth plugin not recognized: %s' % e.args[0])
216
raise usage.UsageError('Unexpected error: %s' % e)
219
def _checkerFactoriesForOptHelpAuth(self):
221
Return a list of which authTypes will be displayed by --help-auth.
222
This makes it a lot easier to test this module.
224
for factory in findCheckerFactories():
225
for interface in factory.credentialInterfaces:
226
if self.supportsInterface(interface):
231
def opt_help_auth(self):
233
Show all authentication methods available.
235
self.authOutput.write("Usage: --auth AuthType[:ArgString]\n")
236
self.authOutput.write("For detailed help: --help-auth-type AuthType\n")
237
self.authOutput.write('\n')
238
# Figure out the right width for our columns
240
for factory in self._checkerFactoriesForOptHelpAuth():
241
if len(factory.authType) > firstLength:
242
firstLength = len(factory.authType)
243
formatString = ' %%-%is\t%%s\n' % firstLength
244
self.authOutput.write(formatString % ('AuthType', 'ArgString format'))
245
self.authOutput.write(formatString % ('========', '================'))
246
for factory in self._checkerFactoriesForOptHelpAuth():
247
self.authOutput.write(
248
formatString % (factory.authType, factory.argStringFormat))
249
self.authOutput.write('\n')
253
def opt_help_auth_type(self, authType):
255
Show help for a particular authentication type.
258
cf = findCheckerFactory(authType)
259
except InvalidAuthType:
260
raise usage.UsageError("Invalid auth type: %s" % authType)
261
self.authOutput.write("Usage: --auth %s[:ArgString]\n" % authType)
262
self.authOutput.write("ArgString format: %s\n" % cf.argStringFormat)
263
self.authOutput.write('\n')
264
for line in cf.authHelp.strip().splitlines():
265
self.authOutput.write(' %s\n' % line.rstrip())
266
self.authOutput.write('\n')
267
if not self.supportsCheckerFactory(cf):
268
self.authOutput.write(' %s\n' % notSupportedWarning)
269
self.authOutput.write('\n')