Initial import to Tizen
[profile/ivi/python-twisted.git] / doc / core / howto / cred.html
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">
2   <head>
3 <title>Twisted Documentation: Cred: Pluggable Authentication</title>
4 <link href="stylesheet.css" rel="stylesheet" type="text/css"/>
5   </head>
6
7   <body bgcolor="white">
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>
10     <div class="content">
11     <span/>
12
13     <h2>Goals<a name="auto0"/></h2>
14
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>
23
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>
30
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/12.1.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/12.1.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/12.1.0/api/twisted.mail.pop3.IMailbox.html" title="twisted.mail.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
46 account.</p>
47
48 <p>Putting all this together, here's how a login request will typically be
49 processed:</p>
50
51 <img src="../img/cred-login.png" title="Cred Login"/>
52
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/12.1.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>
61
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>
65
66 <ul>
67 <li><code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.cred.portal.Portal.login.html" title="twisted.cred.portal.Portal.login">login</a></code><code>(credentials, mind, *interfaces)</code>
68
69 <p>The docstring is quite expansive (see <code class="API"><a href="http://twistedmatrix.com/documents/12.1.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
72 is <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>
75     <ul>
76         <li>interface the avatar implements (which was one of the interfaces passed in the <code>*interfaces</code>
77 tuple)</li>
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>
81     </ul>
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>
84 </li>
85 <li><code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.cred.portal.Portal.registerChecker.html" title="twisted.cred.portal.Portal.registerChecker">registerChecker</a></code><code>(checker, *credentialInterfaces)</code>
86
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>
89 </li></ul>
90
91     <h3>The CredentialChecker<a name="auto3"/></h3>
92
93 <p>This is an object implementing <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.cred.checkers.ICredentialsChecker.html" title="twisted.cred.checkers.ICredentialsChecker">ICredentialsChecker</a></code> which resolves some
94 credentials to an avatar ID.
95
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.
100
101 A credential checker
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>
106
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>
111
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>
115
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>
123
124 <p>Twisted comes with a number of credentials interfaces and implementations
125 in the <code class="API"><a href="http://twistedmatrix.com/documents/12.1.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/12.1.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/12.1.0/api/twisted.cred.credentials.IUsernameHashedPassword.html" title="twisted.cred.credentials.IUsernameHashedPassword">IUsernameHashedPassword</a></code>.</p>
128
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>
132
133 <p><code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.cred.portal.IRealm.html" title="twisted.cred.portal.IRealm">IRealm</a></code> is another one-method interface:</p>
134
135 <ul>
136 <li><code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.cred.portal.IRealm.requestAvatar.html" title="twisted.cred.portal.IRealm.requestAvatar">requestAvatar</a></code><code>(avatarId, mind, *interfaces)</code>
137
138 <p>This method will typically be called from 'Portal.login'.  The avatarId
139 is the one returned by a CredentialChecker.</p>
140
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>
144
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
150 argument is for.</p>
151 </li>
152 </ul>
153
154 <p>Since requestAvatar should be called from a Deferred callback, it may
155 return a Deferred or a synchronous result.</p>
156
157     <h3>The Avatar<a name="auto6"/></h3>
158
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>
163
164     <h3>The Mind<a name="auto7"/></h3>
165
166 <p>As mentioned before, the mind is usually <code>None</code>, so you can skip this
167 bit if you want.</p>
168
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
174 avatar ID.</p>
175
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
179 appropriate.</p>
180
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>
185
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
193 interface.</p>
194
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>
198
199     <h2>Responsibilities<a name="auto8"/></h2>
200
201     <h3>Server protocol implementation<a name="auto9"/></h3>
202
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>
208
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>
215
216 <pre class="python"><p class="py-linenumber"> 1
217  2
218  3
219  4
220  5
221  6
222  7
223  8
224  9
225 10
226 11
227 12
228 13
229 14
230 15
231 16
232 17
233 18
234 19
235 20
236 21
237 22
238 23
239 24
240 25
241 26
242 27
243 28
244 29
245 30
246 31
247 32
248 33
249 34
250 35
251 36
252 37
253 38
254 39
255 40
256 41
257 42
258 43
259 44
260 45
261 46
262 47
263 48
264 49
265 50
266 51
267 52
268 53
269 54
270 55
271 56
272 57
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>
274
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>
279
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">&quot;&quot;&quot;Interface specification for mailbox.&quot;&quot;&quot;</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>
283
284
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>
289
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>()
295
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>)
299
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">&quot;USER required before PASS&quot;</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>)
308
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>
315             )
316         <span class="py-src-keyword">raise</span> <span class="py-src-variable">error</span>.<span class="py-src-variable">UnauthorizedLogin</span>()
317
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>
320
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">&quot;_cbMailbox() called with an interface other than IMailbox&quot;</span>)
324             <span class="py-src-keyword">return</span>
325
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">&quot;Authenticated login for &quot;</span> + <span class="py-src-variable">user</span>)
330 </pre>
331
332    <h3>Application implementation<a name="auto10"/></h3>
333
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>
339
340 <pre class="python"><p class="py-linenumber"> 1
341  2
342  3
343  4
344  5
345  6
346  7
347  8
348  9
349 10
350 11
351 12
352 13
353 14
354 15
355 16
356 17
357 18
358 19
359 20
360 21
361 22
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>
364
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>):
366
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>
370
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">&quot;logged out&quot;</span>
373
374
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>)
377
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">&quot;no interface&quot;</span>)
384 </pre>
385
386    <h3>Deployment<a name="auto11"/></h3>
387
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>
393
394 <pre class="python"><p class="py-linenumber"> 1
395  2
396  3
397  4
398  5
399  6
400  7
401  8
402  9
403 10
404 11
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>
409
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">&quot;guest&quot;</span>, <span class="py-src-string">&quot;password&quot;</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>()
416 </pre>
417
418    <h2>Cred plugins<a name="auto12"/></h2>
419
420    <h3>Authentication with cred plugins<a name="auto13"/></h3>
421
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
425 plugin).</p>
426
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>
429
430    <h3>Building a cred plugin<a name="auto14"/></h3>
431
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/12.1.0/api/twisted.plugins.html" title="twisted.plugins">twisted.plugins</a></code> module path. </p>
436
437 <p> Below is an example file structure for an application that defines
438 such a plugin: </p>
439
440 <ul>
441 <li>MyApplication/
442   <ul>
443   <li>setup.py</li>
444   <li>myapp/
445     <ul>
446     <li>__init__.py</li>
447     <li>cred.py</li>
448     <li>server.py</li>
449     </ul>
450   </li>
451   <li>twisted/
452     <ul>
453     <li>plugins/
454       <ul>
455       <li>myapp_plugins.py</li>
456       </ul>
457     </li>
458     </ul>
459   </li>
460   </ul>
461 </li>
462 </ul>
463
464 <p>
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/12.1.0/api/twisted.cred.strcred.ICheckerFactory.html" title="twisted.cred.strcred.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.)
471 </p>
472
473 <p>
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
478 checker instance.
479 </p>
480
481 <pre class="python"><p class="py-linenumber"> 1
482  2
483  3
484  4
485  5
486  6
487  7
488  8
489  9
490 10
491 11
492 12
493 13
494 14
495 15
496 16
497 17
498 18
499 19
500 20
501 21
502 22
503 23
504 24
505 25
506 26
507 27
508 28
509 29
510 30
511 31
512 32
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>
514
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-variable">strcred</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">ICheckerFactory</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>
518
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">&quot;&quot;&quot;
521     A checker factory for a specialized (fictional) API.
522     &quot;&quot;&quot;</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">ICheckerFactory</span>, <span class="py-src-variable">plugin</span>.<span class="py-src-variable">IPlugin</span>)
526
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">&quot;special&quot;</span>
529
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">&quot;A colon-separated key=value list.&quot;</span>
533
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 &quot;--help-auth-type special&quot; command.</span>
536     <span class="py-src-variable">authHelp</span> = <span class="py-src-string">&quot;&quot;&quot;Some help text goes here ...&quot;&quot;&quot;</span>
537
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">&quot;&quot;</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>)
542
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>()
545 </pre>
546
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>
549
550 <h2>Conclusion<a name="auto15"/></h2>
551
552 <p>After reading through this tutorial, you should be able to
553 </p>
554 <ul>
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>
559 </ul>
560
561 </div>
562
563     <p><a href="index.html">Index</a></p>
564     <span class="version">Version: 12.1.0</span>
565   </body>
566 </html>