diff options
| author | Eli Collins <elic@assurancetechnologies.com> | 2011-12-27 13:38:52 -0500 |
|---|---|---|
| committer | Eli Collins <elic@assurancetechnologies.com> | 2011-12-27 13:38:52 -0500 |
| commit | 73aefa5cdca69e1daf4297d8176d4a99434d33a2 (patch) | |
| tree | 02cbd77b307ed011305db063d56430c82c5cbcd2 /admin | |
| parent | 966116ab976e76863d0105bd1b4682d18436078f (diff) | |
| download | passlib-73aefa5cdca69e1daf4297d8176d4a99434d33a2.tar.gz | |
CryptPolicy rewrite part 2
* refactoring policy kwd parsing & separation with crypt context
* internal record objects now part of context instead of policy.
* min_verify_time now handled by record objects, now optimized away entirely if not used.
* new interface to policy is currently private, will probably delay deprecated / revising
public interface until next release.
* creating policy & context objects is now 30% faster.
* shortened code path when calling context objects now 14% faster.
Diffstat (limited to 'admin')
| -rw-r--r-- | admin/benchmarks.py | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/admin/benchmarks.py b/admin/benchmarks.py new file mode 100644 index 0000000..e1503fd --- /dev/null +++ b/admin/benchmarks.py @@ -0,0 +1,158 @@ +"""admin/benchmarks - misc timing tests + +this is a *very* rough benchmark script hacked together when the context +parsing was being sped up. it could definitely be improved. +""" +#============================================================================= +# init app env +#============================================================================= +import os, sys +sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.path.pardir)) + +#============================================================================= +# imports +#============================================================================= +# core +import logging; log = logging.getLogger(__name__) +from timeit import Timer +import warnings +# site +# pkg +try: + from passlib.utils import PasslibPolicyWarning +except ImportError: + PasslibPolicyWarning = None +from passlib.utils import handlers as uh +# local +__all__ = [ +] + +#============================================================================= +# utils +#============================================================================= + +class BlankHandler(uh.HasRounds, uh.HasSalt, uh.GenericHandler): + + setting_kwds = ("rounds", "salt", "salt_size") + name = "blank" + ident = u"$b$" + + checksum_size = 1 + min_salt_size = max_salt_size = 1 + salt_chars = u"a" + + min_rounds = 1000 + max_rounds = 3000 + default_rounds = 2000 + + @classmethod + def from_string(cls, hash): + r,s,c = uh.parse_mc3(hash, cls.ident, cls.name) + r = int(r) + return cls(rounds=r, salt=s, checksum=c, strict=bool(c)) + + def to_string(self): + return uh.render_mc3(self.ident, self.rounds, self.salt, self.checksum) + + def calc_checksum(self, password): + return unicode(password[0:1]) + +class AnotherHandler(BlankHandler): + name = "another" + ident = u"$a$" + +#============================================================================= +# crypt context tests +#============================================================================= +def setup_policy(): + import os + from passlib.context import _load_default_policy, CryptPolicy, \ + __file__ as mpath + cpath = os.path.abspath(os.path.join(os.path.dirname(mpath), "default.cfg")) + + def test_policy_creation(): + with file(cpath, "rb") as fh: + policy1 = CryptPolicy.from_string(fh.read()) + yield test_policy_creation + + default = _load_default_policy() + def test_policy_composition(): + policy2 = CryptPolicy( + policy=default, + schemes = [ "sha512_crypt", "sha256_crypt", "md5_crypt", + "des_crypt", "unix_fallback" ], + deprecated = [ "des_crypt" ], + ) + yield test_policy_composition + +def setup_context(): + from passlib.context import CryptContext + + def test_context_init(): + return CryptContext( + schemes=[BlankHandler, AnotherHandler], + default="another", + blank__min_rounds=1500, + blank__max_rounds=2500, + another__vary_rounds=100, + ) + yield test_context_init + + ctx = test_context_init() + secret = u"secret" + other = u"other" +# if PasslibPolicyWarning: +# warnings.filterwarnings("ignore", category=PasslibPolicyWarning) + def test_context_calls(): + hash = ctx.encrypt(secret, rounds=2001) + ctx.verify(secret, hash) + ctx.verify_and_update(secret, hash) + ctx.verify_and_update(other, hash) + yield test_context_calls + +#============================================================================= +# main +#============================================================================= +def pptime(secs): + precision = 3 + usec = int(secs * 1e6) + if usec < 1000: + return "%.*g usec" % (precision, usec) + msec = usec / 1000 + if msec < 1000: + return "%.*g msec" % (precision, msec) + sec = msec / 1000 + return "%.*g sec" % (precision, sec) + +def main(*args): + names = args + source = globals() + for key in sorted(source): + if not key.startswith("setup_"): + continue + sname = key[6:] + setup = source[key] + for test in setup(): + name = test.__name__ + if name.startswith("test_"): + name = name[5:] + if names and name not in names: + continue + timer = Timer(test) + number = 1 + while True: + t = timer.timeit(number) + if t > .2: + break + number *= 10 + repeat = 3 + best = min(timer.repeat(repeat, number)) / number + print "%30s %s" % (name, pptime(best)) + +if __name__ == "__main__": + import sys + main(*sys.argv[1:]) + +#============================================================================= +# eof +#============================================================================= |
