source: TracAccountManager/0.10/acct_mgr/pwhash.py @ 13

Last change on this file since 13 was 2, checked in by guillaume, 17 years ago

Ajout TracAccountManager en français

File size: 3.0 KB
Line 
1# -*- coding: utf8 -*-
2#
3# Copyright (C) 2007 Matthew Good <trac@matt-good.net>
4#
5# "THE BEER-WARE LICENSE" (Revision 42):
6# <trac@matt-good.net> wrote this file.  As long as you retain this notice you
7# can do whatever you want with this stuff. If we meet some day, and you think
8# this stuff is worth it, you can buy me a beer in return.   Matthew Good
9#
10# Author: Matthew Good <trac@matt-good.net>
11
12from binascii import hexlify
13import md5, sha
14
15from trac.core import *
16from trac.config import Option
17
18from md5crypt import md5crypt
19
20class IPasswordHashMethod(Interface):
21    def generate_hash(user, password):
22        pass
23
24    def test_hash(user, password, hash):
25        pass
26
27
28class HtPasswdHashMethod(Component):
29    implements(IPasswordHashMethod)
30
31    def generate_hash(self, user, password):
32        password = password.encode('utf-8')
33        return htpasswd(password)
34
35    def check_hash(self, user, password, hash):
36        password = password.encode('utf-8')
37        return hash == htpasswd(password, hash)
38
39
40class HtDigestHashMethod(Component):
41    implements(IPasswordHashMethod)
42
43    realm = Option('account-manager', 'htdigest_realm')
44
45    def generate_hash(self, user, password):
46        user,password,realm = _encode(user, password, self.realm)
47        return ':'.join([realm, htdigest(user, realm, password)])
48
49    def check_hash(self, user, password, hash):
50        user,password,realm = _encode(user, password, self.realm)
51        return hash == self.generate_hash(user, password)
52
53
54def _encode(*args):
55    return [a.encode('utf-8') for a in args]
56
57# check for the availability of the "crypt" module for checking passwords on
58# Unix-like platforms
59# MD5 is still used when adding/updating passwords
60try:
61    from crypt import crypt
62except ImportError:
63    crypt = None
64
65# os.urandom was added in Python 2.4
66# try to fall back on reading from /dev/urandom on older Python versions
67try:
68    from os import urandom
69except ImportError:
70    from random import randrange
71    def urandom(n):
72        return ''.join([chr(randrange(256)) for _ in xrange(n)])
73
74def salt():
75    s = ''
76    v = long(hexlify(urandom(4)), 16)
77    itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
78    for i in range(8):
79        s += itoa64[v & 0x3f]; v >>= 6
80    return s
81
82def htpasswd(password, salt_=None):
83# TODO need unit test of generating new hash
84    if salt_ is None:
85        salt_ = salt()
86        if crypt is None:
87            salt_ = '$apr1$' + salt_
88    if salt_.startswith('$apr1$'):
89        return md5crypt(password, salt_[6:].split('$')[0], '$apr1$')
90    elif salt_.startswith('{SHA}'):
91        return '{SHA}' + sha.new(password).digest().encode('base64')[:-1]
92    elif crypt is None:
93        # crypt passwords are only supported on Unix-like systems
94        raise NotImplementedError(u'Le module "crypt" n\'est pas disponible '
95                                  u'sur cette plateforme.')
96    else:
97        return crypt(password, salt_)
98
99def htdigest(user, realm, password):
100    p = ':'.join([user, realm, password])
101    return md5.new(p).hexdigest()
Note: See TracBrowser for help on using the repository browser.