keystone  18.0.0
About: OpenStack Keystone (Core Service: Identity) provides an authentication and authorization service for other OpenStack services. Provides a catalog of endpoints for all OpenStack services.
The "Victoria" series (maintained release).
  Fossies Dox: keystone-18.0.0.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

password_hashing.py
Go to the documentation of this file.
1 # Copyright 2017 Red Hat
2 # All Rights Reserved.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 # not use this file except in compliance with the License. You may obtain
6 # a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations
14 # under the License.
15 
16 import itertools
17 
18 from oslo_log import log
19 import passlib.hash
20 
21 import keystone.conf
22 from keystone import exception
23 from keystone.i18n import _
24 
25 
26 CONF = keystone.conf.CONF
27 LOG = log.getLogger(__name__)
28 
29 SUPPORTED_HASHERS = frozenset([passlib.hash.bcrypt,
30  passlib.hash.scrypt,
31  passlib.hash.pbkdf2_sha512,
32  passlib.hash.sha512_crypt])
33 
34 _HASHER_NAME_MAP = {hasher.name: hasher for hasher in SUPPORTED_HASHERS}
35 
36 
37 # NOTE(notmorgan): Build the list of prefixes. This comprehension builds
38 # a dictionary where the keys are the prefix (all hashedpasswords are
39 # '$<ident>$<metadata>$<hash>') so we can do a fast-lookup on the hasher to
40 # use. If has hasher has multiple ident options it is encoded in the
41 # .ident_values attribute whereas hashers that have a single option
42 # (sha512_crypt) only has the .ident attribute.
43 _HASHER_IDENT_MAP = {
44  prefix: module for module, prefix in itertools.chain(
45  *[zip([mod] * len(getattr(mod, 'ident_values', (mod.ident,))),
46  getattr(mod, 'ident_values', (mod.ident,)))
47  for mod in SUPPORTED_HASHERS])}
48 
49 
51  try:
52  return _HASHER_IDENT_MAP[hashed[0:hashed.index('$', 1) + 1]]
53  except KeyError:
54  raise ValueError(
55  _('Unsupported password hashing algorithm ident: %s') %
56  hashed[0:hashed.index('$', 1) + 1])
57 
58 
60  """Verify and truncate the provided password to the max_password_length."""
61  max_length = CONF.identity.max_password_length
62  try:
63  if len(password) > max_length:
64  if CONF.strict_password_check:
65  raise exception.PasswordVerificationError(size=max_length)
66  else:
67  msg = "Truncating user password to %d characters."
68  LOG.warning(msg, max_length)
69  return password[:max_length]
70  else:
71  return password
72  except TypeError:
73  raise exception.ValidationError(attribute='string', target='password')
74 
75 
76 def check_password(password, hashed):
77  """Check that a plaintext password matches hashed.
78 
79  hashpw returns the salt value concatenated with the actual hash value.
80  It extracts the actual salt if this value is then passed as the salt.
81 
82  """
83  if password is None or hashed is None:
84  return False
85  password_utf8 = verify_length_and_trunc_password(password).encode('utf-8')
86  hasher = _get_hasher_from_ident(hashed)
87  return hasher.verify(password_utf8, hashed)
88 
89 
91  """Hash a user dict's password without modifying the passed-in dict."""
92  password = user.get('password')
93  if password is None:
94  return user
95 
96  return dict(user, password=hash_password(password))
97 
98 
99 def hash_password(password):
100  """Hash a password. Harder."""
101  params = {}
102  password_utf8 = verify_length_and_trunc_password(password).encode('utf-8')
103  conf_hasher = CONF.identity.password_hash_algorithm
104  hasher = _HASHER_NAME_MAP.get(conf_hasher)
105 
106  if hasher is None:
107  raise RuntimeError(
108  _('Password Hash Algorithm %s not found') %
109  CONF.identity.password_hash_algorithm)
110 
111  if CONF.identity.password_hash_rounds:
112  params['rounds'] = CONF.identity.password_hash_rounds
113  if hasher is passlib.hash.scrypt:
114  if CONF.identity.scrypt_block_size:
115  params['block_size'] = CONF.identity.scrypt_block_size
116  if CONF.identity.scrypt_parallelism:
117  params['parallelism'] = CONF.identity.scrypt_parallelism
118  if CONF.identity.salt_bytesize:
119  params['salt_size'] = CONF.identity.salt_bytesize
120  if hasher is passlib.hash.pbkdf2_sha512:
121  if CONF.identity.salt_bytesize:
122  params['salt_size'] = CONF.identity.salt_bytesize
123 
124  return hasher.using(**params).hash(password_utf8)
keystone.exception.ValidationError
Definition: exception.py:98
keystone.common.password_hashing._get_hasher_from_ident
def _get_hasher_from_ident(hashed)
Definition: password_hashing.py:50
keystone.common.password_hashing.hash_user_password
def hash_user_password(user)
Definition: password_hashing.py:90
keystone.common.password_hashing.hash_password
def hash_password(password)
Definition: password_hashing.py:99
keystone.common.password_hashing.verify_length_and_trunc_password
def verify_length_and_trunc_password(password)
Definition: password_hashing.py:59
keystone.exception.PasswordVerificationError
Definition: exception.py:209
keystone.conf
Definition: __init__.py:1
keystone.common.password_hashing.check_password
def check_password(password, hashed)
Definition: password_hashing.py:76
keystone.i18n._
_
Definition: i18n.py:29
keystone.i18n
Definition: i18n.py:1