| OLD | NEW |
| (Empty) |
| 1 # -*- test-case-name: twisted.test.test_newcred-*- | |
| 2 | |
| 3 # Copyright (c) 2001-2008 Twisted Matrix Laboratories. | |
| 4 # See LICENSE for details. | |
| 5 | |
| 6 | |
| 7 from zope.interface import implements, Interface | |
| 8 | |
| 9 import hmac | |
| 10 import time | |
| 11 import random | |
| 12 | |
| 13 | |
| 14 | |
| 15 class ICredentials(Interface): | |
| 16 """ | |
| 17 I check credentials. | |
| 18 | |
| 19 Implementors _must_ specify which sub-interfaces of ICredentials | |
| 20 to which it conforms, using zope.interface.implements(). | |
| 21 """ | |
| 22 | |
| 23 | |
| 24 | |
| 25 class IUsernameHashedPassword(ICredentials): | |
| 26 """ | |
| 27 I encapsulate a username and a hashed password. | |
| 28 | |
| 29 This credential is used when a hashed password is received from the | |
| 30 party requesting authentication. CredentialCheckers which check this | |
| 31 kind of credential must store the passwords in plaintext (or as | |
| 32 password-equivalent hashes) form so that they can be hashed in a manner | |
| 33 appropriate for the particular credentials class. | |
| 34 | |
| 35 @type username: C{str} | |
| 36 @ivar username: The username associated with these credentials. | |
| 37 """ | |
| 38 | |
| 39 def checkPassword(password): | |
| 40 """Validate these credentials against the correct password. | |
| 41 | |
| 42 @param password: The correct, plaintext password against which to | |
| 43 check. | |
| 44 | |
| 45 @return: a deferred which becomes, or a boolean indicating if the | |
| 46 password matches. | |
| 47 """ | |
| 48 | |
| 49 | |
| 50 | |
| 51 class IUsernamePassword(ICredentials): | |
| 52 """ | |
| 53 I encapsulate a username and a plaintext password. | |
| 54 | |
| 55 This encapsulates the case where the password received over the network | |
| 56 has been hashed with the identity function (That is, not at all). The | |
| 57 CredentialsChecker may store the password in whatever format it desires, | |
| 58 it need only transform the stored password in a similar way before | |
| 59 performing the comparison. | |
| 60 | |
| 61 @type username: C{str} | |
| 62 @ivar username: The username associated with these credentials. | |
| 63 | |
| 64 @type password: C{str} | |
| 65 @ivar password: The password associated with these credentials. | |
| 66 """ | |
| 67 | |
| 68 def checkPassword(password): | |
| 69 """Validate these credentials against the correct password. | |
| 70 | |
| 71 @param password: The correct, plaintext password against which to | |
| 72 check. | |
| 73 | |
| 74 @return: a deferred which becomes, or a boolean indicating if the | |
| 75 password matches. | |
| 76 """ | |
| 77 | |
| 78 | |
| 79 | |
| 80 class IAnonymous(ICredentials): | |
| 81 """ | |
| 82 I am an explicitly anonymous request for access. | |
| 83 """ | |
| 84 | |
| 85 | |
| 86 | |
| 87 class CramMD5Credentials: | |
| 88 implements(IUsernameHashedPassword) | |
| 89 | |
| 90 challenge = '' | |
| 91 response = '' | |
| 92 | |
| 93 def __init__(self, host=None): | |
| 94 self.host = host | |
| 95 | |
| 96 def getChallenge(self): | |
| 97 if self.challenge: | |
| 98 return self.challenge | |
| 99 # The data encoded in the first ready response contains an | |
| 100 # presumptively arbitrary string of random digits, a timestamp, and | |
| 101 # the fully-qualified primary host name of the server. The syntax of | |
| 102 # the unencoded form must correspond to that of an RFC 822 'msg-id' | |
| 103 # [RFC822] as described in [POP3]. | |
| 104 # -- RFC 2195 | |
| 105 r = random.randrange(0x7fffffff) | |
| 106 t = time.time() | |
| 107 self.challenge = '<%d.%d@%s>' % (r, t, self.host) | |
| 108 return self.challenge | |
| 109 | |
| 110 def setResponse(self, response): | |
| 111 self.username, self.response = response.split(None, 1) | |
| 112 | |
| 113 def moreChallenges(self): | |
| 114 return False | |
| 115 | |
| 116 def checkPassword(self, password): | |
| 117 verify = hmac.HMAC(password, self.challenge).hexdigest() | |
| 118 return verify == self.response | |
| 119 | |
| 120 | |
| 121 class UsernameHashedPassword: | |
| 122 implements(IUsernameHashedPassword) | |
| 123 | |
| 124 def __init__(self, username, hashed): | |
| 125 self.username = username | |
| 126 self.hashed = hashed | |
| 127 | |
| 128 def checkPassword(self, password): | |
| 129 return self.hashed == password | |
| 130 | |
| 131 | |
| 132 class UsernamePassword: | |
| 133 implements(IUsernamePassword) | |
| 134 | |
| 135 def __init__(self, username, password): | |
| 136 self.username = username | |
| 137 self.password = password | |
| 138 | |
| 139 def checkPassword(self, password): | |
| 140 return self.password == password | |
| 141 | |
| 142 | |
| 143 class Anonymous: | |
| 144 implements(IAnonymous) | |
| 145 | |
| 146 | |
| 147 | |
| 148 class ISSHPrivateKey(ICredentials): | |
| 149 """ | |
| 150 I encapsulate an SSH public key to be checked against a users private | |
| 151 key. | |
| 152 | |
| 153 @ivar username: Duh? | |
| 154 | |
| 155 @ivar algName: The algorithm name for the blob. | |
| 156 | |
| 157 @ivar blob: The public key blob as sent by the client. | |
| 158 | |
| 159 @ivar sigData: The data the signature was made from. | |
| 160 | |
| 161 @ivar signature: The signed data. This is checked to verify that the user | |
| 162 owns the private key. | |
| 163 """ | |
| 164 | |
| 165 | |
| 166 | |
| 167 class SSHPrivateKey: | |
| 168 implements(ISSHPrivateKey) | |
| 169 def __init__(self, username, algName, blob, sigData, signature): | |
| 170 self.username = username | |
| 171 self.algName = algName | |
| 172 self.blob = blob | |
| 173 self.sigData = sigData | |
| 174 self.signature = signature | |
| 175 | |
| 176 | |
| 177 class IPluggableAuthenticationModules(ICredentials): | |
| 178 """I encapsulate the authentication of a user via PAM (Pluggable | |
| 179 Authentication Modules. I use PyPAM (available from | |
| 180 http://www.tummy.com/Software/PyPam/index.html). | |
| 181 | |
| 182 @ivar username: The username for the user being logged in. | |
| 183 | |
| 184 @ivar pamConversion: A function that is called with a list of tuples | |
| 185 (message, messageType). See the PAM documentation | |
| 186 for the meaning of messageType. The function | |
| 187 returns a Deferred which will fire with a list | |
| 188 of (response, 0), one for each message. The 0 is | |
| 189 currently unused, but is required by the PAM library. | |
| 190 """ | |
| 191 | |
| 192 class PluggableAuthenticationModules: | |
| 193 implements(IPluggableAuthenticationModules) | |
| 194 | |
| 195 def __init__(self, username, pamConversion): | |
| 196 self.username = username | |
| 197 self.pamConversion = pamConversion | |
| 198 | |
| OLD | NEW |