summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Collins <elic@assurancetechnologies.com>2012-04-17 21:58:54 -0400
committerEli Collins <elic@assurancetechnologies.com>2012-04-17 21:58:54 -0400
commit2ad8463a456796300df5340a2bc511e290e62072 (patch)
tree116a85776ae75ecde4c72c29b12c13d777b53c0f
parentceb7a00ddae502624d609bc63a9048f0de9f1b23 (diff)
downloadpasslib-2ad8463a456796300df5340a2bc511e290e62072.tar.gz
disabling saslprep() support under Jython - it lacks the stringprep module
-rw-r--r--docs/lib/passlib.context-options.rst5
-rw-r--r--passlib/tests/test_context.py2
-rw-r--r--passlib/tests/test_context_deprecated.py56
-rw-r--r--passlib/tests/test_handlers.py6
-rw-r--r--passlib/tests/test_utils.py1
-rw-r--r--passlib/tests/utils.py7
-rw-r--r--passlib/utils/__init__.py31
-rw-r--r--passlib/utils/compat.py6
8 files changed, 51 insertions, 63 deletions
diff --git a/docs/lib/passlib.context-options.rst b/docs/lib/passlib.context-options.rst
index 36cb89e..ece9033 100644
--- a/docs/lib/passlib.context-options.rst
+++ b/docs/lib/passlib.context-options.rst
@@ -169,6 +169,11 @@ and :samp:`{option}` is the name of the specific options being set.
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/tests/test_context.py b/passlib/tests/test_context.py
index b1c7828..d039ac6 100644
--- a/passlib/tests/test_context.py
+++ b/passlib/tests/test_context.py
@@ -1263,6 +1263,8 @@ sha512_crypt__min_rounds = 45000
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
diff --git a/passlib/tests/test_context_deprecated.py b/passlib/tests/test_context_deprecated.py
index e6aaffa..f6d33d8 100644
--- a/passlib/tests/test_context_deprecated.py
+++ b/passlib/tests/test_context_deprecated.py
@@ -1105,62 +1105,6 @@ class CryptContextTest(TestCase):
res = ctx.verify_and_update(PASS1, BAD1)
self.assertTrue(res[0] and res[1] and res[1] != BAD1)
- def test_91_passprep(self):
- "test passprep option"
- # 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")))
-
#=========================================================
#eoc
#=========================================================
diff --git a/passlib/tests/test_handlers.py b/passlib/tests/test_handlers.py
index d045e94..102a3dc 100644
--- a/passlib/tests/test_handlers.py
+++ b/passlib/tests/test_handlers.py
@@ -1919,9 +1919,13 @@ class scram_test(HandlerCase):
'$scram$4096$QSXCR.Q6sek8bf92$sha1=HZbuOlKbWl.eR8AfIposuKbhX30',
]
- # silence norm_hash_name() warning
def setUp(self):
super(scram_test, self).setUp()
+
+ # some platforms lack stringprep (e.g. Jython, IronPython)
+ self.require_stringprep()
+
+ # silence norm_hash_name() warning
warnings.filterwarnings("ignore", r"norm_hash_name\(\): unknown hash")
def test_90_algs(self):
diff --git a/passlib/tests/test_utils.py b/passlib/tests/test_utils.py
index 001524d..a468ecf 100644
--- a/passlib/tests/test_utils.py
+++ b/passlib/tests/test_utils.py
@@ -295,6 +295,7 @@ class MiscTest(TestCase):
def test_saslprep(self):
"test saslprep() unicode normalizer"
+ self.require_stringprep()
from passlib.utils import saslprep as sp
# invalid types
diff --git a/passlib/tests/utils.py b/passlib/tests/utils.py
index eb8f3a7..ba439b7 100644
--- a/passlib/tests/utils.py
+++ b/passlib/tests/utils.py
@@ -505,6 +505,13 @@ class TestCase(unittest.TestCase):
msg = "error for case %r:" % (elem.render(1),)
self.assertEqual(result, correct, msg)
+ def require_stringprep(self):
+ "helper to skip test if stringprep is missing"
+ from passlib.utils import stringprep
+ if not stringprep:
+ from passlib.utils import _stringprep_missing_reason
+ raise self.skipTest("not available - stringprep module is " +
+ _stringprep_missing_reason)
#============================================================
#eoc
#============================================================
diff --git a/passlib/utils/__init__.py b/passlib/utils/__init__.py
index d2fe9a5..dc89e4d 100644
--- a/passlib/utils/__init__.py
+++ b/passlib/utils/__init__.py
@@ -2,6 +2,7 @@
#=============================================================================
#imports
#=============================================================================
+from passlib.utils.compat import PYPY, JYTHON
#core
from base64 import b64encode, b64decode
from codecs import lookup as _lookup_codec
@@ -11,9 +12,19 @@ import math
import os
import sys
import random
-import stringprep
+if JYTHON:
+ # Jython 2.5.2 lacks stringprep module -
+ # see http://bugs.jython.org/issue1758320
+ try:
+ import stringprep
+ except ImportError:
+ stringprep = None
+ _stringprep_missing_reason = "not present under Jython"
+else:
+ import stringprep
import time
-import unicodedata
+if stringprep:
+ import unicodedata
from warnings import warn
#site
#pkg
@@ -79,10 +90,6 @@ __all__ = [
# constants
#=================================================================================
-# Python VM identification
-PYPY = hasattr(sys, "pypy_version_info")
-JYTHON = sys.platform.startswith('java')
-
# bitsize of system architecture (32 or 64)
sys_bits = int(math.log(sys.maxsize if PY3 else sys.maxint, 2) + 1.5)
@@ -371,6 +378,11 @@ def saslprep(source, errname="value"):
:returns:
normalized unicode string
+
+ .. note::
+
+ Due to a missing :mod:`!stringprep` module, this feature
+ is not available on Jython.
"""
# saslprep - http://tools.ietf.org/html/rfc4013
# stringprep - http://tools.ietf.org/html/rfc3454
@@ -460,6 +472,13 @@ def saslprep(source, errname="value"):
return data
+# replace saslprep() with stub when stringprep is missing
+if stringprep is None:
+ def saslprep(source, errname="value"):
+ "stub for saslprep()"
+ raise NotImplementedError("saslprep() support requires the 'stringprep' "
+ "module, which is " + _stringprep_missing_reason)
+
#=============================================================================
# bytes helpers
#=============================================================================
diff --git a/passlib/utils/compat.py b/passlib/utils/compat.py
index 77f9c3c..1d88f75 100644
--- a/passlib/utils/compat.py
+++ b/passlib/utils/compat.py
@@ -10,6 +10,12 @@ PY27 = sys.version_info[:2] == (2,7) # supports last 2.x release
PY_MIN_32 = sys.version_info >= (3,2) # py 3.2 or later
#=============================================================================
+# figure out what VM we're running
+#=============================================================================
+PYPY = hasattr(sys, "pypy_version_info")
+JYTHON = sys.platform.startswith('java')
+
+#=============================================================================
# common imports
#=============================================================================
import logging; log = logging.getLogger(__name__)