1
# -*- test-case-name: atop.test_credup -*-
3
from twisted.python.components import implements
4
from twisted.cred.portal import IRealm
5
from twisted.cred.credentials import IUsernamePassword, IUsernameHashedPassword
6
from twisted.cred.checkers import ICredentialsChecker, ANONYMOUS
7
from twisted.cred.error import UnauthorizedLogin
9
from atop.powerup import Storeup
10
from atop.store import SubStore, Pool, NameIndex
11
from atop.fwd import ItemForwardingComponent
13
def _localpartDomainToDBEmail(localpart, domain):
14
dparts = domain.split('.')
16
revdomain = '.'.join(dparts)
17
return (revdomain+'@'+localpart)
20
class Avatar(SubStore):
22
def setSecurePassword(self, passwd):
23
"""Save away a string for use with protocols that do not expose your
24
password on the network.
26
self.securePassword = passwd
28
def setInsecurePassword(self, passwd):
29
"""Save away a string for use with protocols that expose your password
32
self.insecurePassword = passwd
34
def getPassword(self, passwordSecure):
35
"""Retrieve a password.
38
return self.securePassword
40
return self.insecurePassword
44
## Maybe this is pointless
45
## Maybe the adapter being registered on this class
46
## Should just be registered on the Store itself
47
def __init__(self, store):
52
def __init__(self, store, name):
53
Pool.__init__(self, store, name)
54
self.addIndex(NameIndex())
56
class Preauthenticated:
57
__implements__ = IUsernameHashedPassword
59
def __init__(self, username):
60
self.username = username
62
def checkPassword(self, password):
65
def preauth(store, username):
66
"""Utility function to retrieve an avatar from a database by name.
68
return store.getItemByID(
69
ICredentialsChecker(store).
70
requestAvatarId(Preauthenticated(username)))
72
class FwdChecker(ItemForwardingComponent):
73
__implements__ = ICredentialsChecker
74
def __init__(self, fwdTo):
75
ItemForwardingComponent.__init__(self, fwdTo)
76
self.credentialInterfaces = fwdTo.getItem().credentialInterfaces
78
class FwdRealm(ItemForwardingComponent):
79
__implements__ = IRealm
81
class StoreCredentialsChecker(Storeup):
83
__implements__ = ICredentialsChecker
85
credentialInterfaces = (IUsernamePassword, IUsernameHashedPassword)
87
def setUpPools(self, store):
89
domains = Pool(store, 'domains')
90
domains.addIndex(NameIndex())
91
self.domainPoolRef = domains.referenceTo()
92
store.setComponent(ICredentialsChecker, self)
95
"""Retrieve an iterator of all domains in this store.
97
return self.domainPoolRef.getItem().queryIndex()
100
"""Retrieve an iterator of all avatars regardless of domain.
102
This will yield certain avatars twice.
104
for domain in self.getDomains():
105
for avatar in domain.queryIndex():
108
def getDomain(self, name=None):
109
return self.domainPoolRef.getItem().getIndexItem('name', name)
111
def addDomain(self, domainName):
112
x = Domain(self.store, domainName)
113
self.domainPoolRef.getItem().addItem(x)
116
def addAvatar(self, avatar, domainName=None):
118
domain = self.getDomain(domainName)
119
av2 = domain.getIndexItem("name", avatar.name, None)
121
raise UnauthorizedLogin("You can't choose that username in that domain.")
122
domain.addItem(avatar)
123
return self.store.transact(_)
124
addAvatarToDomain = addAvatar
126
def getAvatar(self, localpart, domainName=None):
128
domain = self.getDomain(domainName)
129
return domain.getIndexItem("name", localpart)
130
return self.store.transact(_)
131
getAvatarFromDomain = getAvatar
133
def requestAvatarId(self, credentials):
134
passwordSecure = implements(credentials, IUsernameHashedPassword)
136
usplit = credentials.username.split('@', 1)
137
avatar = self.getAvatarFromDomain(*usplit)
138
password = avatar.getPassword(passwordSecure)
139
if credentials.checkPassword(password):
140
return avatar.storeID
143
raise UnauthorizedLogin()
146
class StoreRealm(Storeup):
148
dependencies = [StoreCredentialsChecker]
150
__implements__ = IRealm
152
def setUpPools(self, store):
153
store.setComponent(IRealm, self)
156
## Actual IRealm implementation
159
def requestAvatar(self, avatarId, mind, interface):
163
if avatarId is ANONYMOUS:
164
avatar = AnonymousUser(self.store)
166
avatar = self.store.getItemByID(avatarId)
167
avatarAspect = interface(avatar, default=None)
168
if avatarAspect is None:
169
raise UnauthorizedLogin("You're not allowed to access that.")
170
logout = getattr(avatarAspect, 'logout', noLogout)
171
return (interface, avatarAspect, logout)
172
return self.store.transact(_)