summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Collins <elic@assurancetechnologies.com>2012-04-27 00:53:47 -0400
committerEli Collins <elic@assurancetechnologies.com>2012-04-27 00:53:47 -0400
commit84d84151a162ad4bac5a9261aff94d0076529177 (patch)
treebc544d008f609b560404cbae226635633bea0dc6
parent03964d1fce1720413498dbb537acc52ba3321566 (diff)
downloadpasslib-84d84151a162ad4bac5a9261aff94d0076529177.tar.gz
stripping out "passprep" feature - code was working, but the api isn't read for release. will adjust issue 24.
-rw-r--r--CHANGES5
-rw-r--r--docs/lib/passlib.context-options.rst36
-rw-r--r--passlib/apps.py5
-rw-r--r--passlib/context.py62
-rw-r--r--passlib/tests/test_context.py58
5 files changed, 2 insertions, 164 deletions
diff --git a/CHANGES b/CHANGES
index 4e6f7a2..7cfab56 100644
--- a/CHANGES
+++ b/CHANGES
@@ -68,11 +68,6 @@ Release History
.. currentmodule:: passlib.context
- * :class:`~CryptContext` now supports a :ref:`passprep <passprep>` option,
- which can be used to run all passwords through SASLPrep (:rfc:`4013`),
- in order to normalize their unicode representation before hashing
- [issue 24].
-
* The :class:`!CryptContext` option
:ref:`min_verify_time <min-verify-time>` has been deprecated,
will be ignored in release 1.7, and will be removed in release 1.8.
diff --git a/docs/lib/passlib.context-options.rst b/docs/lib/passlib.context-options.rst
index ece9033..52146a4 100644
--- a/docs/lib/passlib.context-options.rst
+++ b/docs/lib/passlib.context-options.rst
@@ -138,42 +138,6 @@ and :samp:`{option}` is the name of the specific options being set.
These are configurable per-context limits,
they will be clipped by any hard limits set in the hash algorithm itself.
-.. _passprep:
-
-:samp:`{hash}__passprep`
-
- Normalize unicode passwords before passing them to the underlying
- hash algorithm. This is primarily useful if users are likely
- to use non-ascii characters in their password (e.g. vowels characters
- with accent marks), which unicode offers multiple representations for.
-
- This may be one of the following values:
-
- * ``"raw"`` - use all unicode inputs as-is (the default).
- unnormalized unicode input may not verify against a hash
- generated from normalized unicode input (or vice versa).
-
- * ``"saslprep"`` - run all passwords through the SASLPrep
- unicode normalization algorithm (:rfc:`4013`) before hashing.
- this is recommended for new deployments, particularly
- in non-ascii environments.
-
- * ``"saslprep,raw"`` - compatibility mode: encryption of new passwords
- will be run through SASLPrep; but verification will be done
- against the SASLPrep *and* raw versions of the password. This allows
- existing hashes that were generated from unnormalized input
- to continue to work.
-
- .. note::
-
- It is recommended to set this for all hashes via ``all__passprep``,
- instead of settings it per algorithm.
-
- .. note::
-
- Due to a missing :mod:`!stringprep` module, this feature
- is not available on Jython.
-
:samp:`{hash}__{setting}`
Any other option values, which match the name of a parameter listed
diff --git a/passlib/apps.py b/passlib/apps.py
index 017de7e..9bb4a64 100644
--- a/passlib/apps.py
+++ b/passlib/apps.py
@@ -29,11 +29,6 @@ custom_app_context = LazyCryptContext(
#choose some reasonbly strong schemes
schemes=["sha512_crypt", "sha256_crypt"],
- # TODO: enable passprep for default policy? would definitely be a good
- # idea for most applications; but want passprep to get a release or
- # two worth of deployment & feedback before turning it on here.
- ## all__passprep = "saslprep,raw",
-
#set some useful global options
all__vary_rounds = "10%",
default="sha256_crypt" if sys_bits < 64 else "sha512_crypt",
diff --git a/passlib/context.py b/passlib/context.py
index 3d14238..57b1646 100644
--- a/passlib/context.py
+++ b/passlib/context.py
@@ -18,7 +18,7 @@ from warnings import warn
#libs
from passlib.exc import PasslibConfigWarning, ExpectedStringError, ExpectedTypeError
from passlib.registry import get_crypt_handler, _validate_handler_name
-from passlib.utils import is_crypt_handler, rng, saslprep, tick, to_bytes, \
+from passlib.utils import is_crypt_handler, rng, tick, to_bytes, \
to_unicode
from passlib.utils.compat import bytes, iteritems, num_types, \
PY3, PY_MIN_32, unicode, SafeConfigParser, \
@@ -62,12 +62,6 @@ _coerce_scheme_options = dict(
salt_size=int,
)
-# dict mapping passprep policy name -> implementation
-_passprep_funcs = dict(
- saslprep=saslprep,
- raw=lambda s: s,
-)
-
def _splitcomma(source):
"split comma-separated string into list of strings"
source = source.strip()
@@ -643,7 +637,7 @@ class _CryptRecord(object):
#================================================================
def __init__(self, handler, category=None, deprecated=False,
min_rounds=None, max_rounds=None, default_rounds=None,
- vary_rounds=None, min_verify_time=None, passprep=None,
+ vary_rounds=None, min_verify_time=None,
**settings):
# store basic bits
self.handler = handler
@@ -664,9 +658,6 @@ class _CryptRecord(object):
self.identify = handler.identify
self.genhash = handler.genhash
- # let stringprep code wrap genhash/encrypt/verify if needed
- self._init_passprep(passprep)
-
#================================================================
# virtual attrs
#================================================================
@@ -991,55 +982,6 @@ class _CryptRecord(object):
return False
#================================================================
- # password stringprep
- #================================================================
- def _init_passprep(self, value):
- # NOTE: all of this code assumes secret uses utf-8 encoding if bytes.
- if not value:
- return
- self._stringprep = value
- names = _splitcomma(value)
- if names == ["raw"]:
- return
- funcs = [_passprep_funcs[name] for name in names]
-
- first = funcs[0]
- def wrap(orig):
- def wrapper(secret, *args, **kwds):
- if isinstance(secret, bytes):
- secret = secret.decode("utf-8")
- return orig(first(secret), *args, **kwds)
- update_wrapper(wrapper, orig)
- wrapper._wrapped = orig
- return wrapper
-
- # wrap genhash & encrypt so secret is prep'd
- self.genhash = wrap(self.genhash)
- self.encrypt = wrap(self.encrypt)
-
- # wrap verify so secret is prep'd
- if len(funcs) == 1:
- self.verify = wrap(self.verify)
- else:
- # if multiple fallback prep functions,
- # try to verify with each of them.
- verify = self.verify
- def wrapper(secret, *args, **kwds):
- if isinstance(secret, bytes):
- secret = secret.decode("utf-8")
- seen = set()
- for prep in funcs:
- tmp = prep(secret)
- if tmp not in seen:
- if verify(tmp, *args, **kwds):
- return True
- seen.add(tmp)
- return False
- update_wrapper(wrapper, verify)
- wrapper._wrapped = verify
- self.verify = wrapper
-
- #================================================================
# eoc
#================================================================
diff --git a/passlib/tests/test_context.py b/passlib/tests/test_context.py
index 2abbccf..20b6dc6 100644
--- a/passlib/tests/test_context.py
+++ b/passlib/tests/test_context.py
@@ -1266,64 +1266,6 @@ sha512_crypt__min_rounds = 45000
self.assertAlmostEqual(elapsed, max_delay, delta=delta)
self.consumeWarningList(wlog, ".*verify exceeded min_verify_time")
- def test_61_passprep(self):
- "test passprep option"
- self.require_stringprep()
-
- # saslprep should normalize pu -> pn
- pu = u("a\u0300") # unnormalized unicode
- pn = u("\u00E0") # normalized unicode
-
- # create contexts w/ various options
- craw = CryptContext(["md5_crypt"])
- cnorm = CryptContext(["md5_crypt"], all__passprep="saslprep")
- cback = CryptContext(["md5_crypt"], all__passprep="saslprep,raw")
- clst = [craw,cnorm,cback]
-
- # check raw encrypt against verify methods
- h = craw.encrypt(pu)
-
- self.assertTrue(craw.verify(pu, h))
- self.assertFalse(cnorm.verify(pu, h))
- self.assertTrue(cback.verify(pu, h))
-
- self.assertFalse(craw.verify(pn, h))
- self.assertFalse(craw.verify(pn, h))
- self.assertFalse(craw.verify(pn, h))
-
- # check normalized encrypt against verify methods
- for ctx in [cnorm, cback]:
- h = ctx.encrypt(pu)
-
- self.assertFalse(craw.verify(pu, h))
- self.assertTrue(cnorm.verify(pu, h))
- self.assertTrue(cback.verify(pu, h))
-
- for ctx2 in clst:
- self.assertTrue(ctx2.verify(pn, h))
-
- # check all encrypts leave normalized input alone
- for ctx in clst:
- h = ctx.encrypt(pn)
-
- self.assertFalse(craw.verify(pu, h))
- self.assertTrue(cnorm.verify(pu, h))
- self.assertTrue(cback.verify(pu, h))
-
- for ctx2 in clst:
- self.assertTrue(ctx2.verify(pn, h))
-
- # test invalid name
- self.assertRaises(KeyError, CryptContext, ["md5_crypt"],
- all__passprep="xxx")
-
- # test per-hash passprep
- ctx = CryptContext(["md5_crypt", "sha256_crypt"],
- all__passprep="raw", sha256_crypt__passprep="saslprep",
- )
- self.assertFalse(ctx.verify(pu, ctx.encrypt(pn, scheme="md5_crypt")))
- self.assertTrue(ctx.verify(pu, ctx.encrypt(pn, scheme="sha256_crypt")))
-
#=========================================================
# handler deprecation detectors
#=========================================================