You are right, it is an accident that unicode can be encoded to base64. It just annoys me that the Python 2.6 error for this is "TypeError: character mapping must return integer, None or unicode".<br><br>In that case, how would you feel about updating PlainTextPasswordManager instead? It is not like the others because it won't work unless hash is a unicode<br>
<br>PlainTextPasswordManager().encodePassword(u"password") => unicode<br>PlainTextPasswordManager().checkPassword(unicode, unicode)<br><br>and the others break unless hash is always a str.<br><br>.encodePassword(u"password") => str<br>
.checkPassword(str, unicode)<br><br><br>Here's my DelegatingPasswordManager. I might update it so .encodePassword() uses the unnamed IPasswordManager if installed. It would be nice if IPasswordManager included the name of the scheme to go between {} before the hash proper.<br>
<br><span style="font-family: courier new,monospace;">class DelegatingPasswordManager(object):</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> """Check passwords stored RFC 2307 style as {scheme}hash.</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> </span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> Delegates to named IPasswordManager utilities."""</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> implements(IPasswordManager)</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> SCHEME = u"Delegating Password Manager"</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> _scheme = re.compile(r"^{(?P<scheme>[^}]*)}(?P<hash>.*)$")</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> def encodePassword(self, password):</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> raise NotImplementedError("DelegatingPasswordManager can only check passwords")</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> def checkPassword(self, encoded_password, password):</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> handler = None</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> match = self._scheme.match(encoded_password)</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> if not match:</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> raise ValueError("Encoded password must be formatted as {scheme}hash.")</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> try:</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> scheme = match.group("scheme")</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> handler = getUtility(IPasswordManager, scheme)</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> except zope.component.interfaces.ComponentLookupError, e:</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> raise LookupError("Handler for password encryption scheme {%s} not found." % scheme, e)</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> if handler != self:</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> return handler.checkPassword(encoded_password, password)</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> return False</span><br><br>