1
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml">
3
<title>Twisted Documentation: Cred: Pluggable Authentication</title>
4
<link href="stylesheet.css" rel="stylesheet" type="text/css"/>
8
<h1 class="title">Cred: Pluggable Authentication</h1>
9
<div class="toc"><ol><li><a href="#auto0">Goals</a></li><li><a href="#auto1">Cred objects</a></li><ul><li><a href="#auto2">The Portal</a></li><li><a href="#auto3">The CredentialChecker</a></li><li><a href="#auto4">The Credentials</a></li><li><a href="#auto5">The Realm</a></li><li><a href="#auto6">The Avatar</a></li><li><a href="#auto7">The Mind</a></li></ul><li><a href="#auto8">Responsibilities</a></li><ul><li><a href="#auto9">Server protocol implementation</a></li><li><a href="#auto10">Application implementation</a></li><li><a href="#auto11">Deployment</a></li></ul><li><a href="#auto12">Cred plugins</a></li><ul><li><a href="#auto13">Authentication with cred plugins</a></li><li><a href="#auto14">Building a cred plugin</a></li></ul><li><a href="#auto15">Conclusion</a></li></ol></div>
13
<h2>Goals<a name="auto0"/></h2>
15
<p>Cred is a pluggable authentication system for servers. It allows any
16
number of network protocols to connect and authenticate to a system, and
17
communicate to those aspects of the system which are meaningful to the specific
18
protocol. For example, Twisted's POP3 support passes a <q>username and
19
password</q> set of credentials to get back a mailbox for the specified email
20
account. IMAP does the same, but retrieves a slightly different view of the
21
same mailbox, enabling those features specific to IMAP which are not available
22
in other mail protocols.</p>
24
<p>Cred is designed to allow both the backend implementation of the business
25
logic - called the <em>avatar</em> - and the authentication database - called
26
the <em>credential checker</em> - to be decided during deployment. For example,
27
the same POP3 server should be able to authenticate against the local UNIX
28
password database or an LDAP server without having to know anything about how
29
or where mail is stored. </p>
31
<p>To sketch out how this works - a <q>Realm</q> corresponds to an application
32
domain and is in charge of avatars, which are network-accessible business logic
33
objects. To connect this to an authentication database, a top-level object
34
called a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.cred.portal.Portal.html" title="twisted.cred.portal.Portal">Portal</a></code> stores a
35
realm, and a number of credential checkers. Something that wishes to log in,
36
such as a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.protocol.Protocol.html" title="twisted.internet.protocol.Protocol">Protocol</a></code>,
37
stores a reference to the portal. Login consists of passing credentials and a
38
request interface (e.g. POP3's <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.protocols.pop3.IMailbox.html" title="twisted.protocols.pop3.IMailbox">IMailbox</a></code>) to the portal. The portal passes
39
the credentials to the appropriate credential checker, which returns an avatar
40
ID. The ID is passed to the realm, which returns the appropriate avatar. For a
41
Portal that has a realm that creates mailbox objects and a credential checker
42
that checks /etc/passwd, login consists of passing in a username/password and
43
the IMailbox interface to the portal. The portal passes this to the /etc/passwd
44
credential checker, gets back a avatar ID corresponding to an email account,
45
passes that to the realm and gets back a mailbox object for that email
48
<p>Putting all this together, here's how a login request will typically be
51
<img src="../img/cred-login.png" title="Cred Login"/>
53
<h2>Cred objects<a name="auto1"/></h2>
54
<h3>The Portal<a name="auto2"/></h3>
55
<p>This is the the core of login, the point of integration between all the objects
56
in the cred system. There is one
57
concrete implementation of Portal, and no interface - it does a very
58
simple task. A <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.cred.portal.Portal.html" title="twisted.cred.portal.Portal">Portal</a></code>
59
associates one (1) Realm with a collection of
60
CredentialChecker instances. (More on those later.)</p>
62
<p>If you are writing a protocol that needs to authenticate against
63
something, you will need a reference to a Portal, and to nothing else.
64
This has only 2 methods -</p>
67
<li><code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.cred.portal.Portal.login.html" title="twisted.cred.portal.Portal.login">login</a></code><code>(credentials, mind, *interfaces)</code>
69
<p>The docstring is quite expansive (see <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.cred.portal.html" title="twisted.cred.portal">twisted.cred.portal</a></code>), but in
70
brief, this is what you call when you need to call in order to connect
71
a user to the system. Typically you only pass in one interface, and the mind is
72
<code class="python">None</code>. The interfaces are the possible interfaces the returned
73
avatar is expected to implement, in order of preference.
74
The result is a deferred which fires a tuple of:</p>
76
<li>interface the avatar implements (which was one of the interfaces passed in the *interfaces
78
<li>an object that implements that interface (an avatar)</li>
79
<li>logout, a 0-argument callable which disconnects the connection that was
80
established by this call to login</li>
82
<p>The logout method has to be called when the avatar is logged out. For POP3 this means
83
when the protocol is disconnected or logged out, etc..</p>
85
<li><code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.cred.portal.Portal.registerChecker.html" title="twisted.cred.portal.Portal.registerChecker">registerChecker</a></code><code>(checker, *credentialInterfaces)</code>
87
<p>which adds a CredentialChecker to the portal. The optional list of interfaces are interfaces of credentials
88
that the checker is able to check.</p>
91
<h3>The CredentialChecker<a name="auto3"/></h3>
93
<p>This is an object implementing <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.cred.checkers.ICredentialsChecker.html" title="twisted.cred.checkers.ICredentialsChecker">ICredentialsChecker</a></code> which resolves some
94
credentials to an avatar ID.
96
Whether the credentials are stored in an in-memory data structure, an
97
Apache-style htaccess file, a UNIX password database, an SSH key database,
98
or any other form, an implementation of <code>ICredentialsChecker</code> is
99
how this data is connected to cred.
102
stipulates some requirements of the credentials it can check by
103
specifying a credentialInterfaces attribute, which is a list of
104
interfaces. Credentials passed to its requestAvatarId method must
105
implement one of those interfaces.</p>
107
<p>For the most part, these things will just check usernames and passwords
108
and produce the username as the result, but hopefully we will be seeing
109
some public-key, challenge-response, and certificate based credential
110
checker mechanisms soon.</p>
112
<p>A credential checker should raise an error if it cannot authenticate
113
the user, and return <code>twisted.cred.checkers.ANONYMOUS</code>
114
for anonymous access.</p>
116
<h3>The Credentials<a name="auto4"/></h3>
117
<p>Oddly enough, this represents some credentials that the user presents.
118
Usually this will just be a small static blob of data, but in some
119
cases it will actually be an object connected to a network protocol.
120
For example, a username/password pair is static, but a
121
challenge/response server is an active state-machine that will require
122
several method calls in order to determine a result.</p>
124
<p>Twisted comes with a number of credentials interfaces and implementations
125
in the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.cred.credentials.html" title="twisted.cred.credentials">twisted.cred.credentials</a></code> module,
126
such as <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.cred.credentials.IUsernamePassword.html" title="twisted.cred.credentials.IUsernamePassword">IUsernamePassword</a></code>
127
and <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.cred.credentials.IUsernameHashedPassword.html" title="twisted.cred.credentials.IUsernameHashedPassword">IUsernameHashedPassword</a></code>.</p>
129
<h3>The Realm<a name="auto5"/></h3>
130
<p>A realm is an interface which connects your universe of <q>business
131
objects</q> to the authentication system.</p>
133
<p><code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.cred.portal.IRealm.html" title="twisted.cred.portal.IRealm">IRealm</a></code> is another one-method interface:</p>
136
<li><code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.cred.portal.IRealm.requestAvatar.html" title="twisted.cred.portal.IRealm.requestAvatar">requestAvatar</a></code><code>(avatarId, mind, *interfaces)</code>
138
<p>This method will typically be called from 'Portal.login'. The avatarId
139
is the one returned by a CredentialChecker.</p>
141
<div class="note"><strong>Note: </strong>Note that <code>avatarId</code> must always be a string. In
142
particular, do not use unicode strings. If internationalized support is needed,
143
it is recommended to use UTF-8, and take care of decoding in the realm. </div>
145
<p>The important thing to realize about this method is that if it is being
146
called, <em>the user has already authenticated</em>. Therefore, if possible,
147
the Realm should create a new user if one does not already exist
148
whenever possible. Of course, sometimes this will be impossible
149
without more information, and that is the case that the interfaces
154
<p>Since requestAvatar should be called from a Deferred callback, it may
155
return a Deferred or a synchronous result.</p>
157
<h3>The Avatar<a name="auto6"/></h3>
159
<p>An avatar is a business logic object for a specific user. For POP3, it's
160
a mailbox, for a first-person-shooter it's the object that interacts with
161
the game, the actor as it were. Avatars are specific to an application,
162
and each avatar represents a single <q>user</q>.</p>
164
<h3>The Mind<a name="auto7"/></h3>
166
<p>As mentioned before, the mind is usually None, so you can skip this
169
<p>Masters of Perspective Broker already know this object as the ill-named
170
<q>client object</q>. There is no <q>mind</q> class, or even interface, but it
171
is an object which serves an important role - any notifications which are to be
172
relayed to an authenticated client are passed through a 'mind'. In addition, it
173
allows passing more information to the realm during login in addition to the
176
<p>The name may seem rather unusual, but considering that a Mind is
177
representative of the entity on the <q>other end</q> of a network connection
178
that is both receiving updates and issuing commands, I believe it is
181
<p>Although many protocols will not use this, it serves an important role.
182
It is provided as an argument both to the Portal and to the Realm,
183
although a CredentialChecker should interact with a client program
184
exclusively through a Credentials instance.</p>
186
<p>Unlike the original Perspective Broker <q>client object</q>, a Mind's
187
implementation is most often dictated by the protocol that is
188
connecting rather than the Realm. A Realm which requires a particular
189
interface to issue notifications will need to wrap the Protocol's mind
190
implementation with an adapter in order to get one that conforms to its
191
expected interface - however, Perspective Broker will likely continue
192
to use the model where the client object has a pre-specified remote
195
<p>(If you don't quite understand this, it's fine. It's hard to explain,
196
and it's not used in simple usages of cred, so feel free to pass None
197
until you find yourself requiring something like this.)</p>
199
<h2>Responsibilities<a name="auto8"/></h2>
201
<h3>Server protocol implementation<a name="auto9"/></h3>
203
<p>The protocol implementor should define the interface the avatar should implement,
204
and design the protocol to have a portal attached. When a user logs in using the
205
protocol, a credential object is created, passed to the portal, and an avatar
206
with the appropriate interface is requested. When the user logs out or the protocol
207
is disconnected, the avatar should be logged out.</p>
209
<p>The protocol designer should not hardcode how users are authenticated or the
210
realm implemented. For example, a POP3 protocol implementation would require a portal whose
211
realm returns avatars implementing IMailbox and whose credential checker accepts
212
username/password credentials, but that is all. Here's a sketch of how the code
213
might look - note that USER and PASS are the protocol commands used to login, and
214
the DELE command can only be used after you are logged in:</p>
216
<pre class="python"><p class="py-linenumber"> 1
273
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Interface</span>
275
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">protocols</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">basic</span>
276
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">log</span>
277
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">cred</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">credentials</span>, <span class="py-src-variable">error</span>
278
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span>
280
<span class="py-src-keyword">class</span> <span class="py-src-identifier">IMailbox</span>(<span class="py-src-parameter">Interface</span>):
281
<span class="py-src-string">"""Interface specification for mailbox."""</span>
282
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deleteMessage</span>(<span class="py-src-parameter">index</span>): <span class="py-src-keyword">pass</span>
285
<span class="py-src-keyword">class</span> <span class="py-src-identifier">POP3</span>(<span class="py-src-parameter">basic</span>.<span class="py-src-parameter">LineReceiver</span>):
286
<span class="py-src-comment"># ...</span>
287
<span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">portal</span>):
288
<span class="py-src-variable">self</span>.<span class="py-src-variable">portal</span> = <span class="py-src-variable">portal</span>
290
<span class="py-src-keyword">def</span> <span class="py-src-identifier">do_DELE</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">i</span>):
291
<span class="py-src-comment"># uses self.mbox, which is set after login</span>
292
<span class="py-src-variable">i</span> = <span class="py-src-variable">int</span>(<span class="py-src-variable">i</span>)-<span class="py-src-number">1</span>
293
<span class="py-src-variable">self</span>.<span class="py-src-variable">mbox</span>.<span class="py-src-variable">deleteMessage</span>(<span class="py-src-variable">i</span>)
294
<span class="py-src-variable">self</span>.<span class="py-src-variable">successResponse</span>()
296
<span class="py-src-keyword">def</span> <span class="py-src-identifier">do_USER</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">user</span>):
297
<span class="py-src-variable">self</span>.<span class="py-src-variable">_userIs</span> = <span class="py-src-variable">user</span>
298
<span class="py-src-variable">self</span>.<span class="py-src-variable">successResponse</span>(<span class="py-src-string">'USER accepted, send PASS'</span>)
300
<span class="py-src-keyword">def</span> <span class="py-src-identifier">do_PASS</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">password</span>):
301
<span class="py-src-keyword">if</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_userIs</span> <span class="py-src-keyword">is</span> <span class="py-src-variable">None</span>:
302
<span class="py-src-variable">self</span>.<span class="py-src-variable">failResponse</span>(<span class="py-src-string">"USER required before PASS"</span>)
303
<span class="py-src-keyword">return</span>
304
<span class="py-src-variable">user</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">_userIs</span>
305
<span class="py-src-variable">self</span>.<span class="py-src-variable">_userIs</span> = <span class="py-src-variable">None</span>
306
<span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">maybeDeferred</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">authenticateUserPASS</span>, <span class="py-src-variable">user</span>, <span class="py-src-variable">password</span>)
307
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">_cbMailbox</span>, <span class="py-src-variable">user</span>)
309
<span class="py-src-keyword">def</span> <span class="py-src-identifier">authenticateUserPASS</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">user</span>, <span class="py-src-parameter">password</span>):
310
<span class="py-src-keyword">if</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">portal</span> <span class="py-src-keyword">is</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">None</span>:
311
<span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">portal</span>.<span class="py-src-variable">login</span>(
312
<span class="py-src-variable">cred</span>.<span class="py-src-variable">credentials</span>.<span class="py-src-variable">UsernamePassword</span>(<span class="py-src-variable">user</span>, <span class="py-src-variable">password</span>),
313
<span class="py-src-variable">None</span>,
314
<span class="py-src-variable">IMailbox</span>
316
<span class="py-src-keyword">raise</span> <span class="py-src-variable">error</span>.<span class="py-src-variable">UnauthorizedLogin</span>()
318
<span class="py-src-keyword">def</span> <span class="py-src-identifier">_cbMailbox</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">ial</span>, <span class="py-src-parameter">user</span>):
319
<span class="py-src-variable">interface</span>, <span class="py-src-variable">avatar</span>, <span class="py-src-variable">logout</span> = <span class="py-src-variable">ial</span>
321
<span class="py-src-keyword">if</span> <span class="py-src-variable">interface</span> <span class="py-src-keyword">is</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">IMailbox</span>:
322
<span class="py-src-variable">self</span>.<span class="py-src-variable">failResponse</span>(<span class="py-src-string">'Authentication failed'</span>)
323
<span class="py-src-variable">log</span>.<span class="py-src-variable">err</span>(<span class="py-src-string">"_cbMailbox() called with an interface other than IMailbox"</span>)
324
<span class="py-src-keyword">return</span>
326
<span class="py-src-variable">self</span>.<span class="py-src-variable">mbox</span> = <span class="py-src-variable">avatar</span>
327
<span class="py-src-variable">self</span>.<span class="py-src-variable">_onLogout</span> = <span class="py-src-variable">logout</span>
328
<span class="py-src-variable">self</span>.<span class="py-src-variable">successResponse</span>(<span class="py-src-string">'Authentication succeeded'</span>)
329
<span class="py-src-variable">log</span>.<span class="py-src-variable">msg</span>(<span class="py-src-string">"Authenticated login for "</span> + <span class="py-src-variable">user</span>)
332
<h3>Application implementation<a name="auto10"/></h3>
334
<p>The application developer can implement realms and credential checkers. For example,
335
she might implement a realm that returns IMailbox implementing avatars, using MySQL
336
for storage, or perhaps a credential checker that uses LDAP for authentication.
337
In the following example, the Realm for a simple remote object service (using
338
Twisted's Perspective Broker protocol) is implemented:</p>
340
<pre class="python"><p class="py-linenumber"> 1
362
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
363
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">cred</span>.<span class="py-src-variable">portal</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">IRealm</span>
365
<span class="py-src-keyword">class</span> <span class="py-src-identifier">SimplePerspective</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Avatar</span>):
367
<span class="py-src-keyword">def</span> <span class="py-src-identifier">perspective_echo</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">text</span>):
368
<span class="py-src-keyword">print</span> <span class="py-src-string">'echoing'</span>,<span class="py-src-variable">text</span>
369
<span class="py-src-keyword">return</span> <span class="py-src-variable">text</span>
371
<span class="py-src-keyword">def</span> <span class="py-src-identifier">logout</span>(<span class="py-src-parameter">self</span>):
372
<span class="py-src-keyword">print</span> <span class="py-src-variable">self</span>, <span class="py-src-string">"logged out"</span>
375
<span class="py-src-keyword">class</span> <span class="py-src-identifier">SimpleRealm</span>:
376
<span class="py-src-variable">implements</span>(<span class="py-src-variable">IRealm</span>)
378
<span class="py-src-keyword">def</span> <span class="py-src-identifier">requestAvatar</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">avatarId</span>, <span class="py-src-parameter">mind</span>, *<span class="py-src-parameter">interfaces</span>):
379
<span class="py-src-keyword">if</span> <span class="py-src-variable">pb</span>.<span class="py-src-variable">IPerspective</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">interfaces</span>:
380
<span class="py-src-variable">avatar</span> = <span class="py-src-variable">SimplePerspective</span>()
381
<span class="py-src-keyword">return</span> <span class="py-src-variable">pb</span>.<span class="py-src-variable">IPerspective</span>, <span class="py-src-variable">avatar</span>, <span class="py-src-variable">avatar</span>.<span class="py-src-variable">logout</span>
382
<span class="py-src-keyword">else</span>:
383
<span class="py-src-keyword">raise</span> <span class="py-src-variable">NotImplementedError</span>(<span class="py-src-string">"no interface"</span>)
386
<h3>Deployment<a name="auto11"/></h3>
388
<p>Deployment involves tying together a protocol, an appropriate realm and a credential
389
checker. For example, a POP3 server can be constructed by attaching to it a portal
390
that wraps the MySQL-based realm and an /etc/passwd credential checker, or perhaps
391
the LDAP credential checker if that is more useful. The following example shows
392
how the SimpleRealm in the previous example is deployed using an in-memory credential checker:</p>
394
<pre class="python"><p class="py-linenumber"> 1
405
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
406
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
407
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">cred</span>.<span class="py-src-variable">portal</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Portal</span>
408
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">cred</span>.<span class="py-src-variable">checkers</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">InMemoryUsernamePasswordDatabaseDontUse</span>
410
<span class="py-src-variable">portal</span> = <span class="py-src-variable">Portal</span>(<span class="py-src-variable">SimpleRealm</span>())
411
<span class="py-src-variable">checker</span> = <span class="py-src-variable">InMemoryUsernamePasswordDatabaseDontUse</span>()
412
<span class="py-src-variable">checker</span>.<span class="py-src-variable">addUser</span>(<span class="py-src-string">"guest"</span>, <span class="py-src-string">"password"</span>)
413
<span class="py-src-variable">portal</span>.<span class="py-src-variable">registerChecker</span>(<span class="py-src-variable">checker</span>)
414
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">9986</span>, <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBServerFactory</span>(<span class="py-src-variable">portal</span>))
415
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
418
<h2>Cred plugins<a name="auto12"/></h2>
420
<h3>Authentication with cred plugins<a name="auto13"/></h3>
422
<p> Cred offers a plugin architecture for authentication methods. The
423
primary API for this architecture is the command-line; the plugins are
424
meant to be specified by the end-user when deploying a TAP (twistd
427
<p> For more information on writing a twistd plugin and using cred
428
plugins for your application, please refer to the <a href="tap.html" shape="rect">Writing a twistd plugin</a> document.</p>
430
<h3>Building a cred plugin<a name="auto14"/></h3>
432
<p> To build a plugin for cred, you should first define an <code class="python">authType</code>, a short one-word string that defines
433
your plugin to the command-line. Once you have this, the convention is
434
to create a file named <code>myapp_plugins.py</code> in the
435
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.plugins.html" title="twisted.plugins">twisted.plugins</a></code> module path. </p>
437
<p> Below is an example file structure for an application that defines
455
<li>myapp_plugins.py</li>
465
Once you have created this structure within your application, you can
466
create the code for your cred plugin by building a factory class which
467
implements <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.cred.checkers.ICheckerFactory.html" title="twisted.cred.checkers.ICheckerFactory">ICheckerFactory</a></code>.
468
These factory classes should not consist of a tremendous amount of
469
code. Most of the real application logic should reside in the cred
470
checker itself. (For help on building those, scroll up.)
474
The core purpose of the CheckerFactory is to translate an <code class="python">argstring</code>, which is passed on the command line,
475
into a suitable set of initialization parameters for a Checker
476
class. In most cases this should be little more than constructing a
477
dictionary or a tuple of arguments, then passing them along to a new
481
<pre class="python"><p class="py-linenumber"> 1
513
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>
515
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">plugin</span>
516
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">cred</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">checkers</span>
517
<span class="py-src-keyword">from</span> <span class="py-src-variable">myapp</span>.<span class="py-src-variable">cred</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">SpecialChecker</span>
519
<span class="py-src-keyword">class</span> <span class="py-src-identifier">SpecialCheckerFactory</span>(<span class="py-src-parameter">object</span>):
520
<span class="py-src-string">"""
521
A checker factory for a specialized (fictional) API.
522
"""</span>
523
<span class="py-src-comment"># The class needs to implement both of these interfaces</span>
524
<span class="py-src-comment"># for the plugin system to find our factory.</span>
525
<span class="py-src-variable">implements</span>(<span class="py-src-variable">checkers</span>.<span class="py-src-variable">ICheckerFactory</span>, <span class="py-src-variable">plugin</span>.<span class="py-src-variable">IPlugin</span>)
527
<span class="py-src-comment"># This tells AuthOptionsMixin how to find this factory.</span>
528
<span class="py-src-variable">authType</span> = <span class="py-src-string">"special"</span>
530
<span class="py-src-comment"># This is a one-line explanation of what arguments, if any,</span>
531
<span class="py-src-comment"># your particular cred plugin requires at the command-line.</span>
532
<span class="py-src-variable">argStringFormat</span> = <span class="py-src-string">"A colon-separated key=value list."</span>
534
<span class="py-src-comment"># This help text can be multiple lines. It will be displayed</span>
535
<span class="py-src-comment"># when someone uses the "--help-auth-type special" command.</span>
536
<span class="py-src-variable">authHelp</span> = <span class="py-src-string">"""Some help text goes here ..."""</span>
538
<span class="py-src-comment"># This will be called once per command-line.</span>
539
<span class="py-src-keyword">def</span> <span class="py-src-identifier">generateChecker</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">argstring</span>=<span class="py-src-string">""</span>):
540
<span class="py-src-variable">argdict</span> = <span class="py-src-variable">dict</span>((<span class="py-src-variable">x</span>.<span class="py-src-variable">split</span>(<span class="py-src-string">'='</span>) <span class="py-src-keyword">for</span> <span class="py-src-variable">x</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">argstring</span>.<span class="py-src-variable">split</span>(<span class="py-src-string">':'</span>)))
541
<span class="py-src-keyword">return</span> <span class="py-src-variable">SpecialChecker</span>(**<span class="py-src-variable">dict</span>)
543
<span class="py-src-comment"># We need to instantiate our class for the plugin to work.</span>
544
<span class="py-src-variable">theSpecialCheckerFactory</span> = <span class="py-src-variable">SpecialCheckerFactory</span>()
547
<p> For more information on how your plugin can be used in your
548
application (and by other application developers), please see the <a href="tap.html" shape="rect">Writing a twistd plugin</a> document.</p>
550
<h2>Conclusion<a name="auto15"/></h2>
552
<p>After reading through this tutorial, you should be able to
555
<li>Understand how the cred architecture applies to your application</li>
556
<li>Integrate your application with cred's object model</li>
557
<li>Deploy an application that uses cred for authentication</li>
558
<li>Allow your users to use command-line authentication plugins</li>
563
<p><a href="index.html">Index</a></p>
564
<span class="version">Version: 10.0.0</span>
b'\\ No newline at end of file'