Fix day filter
[cds-indico.git] / indico / util / passwords.py
blob12eb4efbc4611cce59ce545fd26bf3c40c661e50
1 # This file is part of Indico.
2 # Copyright (C) 2002 - 2015 European Organization for Nuclear Research (CERN).
4 # Indico is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3 of the
7 # License, or (at your option) any later version.
9 # Indico is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with Indico; if not, see <http://www.gnu.org/licenses/>.
17 from __future__ import unicode_literals
19 import bcrypt
22 class BCryptPassword(object):
23 def __init__(self, hash_):
24 self.hash = str(hash_)
26 def __eq__(self, value):
27 if not self.hash or not value:
28 # For security reasons we never consider an empty password/hash valid
29 return False
30 if isinstance(value, unicode):
31 value = value.encode('utf-8')
32 return self.hash == bcrypt.hashpw(value, self.hash)
34 def __ne__(self, other):
35 return not (self == other)
37 def __hash__(self): # pragma: no cover
38 return hash(self.hash)
40 def __repr__(self):
41 return '<BCryptPassword({})>'.format(self.hash)
43 @staticmethod
44 def hash(value):
45 if isinstance(value, unicode):
46 value = value.encode('utf-8')
47 return bcrypt.hashpw(value, bcrypt.gensalt())
50 class PasswordProperty(object):
51 """Defines a hashed password property.
53 When reading this property, it will return an object which will
54 let you use the ``==`` operator to compare the password against
55 a plaintext password. When assigning a value to it, it will be
56 hashed and stored in :attr:`attr` of the containing object.
58 :param attr: The attribute of the containing object where the
59 password hash is stored.
60 :param backend: The password backend that handles hashing/checking
61 passwords.
62 """
64 def __init__(self, attr, backend=BCryptPassword):
65 self.attr = attr
66 self.backend = backend
68 def __get__(self, instance, owner):
69 return self.backend(getattr(instance, self.attr, None))
71 def __set__(self, instance, value):
72 if not value:
73 raise ValueError('Password may not be empty')
74 setattr(instance, self.attr, self.backend.hash(value))
76 def __delete__(self, instance):
77 setattr(instance, self.attr, None)