OLD | NEW |
| (Empty) |
1 # -*- test-case-name: twisted.test.test_newcred -*- | |
2 | |
3 # Copyright (c) 2001-2007 Twisted Matrix Laboratories. | |
4 # See LICENSE for details. | |
5 | |
6 """ | |
7 The point of integration of application and authentication. | |
8 """ | |
9 | |
10 | |
11 from twisted.internet import defer | |
12 from twisted.internet.defer import maybeDeferred | |
13 from twisted.python import failure, reflect | |
14 from twisted.cred import error | |
15 from zope.interface import providedBy, Interface | |
16 | |
17 | |
18 class IRealm(Interface): | |
19 """ | |
20 The realm connects application-specific objects to the | |
21 authentication system. | |
22 """ | |
23 def requestAvatar(avatarId, mind, *interfaces): | |
24 """ | |
25 Return avatar which provides one of the given interfaces. | |
26 | |
27 @param avatarId: a string that identifies an avatar, as returned by | |
28 L{ICredentialsChecker.requestAvatarId<twisted.cred.checkers.ICredent
ialsChecker.requestAvatarId>} | |
29 (via a Deferred). Alternatively, it may be | |
30 C{twisted.cred.checkers.ANONYMOUS}. | |
31 @param mind: usually None. See the description of mind in | |
32 L{Portal.login}. | |
33 @param interfaces: the interface(s) the returned avatar should | |
34 implement, e.g. C{IMailAccount}. See the description of | |
35 L{Portal.login}. | |
36 | |
37 @returns: a deferred which will fire a tuple of (interface, | |
38 avatarAspect, logout), or the tuple itself. The interface will be | |
39 one of the interfaces passed in the 'interfaces' argument. The | |
40 'avatarAspect' will implement that interface. The 'logout' object | |
41 is a callable which will detach the mind from the avatar. | |
42 """ | |
43 | |
44 | |
45 class Portal: | |
46 """ | |
47 A mediator between clients and a realm. | |
48 | |
49 A portal is associated with one Realm and zero or more credentials checkers. | |
50 When a login is attempted, the portal finds the appropriate credentials | |
51 checker for the credentials given, invokes it, and if the credentials are | |
52 valid, retrieves the appropriate avatar from the Realm. | |
53 | |
54 This class is not intended to be subclassed. Customization should be done | |
55 in the realm object and in the credentials checker objects. | |
56 """ | |
57 def __init__(self, realm, checkers=()): | |
58 """ | |
59 Create a Portal to a L{IRealm}. | |
60 """ | |
61 self.realm = realm | |
62 self.checkers = {} | |
63 for checker in checkers: | |
64 self.registerChecker(checker) | |
65 | |
66 def listCredentialsInterfaces(self): | |
67 """ | |
68 Return list of credentials interfaces that can be used to login. | |
69 """ | |
70 return self.checkers.keys() | |
71 | |
72 def registerChecker(self, checker, *credentialInterfaces): | |
73 if not credentialInterfaces: | |
74 credentialInterfaces = checker.credentialInterfaces | |
75 for credentialInterface in credentialInterfaces: | |
76 self.checkers[credentialInterface] = checker | |
77 | |
78 def login(self, credentials, mind, *interfaces): | |
79 """ | |
80 @param credentials: an implementor of | |
81 L{twisted.cred.credentials.ICredentials} | |
82 | |
83 @param mind: an object which implements a client-side interface for | |
84 your particular realm. In many cases, this may be None, so if the | |
85 word 'mind' confuses you, just ignore it. | |
86 | |
87 @param interfaces: list of interfaces for the perspective that the mind | |
88 wishes to attach to. Usually, this will be only one interface, for | |
89 example IMailAccount. For highly dynamic protocols, however, this | |
90 may be a list like (IMailAccount, IUserChooser, IServiceInfo). To | |
91 expand: if we are speaking to the system over IMAP, any information | |
92 that will be relayed to the user MUST be returned as an | |
93 IMailAccount implementor; IMAP clients would not be able to | |
94 understand anything else. Any information about unusual status | |
95 would have to be relayed as a single mail message in an | |
96 otherwise-empty mailbox. However, in a web-based mail system, or a | |
97 PB-based client, the ``mind'' object inside the web server | |
98 (implemented with a dynamic page-viewing mechanism such as woven) | |
99 or on the user's client program may be intelligent enough to | |
100 respond to several ``server''-side interfaces. | |
101 | |
102 @return: A deferred which will fire a tuple of (interface, | |
103 avatarAspect, logout). The interface will be one of the interfaces | |
104 passed in the 'interfaces' argument. The 'avatarAspect' will | |
105 implement that interface. The 'logout' object is a callable which | |
106 will detach the mind from the avatar. It must be called when the | |
107 user has conceptually disconnected from the service. Although in | |
108 some cases this will not be in connectionLost (such as in a | |
109 web-based session), it will always be at the end of a user's | |
110 interactive session. | |
111 """ | |
112 for i in self.checkers: | |
113 if i.providedBy(credentials): | |
114 return maybeDeferred(self.checkers[i].requestAvatarId, credentia
ls | |
115 ).addCallback(self.realm.requestAvatar, mind, *interfaces | |
116 ) | |
117 ifac = providedBy(credentials) | |
118 return defer.fail(failure.Failure(error.UnhandledCredentials( | |
119 "No checker for %s" % ', '.join(map(reflect.qual, ifac))))) | |
120 | |
OLD | NEW |