Mercurial > p > roundup > code
comparison roundup/password.py @ 1356:83f33642d220 maint-0.5
[[Metadata associated with this commit was garbled during conversion from CVS
to Subversion.]]
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Thu, 09 Jan 2003 22:59:22 +0000 |
| parents | |
| children | 6d1af2e441f4 |
comparison
equal
deleted
inserted
replaced
| 1242:3d0158c8c32b | 1356:83f33642d220 |
|---|---|
| 1 # | |
| 2 # Copyright (c) 2001 Bizar Software Pty Ltd (http://www.bizarsoftware.com.au/) | |
| 3 # This module is free software, and you may redistribute it and/or modify | |
| 4 # under the same terms as Python, so long as this copyright message and | |
| 5 # disclaimer are retained in their original form. | |
| 6 # | |
| 7 # IN NO EVENT SHALL BIZAR SOFTWARE PTY LTD BE LIABLE TO ANY PARTY FOR | |
| 8 # DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING | |
| 9 # OUT OF THE USE OF THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE | |
| 10 # POSSIBILITY OF SUCH DAMAGE. | |
| 11 # | |
| 12 # BIZAR SOFTWARE PTY LTD SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | |
| 13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 14 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" | |
| 15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, | |
| 16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | |
| 17 # | |
| 18 # $Id: password.py,v 1.8 2002-12-18 23:57:09 richard Exp $ | |
| 19 | |
| 20 __doc__ = """ | |
| 21 Password handling (encoding, decoding). | |
| 22 """ | |
| 23 | |
| 24 import sha, re, string | |
| 25 try: | |
| 26 import crypt | |
| 27 except: | |
| 28 crypt = None | |
| 29 pass | |
| 30 | |
| 31 def encodePassword(plaintext, scheme, other=None): | |
| 32 '''Encrypt the plaintext password. | |
| 33 ''' | |
| 34 if plaintext is None: | |
| 35 plaintext = "" | |
| 36 if scheme == 'SHA': | |
| 37 s = sha.sha(plaintext).hexdigest() | |
| 38 elif scheme == 'crypt' and crypt is not None: | |
| 39 if other is not None: | |
| 40 salt = other[:2] | |
| 41 else: | |
| 42 saltchars = './0123456789'+string.letters | |
| 43 salt = random.choice(saltchars) + random.choice(saltchars) | |
| 44 s = crypt.crypt(plaintext, salt) | |
| 45 elif scheme == 'plaintext': | |
| 46 s = plaintext | |
| 47 else: | |
| 48 raise ValueError, 'Unknown encryption scheme "%s"'%scheme | |
| 49 return s | |
| 50 | |
| 51 class Password: | |
| 52 '''The class encapsulates a Password property type value in the database. | |
| 53 | |
| 54 The encoding of the password is one if None, 'SHA' or 'plaintext'. The | |
| 55 encodePassword function is used to actually encode the password from | |
| 56 plaintext. The None encoding is used in legacy databases where no | |
| 57 encoding scheme is identified. | |
| 58 | |
| 59 The scheme is stored with the encoded data in the database: | |
| 60 {scheme}data | |
| 61 | |
| 62 Example usage: | |
| 63 >>> p = Password('sekrit') | |
| 64 >>> p == 'sekrit' | |
| 65 1 | |
| 66 >>> p != 'not sekrit' | |
| 67 1 | |
| 68 >>> 'sekrit' == p | |
| 69 1 | |
| 70 >>> 'not sekrit' != p | |
| 71 1 | |
| 72 ''' | |
| 73 | |
| 74 default_scheme = 'SHA' # new encryptions use this scheme | |
| 75 pwre = re.compile(r'{(\w+)}(.+)') | |
| 76 | |
| 77 def __init__(self, plaintext=None, scheme=None): | |
| 78 '''Call setPassword if plaintext is not None.''' | |
| 79 if scheme is None: | |
| 80 scheme = self.default_scheme | |
| 81 if plaintext is not None: | |
| 82 self.password = encodePassword(plaintext, self.default_scheme) | |
| 83 self.scheme = self.default_scheme | |
| 84 else: | |
| 85 self.password = None | |
| 86 self.scheme = self.default_scheme | |
| 87 | |
| 88 def unpack(self, encrypted): | |
| 89 '''Set the password info from the scheme:<encryted info> string | |
| 90 (the inverse of __str__) | |
| 91 ''' | |
| 92 m = self.pwre.match(encrypted) | |
| 93 if m: | |
| 94 self.scheme = m.group(1) | |
| 95 self.password = m.group(2) | |
| 96 else: | |
| 97 # currently plaintext - encrypt | |
| 98 self.password = encodePassword(encrypted, self.default_scheme) | |
| 99 self.scheme = self.default_scheme | |
| 100 | |
| 101 def setPassword(self, plaintext, scheme=None): | |
| 102 '''Sets encrypts plaintext.''' | |
| 103 if scheme is None: | |
| 104 scheme = self.default_scheme | |
| 105 self.password = encodePassword(plaintext, scheme) | |
| 106 | |
| 107 def __cmp__(self, other): | |
| 108 '''Compare this password against another password.''' | |
| 109 # check to see if we're comparing instances | |
| 110 if isinstance(other, Password): | |
| 111 if self.scheme != other.scheme: | |
| 112 return cmp(self.scheme, other.scheme) | |
| 113 return cmp(self.password, other.password) | |
| 114 | |
| 115 # assume password is plaintext | |
| 116 if self.password is None: | |
| 117 raise ValueError, 'Password not set' | |
| 118 return cmp(self.password, encodePassword(other, self.scheme, | |
| 119 self.password)) | |
| 120 | |
| 121 def __str__(self): | |
| 122 '''Stringify the encrypted password for database storage.''' | |
| 123 if self.password is None: | |
| 124 raise ValueError, 'Password not set' | |
| 125 return '{%s}%s'%(self.scheme, self.password) | |
| 126 | |
| 127 def test(): | |
| 128 # SHA | |
| 129 p = Password('sekrit') | |
| 130 assert p == 'sekrit' | |
| 131 assert p != 'not sekrit' | |
| 132 assert 'sekrit' == p | |
| 133 assert 'not sekrit' != p | |
| 134 | |
| 135 # crypt | |
| 136 p = Password('sekrit', 'crypt') | |
| 137 assert p == 'sekrit' | |
| 138 assert p != 'not sekrit' | |
| 139 assert 'sekrit' == p | |
| 140 assert 'not sekrit' != p | |
| 141 | |
| 142 if __name__ == '__main__': | |
| 143 test() | |
| 144 | |
| 145 # vim: set filetype=python ts=4 sw=4 et si |
