6
from twisted.python import defer
9
from util import respond
10
from util import challenge
13
"""An identity, with different methods for verification.
15
An identity represents a user's permissions with a particular
16
application. It is a username, a password, and a collection of
17
Perspective/Service name pairs, each of which is a perspective
18
that this identity is allowed to access.
22
def __init__(self, name, application):
23
"""Create an identity.
25
I must have a name, and a backreference to the Application that the
26
Keys on my keyring make reference to.
29
self.application = application
32
def addKeyForPerspective(self, perspective):
33
"""Add a key for the given perspective.
35
perspectiveName = perspective.getPerspectiveName()
36
serviceName = perspective.service.getServiceName()
37
self.addKeyByString(serviceName, perspectiveName)
39
def addKeyByString(self, serviceName, perspectiveName):
40
"""Put a key on my keyring.
42
This key will give me a token to access to some service in the
45
self.keyring[(serviceName, perspectiveName)] = 1
47
def requestPerspectiveForService(self, serviceName):
48
"""Get the first available perspective for a given service.
50
keys = self.keyring.keys()
52
for serviceN, perspectiveN in keys:
53
if serviceN == serviceName:
54
return self.requestPerspectiveForKey(serviceName, perspectiveN)
55
return defer.fail("No such perspective.")
57
def requestPerspectiveForKey(self, serviceName, perspectiveName):
58
"""Get a perspective request (a Deferred) for the given key.
60
If this identity does not have access to the given (serviceName,
61
perspectiveName) pair, I will raise KeyError.
64
check = self.keyring[(serviceName, perspectiveName)]
66
return defer.fail(failure.Failure())
67
return self.application.getServiceNamed(serviceName).getPerspectiveRequest(perspectiveName)
70
"""Returns a list of all services and perspectives this identity can connect to.
72
This returns a sequence of keys.
74
return self.keyring.keys()
76
def removeKey(self, serviceName, perspectiveName):
77
"""Remove a key from my keyring.
79
If this key is not present, raise KeyError.
81
del self.keyring[(serviceName, perspectiveName)]
83
def setPassword(self, plaintext):
85
self.hashedPassword = None
87
self.hashedPassword = md5.new(plaintext).digest()
89
def setAlreadyHashedPassword(self, cyphertext):
90
"""(legacy) Set a password for this identity, already md5 hashed.
92
self.hashedPassword = cyphertext
95
"""I return some random data.
97
This is a method in addition to the module-level function
98
because it is anticipated that we will want to change this
99
to store salted passwords.
103
def verifyPassword(self, challenge, hashedPassword):
104
"""Verify a challenge/response password.
107
md.update(self.hashedPassword)
109
correct = md.digest()
110
result = (hashedPassword == correct)
113
def verifyPlainPassword(self, plaintext):
114
"""Verify plain text password.
116
This is insecure, but necessary to support legacy protocols such
117
as IRC, POP3, HTTP, etc.
122
userPass = md.digest()
123
return (userPass == self.hashedPassword)
127
# TODO: service discovery through listing of self.keyring.