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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
|
"""tests for passlib.hash -- (c) Assurance Technologies 2003-2009"""
# core
import sys
import warnings
from logging import getLogger
import pytest
import passlib.utils.handlers as uh
# site
# pkg
from passlib import exc, hash, registry
from passlib.registry import (
_unload_handler_name as unload_handler_name,
)
from passlib.registry import (
get_crypt_handler,
list_crypt_handlers,
register_crypt_handler,
register_crypt_handler_path,
)
from tests.utils import TestCase
# module
log = getLogger(__name__)
# =============================================================================
# dummy handlers
#
# NOTE: these are defined outside of test case
# since they're used by test_register_crypt_handler_path(),
# which needs them to be available as module globals.
# =============================================================================
class dummy_0(uh.StaticHandler):
name = "dummy_0"
class alt_dummy_0(uh.StaticHandler):
name = "dummy_0"
dummy_x = 1
class RegistryTest(TestCase):
descriptionPrefix = "passlib.registry"
def setUp(self):
super().setUp()
# backup registry state & restore it after test.
locations = dict(registry._locations)
handlers = dict(registry._handlers)
def restore():
registry._locations.clear()
registry._locations.update(locations)
registry._handlers.clear()
registry._handlers.update(handlers)
self.addCleanup(restore)
def test_hash_proxy(self):
"""test passlib.hash proxy object"""
# check dir works
dir(hash)
# check repr works
repr(hash)
# check non-existent attrs raise error
with pytest.raises(AttributeError):
getattr(hash, "fooey")
# GAE tries to set __loader__,
# make sure that doesn't call register_crypt_handler.
old = getattr(hash, "__loader__", None)
test = object()
hash.__loader__ = test
assert hash.__loader__ is test
if old is None:
del hash.__loader__
assert not hasattr(hash, "__loader__")
else:
hash.__loader__ = old
assert hash.__loader__ is old
# check storing attr calls register_crypt_handler
class dummy_1(uh.StaticHandler):
name = "dummy_1"
hash.dummy_1 = dummy_1
assert get_crypt_handler("dummy_1") is dummy_1
# check storing under wrong name results in error
with pytest.raises(ValueError):
setattr(hash, "dummy_1x", dummy_1)
def test_register_crypt_handler_path(self):
"""test register_crypt_handler_path()"""
# NOTE: this messes w/ internals of registry, shouldn't be used publically.
paths = registry._locations
# check namespace is clear
assert "dummy_0" not in paths
assert not hasattr(hash, "dummy_0")
# check invalid names are rejected
with pytest.raises(ValueError):
register_crypt_handler_path("dummy_0", ".test_registry")
with pytest.raises(ValueError):
register_crypt_handler_path(
"dummy_0",
__name__ + ":dummy_0:xxx",
)
with pytest.raises(ValueError):
register_crypt_handler_path(
"dummy_0",
__name__ + ":dummy_0.xxx",
)
# try lazy load
register_crypt_handler_path("dummy_0", __name__)
assert "dummy_0" in list_crypt_handlers()
assert "dummy_0" not in list_crypt_handlers(loaded_only=True)
assert hash.dummy_0 is dummy_0
assert "dummy_0" in list_crypt_handlers(loaded_only=True)
unload_handler_name("dummy_0")
# try lazy load w/ alt
register_crypt_handler_path("dummy_0", __name__ + ":alt_dummy_0")
assert hash.dummy_0 is alt_dummy_0
unload_handler_name("dummy_0")
# check lazy load w/ wrong type fails
register_crypt_handler_path("dummy_x", __name__)
with pytest.raises(TypeError):
get_crypt_handler("dummy_x")
# check lazy load w/ wrong name fails
register_crypt_handler_path("alt_dummy_0", __name__)
with pytest.raises(ValueError):
get_crypt_handler("alt_dummy_0")
unload_handler_name("alt_dummy_0")
# TODO: check lazy load which calls register_crypt_handler (warning should be issued)
sys.modules.pop("tests._test_bad_register", None)
register_crypt_handler_path("dummy_bad", "tests._test_bad_register")
with warnings.catch_warnings():
warnings.filterwarnings("ignore", "xxxxxxxxxx", DeprecationWarning)
h = get_crypt_handler("dummy_bad")
from tests import _test_bad_register as tbr
assert h is tbr.alt_dummy_bad
def test_register_crypt_handler(self):
"""test register_crypt_handler()"""
with pytest.raises(TypeError):
register_crypt_handler({})
with pytest.raises(ValueError):
register_crypt_handler(
type("x", (uh.StaticHandler,), dict(name=None)),
)
with pytest.raises(ValueError):
register_crypt_handler(
type("x", (uh.StaticHandler,), dict(name="AB_CD")),
)
with pytest.raises(ValueError):
register_crypt_handler(
type("x", (uh.StaticHandler,), dict(name="ab-cd")),
)
with pytest.raises(ValueError):
register_crypt_handler(
type("x", (uh.StaticHandler,), dict(name="ab__cd")),
)
with pytest.raises(ValueError):
register_crypt_handler(
type("x", (uh.StaticHandler,), dict(name="default")),
)
class dummy_1(uh.StaticHandler):
name = "dummy_1"
class dummy_1b(uh.StaticHandler):
name = "dummy_1"
assert "dummy_1" not in list_crypt_handlers()
register_crypt_handler(dummy_1)
register_crypt_handler(dummy_1)
assert get_crypt_handler("dummy_1") is dummy_1
with pytest.raises(KeyError):
register_crypt_handler(dummy_1b)
assert get_crypt_handler("dummy_1") is dummy_1
register_crypt_handler(dummy_1b, force=True)
assert get_crypt_handler("dummy_1") is dummy_1b
assert "dummy_1" in list_crypt_handlers()
def test_get_crypt_handler(self):
"""test get_crypt_handler()"""
class dummy_1(uh.StaticHandler):
name = "dummy_1"
# without available handler
with pytest.raises(KeyError):
get_crypt_handler("dummy_1")
assert get_crypt_handler("dummy_1", None) is None
# already loaded handler
register_crypt_handler(dummy_1)
assert get_crypt_handler("dummy_1") is dummy_1
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore",
"handler names should be lower-case, and use underscores instead of hyphens:.*",
UserWarning,
)
# already loaded handler, using incorrect name
assert get_crypt_handler("DUMMY-1") is dummy_1
# lazy load of unloaded handler, using incorrect name
register_crypt_handler_path("dummy_0", __name__)
assert get_crypt_handler("DUMMY-0") is dummy_0
# check system & private names aren't returned
from passlib import hash
hash.__dict__["_fake"] = "dummy"
for name in ["_fake", "__package__"]:
with pytest.raises(KeyError):
get_crypt_handler(name)
assert get_crypt_handler(name, None) is None
def test_list_crypt_handlers(self):
"""test list_crypt_handlers()"""
from passlib.registry import list_crypt_handlers
# check system & private names aren't returned
hash.__dict__["_fake"] = "dummy"
for name in list_crypt_handlers():
assert not name.startswith("_"), f"{name!r}: "
unload_handler_name("_fake")
def test_handlers(self):
"""verify we have tests for all builtin handlers"""
from passlib.registry import list_crypt_handlers
from tests.test_handlers import (
conditionally_available_hashes,
get_handler_case,
)
for name in list_crypt_handlers():
# skip some wrappers that don't need independant testing
if name.startswith("ldap_") and name[5:] in list_crypt_handlers():
continue
if name in ["roundup_plaintext"]:
continue
# check the remaining ones all have a handler
try:
assert get_handler_case(name)
except exc.MissingBackendError:
if (
name in conditionally_available_hashes
): # expected to fail on some setups
continue
raise
|