No way to specify password strength in keystone.

Bug #1484366 reported by Mahesh Sawaiker
8
This bug affects 1 person
Affects Status Importance Assigned to Milestone
OpenStack Identity (keystone)
Won't Fix
Wishlist
Unassigned

Bug Description

There is a way to set the regular expression for horizon for a password, but there is no way to do this in keystone.

We need a configuration parameter in keystone for the regular expression and another one for the message to be shown when the password is not valid.

#password regularexpression for user password
password_regex=((?=(.*(\d|[~!@#$%^&*_=+])){2,})(?=.*[a-z])(?=.*[A-Z]).{8,20})
password_regex_message=Password is not strong enough

These then need to be validated in the respective controllers (both v2 and v3)
example in ./keystone/identity/controllers.py

209 @staticmethod
210 def check_syntax(password):
211 a = re.match(CONF.password_regex, password)
212 if not a:
213 raise exception.ValidationError(CONF.password_regex_message)
214
215 @staticmethod
216 def check_pwd_policies(password, name):
217
218 #if passsword is empty allow it,
219 #since empty password wont allow user to login
220 if password is None:
221 return
222 if name in password or password in name:
223 raise exception.ValidationError("Password not strong enough: user name cannot be part of the password")
224 User.check_syntax(password)
225

243 @controller.protected()
244 def create_user(self, context, user):
245 self._require_attribute(user, 'name')
246
247 if user.get('password') is not None:
248 User.check_pwd_policies(user['password'], user['name'])
249 # The manager layer will generate the unique ID for users
250 ref = self._normalize_dict(user)
251 ref = self._normalize_domain_id(context, ref)
252 ref = self.identity_api.create_user(ref)
253 return UserV3.wrap_member(context, ref)
254

276 def _update_user(self, context, user_id, user):
277
278 #if password is being changed
279 #then check if name is not part of password
280 if 'password' in user:
281 #if name is not present then get it from the backend
282 if 'name' not in user:
283 old_user_ref = self.identity_api.get_user(user_id)
284 name = old_user_ref['name']
285 else:
286 name = user['name']
287 User.check_pwd_policies(user['password'], name)
288
289 self._require_matching_id(user_id, user)
290 self._require_matching_domain_id(
291 user_id, user, self.identity_api.get_user)
292 ref = self.identity_api.update_user(user_id, user)
293 return UserV3.wrap_member(context, ref)

315 @controller.protected()
316 def change_password(self, context, user_id, user):
317 original_password = user.get('original_password')
318 if original_password is None:
319 raise exception.ValidationError(target='user',
320 attribute='original_password')
321
322 password = user.get('password')
323 if password is None:
324 raise exception.ValidationError(target='user',
325 attribute='password')
326 #if name is not present then get it from the backend
327 if 'name' not in user:
328 old_user_ref = self.identity_api.get_user(user_id)
329 name = old_user_ref['name']
330 else:
331 name = user['name']
332
333 User.check_pwd_policies(password, name)
334
335 try:
336 self.identity_api.change_password(
337 context, user_id, original_password, password)
338 except AssertionError:
339 raise exception.Unauthorized()
340

affects: bagpipe-l2 → keystone
Revision history for this message
Steve Martinelli (stevemar) wrote :

keystone should not have to handle passwords, users should exist in ldap or through an identity provider. the only passwords we handle are for service accounts (admin/nova/glance/etc...), so the need for investing in additional logic to handle passwords is not worth it for us. furthermore, each deployer may want to set their own password policy, independent of whatever we suggest.

Changed in keystone:
importance: Undecided → Wishlist
status: New → Triaged
Revision history for this message
Nikhil Gupta (lihkin) wrote :

Steve, for the identity provider case, I agree it does not matter. But for the cases where we have a ldap backend, or even for the sql backend if the deployer wants to enable a password complexity policy, there is no way to do that. This is suggesting a way to allow enablement of such policy and it could be completely optional.

Revision history for this message
Dolph Mathews (dolph) wrote :

The complexities of re-inventing a first class identity provider in keystone are not in our best interests. Use a real identity provider (via either LDAP or federation) that supports these features if you need them, not the SQL backend.

Changed in keystone:
status: Triaged → Won't Fix
Revision history for this message
Mahesh Sawaiker (mahesh-sawaiker) wrote :

Well, there is a corner case there with the ldap backend which hampers user experience.
User account lockout and password expiry is not reported as http error 500 by keystone. (we need a hook somewhere to fix this since exceptions may be ldap vendor specific eg. openldap v/s active directory, but error codes should be consistent)
ldap exception x => (http error code 401, user friendly msg x)
ldap exception z => (http error code 401,user friendly msg z)

Bad password during user creation is also reported as http error 500, but that's not a valid case since a user in an IdP is not expected to be created by keystone.

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.