| 1 | import md5 |
|---|
| 2 | |
|---|
| 3 | from twisted.cred import credentials, error |
|---|
| 4 | from twisted.web2.auth.digest import IUsernameDigestHash |
|---|
| 5 | |
|---|
| 6 | from zope.interface import implements |
|---|
| 7 | |
|---|
| 8 | def makeHash(username, realm, password): |
|---|
| 9 | s = '%s:%s:%s' % (username, realm, password) |
|---|
| 10 | return md5.new(s).hexdigest() |
|---|
| 11 | |
|---|
| 12 | class BasicCredentials(credentials.UsernamePassword): |
|---|
| 13 | """Custom Basic Credentials, which support both plain and hashed checks.""" |
|---|
| 14 | |
|---|
| 15 | implements(credentials.IUsernamePassword, IUsernameDigestHash) |
|---|
| 16 | |
|---|
| 17 | def __init__(self, username, password, realm): |
|---|
| 18 | self.username = username |
|---|
| 19 | self.password = password |
|---|
| 20 | self.realm = realm |
|---|
| 21 | |
|---|
| 22 | def checkHash(self, digestHash): |
|---|
| 23 | return digestHash == makeHash(self.username, self.realm, self.password) |
|---|
| 24 | |
|---|
| 25 | |
|---|
| 26 | def decode(self, response, request): |
|---|
| 27 | try: |
|---|
| 28 | creds = (response + '===').decode('base64') |
|---|
| 29 | except Exception: |
|---|
| 30 | raise error.LoginFailed('Invalid credentials') |
|---|
| 31 | |
|---|
| 32 | creds = creds.split(':', 1) |
|---|
| 33 | if len(creds) == 2: |
|---|
| 34 | creds = BasicCredentials(creds[0], creds[1], self.realm) # our change |
|---|
| 35 | return creds |
|---|
| 36 | else: |
|---|
| 37 | raise error.LoginFailed('Invalid credentials') |
|---|
| 38 | |
|---|
| 39 | def tweak_BasicCredentialFactory(): |
|---|
| 40 | import new |
|---|
| 41 | from twisted.web2.auth.basic import BasicCredentialFactory |
|---|
| 42 | method = new.instancemethod(decode, None, BasicCredentialFactory) |
|---|
| 43 | BasicCredentialFactory.decode = method |
|---|