~certify-web-dev/twisted/certify-trunk

« back to all changes in this revision

Viewing changes to twisted/cred/identity.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2007-01-17 14:52:35 UTC
  • mfrom: (1.1.5 upstream) (2.1.2 etch)
  • Revision ID: james.westby@ubuntu.com-20070117145235-btmig6qfmqfen0om
Tags: 2.5.0-0ubuntu1
New upstream version, compatible with python2.5.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
2
 
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
3
 
# See LICENSE for details.
4
 
 
5
 
 
6
 
"""DEPRECATED.
7
 
 
8
 
Base authentication mechanisms for Twisted.
9
 
 
10
 
Maintainer: U{Glyph Lefkowitz<mailto:glyph@twistedmatrix.com>}
11
 
 
12
 
Stability: semi-stable
13
 
 
14
 
Future Plans: There needs to be more pluggable support for different, disparate
15
 
authentication mechanisms being supported by the same Identity as long as it
16
 
supports the appropriate persistent data-storage fields.  This will likely be
17
 
accomplished with Adapters and possibly Componentized, although it may just be
18
 
the addition of more methods in the base Identity.
19
 
 
20
 
"""
21
 
 
22
 
# System Imports
23
 
import md5, types, sys, warnings
24
 
 
25
 
# Twisted Imports
26
 
from twisted.python import failure
27
 
from twisted.internet import defer
28
 
 
29
 
# Sibling Imports
30
 
from util import respond
31
 
from util import challenge
32
 
from error import Unauthorized, KeyNotFound
33
 
 
34
 
 
35
 
class Identity:
36
 
    """An identity, with different methods for verification.
37
 
 
38
 
    An identity represents a user's permissions with a particular
39
 
    application.  It is a username, a password, and a collection of
40
 
    Perspective/Service name pairs, each of which is a perspective
41
 
    that this identity is allowed to access.
42
 
    """
43
 
    hashedPassword = None
44
 
 
45
 
    def __init__(self, name, authorizer):
46
 
        """Create an identity.
47
 
 
48
 
        I must have a name, and a backreference to the Application that the
49
 
        Keys on my keyring make reference to.
50
 
        """
51
 
        warnings.warn("Identities are deprecated, switch to credentialcheckers etc.",
52
 
                      category=DeprecationWarning, stacklevel=2)
53
 
        if not isinstance(name, types.StringType):
54
 
            raise TypeError
55
 
        from twisted.internet import app
56
 
        if isinstance(authorizer, app.Application):
57
 
            authorizer = authorizer.authorizer
58
 
        self.name = name
59
 
        self.authorizer = authorizer
60
 
        self.keyring = {}
61
 
 
62
 
    def upgradeToVersion2(self):
63
 
        self.authorizer = self.application.authorizer
64
 
        del self.application
65
 
 
66
 
    def addKeyForPerspective(self, perspective):
67
 
        """Add a key for the given perspective.
68
 
        """
69
 
        perspectiveName = perspective.getPerspectiveName()
70
 
        serviceName = perspective.service.getServiceName()
71
 
        self.addKeyByString(serviceName, perspectiveName)
72
 
 
73
 
    def addKeyByString(self, serviceName, perspectiveName):
74
 
        """Put a key on my keyring.
75
 
 
76
 
        This key will give me a token to access to some service in the
77
 
        future.
78
 
        """
79
 
        self.keyring[(serviceName, perspectiveName)] = 1
80
 
 
81
 
    def requestPerspectiveForService(self, serviceName):
82
 
        """Get the first available perspective for a given service.
83
 
        """
84
 
        keys = self.keyring.keys()
85
 
        keys.sort()
86
 
        for serviceN, perspectiveN in keys:
87
 
            if serviceN == serviceName:
88
 
                return self.requestPerspectiveForKey(serviceName, perspectiveN)
89
 
        return defer.fail("No such perspective.")
90
 
 
91
 
    def requestPerspectiveForKey(self, serviceName, perspectiveName):
92
 
        """Get a perspective request (a Deferred) for the given key.
93
 
 
94
 
        If this identity does not have access to the given C{(serviceName,
95
 
        perspectiveName)} pair, I will raise L{KeyNotFound<error.KeyNotFound>}.
96
 
        """
97
 
        try:
98
 
            check = self.keyring[(serviceName, perspectiveName)]
99
 
        except KeyError:
100
 
            e = KeyNotFound(serviceName, perspectiveName)
101
 
            return defer.fail(failure.Failure(e, KeyNotFound,
102
 
                                              sys.exc_info()[2]))
103
 
        return self.authorizer.getServiceNamed(serviceName).getPerspectiveForIdentity(perspectiveName, self)
104
 
 
105
 
    def getAllKeys(self):
106
 
        """Returns a list of all services and perspectives this identity can connect to.
107
 
 
108
 
        This returns a sequence of keys.
109
 
        """
110
 
        return self.keyring.keys()
111
 
 
112
 
    def removeKey(self, serviceName, perspectiveName):
113
 
        """Remove a key from my keyring.
114
 
 
115
 
        If this key is not present, raise KeyError.
116
 
        """
117
 
        del self.keyring[(serviceName, perspectiveName)]
118
 
 
119
 
    def save(self):
120
 
        """Persist this Identity to the authorizer.
121
 
        """
122
 
        return self.authorizer.addIdentity(self)
123
 
 
124
 
    ### Authentication Mechanisms
125
 
 
126
 
    def setPassword(self, plaintext):
127
 
        if plaintext is None:
128
 
            self.hashedPassword = None
129
 
        else:
130
 
            self.hashedPassword = md5.new(plaintext).digest()
131
 
 
132
 
    def setAlreadyHashedPassword(self, cyphertext):
133
 
        """(legacy) Set a password for this identity, already md5 hashed.
134
 
        """
135
 
        self.hashedPassword = cyphertext
136
 
 
137
 
    def challenge(self):
138
 
        """I return some random data.
139
 
 
140
 
        This is a method in addition to the module-level function
141
 
        because it is anticipated that we will want to change this
142
 
        to store salted passwords.
143
 
        """
144
 
        return challenge()
145
 
 
146
 
    def verifyPassword(self, challenge, hashedPassword):
147
 
        """Verify a challenge/response password.
148
 
        """
149
 
        req = defer.Deferred()
150
 
        if self.hashedPassword is None:
151
 
            # no password was set, so we can't log in
152
 
            req.errback(Unauthorized("account is disabled"))
153
 
            return req
154
 
        md = md5.new()
155
 
        md.update(self.hashedPassword)
156
 
        md.update(challenge)
157
 
        correct = md.digest()
158
 
        if hashedPassword == correct:
159
 
            req.callback("password verified")
160
 
        else:
161
 
            req.errback(Unauthorized("incorrect password"))
162
 
        return req
163
 
 
164
 
    def verifyPlainPassword(self, plaintext):
165
 
        """Verify plain text password.
166
 
 
167
 
        This is insecure, but necessary to support legacy protocols such
168
 
        as IRC, POP3, HTTP, etc.
169
 
        """
170
 
        req = defer.Deferred()
171
 
        if self.hashedPassword is None:
172
 
            # no password was set, so we can't log in
173
 
            req.errback(Unauthorized("account is disabled"))
174
 
            return req
175
 
        md = md5.new()
176
 
        md.update(plaintext)
177
 
        userPass = md.digest()
178
 
        if userPass == self.hashedPassword:
179
 
            req.callback("password verified")
180
 
        else:
181
 
            req.errback(Unauthorized("incorrect password"))
182
 
        return req
183
 
 
184
 
    def __repr__(self):
185
 
        return "<%s %r at 0x%x>" % (self.__class__, self.name, id(self))
186
 
 
187
 
 
188
 
    # TODO: service discovery through listing of self.keyring.