Projet

Général

Profil

0001-misc-add-support-for-passwords-hashed-by-Plone-29430.patch

Frédéric Péters, 03 janvier 2019 16:26

Télécharger (3,47 ko)

Voir les différences:

Subject: [PATCH] misc: add support for passwords hashed by Plone (#29430)

 src/authentic2/hashers.py  | 46 ++++++++++++++++++++++++++++++++++++++
 src/authentic2/settings.py |  3 ++-
 tests/test_hashers.py      |  7 ++++++
 3 files changed, 55 insertions(+), 1 deletion(-)
src/authentic2/hashers.py
235 235
            return '%s:%s' % (_hash, salt.decode('hex'))
236 236
        else:
237 237
            return _hash
238

  
239

  
240
class PloneSHA1PasswordHasher(hashers.SHA1PasswordHasher):
241
    # from https://www.fourdigits.nl/blog/converting-plone-data-to-django/
242
    """
243
    The SHA1 password hashing algorithm used by Plone.
244

  
245
    Plone uses `password + salt`, Django has `salt + password`.
246
    """
247

  
248
    algorithm = "plonesha1"
249
    _prefix = '{SSHA}'
250

  
251
    def encode(self, password, salt):
252
        """Encode a plain text password into a plonesha1 style hash."""
253
        assert password is not None
254
        assert salt
255
        password = force_bytes(password)
256
        salt = force_bytes(salt)
257

  
258
        hashed = base64.b64encode(hashlib.sha1(password + salt).digest() + salt)
259
        return "%s$%s%s" % (self.algorithm, self._prefix, hashed)
260

  
261
    def verify(self, password, encoded):
262
        """Verify the given password against the encoded string."""
263
        algorithm, data = encoded.split('$', 1)
264
        assert algorithm == self.algorithm
265

  
266
        # throw away the prefix
267
        if data.startswith(self._prefix):
268
            data = data[len(self._prefix):]
269

  
270
        # extract salt from encoded data
271
        intermediate = base64.b64decode(data)
272
        salt = intermediate[20:].strip()
273

  
274
        password_encoded = self.encode(password, salt)
275
        return constant_time_compare(password_encoded, encoded)
276

  
277
    def safe_summary(self, encoded):
278
        algorithm, hash = encoded.split('$', 1)
279
        assert algorithm == self.algorithm
280
        return OrderedDict([
281
            (_('algorithm'), algorithm),
282
            (_('hash'), hashers.mask_hash(hash)),
283
        ])
src/authentic2/settings.py
191 191
        'authentic2.hashers.SSHA1PasswordHasher',
192 192
        'authentic2.hashers.SMD5PasswordHasher',
193 193
        'authentic2.hashers.SHA1OLDAPPasswordHasher',
194
        'authentic2.hashers.MD5OLDAPPasswordHasher'
194
        'authentic2.hashers.MD5OLDAPPasswordHasher',
195
        'authentic2.hashers.PloneSHA1PasswordHasher',
195 196
]
196 197

  
197 198
# Admin tools
tests/test_hashers.py
30 30

  
31 31
    assert hashers.JoomlaPasswordHasher().verify(pwd, dj_encoded)
32 32
    assert hashers.JoomlaPasswordHasher.to_joomla(dj_encoded) == encoded
33

  
34

  
35
def test_plone_hasher():
36
    hasher = hashers.PloneSHA1PasswordHasher()
37
    hashed = hasher.encode('admin', 'salt')
38
    assert hasher.verify('admin', hashed)
39
    assert hashed == 'plonesha1${SSHA}m8eqVfCP2tk1w/g2LT9IvPcOsoBzYWx0'
33
-