summaryrefslogtreecommitdiff
path: root/passlib/tests/test_handler.py
blob: 8668c3d04c912ee48ac9f741d11ae942864e6bac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
"""tests for passlib.pwhash -- (c) Assurance Technologies 2003-2009"""
#=========================================================
#imports
#=========================================================
from __future__ import with_statement
#core
import re
import hashlib
from logging import getLogger
#site
#pkg
from passlib.handler import CryptHandler
from passlib.tests.handler_utils import _HandlerTestCase
from passlib.utils import generate_h64_salt
#module
log = getLogger(__name__)

#=========================================================
#sample algorithms - these serve as known quantities
# to test the unittests themselves, as well as other
# parts of passlib
#=========================================================
class UnsaltedHash(CryptHandler):
    "example algorithm which lacks a salt [REALLY INSECURE - DO NOT USE]"
    name = "unsalted-example"
    #stats: 160 bit checksum, no salt

    @classmethod
    def identify(cls, hash):
        return bool(hash and re.match("^[0-9a-f]{40}$", hash))

    @classmethod
    def genhash(cls, secret, config):
        return hashlib.sha1("boblious" + secret).hexdigest()

class SaltedHash(CryptHandler):
    "example algorithm with a salt [REALLY INSECURE - DO NOT USE]"
    name = "salted-example"
    #stats: 160 bit checksum, 12 bit salt

    setting_kwds = ("salt",)

    @classmethod
    def identify(cls, hash):
        return bool(hash and re.match("^@salt[0-9a-zA-Z./]{2}[0-9a-f]{40}$", hash))

    @classmethod
    def _parse(cls, hash):
        if not cls.identify(hash):
            raise ValueError, "not a salted-example hash"
        return dict(
            salt=hash[5:7],
            checksum=hash[7:],
        )

    @classmethod
    def _render(cls, salt, checksum):
        assert len(salt) == 2
        assert len(checksum) == 40
        return "@salt%s%s" % (salt, checksum)

    @classmethod
    def genconfig(cls, salt=None):
        if not salt:
            salt = generate_h64_salt(2)
        return cls._render(salt[:2], '0' * 40)

    @classmethod
    def genhash(cls, secret, config):
        salt = cls._parse(config)['salt']
        checksum = hashlib.sha1(salt+secret).hexdigest()
        return cls._render(salt, checksum)

#=========================================================
#test sample algorithms
#=========================================================

#TODO: provide data samples for algorithms
# (positive knowns, negative knowns, invalid identify)

class UnsaltedHashTest(_HandlerTestCase):
    handler = UnsaltedHash

class SaltedHashTest(_HandlerTestCase):
    handler = SaltedHash

#=========================================================
#
#=========================================================

#TODO: test registry system

#=========================================================
#EOF
#=========================================================