)]}'
{"keystone/conf/security_compliance.py":[{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"b42bfff2a2a42d9c9285af28b969cd36b1a3d6f3","unresolved":false,"context_lines":[{"line_number":38,"context_line":"    default\u003dNone,"},{"line_number":39,"context_line":"    min\u003d1,"},{"line_number":40,"context_line":"    help\u003dutils.fmt(\"\"\""},{"line_number":41,"context_line":"If a user account becomes locked, this defines the the number of seconds the"},{"line_number":42,"context_line":"user will be locked out from attempting to login."},{"line_number":43,"context_line":"\"\"\"))"},{"line_number":44,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"1aa78d24_782748b6","line":41,"updated":"2016-07-11 21:50:32.000000000","message":"After the lockout duration, do users get another X attempts to authenticate? When I tested this locally, I set lockout_failure_attempts to 5 and lockout_duration to 60. I failed to authenticate 5 times and my user was locked out for 60 seconds, which is exactly what I was expecting. When the 60 second timeout was up, I tried to authenticate with a bad password again and my account was immediately locked (because the failed_auth_cnt was not reset in the database).\n\nI was thinking that after the first 60 second wait period I would have another five chances to authenticate.","commit_id":"ceb46a67f0e2a866f330879b23d45a8ac06c7fe1"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"2f78cc50eb882e752df3cf4bcc08d276398aeb75","unresolved":false,"context_lines":[{"line_number":38,"context_line":"    default\u003dNone,"},{"line_number":39,"context_line":"    min\u003d1,"},{"line_number":40,"context_line":"    help\u003dutils.fmt(\"\"\""},{"line_number":41,"context_line":"If a user account becomes locked, this defines the the number of seconds the"},{"line_number":42,"context_line":"user will be locked out from attempting to login."},{"line_number":43,"context_line":"\"\"\"))"},{"line_number":44,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"1aa78d24_18a8c476","line":41,"in_reply_to":"1aa78d24_782748b6","updated":"2016-07-11 22:04:27.000000000","message":"Yep, that would be the expected behavior.  I\u0027ll add a test case for this.","commit_id":"ceb46a67f0e2a866f330879b23d45a8ac06c7fe1"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"b42bfff2a2a42d9c9285af28b969cd36b1a3d6f3","unresolved":false,"context_lines":[{"line_number":39,"context_line":"    min\u003d1,"},{"line_number":40,"context_line":"    help\u003dutils.fmt(\"\"\""},{"line_number":41,"context_line":"If a user account becomes locked, this defines the the number of seconds the"},{"line_number":42,"context_line":"user will be locked out from attempting to login."},{"line_number":43,"context_line":"\"\"\"))"},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"password_expires_days \u003d cfg.IntOpt("}],"source_content_type":"text/x-python","patch_set":4,"id":"1aa78d24_bd3fe2b2","line":42,"updated":"2016-07-11 21:50:32.000000000","message":"(nit):\n\n  this defines the number of seconds until the user can attempt to login.","commit_id":"ceb46a67f0e2a866f330879b23d45a8ac06c7fe1"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"81246e4336ba48e685dd4d7fe91db14b0df14505","unresolved":false,"context_lines":[{"line_number":39,"context_line":"    min\u003d1,"},{"line_number":40,"context_line":"    help\u003dutils.fmt(\"\"\""},{"line_number":41,"context_line":"If a user account becomes locked, this defines the the number of seconds the"},{"line_number":42,"context_line":"user will be locked out from attempting to login."},{"line_number":43,"context_line":"\"\"\"))"},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"password_expires_days \u003d cfg.IntOpt("}],"source_content_type":"text/x-python","patch_set":4,"id":"1aa78d24_e16b801c","line":42,"in_reply_to":"1aa78d24_bd3fe2b2","updated":"2016-07-12 02:38:35.000000000","message":"Done","commit_id":"ceb46a67f0e2a866f330879b23d45a8ac06c7fe1"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"6197c71a1dcd775479f09cc26d94ea05e0cc5ea4","unresolved":false,"context_lines":[{"line_number":31,"context_line":"The number of times a user can fail logging in before their account is locked."},{"line_number":32,"context_line":"If lockout_failure_attempts is set and lockout_duration is not set, manual override is required to"},{"line_number":33,"context_line":"unlock the user account. This can be done by setting enable to True for the user. This feature is"},{"line_number":34,"context_line":"disabled by default. Note: this feature is only supported via the SQL backend driver for identity."},{"line_number":35,"context_line":"\"\"\"))"},{"line_number":36,"context_line":""},{"line_number":37,"context_line":"lockout_duration \u003d cfg.IntOpt("}],"source_content_type":"text/x-python","patch_set":7,"id":"1aa78d24_66a2e2fd","line":34,"updated":"2016-07-12 14:56:07.000000000","message":"++ awesome!","commit_id":"04c453df78138844f7949aeacf9053a290dc02af"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a402890d6dd5c1774dfae3390d8bf873d0d5093","unresolved":false,"context_lines":[{"line_number":38,"context_line":"`[security_compliance] lockout_duration`. This feature is disabled by"},{"line_number":39,"context_line":"default. If this feature is enabled and `[security_compliance]"},{"line_number":40,"context_line":"lockout_duration` is not set, then manual override is required to unlock"},{"line_number":41,"context_line":"the user account. This can be done by setting enable to True for the user."},{"line_number":42,"context_line":"This feature depends on the `sql` backend for the `[identity] driver`."},{"line_number":43,"context_line":"\"\"\"))"},{"line_number":44,"context_line":""}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_4739c8a3","line":41,"updated":"2016-07-29 17:36:37.000000000","message":"\"setting enable to True\" is a bit misleading. Firstly, it *might* suggest that you can set it directly in the DB, which is not the case. But more to the point, \"True\" is a Python representation of a boolean, as opposed to \"true\", the JSON representation of a boolean, which is what the user would actually set if using the HTTP API manually. More likely though, they\u0027re going to set --enable or --disable through a command line client, so we really shouldn\u0027t be referring to specific API attributes in these docs -- it\u0027s just not user-friendly language.\n\n\n  If this feature is enabled and `[security_compliance]\n  lockout_duration` is not set, then users may be locked out\n  indefinitely until the user is explicitly enabled via the API.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"efa989be9faf0e7f8daf076a2be9007e00214f2a","unresolved":false,"context_lines":[{"line_number":38,"context_line":"`[security_compliance] lockout_duration`. This feature is disabled by"},{"line_number":39,"context_line":"default. If this feature is enabled and `[security_compliance]"},{"line_number":40,"context_line":"lockout_duration` is not set, then manual override is required to unlock"},{"line_number":41,"context_line":"the user account. This can be done by setting enable to True for the user."},{"line_number":42,"context_line":"This feature depends on the `sql` backend for the `[identity] driver`."},{"line_number":43,"context_line":"\"\"\"))"},{"line_number":44,"context_line":""}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_4df0c967","line":41,"in_reply_to":"bacf61ea_4739c8a3","updated":"2016-07-29 18:26:37.000000000","message":"Yeah, that makes sense. Done.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"}],"keystone/exception.py":[{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a402890d6dd5c1774dfae3390d8bf873d0d5093","unresolved":false,"context_lines":[{"line_number":217,"context_line":""},{"line_number":218,"context_line":""},{"line_number":219,"context_line":"class AccountLocked(Unauthorized):"},{"line_number":220,"context_line":"    message_format \u003d _(\"The user account is locked\")"},{"line_number":221,"context_line":""},{"line_number":222,"context_line":""},{"line_number":223,"context_line":"class AuthMethodNotSupported(AuthPluginException):"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_e7ec3cf5","line":220,"updated":"2016-07-29 17:36:37.000000000","message":"Error messages that don\u0027t end in a value (like \"... user: %{user_id}s\" above) are complete sentences and end with periods.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"efa989be9faf0e7f8daf076a2be9007e00214f2a","unresolved":false,"context_lines":[{"line_number":217,"context_line":""},{"line_number":218,"context_line":""},{"line_number":219,"context_line":"class AccountLocked(Unauthorized):"},{"line_number":220,"context_line":"    message_format \u003d _(\"The user account is locked\")"},{"line_number":221,"context_line":""},{"line_number":222,"context_line":""},{"line_number":223,"context_line":"class AuthMethodNotSupported(AuthPluginException):"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_cd04b94b","line":220,"in_reply_to":"bacf61ea_e7ec3cf5","updated":"2016-07-29 18:26:37.000000000","message":"Done","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"}],"keystone/identity/backends/sql.py":[{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"95d419e320ae4709f80a584e74af351c2f93a337","unresolved":false,"context_lines":[{"line_number":77,"context_line":"        lockout_duration \u003d CONF.security_compliance.lockout_duration"},{"line_number":78,"context_line":"        if max_attempts and (attempts \u003e\u003d max_attempts):"},{"line_number":79,"context_line":"            if not lockout_duration:"},{"line_number":80,"context_line":"                is_locked \u003d True"},{"line_number":81,"context_line":"            else:"},{"line_number":82,"context_line":"                delta \u003d datetime.timedelta(seconds\u003dlockout_duration)"},{"line_number":83,"context_line":"                last_failure \u003d user_ref.local_user.failed_auth_at"}],"source_content_type":"text/x-python","patch_set":6,"id":"1aa78d24_a042f23b","line":80,"updated":"2016-07-12 14:28:32.000000000","message":"In testing this locally - if I don\u0027t configure keystone with a lockout_duration and a user exceeds the number of failed authentication attempts - it will lock the user out and the only way for them to be unlocked would be for an admin to reset their enabled attribute, right?\n\nThat seems like the desired outcome but maybe we can clarify that in the help text of the lockout_duration option. Just saying that if lockout_failure_attempts is set and not given a duration, manual override is required to unlock user accounts.","commit_id":"afdcf7aab4f2d707ec7ef0d5691b736d992f6ba2"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"c6d072602b8c42a3972dcc7570cc037bd3f7229d","unresolved":false,"context_lines":[{"line_number":77,"context_line":"        lockout_duration \u003d CONF.security_compliance.lockout_duration"},{"line_number":78,"context_line":"        if max_attempts and (attempts \u003e\u003d max_attempts):"},{"line_number":79,"context_line":"            if not lockout_duration:"},{"line_number":80,"context_line":"                is_locked \u003d True"},{"line_number":81,"context_line":"            else:"},{"line_number":82,"context_line":"                delta \u003d datetime.timedelta(seconds\u003dlockout_duration)"},{"line_number":83,"context_line":"                last_failure \u003d user_ref.local_user.failed_auth_at"}],"source_content_type":"text/x-python","patch_set":6,"id":"1aa78d24_a0a4b2a5","line":80,"in_reply_to":"1aa78d24_a042f23b","updated":"2016-07-12 14:34:38.000000000","message":"Correct.  Done.","commit_id":"afdcf7aab4f2d707ec7ef0d5691b736d992f6ba2"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"95d419e320ae4709f80a584e74af351c2f93a337","unresolved":false,"context_lines":[{"line_number":84,"context_line":"                if (last_failure + delta) \u003e datetime.datetime.now():"},{"line_number":85,"context_line":"                    is_locked \u003d True"},{"line_number":86,"context_line":"                else:"},{"line_number":87,"context_line":"                    self._reset_failed_auth(user_id)"},{"line_number":88,"context_line":"        return is_locked"},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"    def _record_failed_auth(self, user_id):"}],"source_content_type":"text/x-python","patch_set":6,"id":"1aa78d24_ba733f7f","line":87,"updated":"2016-07-12 14:28:32.000000000","message":"Cool - this seems to have fixed the issue I was running into on patch set 4. Is there a way we can add a test case for this?","commit_id":"afdcf7aab4f2d707ec7ef0d5691b736d992f6ba2"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"461ccfa1cbe1a502a481b1018d0f6bb1ac88dd51","unresolved":false,"context_lines":[{"line_number":84,"context_line":"                if (last_failure + delta) \u003e datetime.datetime.now():"},{"line_number":85,"context_line":"                    is_locked \u003d True"},{"line_number":86,"context_line":"                else:"},{"line_number":87,"context_line":"                    self._reset_failed_auth(user_id)"},{"line_number":88,"context_line":"        return is_locked"},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"    def _record_failed_auth(self, user_id):"}],"source_content_type":"text/x-python","patch_set":6,"id":"1aa78d24_209602f0","line":87,"in_reply_to":"1aa78d24_ba733f7f","updated":"2016-07-12 14:35:57.000000000","message":"Working on a test case for this; need to learn FreezeGun :)","commit_id":"afdcf7aab4f2d707ec7ef0d5691b736d992f6ba2"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"f540b17c81b00fdc85e7383ed050341ffa2d810e","unresolved":false,"context_lines":[{"line_number":82,"context_line":"            else:"},{"line_number":83,"context_line":"                delta \u003d datetime.timedelta(seconds\u003dlockout_duration)"},{"line_number":84,"context_line":"                last_failure \u003d user_ref.local_user.failed_auth_at"},{"line_number":85,"context_line":"                if (last_failure + delta) \u003e datetime.datetime.now():"},{"line_number":86,"context_line":"                    is_locked \u003d True"},{"line_number":87,"context_line":"                else:"},{"line_number":88,"context_line":"                    self._reset_failed_auth(user_id)"}],"source_content_type":"text/x-python","patch_set":25,"id":"fad55976_5ec74745","line":85,"updated":"2016-07-15 21:13:25.000000000","message":"This should use utcnow() not now(), otherwise it is inconsistent with what _record_failed_auth is using","commit_id":"561d9068e7e23764704716b57a3b99cb5729b81c"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"cba3a883571449da2b6820b17802cb8061a0c4fb","unresolved":false,"context_lines":[{"line_number":82,"context_line":"            else:"},{"line_number":83,"context_line":"                delta \u003d datetime.timedelta(seconds\u003dlockout_duration)"},{"line_number":84,"context_line":"                last_failure \u003d user_ref.local_user.failed_auth_at"},{"line_number":85,"context_line":"                if (last_failure + delta) \u003e datetime.datetime.now():"},{"line_number":86,"context_line":"                    is_locked \u003d True"},{"line_number":87,"context_line":"                else:"},{"line_number":88,"context_line":"                    self._reset_failed_auth(user_id)"}],"source_content_type":"text/x-python","patch_set":25,"id":"fad55976_4408bb2c","line":85,"in_reply_to":"fad55976_5ec74745","updated":"2016-07-16 15:07:52.000000000","message":"Done","commit_id":"561d9068e7e23764704716b57a3b99cb5729b81c"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"0c18a57b7bc33d121842769277b3d68ce355cf73","unresolved":false,"context_lines":[{"line_number":82,"context_line":"            else:"},{"line_number":83,"context_line":"                delta \u003d datetime.timedelta(seconds\u003dlockout_duration)"},{"line_number":84,"context_line":"                last_failure \u003d user_ref.local_user.failed_auth_at"},{"line_number":85,"context_line":"                if (last_failure + delta) \u003e datetime.datetime.now():"},{"line_number":86,"context_line":"                    is_locked \u003d True"},{"line_number":87,"context_line":"                else:"},{"line_number":88,"context_line":"                    self._reset_failed_auth(user_id)"}],"source_content_type":"text/x-python","patch_set":25,"id":"fad55976_8419138b","line":85,"in_reply_to":"fad55976_5ec74745","updated":"2016-07-16 15:07:42.000000000","message":"Good catch Colleen, don\u0027t know how I missed that one.","commit_id":"561d9068e7e23764704716b57a3b99cb5729b81c"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"dfbad4ca0934e95ae21afbf0b60e883c1199b59a","unresolved":false,"context_lines":[{"line_number":57,"context_line":"        if not self._check_password(password, user_ref):"},{"line_number":58,"context_line":"            raise AssertionError(_(\u0027Invalid user / password\u0027))"},{"line_number":59,"context_line":"        elif not user_ref.enabled:"},{"line_number":60,"context_line":"            raise exception.UserDisabled(user_id\u003duser_id)"},{"line_number":61,"context_line":"        return base.filter_user(user_ref.to_dict())"},{"line_number":62,"context_line":""},{"line_number":63,"context_line":"    # user crud"}],"source_content_type":"text/x-python","patch_set":29,"id":"bacf61ea_375e0246","side":"PARENT","line":60,"updated":"2016-07-27 15:43:12.000000000","message":"Looks like when a user is disabled this exception isn\u0027t raised. It looks like this is raised instead: \n\nhttps://github.com/openstack/keystone/blob/9d54eb33c1d74ff39c947af6ff984ef2e0bf4be4/keystone/identity/core.py#L902\n\nWhich is an AssertionError instead of a UserDisabled error. This means that exception.UserDisabled could have the same issue as exception.AccountLocked where it displays a `missing exception kwargs` programming error.","commit_id":"38aa65336686205e9ab07fdacb454ace01eca695"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"e5520c926693645586d6b5e723d2b70f4deb6b41","unresolved":false,"context_lines":[{"line_number":59,"context_line":"            except exception.UserNotFound:"},{"line_number":60,"context_line":"                raise AssertionError(_(\u0027Invalid user / password\u0027))"},{"line_number":61,"context_line":"        if self._is_account_locked(user_id, user_ref):"},{"line_number":62,"context_line":"            raise exception.AccountLocked(user_id\u003duser_id)"},{"line_number":63,"context_line":"        elif not self._check_password(password, user_ref):"},{"line_number":64,"context_line":"            self._record_failed_auth(user_id)"},{"line_number":65,"context_line":"            raise AssertionError(_(\u0027Invalid user / password\u0027))"}],"source_content_type":"text/x-python","patch_set":29,"id":"bacf61ea_313f3227","line":62,"updated":"2016-07-27 14:48:53.000000000","message":"Hmm for some reason this seems to log: \n\n  missing exception kwargs (programmer error)\n\nI can recreate what Colleen was seeing. I also tried recreating this with the UserDisabled exception (since that exception is inheriting the Unauthorized exception and using kwargs the same way as AccountLocked), but for some reason UserDisabled doesn\u0027t emit the `missing exception kwargs` message in the logs.\n\nHere is my entire traceback: http://cdn.pasteraw.com/douk85rdz0qw6saznn7n5ma5b3q0wz4\n\nI deployed the change, set my lockout attempts to 3, and then authenticated several times to recreate the issue.","commit_id":"1c36cd677731ebcce59d284729e975ef1964e168"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"59fdb487fd05e461b6777a5ddb0f036f25db30db","unresolved":false,"context_lines":[{"line_number":59,"context_line":"            except exception.UserNotFound:"},{"line_number":60,"context_line":"                raise AssertionError(_(\u0027Invalid user / password\u0027))"},{"line_number":61,"context_line":"        if self._is_account_locked(user_id, user_ref):"},{"line_number":62,"context_line":"            raise exception.AccountLocked(user_id\u003duser_id)"},{"line_number":63,"context_line":"        elif not self._check_password(password, user_ref):"},{"line_number":64,"context_line":"            self._record_failed_auth(user_id)"},{"line_number":65,"context_line":"            raise AssertionError(_(\u0027Invalid user / password\u0027))"}],"source_content_type":"text/x-python","patch_set":29,"id":"bacf61ea_8465e9e2","line":62,"in_reply_to":"bacf61ea_23819a4b","updated":"2016-07-27 22:12:58.000000000","message":"Thanks for your help on this.  As a workaround, I log the error and removed the user_id parameter from the exception.","commit_id":"1c36cd677731ebcce59d284729e975ef1964e168"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"dfbad4ca0934e95ae21afbf0b60e883c1199b59a","unresolved":false,"context_lines":[{"line_number":59,"context_line":"            except exception.UserNotFound:"},{"line_number":60,"context_line":"                raise AssertionError(_(\u0027Invalid user / password\u0027))"},{"line_number":61,"context_line":"        if self._is_account_locked(user_id, user_ref):"},{"line_number":62,"context_line":"            raise exception.AccountLocked(user_id\u003duser_id)"},{"line_number":63,"context_line":"        elif not self._check_password(password, user_ref):"},{"line_number":64,"context_line":"            self._record_failed_auth(user_id)"},{"line_number":65,"context_line":"            raise AssertionError(_(\u0027Invalid user / password\u0027))"}],"source_content_type":"text/x-python","patch_set":29,"id":"bacf61ea_9d3b8f9c","line":62,"in_reply_to":"bacf61ea_313f3227","updated":"2016-07-27 15:43:12.000000000","message":"Looks like this is the product of: \n\nhttps://github.com/openstack/keystone/blob/master/keystone/exception.py#L61-L67","commit_id":"1c36cd677731ebcce59d284729e975ef1964e168"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"ca88edc93ad366aed4216b3d091b6dda3ceb9eab","unresolved":false,"context_lines":[{"line_number":59,"context_line":"            except exception.UserNotFound:"},{"line_number":60,"context_line":"                raise AssertionError(_(\u0027Invalid user / password\u0027))"},{"line_number":61,"context_line":"        if self._is_account_locked(user_id, user_ref):"},{"line_number":62,"context_line":"            raise exception.AccountLocked(user_id\u003duser_id)"},{"line_number":63,"context_line":"        elif not self._check_password(password, user_ref):"},{"line_number":64,"context_line":"            self._record_failed_auth(user_id)"},{"line_number":65,"context_line":"            raise AssertionError(_(\u0027Invalid user / password\u0027))"}],"source_content_type":"text/x-python","patch_set":29,"id":"bacf61ea_23819a4b","line":62,"in_reply_to":"bacf61ea_9d3b8f9c","updated":"2016-07-27 19:52:51.000000000","message":"Looks like we can actually fix this by doing something like - http://cdn.pasteraw.com/bxtpgziuj7cbq4gqickwu9el2ymiouw\n\nReference our debug session in #openstack-keystone if more context is needed :) \n\nhttp://eavesdrop.openstack.org/irclogs/%23openstack-keystone/%23openstack-keystone.2016-07-27.log.html#t2016-07-27T14:49:24","commit_id":"1c36cd677731ebcce59d284729e975ef1964e168"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a402890d6dd5c1774dfae3390d8bf873d0d5093","unresolved":false,"context_lines":[{"line_number":61,"context_line":"            except exception.UserNotFound:"},{"line_number":62,"context_line":"                raise AssertionError(_(\u0027Invalid user / password\u0027))"},{"line_number":63,"context_line":"        if self._is_account_locked(user_id, user_ref):"},{"line_number":64,"context_line":"            # logging a warning as a workaround for bug 1607107"},{"line_number":65,"context_line":"            LOG.warning(_LW(\u0027The account is locked for user: \u0027"},{"line_number":66,"context_line":"                            \u0027%(user_id)s\u0027) % {\u0027user_id\u0027: user_id})"},{"line_number":67,"context_line":"            raise exception.AccountLocked()"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_a7a24497","line":64,"updated":"2016-07-29 17:36:37.000000000","message":"Didn\u0027t Stanek find a fix for this? I don\u0027t understand what you\u0027re having to work around.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"4ded4d84b489d2c3867646ca813720b2e9f83df0","unresolved":false,"context_lines":[{"line_number":61,"context_line":"            except exception.UserNotFound:"},{"line_number":62,"context_line":"                raise AssertionError(_(\u0027Invalid user / password\u0027))"},{"line_number":63,"context_line":"        if self._is_account_locked(user_id, user_ref):"},{"line_number":64,"context_line":"            # logging a warning as a workaround for bug 1607107"},{"line_number":65,"context_line":"            LOG.warning(_LW(\u0027The account is locked for user: \u0027"},{"line_number":66,"context_line":"                            \u0027%(user_id)s\u0027) % {\u0027user_id\u0027: user_id})"},{"line_number":67,"context_line":"            raise exception.AccountLocked()"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_b5f6a08c","line":64,"in_reply_to":"bacf61ea_559f6e5e","updated":"2016-08-01 15:45:21.000000000","message":"Okay, I\u0027ve based my patch on Stanek\u0027s.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"efa989be9faf0e7f8daf076a2be9007e00214f2a","unresolved":false,"context_lines":[{"line_number":61,"context_line":"            except exception.UserNotFound:"},{"line_number":62,"context_line":"                raise AssertionError(_(\u0027Invalid user / password\u0027))"},{"line_number":63,"context_line":"        if self._is_account_locked(user_id, user_ref):"},{"line_number":64,"context_line":"            # logging a warning as a workaround for bug 1607107"},{"line_number":65,"context_line":"            LOG.warning(_LW(\u0027The account is locked for user: \u0027"},{"line_number":66,"context_line":"                            \u0027%(user_id)s\u0027) % {\u0027user_id\u0027: user_id})"},{"line_number":67,"context_line":"            raise exception.AccountLocked()"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_ad5d0549","line":64,"in_reply_to":"bacf61ea_a7a24497","updated":"2016-07-29 18:26:37.000000000","message":"The fix has not been merged and I created this workaround prior to there being a fix.\n\nThe error occurs when you pass a parameter in the exception. Thus, I\u0027m logging the message instead as a workaround.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"68fb21a188ef32fdab734f01c98212d620db0dff","unresolved":false,"context_lines":[{"line_number":61,"context_line":"            except exception.UserNotFound:"},{"line_number":62,"context_line":"                raise AssertionError(_(\u0027Invalid user / password\u0027))"},{"line_number":63,"context_line":"        if self._is_account_locked(user_id, user_ref):"},{"line_number":64,"context_line":"            # logging a warning as a workaround for bug 1607107"},{"line_number":65,"context_line":"            LOG.warning(_LW(\u0027The account is locked for user: \u0027"},{"line_number":66,"context_line":"                            \u0027%(user_id)s\u0027) % {\u0027user_id\u0027: user_id})"},{"line_number":67,"context_line":"            raise exception.AccountLocked()"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_559f6e5e","line":64,"in_reply_to":"bacf61ea_ad5d0549","updated":"2016-08-01 13:21:57.000000000","message":"Base your patch on top of his if you need to leverage it. Leaving this sort of comment in the code is really odd.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a402890d6dd5c1774dfae3390d8bf873d0d5093","unresolved":false,"context_lines":[{"line_number":70,"context_line":"            raise AssertionError(_(\u0027Invalid user / password\u0027))"},{"line_number":71,"context_line":"        elif not user_ref.enabled:"},{"line_number":72,"context_line":"            raise exception.UserDisabled(user_id\u003duser_id)"},{"line_number":73,"context_line":"        # successful auth, reset failed cnt if present"},{"line_number":74,"context_line":"        if user_ref.local_user.failed_auth_cnt:"},{"line_number":75,"context_line":"            self._reset_failed_auth(user_id)"},{"line_number":76,"context_line":"        return base.filter_user(user_ref.to_dict())"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_477b88f5","line":73,"updated":"2016-07-29 17:36:37.000000000","message":"\"Count\" should be spelled out in the comments if not in the variable name.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"efa989be9faf0e7f8daf076a2be9007e00214f2a","unresolved":false,"context_lines":[{"line_number":70,"context_line":"            raise AssertionError(_(\u0027Invalid user / password\u0027))"},{"line_number":71,"context_line":"        elif not user_ref.enabled:"},{"line_number":72,"context_line":"            raise exception.UserDisabled(user_id\u003duser_id)"},{"line_number":73,"context_line":"        # successful auth, reset failed cnt if present"},{"line_number":74,"context_line":"        if user_ref.local_user.failed_auth_cnt:"},{"line_number":75,"context_line":"            self._reset_failed_auth(user_id)"},{"line_number":76,"context_line":"        return base.filter_user(user_ref.to_dict())"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_4d33a914","line":73,"in_reply_to":"bacf61ea_477b88f5","updated":"2016-07-29 18:26:37.000000000","message":"Done","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a402890d6dd5c1774dfae3390d8bf873d0d5093","unresolved":false,"context_lines":[{"line_number":75,"context_line":"            self._reset_failed_auth(user_id)"},{"line_number":76,"context_line":"        return base.filter_user(user_ref.to_dict())"},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"    def _is_account_locked(self, user_id, user_ref):"},{"line_number":79,"context_line":"        is_locked \u003d False"},{"line_number":80,"context_line":"        attempts \u003d (user_ref.local_user.failed_auth_cnt if"},{"line_number":81,"context_line":"                    user_ref.local_user.failed_auth_cnt else 0)"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_a701a43a","line":78,"updated":"2016-07-29 17:36:37.000000000","message":"docstring all the things!\n\nI feel like this method is really hard to follow, just because the exit conditions are not easy to follow -- nor are any of them documented up front.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"c6cec6c334fd4273fcabd00979aa14524867326c","unresolved":false,"context_lines":[{"line_number":75,"context_line":"            self._reset_failed_auth(user_id)"},{"line_number":76,"context_line":"        return base.filter_user(user_ref.to_dict())"},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"    def _is_account_locked(self, user_id, user_ref):"},{"line_number":79,"context_line":"        is_locked \u003d False"},{"line_number":80,"context_line":"        attempts \u003d (user_ref.local_user.failed_auth_cnt if"},{"line_number":81,"context_line":"                    user_ref.local_user.failed_auth_cnt else 0)"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_0a706d0a","line":78,"in_reply_to":"bacf61ea_a701a43a","updated":"2016-07-29 23:40:21.000000000","message":"Done","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a402890d6dd5c1774dfae3390d8bf873d0d5093","unresolved":false,"context_lines":[{"line_number":78,"context_line":"    def _is_account_locked(self, user_id, user_ref):"},{"line_number":79,"context_line":"        is_locked \u003d False"},{"line_number":80,"context_line":"        attempts \u003d (user_ref.local_user.failed_auth_cnt if"},{"line_number":81,"context_line":"                    user_ref.local_user.failed_auth_cnt else 0)"},{"line_number":82,"context_line":"        max_attempts \u003d CONF.security_compliance.lockout_failure_attempts"},{"line_number":83,"context_line":"        lockout_duration \u003d CONF.security_compliance.lockout_duration"},{"line_number":84,"context_line":"        if max_attempts and (attempts \u003e\u003d max_attempts):"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_f25078d6","line":81,"updated":"2016-07-29 17:36:37.000000000","message":"Yay, Python!\n\n  attempts \u003d user_ref.local_user.failed_auth_cnt or 0","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"efa989be9faf0e7f8daf076a2be9007e00214f2a","unresolved":false,"context_lines":[{"line_number":78,"context_line":"    def _is_account_locked(self, user_id, user_ref):"},{"line_number":79,"context_line":"        is_locked \u003d False"},{"line_number":80,"context_line":"        attempts \u003d (user_ref.local_user.failed_auth_cnt if"},{"line_number":81,"context_line":"                    user_ref.local_user.failed_auth_cnt else 0)"},{"line_number":82,"context_line":"        max_attempts \u003d CONF.security_compliance.lockout_failure_attempts"},{"line_number":83,"context_line":"        lockout_duration \u003d CONF.security_compliance.lockout_duration"},{"line_number":84,"context_line":"        if max_attempts and (attempts \u003e\u003d max_attempts):"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_5f286c86","line":81,"in_reply_to":"bacf61ea_f25078d6","updated":"2016-07-29 18:26:37.000000000","message":"Done","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a402890d6dd5c1774dfae3390d8bf873d0d5093","unresolved":false,"context_lines":[{"line_number":83,"context_line":"        lockout_duration \u003d CONF.security_compliance.lockout_duration"},{"line_number":84,"context_line":"        if max_attempts and (attempts \u003e\u003d max_attempts):"},{"line_number":85,"context_line":"            if not lockout_duration:"},{"line_number":86,"context_line":"                is_locked \u003d True"},{"line_number":87,"context_line":"            else:"},{"line_number":88,"context_line":"                delta \u003d datetime.timedelta(seconds\u003dlockout_duration)"},{"line_number":89,"context_line":"                last_failure \u003d user_ref.local_user.failed_auth_at"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_926c9cd1","line":86,"updated":"2016-07-29 17:36:37.000000000","message":"This could use an inline comment to explain that if no lockout duration is set, the account is locked out indefinitely, so just always return True.\n\n  return True  # also, i\u0027m personally a fan of short circuiting, but that\u0027s just me","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"efa989be9faf0e7f8daf076a2be9007e00214f2a","unresolved":false,"context_lines":[{"line_number":83,"context_line":"        lockout_duration \u003d CONF.security_compliance.lockout_duration"},{"line_number":84,"context_line":"        if max_attempts and (attempts \u003e\u003d max_attempts):"},{"line_number":85,"context_line":"            if not lockout_duration:"},{"line_number":86,"context_line":"                is_locked \u003d True"},{"line_number":87,"context_line":"            else:"},{"line_number":88,"context_line":"                delta \u003d datetime.timedelta(seconds\u003dlockout_duration)"},{"line_number":89,"context_line":"                last_failure \u003d user_ref.local_user.failed_auth_at"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_ff8b2066","line":86,"in_reply_to":"bacf61ea_926c9cd1","updated":"2016-07-29 18:26:37.000000000","message":"Done","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a402890d6dd5c1774dfae3390d8bf873d0d5093","unresolved":false,"context_lines":[{"line_number":87,"context_line":"            else:"},{"line_number":88,"context_line":"                delta \u003d datetime.timedelta(seconds\u003dlockout_duration)"},{"line_number":89,"context_line":"                last_failure \u003d user_ref.local_user.failed_auth_at"},{"line_number":90,"context_line":"                if (last_failure + delta) \u003e datetime.datetime.utcnow():"},{"line_number":91,"context_line":"                    is_locked \u003d True"},{"line_number":92,"context_line":"                else:"},{"line_number":93,"context_line":"                    self._reset_failed_auth(user_id)"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_92801cf9","line":90,"updated":"2016-07-29 17:36:37.000000000","message":"Man, this shows how dated PCI is as a standard!","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a402890d6dd5c1774dfae3390d8bf873d0d5093","unresolved":false,"context_lines":[{"line_number":95,"context_line":""},{"line_number":96,"context_line":"    def _record_failed_auth(self, user_id):"},{"line_number":97,"context_line":"        with sql.session_for_write() as session:"},{"line_number":98,"context_line":"            user_ref \u003d session.query(model.User).get(user_id)"},{"line_number":99,"context_line":"            if not user_ref.local_user.failed_auth_cnt:"},{"line_number":100,"context_line":"                user_ref.local_user.failed_auth_cnt \u003d 0"},{"line_number":101,"context_line":"            user_ref.local_user.failed_auth_cnt +\u003d 1"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_52dfc40c","line":98,"updated":"2016-07-29 17:36:37.000000000","message":"Same as below -- all you\u0027re doing is writing at this point -- you shouldn\u0027t need to do anything transactional :(\n\n  q \u003d session.query(model.User)\n  q \u003d q.filter_by(id\u003duser_id)\n  q \u003d q.update({\u0027count\u0027: model.User.failed_auth_cnt + 1})\n\nOtherwise, I\u0027d be seriously worried about performance under load.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"68fb21a188ef32fdab734f01c98212d620db0dff","unresolved":false,"context_lines":[{"line_number":95,"context_line":""},{"line_number":96,"context_line":"    def _record_failed_auth(self, user_id):"},{"line_number":97,"context_line":"        with sql.session_for_write() as session:"},{"line_number":98,"context_line":"            user_ref \u003d session.query(model.User).get(user_id)"},{"line_number":99,"context_line":"            if not user_ref.local_user.failed_auth_cnt:"},{"line_number":100,"context_line":"                user_ref.local_user.failed_auth_cnt \u003d 0"},{"line_number":101,"context_line":"            user_ref.local_user.failed_auth_cnt +\u003d 1"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_d5fd1e6f","line":98,"in_reply_to":"bacf61ea_2a47314c","updated":"2016-08-01 13:21:57.000000000","message":"This is an opportunity for an unauthenticated denial of service attack against keystone if this isn\u0027t optimized before it merges, especially because nothing about this write appears to be optional or fault tolerant.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"efa989be9faf0e7f8daf076a2be9007e00214f2a","unresolved":false,"context_lines":[{"line_number":95,"context_line":""},{"line_number":96,"context_line":"    def _record_failed_auth(self, user_id):"},{"line_number":97,"context_line":"        with sql.session_for_write() as session:"},{"line_number":98,"context_line":"            user_ref \u003d session.query(model.User).get(user_id)"},{"line_number":99,"context_line":"            if not user_ref.local_user.failed_auth_cnt:"},{"line_number":100,"context_line":"                user_ref.local_user.failed_auth_cnt \u003d 0"},{"line_number":101,"context_line":"            user_ref.local_user.failed_auth_cnt +\u003d 1"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_ffa84079","line":98,"in_reply_to":"bacf61ea_52dfc40c","updated":"2016-07-29 18:26:37.000000000","message":"Hmm... was just easier, but see your point. I\u0027ll need to work on the syntax for this.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"c6cec6c334fd4273fcabd00979aa14524867326c","unresolved":false,"context_lines":[{"line_number":95,"context_line":""},{"line_number":96,"context_line":"    def _record_failed_auth(self, user_id):"},{"line_number":97,"context_line":"        with sql.session_for_write() as session:"},{"line_number":98,"context_line":"            user_ref \u003d session.query(model.User).get(user_id)"},{"line_number":99,"context_line":"            if not user_ref.local_user.failed_auth_cnt:"},{"line_number":100,"context_line":"                user_ref.local_user.failed_auth_cnt \u003d 0"},{"line_number":101,"context_line":"            user_ref.local_user.failed_auth_cnt +\u003d 1"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_2a47314c","line":98,"in_reply_to":"bacf61ea_52dfc40c","updated":"2016-07-29 23:40:21.000000000","message":"I tried several things, including this code:\nhttp://paste.openstack.org/show/544027/\n\nHowever, there seems to be a delay with that sort of update. Initially, I\u0027d run the unit tests and they would pass. But if I ran the tests repeatedly, eventually they would fail as if the count hadn\u0027t register quick enough. \n\nLeaving this as is for now. I\u0027ll try to optimize this in a subsequent patch.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"69b7a97a48bcecd2c26f7f34b0bb816394ce99e7","unresolved":false,"context_lines":[{"line_number":95,"context_line":""},{"line_number":96,"context_line":"    def _record_failed_auth(self, user_id):"},{"line_number":97,"context_line":"        with sql.session_for_write() as session:"},{"line_number":98,"context_line":"            user_ref \u003d session.query(model.User).get(user_id)"},{"line_number":99,"context_line":"            if not user_ref.local_user.failed_auth_cnt:"},{"line_number":100,"context_line":"                user_ref.local_user.failed_auth_cnt \u003d 0"},{"line_number":101,"context_line":"            user_ref.local_user.failed_auth_cnt +\u003d 1"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_d2fb6a77","line":98,"in_reply_to":"bacf61ea_d5fd1e6f","updated":"2016-08-01 15:33:48.000000000","message":"Done","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"e3c3886d664c0df6af7bfb02722418ee9ebdc831","unresolved":false,"context_lines":[{"line_number":95,"context_line":""},{"line_number":96,"context_line":"    def _record_failed_auth(self, user_id):"},{"line_number":97,"context_line":"        with sql.session_for_write() as session:"},{"line_number":98,"context_line":"            user_ref \u003d session.query(model.User).get(user_id)"},{"line_number":99,"context_line":"            if not user_ref.local_user.failed_auth_cnt:"},{"line_number":100,"context_line":"                user_ref.local_user.failed_auth_cnt \u003d 0"},{"line_number":101,"context_line":"            user_ref.local_user.failed_auth_cnt +\u003d 1"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_5525595a","line":98,"in_reply_to":"bacf61ea_d5fd1e6f","updated":"2016-08-02 19:36:24.000000000","message":"I\u0027ve tried several update queries and they all result in the same behavior, the lockout tests run successfully, but eventually fail when executed repeatedly. When the tests fail, the failed_auth_count never gets updated.\n\nThe tests always succeed when querying the object first and then setting the attribute, which is how we are doing updates throughout keystone. And thinking about this some more, I don\u0027t feel that this will be a performance issue, even under heavy loads, as this write will only occur during failed auth attempts.\n\nAs with all of the PCI features, this write is optional. If you don\u0027t set the lockout_failure_attempts property, this method will never be called.\n\nTherefore, I propose that we revert the code back and not do the update query.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"051cec4268cc5adfc865a3ebabee3ccd488f742d","unresolved":false,"context_lines":[{"line_number":95,"context_line":""},{"line_number":96,"context_line":"    def _record_failed_auth(self, user_id):"},{"line_number":97,"context_line":"        with sql.session_for_write() as session:"},{"line_number":98,"context_line":"            user_ref \u003d session.query(model.User).get(user_id)"},{"line_number":99,"context_line":"            if not user_ref.local_user.failed_auth_cnt:"},{"line_number":100,"context_line":"                user_ref.local_user.failed_auth_cnt \u003d 0"},{"line_number":101,"context_line":"            user_ref.local_user.failed_auth_cnt +\u003d 1"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_32e3e6da","line":98,"in_reply_to":"bacf61ea_d5fd1e6f","updated":"2016-08-01 15:33:24.000000000","message":"True; tried something different.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a402890d6dd5c1774dfae3390d8bf873d0d5093","unresolved":false,"context_lines":[{"line_number":103,"context_line":""},{"line_number":104,"context_line":"    def _reset_failed_auth(self, user_id):"},{"line_number":105,"context_line":"        with sql.session_for_write() as session:"},{"line_number":106,"context_line":"            user_ref \u003d session.query(model.User).get(user_id)"},{"line_number":107,"context_line":"            user_ref.local_user.failed_auth_cnt \u003d 0"},{"line_number":108,"context_line":"            user_ref.local_user.failed_auth_at \u003d None"},{"line_number":109,"context_line":""}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_12ac2c8b","line":106,"updated":"2016-07-29 17:36:37.000000000","message":"Do you really have to do a SELECT first? This seems really inefficient if it actually emits one.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"c6cec6c334fd4273fcabd00979aa14524867326c","unresolved":false,"context_lines":[{"line_number":103,"context_line":""},{"line_number":104,"context_line":"    def _reset_failed_auth(self, user_id):"},{"line_number":105,"context_line":"        with sql.session_for_write() as session:"},{"line_number":106,"context_line":"            user_ref \u003d session.query(model.User).get(user_id)"},{"line_number":107,"context_line":"            user_ref.local_user.failed_auth_cnt \u003d 0"},{"line_number":108,"context_line":"            user_ref.local_user.failed_auth_at \u003d None"},{"line_number":109,"context_line":""}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_aa7161aa","line":106,"in_reply_to":"bacf61ea_12ac2c8b","updated":"2016-07-29 23:40:21.000000000","message":"See comment above.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"32bcca616fd48bd9d4fbed99d3a391fa5cbc8a52","unresolved":false,"context_lines":[{"line_number":75,"context_line":"    def _is_account_locked(self, user_id, user_ref):"},{"line_number":76,"context_line":"        \"\"\"Check if the user account is locked."},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"        Checks if the user account is locked based on the number of failed"},{"line_number":79,"context_line":"        authentication attempts."},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"        :param user_id: The user ID"},{"line_number":82,"context_line":"        :param user_ref: Reference to the user object"}],"source_content_type":"text/x-python","patch_set":45,"id":"bacf61ea_fb1cb467","line":79,"range":{"start_line":78,"start_character":8,"end_line":79,"end_character":32},"updated":"2016-08-05 05:17:58.000000000","message":"may want to expand on this as there are other checks that happen for when the config is not setup","commit_id":"0e2cc0562a5a97c836356df0a016ca2b28d97c36"},{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"32bcca616fd48bd9d4fbed99d3a391fa5cbc8a52","unresolved":false,"context_lines":[{"line_number":83,"context_line":"        :returns Boolean: True if the account is locked; False otherwise"},{"line_number":84,"context_line":""},{"line_number":85,"context_line":"        \"\"\""},{"line_number":86,"context_line":"        attempts \u003d user_ref.local_user.failed_auth_count or 0"},{"line_number":87,"context_line":"        max_attempts \u003d CONF.security_compliance.lockout_failure_attempts"},{"line_number":88,"context_line":"        lockout_duration \u003d CONF.security_compliance.lockout_duration"},{"line_number":89,"context_line":"        if max_attempts and (attempts \u003e\u003d max_attempts):"},{"line_number":90,"context_line":"            if not lockout_duration:"},{"line_number":91,"context_line":"                return True"},{"line_number":92,"context_line":"            else:"},{"line_number":93,"context_line":"                delta \u003d datetime.timedelta(seconds\u003dlockout_duration)"},{"line_number":94,"context_line":"                last_failure \u003d user_ref.local_user.failed_auth_at"},{"line_number":95,"context_line":"                if (last_failure + delta) \u003e datetime.datetime.utcnow():"},{"line_number":96,"context_line":"                    return True"},{"line_number":97,"context_line":"                else:"},{"line_number":98,"context_line":"                    self._reset_failed_auth(user_id)"},{"line_number":99,"context_line":"        return False"},{"line_number":100,"context_line":""},{"line_number":101,"context_line":"    def _record_failed_auth(self, user_id):"}],"source_content_type":"text/x-python","patch_set":45,"id":"bacf61ea_fb6af4b3","line":98,"range":{"start_line":86,"start_character":8,"end_line":98,"end_character":52},"updated":"2016-08-05 05:17:58.000000000","message":"comments would help with readability","commit_id":"0e2cc0562a5a97c836356df0a016ca2b28d97c36"}],"keystone/identity/backends/sql_model.py":[{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"bd46088b97291ffdb69e45768ffce1caf7d735c8","unresolved":false,"context_lines":[{"line_number":152,"context_line":"            self.last_active_at \u003d datetime.datetime.utcnow().date()"},{"line_number":153,"context_line":"        if value and self.local_user:"},{"line_number":154,"context_line":"            self.local_user.failed_auth_cnt \u003d 0"},{"line_number":155,"context_line":"            self.local_user.failed_auth_at \u003d None"},{"line_number":156,"context_line":"        self._enabled \u003d value"},{"line_number":157,"context_line":""},{"line_number":158,"context_line":"    @enabled.expression"}],"source_content_type":"text/x-python","patch_set":25,"id":"fad55976_4af948c8","line":155,"updated":"2016-07-15 19:33:07.000000000","message":"Couldn\u0027t a user be enabled but also have a history of failed auth attempts?","commit_id":"561d9068e7e23764704716b57a3b99cb5729b81c"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"ce2381b20584ee5e595b38b4b73abeb795657598","unresolved":false,"context_lines":[{"line_number":152,"context_line":"            self.last_active_at \u003d datetime.datetime.utcnow().date()"},{"line_number":153,"context_line":"        if value and self.local_user:"},{"line_number":154,"context_line":"            self.local_user.failed_auth_cnt \u003d 0"},{"line_number":155,"context_line":"            self.local_user.failed_auth_at \u003d None"},{"line_number":156,"context_line":"        self._enabled \u003d value"},{"line_number":157,"context_line":""},{"line_number":158,"context_line":"    @enabled.expression"}],"source_content_type":"text/x-python","patch_set":25,"id":"fad55976_9800b7ac","line":155,"in_reply_to":"fad55976_4af948c8","updated":"2016-07-15 20:10:40.000000000","message":"Yes, but if you set enabled to True, it will reset failed auth attempts.  This will allow admins to manually unlock a user account.","commit_id":"561d9068e7e23764704716b57a3b99cb5729b81c"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a402890d6dd5c1774dfae3390d8bf873d0d5093","unresolved":false,"context_lines":[{"line_number":180,"context_line":"                                 lazy\u003d\u0027subquery\u0027,"},{"line_number":181,"context_line":"                                 backref\u003d\u0027local_user\u0027,"},{"line_number":182,"context_line":"                                 order_by\u003d\u0027Password.created_at\u0027)"},{"line_number":183,"context_line":"    failed_auth_cnt \u003d sql.Column(sql.Integer, nullable\u003dTrue)"},{"line_number":184,"context_line":"    failed_auth_at \u003d sql.Column(sql.DateTime, nullable\u003dTrue)"},{"line_number":185,"context_line":"    __table_args__ \u003d (sql.UniqueConstraint(\u0027domain_id\u0027, \u0027name\u0027), {})"},{"line_number":186,"context_line":""}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_32321060","line":183,"updated":"2016-07-29 17:36:37.000000000","message":"Can we not spell out \"count\" for some reason?","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"efa989be9faf0e7f8daf076a2be9007e00214f2a","unresolved":false,"context_lines":[{"line_number":180,"context_line":"                                 lazy\u003d\u0027subquery\u0027,"},{"line_number":181,"context_line":"                                 backref\u003d\u0027local_user\u0027,"},{"line_number":182,"context_line":"                                 order_by\u003d\u0027Password.created_at\u0027)"},{"line_number":183,"context_line":"    failed_auth_cnt \u003d sql.Column(sql.Integer, nullable\u003dTrue)"},{"line_number":184,"context_line":"    failed_auth_at \u003d sql.Column(sql.DateTime, nullable\u003dTrue)"},{"line_number":185,"context_line":"    __table_args__ \u003d (sql.UniqueConstraint(\u0027domain_id\u0027, \u0027name\u0027), {})"},{"line_number":186,"context_line":""}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_5fb86cc8","line":183,"in_reply_to":"bacf61ea_32321060","updated":"2016-07-29 18:26:37.000000000","message":"Done","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"}],"keystone/tests/unit/identity/test_backend_sql.py":[{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"d09d847701f7355e8574eb165ecb1629cbedf8c4","unresolved":false,"context_lines":[{"line_number":13,"context_line":"import datetime"},{"line_number":14,"context_line":"import uuid"},{"line_number":15,"context_line":""},{"line_number":16,"context_line":"from freezegun import freeze_time"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"import keystone.conf"},{"line_number":19,"context_line":"from keystone import exception"}],"source_content_type":"text/x-python","patch_set":10,"id":"1aa78d24_68a0dff4","line":16,"updated":"2016-07-12 19:47:40.000000000","message":"we typically only do module level imports\n\n    import freezegun\n    ....\n    freezegun.freeze_time()","commit_id":"1a8abfa650157edfe7b608b3299f01cdf0418fc6"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"1e3bf7fea2eef1a5de0737910b1f3d2954e8eb97","unresolved":false,"context_lines":[{"line_number":13,"context_line":"import datetime"},{"line_number":14,"context_line":"import uuid"},{"line_number":15,"context_line":""},{"line_number":16,"context_line":"from freezegun import freeze_time"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"import keystone.conf"},{"line_number":19,"context_line":"from keystone import exception"}],"source_content_type":"text/x-python","patch_set":10,"id":"1aa78d24_a83c87e1","line":16,"in_reply_to":"1aa78d24_68a0dff4","updated":"2016-07-12 20:09:47.000000000","message":"Ah, right.  Done.","commit_id":"1a8abfa650157edfe7b608b3299f01cdf0418fc6"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"d09d847701f7355e8574eb165ecb1629cbedf8c4","unresolved":false,"context_lines":[{"line_number":96,"context_line":"                                                      user_id\u003dself.user[\u0027id\u0027],"},{"line_number":97,"context_line":"                                                      password\u003dself.password)"},{"line_number":98,"context_line":"            self.assertEqual(self.user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":99,"context_line":"            # authenticate with wrong password, test fail auth cnt gets reset"},{"line_number":100,"context_line":"            self.assertRaises(AssertionError,"},{"line_number":101,"context_line":"                              self.identity_api.authenticate,"},{"line_number":102,"context_line":"                              context\u003d{},"}],"source_content_type":"text/x-python","patch_set":10,"id":"1aa78d24_e86faf8f","line":99,"updated":"2016-07-12 19:47:40.000000000","message":"we should make sure we can attempt to authenticate (or fail to authenticate) self.max_attempts.. that way we know for sure that failed_auth_cnt was reset in the database.","commit_id":"1a8abfa650157edfe7b608b3299f01cdf0418fc6"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"1e3bf7fea2eef1a5de0737910b1f3d2954e8eb97","unresolved":false,"context_lines":[{"line_number":96,"context_line":"                                                      user_id\u003dself.user[\u0027id\u0027],"},{"line_number":97,"context_line":"                                                      password\u003dself.password)"},{"line_number":98,"context_line":"            self.assertEqual(self.user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":99,"context_line":"            # authenticate with wrong password, test fail auth cnt gets reset"},{"line_number":100,"context_line":"            self.assertRaises(AssertionError,"},{"line_number":101,"context_line":"                              self.identity_api.authenticate,"},{"line_number":102,"context_line":"                              context\u003d{},"}],"source_content_type":"text/x-python","patch_set":10,"id":"1aa78d24_9cebcc12","line":99,"in_reply_to":"1aa78d24_e86faf8f","updated":"2016-07-12 20:09:47.000000000","message":"Added a new test case for this where:\n1. lockout user\n2. go past duration\n3. immediately test again with wrong password, expecting AssertionError and not AccountLocked exception.","commit_id":"1a8abfa650157edfe7b608b3299f01cdf0418fc6"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"243d6af5ad7766b567221d69cdb2dfb2364d101d","unresolved":false,"context_lines":[{"line_number":118,"context_line":"            # freeze time past the duration, failed_auth_cnt should reset"},{"line_number":119,"context_line":"            frozen_datetime.tick("},{"line_number":120,"context_line":"                delta\u003ddatetime.timedelta(seconds\u003dself.max_duration + 1))"},{"line_number":121,"context_line":"            # authenticate with wrong password"},{"line_number":122,"context_line":"            self.assertRaises(AssertionError,"},{"line_number":123,"context_line":"                              self.identity_api.authenticate,"},{"line_number":124,"context_line":"                              context\u003d{},"}],"source_content_type":"text/x-python","patch_set":11,"id":"1aa78d24_bc36884e","line":121,"updated":"2016-07-12 20:18:00.000000000","message":"we should be able to lock the user out by failing authentication 6 times.","commit_id":"66d74496f4791ab59de49f21572f3f6a25e88437"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"375b92d0271fb6151d7edfa379c3074cf08d9339","unresolved":false,"context_lines":[{"line_number":118,"context_line":"            # freeze time past the duration, failed_auth_cnt should reset"},{"line_number":119,"context_line":"            frozen_datetime.tick("},{"line_number":120,"context_line":"                delta\u003ddatetime.timedelta(seconds\u003dself.max_duration + 1))"},{"line_number":121,"context_line":"            # authenticate with wrong password"},{"line_number":122,"context_line":"            self.assertRaises(AssertionError,"},{"line_number":123,"context_line":"                              self.identity_api.authenticate,"},{"line_number":124,"context_line":"                              context\u003d{},"}],"source_content_type":"text/x-python","patch_set":11,"id":"1aa78d24_7279e992","line":121,"in_reply_to":"1aa78d24_bc36884e","updated":"2016-07-12 20:48:28.000000000","message":"Modified the test case to do this.  Done.","commit_id":"66d74496f4791ab59de49f21572f3f6a25e88437"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"5e047b353969841aa60fc24c7fe7bcc0e3364b7e","unresolved":false,"context_lines":[{"line_number":220,"context_line":"                              user_id\u003dself.user[\u0027id\u0027],"},{"line_number":221,"context_line":"                              password\u003dself.wrong_password)"},{"line_number":222,"context_line":"            # TODO(rderose) checking for None here as a workaround to get past"},{"line_number":223,"context_line":"            # the keystone-coverage-db gate. remove this when the gate is fixed."},{"line_number":224,"context_line":"            if frozen_datetime:"},{"line_number":225,"context_line":"                # freeze time past the duration, user should be unlocked"},{"line_number":226,"context_line":"                frozen_datetime.tick("}],"source_content_type":"text/x-python","patch_set":16,"id":"1aa78d24_dd05257a","line":223,"updated":"2016-07-13 14:24:33.000000000","message":"We could do this with self.skipTest(). That way it\u0027s easier to find when we figure out what is going on with the keystone-coverage job.\n\nhttps://github.com/openstack/keystone/blob/7923a4669278c1386bea2520adf097760a3ec4fd/keystone/tests/unit/backend/legacy_drivers/resource/V8/sql.py#L39","commit_id":"f3a68e230d602d0c3ae8e1e2ae79db6aa43fd5c2"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"59b410b5084ab4ff8e2aeaac6ce84440712d6574","unresolved":false,"context_lines":[{"line_number":220,"context_line":"                              user_id\u003dself.user[\u0027id\u0027],"},{"line_number":221,"context_line":"                              password\u003dself.wrong_password)"},{"line_number":222,"context_line":"            # TODO(rderose) checking for None here as a workaround to get past"},{"line_number":223,"context_line":"            # the keystone-coverage-db gate. remove this when the gate is fixed."},{"line_number":224,"context_line":"            if frozen_datetime:"},{"line_number":225,"context_line":"                # freeze time past the duration, user should be unlocked"},{"line_number":226,"context_line":"                frozen_datetime.tick("}],"source_content_type":"text/x-python","patch_set":16,"id":"1aa78d24_4b604a01","line":223,"in_reply_to":"1aa78d24_dd05257a","updated":"2016-07-13 16:06:31.000000000","message":"Nice.  Done.","commit_id":"f3a68e230d602d0c3ae8e1e2ae79db6aa43fd5c2"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a402890d6dd5c1774dfae3390d8bf873d0d5093","unresolved":false,"context_lines":[{"line_number":157,"context_line":"    def setUp(self):"},{"line_number":158,"context_line":"        super(LockingOutUserTests, self).setUp()"},{"line_number":159,"context_line":"        self.max_attempts \u003d 6"},{"line_number":160,"context_line":"        self.max_duration \u003d 5"},{"line_number":161,"context_line":"        self.config_fixture.config("},{"line_number":162,"context_line":"            group\u003d\u0027security_compliance\u0027,"},{"line_number":163,"context_line":"            lockout_failure_attempts\u003dself.max_attempts)"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_d228d4e4","line":160,"updated":"2016-07-29 17:36:37.000000000","message":"self.lockout_duration? I didn\u0027t know what this was for until I chased it around. And do you need instance attributes for these, or can you just read back from config in the tests? More instance attributes just makes the tests harder to maintain.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"c6cec6c334fd4273fcabd00979aa14524867326c","unresolved":false,"context_lines":[{"line_number":157,"context_line":"    def setUp(self):"},{"line_number":158,"context_line":"        super(LockingOutUserTests, self).setUp()"},{"line_number":159,"context_line":"        self.max_attempts \u003d 6"},{"line_number":160,"context_line":"        self.max_duration \u003d 5"},{"line_number":161,"context_line":"        self.config_fixture.config("},{"line_number":162,"context_line":"            group\u003d\u0027security_compliance\u0027,"},{"line_number":163,"context_line":"            lockout_failure_attempts\u003dself.max_attempts)"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_f3c35087","line":160,"in_reply_to":"bacf61ea_d228d4e4","updated":"2016-07-29 23:40:21.000000000","message":"Changed to self.lockout_duration. I use these variable in several of the tests. To me it\u0027s cleaner to use the smaller names.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"68fb21a188ef32fdab734f01c98212d620db0dff","unresolved":false,"context_lines":[{"line_number":157,"context_line":"    def setUp(self):"},{"line_number":158,"context_line":"        super(LockingOutUserTests, self).setUp()"},{"line_number":159,"context_line":"        self.max_attempts \u003d 6"},{"line_number":160,"context_line":"        self.max_duration \u003d 5"},{"line_number":161,"context_line":"        self.config_fixture.config("},{"line_number":162,"context_line":"            group\u003d\u0027security_compliance\u0027,"},{"line_number":163,"context_line":"            lockout_failure_attempts\u003dself.max_attempts)"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_f52302bb","line":160,"in_reply_to":"bacf61ea_f3c35087","updated":"2016-08-01 13:21:57.000000000","message":"I see that, but it\u0027s unnecessary indirection for the reader.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"051cec4268cc5adfc865a3ebabee3ccd488f742d","unresolved":false,"context_lines":[{"line_number":157,"context_line":"    def setUp(self):"},{"line_number":158,"context_line":"        super(LockingOutUserTests, self).setUp()"},{"line_number":159,"context_line":"        self.max_attempts \u003d 6"},{"line_number":160,"context_line":"        self.max_duration \u003d 5"},{"line_number":161,"context_line":"        self.config_fixture.config("},{"line_number":162,"context_line":"            group\u003d\u0027security_compliance\u0027,"},{"line_number":163,"context_line":"            lockout_failure_attempts\u003dself.max_attempts)"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_3295a632","line":160,"in_reply_to":"bacf61ea_f52302bb","updated":"2016-08-01 15:33:24.000000000","message":"Okay, see your point; removed the instance variables.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a402890d6dd5c1774dfae3390d8bf873d0d5093","unresolved":false,"context_lines":[{"line_number":166,"context_line":"            lockout_duration\u003dself.max_duration)"},{"line_number":167,"context_line":"        # setup user and passwords"},{"line_number":168,"context_line":"        self.password \u003d uuid.uuid4().hex"},{"line_number":169,"context_line":"        self.wrong_password \u003d uuid.uuid4().hex"},{"line_number":170,"context_line":"        self.user \u003d self._get_new_user(self.password)"},{"line_number":171,"context_line":""},{"line_number":172,"context_line":"    def test_locking_out_user_after_max_failed_attempts(self):"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_4d39e9a3","line":169,"updated":"2016-07-29 17:36:37.000000000","message":"Nowhere else in tests do we \"remember\" garbage data (like an invalid password) -- instead, we just generate a new uuid.uuid4().hex every time we need garbage. It\u0027s cheap enough, clear, and eliminates a variable.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"c6cec6c334fd4273fcabd00979aa14524867326c","unresolved":false,"context_lines":[{"line_number":166,"context_line":"            lockout_duration\u003dself.max_duration)"},{"line_number":167,"context_line":"        # setup user and passwords"},{"line_number":168,"context_line":"        self.password \u003d uuid.uuid4().hex"},{"line_number":169,"context_line":"        self.wrong_password \u003d uuid.uuid4().hex"},{"line_number":170,"context_line":"        self.user \u003d self._get_new_user(self.password)"},{"line_number":171,"context_line":""},{"line_number":172,"context_line":"    def test_locking_out_user_after_max_failed_attempts(self):"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_53bdfc00","line":169,"in_reply_to":"bacf61ea_4d39e9a3","updated":"2016-07-29 23:40:21.000000000","message":"Done","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a402890d6dd5c1774dfae3390d8bf873d0d5093","unresolved":false,"context_lines":[{"line_number":176,"context_line":"                          self.make_request(),"},{"line_number":177,"context_line":"                          user_id\u003dself.user[\u0027id\u0027],"},{"line_number":178,"context_line":"                          password\u003dself.wrong_password)"},{"line_number":179,"context_line":"        # authenticate with right password"},{"line_number":180,"context_line":"        self.identity_api.authenticate(self.make_request(),"},{"line_number":181,"context_line":"                                       user_id\u003dself.user[\u0027id\u0027],"},{"line_number":182,"context_line":"                                       password\u003dself.password)"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_f2535837","line":179,"updated":"2016-07-29 17:36:37.000000000","message":"\"correct\" is easier for non-native speakers","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"efa989be9faf0e7f8daf076a2be9007e00214f2a","unresolved":false,"context_lines":[{"line_number":176,"context_line":"                          self.make_request(),"},{"line_number":177,"context_line":"                          user_id\u003dself.user[\u0027id\u0027],"},{"line_number":178,"context_line":"                          password\u003dself.wrong_password)"},{"line_number":179,"context_line":"        # authenticate with right password"},{"line_number":180,"context_line":"        self.identity_api.authenticate(self.make_request(),"},{"line_number":181,"context_line":"                                       user_id\u003dself.user[\u0027id\u0027],"},{"line_number":182,"context_line":"                                       password\u003dself.password)"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_ffede0b7","line":179,"in_reply_to":"bacf61ea_f2535837","updated":"2016-07-29 18:26:37.000000000","message":"Done","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a402890d6dd5c1774dfae3390d8bf873d0d5093","unresolved":false,"context_lines":[{"line_number":182,"context_line":"                                       password\u003dself.password)"},{"line_number":183,"context_line":"        # test locking out user after max failed attempts"},{"line_number":184,"context_line":"        self._fail_auth(self.user[\u0027id\u0027], self.wrong_password,"},{"line_number":185,"context_line":"                        self.max_attempts)"},{"line_number":186,"context_line":"        self.assertRaises(exception.AccountLocked,"},{"line_number":187,"context_line":"                          self.identity_api.authenticate,"},{"line_number":188,"context_line":"                          self.make_request(),"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_0d1c1169","line":185,"updated":"2016-07-29 17:36:37.000000000","message":"If max_attempts is 6, why does it fail after just 1 attempt?","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"efa989be9faf0e7f8daf076a2be9007e00214f2a","unresolved":false,"context_lines":[{"line_number":182,"context_line":"                                       password\u003dself.password)"},{"line_number":183,"context_line":"        # test locking out user after max failed attempts"},{"line_number":184,"context_line":"        self._fail_auth(self.user[\u0027id\u0027], self.wrong_password,"},{"line_number":185,"context_line":"                        self.max_attempts)"},{"line_number":186,"context_line":"        self.assertRaises(exception.AccountLocked,"},{"line_number":187,"context_line":"                          self.identity_api.authenticate,"},{"line_number":188,"context_line":"                          self.make_request(),"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_3f1938d8","line":185,"in_reply_to":"bacf61ea_0d1c1169","updated":"2016-07-29 18:26:37.000000000","message":"The fail_auth method will repeat failing authentication the max times; not 1.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a402890d6dd5c1774dfae3390d8bf873d0d5093","unresolved":false,"context_lines":[{"line_number":235,"context_line":""},{"line_number":236,"context_line":"    def test_lockout_duration_failed_auth_cnt_resets(self):"},{"line_number":237,"context_line":"        # freeze time"},{"line_number":238,"context_line":"        time \u003d datetime.datetime.now()"},{"line_number":239,"context_line":"        with freezegun.freeze_time(time) as frozen_datetime:"},{"line_number":240,"context_line":"            # lockout user"},{"line_number":241,"context_line":"            self._fail_auth(self.user[\u0027id\u0027], self.wrong_password,"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_ad3985d9","line":238,"updated":"2016-07-29 17:36:37.000000000","message":"this has a local timezone - bad habit! Do you actually need this though? It seems you only pass it to freeze_time(), but I would have assumed that freeze_time() would default to \"now\" on it\u0027s own.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"efa989be9faf0e7f8daf076a2be9007e00214f2a","unresolved":false,"context_lines":[{"line_number":235,"context_line":""},{"line_number":236,"context_line":"    def test_lockout_duration_failed_auth_cnt_resets(self):"},{"line_number":237,"context_line":"        # freeze time"},{"line_number":238,"context_line":"        time \u003d datetime.datetime.now()"},{"line_number":239,"context_line":"        with freezegun.freeze_time(time) as frozen_datetime:"},{"line_number":240,"context_line":"            # lockout user"},{"line_number":241,"context_line":"            self._fail_auth(self.user[\u0027id\u0027], self.wrong_password,"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_bf25280a","line":238,"in_reply_to":"bacf61ea_ad3985d9","updated":"2016-07-29 18:26:37.000000000","message":"Done","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a402890d6dd5c1774dfae3390d8bf873d0d5093","unresolved":false,"context_lines":[{"line_number":259,"context_line":"                              password\u003dself.wrong_password)"},{"line_number":260,"context_line":""},{"line_number":261,"context_line":"    def _fail_auth(self, user_id, wrong_password, attempts):"},{"line_number":262,"context_line":"        for _ in range(attempts):"},{"line_number":263,"context_line":"            self.assertRaises(AssertionError,"},{"line_number":264,"context_line":"                              self.identity_api.authenticate,"},{"line_number":265,"context_line":"                              self.make_request(),"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_ed189d77","line":262,"updated":"2016-07-29 17:36:37.000000000","message":"Is this method useful enough to keep? It seems to be saving you one line of code, and it\u0027s not obvious from the method name what it actually does (I did not expect it to loop, for sure).","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"efa989be9faf0e7f8daf076a2be9007e00214f2a","unresolved":false,"context_lines":[{"line_number":259,"context_line":"                              password\u003dself.wrong_password)"},{"line_number":260,"context_line":""},{"line_number":261,"context_line":"    def _fail_auth(self, user_id, wrong_password, attempts):"},{"line_number":262,"context_line":"        for _ in range(attempts):"},{"line_number":263,"context_line":"            self.assertRaises(AssertionError,"},{"line_number":264,"context_line":"                              self.identity_api.authenticate,"},{"line_number":265,"context_line":"                              self.make_request(),"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_ffe04098","line":262,"in_reply_to":"bacf61ea_ed189d77","updated":"2016-07-29 18:26:37.000000000","message":"I doing this in several places, so I think the method has value.  Changed the name to make it more apparent that it is looping.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a402890d6dd5c1774dfae3390d8bf873d0d5093","unresolved":false,"context_lines":[{"line_number":266,"context_line":"                              user_id\u003duser_id,"},{"line_number":267,"context_line":"                              password\u003dwrong_password)"},{"line_number":268,"context_line":""},{"line_number":269,"context_line":"    def _get_new_user(self, password):"},{"line_number":270,"context_line":"        user \u003d {"},{"line_number":271,"context_line":"            \u0027name\u0027: uuid.uuid4().hex,"},{"line_number":272,"context_line":"            \u0027domain_id\u0027: CONF.identity.default_domain_id,"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_ed67fdb4","line":269,"updated":"2016-07-29 17:36:37.000000000","message":"You only call this once -- definitely remove this method.","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"efa989be9faf0e7f8daf076a2be9007e00214f2a","unresolved":false,"context_lines":[{"line_number":266,"context_line":"                              user_id\u003duser_id,"},{"line_number":267,"context_line":"                              password\u003dwrong_password)"},{"line_number":268,"context_line":""},{"line_number":269,"context_line":"    def _get_new_user(self, password):"},{"line_number":270,"context_line":"        user \u003d {"},{"line_number":271,"context_line":"            \u0027name\u0027: uuid.uuid4().hex,"},{"line_number":272,"context_line":"            \u0027domain_id\u0027: CONF.identity.default_domain_id,"}],"source_content_type":"text/x-python","patch_set":36,"id":"bacf61ea_bf76c8d4","line":269,"in_reply_to":"bacf61ea_ed67fdb4","updated":"2016-07-29 18:26:37.000000000","message":"Done","commit_id":"388e6c463a1b0d4cb6fd5c40185024a1b8d557f4"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"0ad56228ecc020dc91017d0fd6e294ac0d607e4a","unresolved":false,"context_lines":[{"line_number":236,"context_line":""},{"line_number":237,"context_line":"    def test_lockout_duration_failed_auth_cnt_resets(self):"},{"line_number":238,"context_line":"        # freeze time"},{"line_number":239,"context_line":"        with freezegun.freeze_time(datetime.datetime.now()) as frozen_time:"},{"line_number":240,"context_line":"            # lockout user"},{"line_number":241,"context_line":"            self._fail_auth_repeatedly(self.user[\u0027id\u0027], self.max_attempts)"},{"line_number":242,"context_line":"            self.assertRaises(exception.AccountLocked,"}],"source_content_type":"text/x-python","patch_set":39,"id":"bacf61ea_673489dd","line":239,"updated":"2016-08-01 13:22:17.000000000","message":"This still isn\u0027t using utcnow() - just a bad habit!","commit_id":"6d9678f622e5272d946b023ca341938e06fba281"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"012a486baa33554a3ca5828ac4144b0293589edb","unresolved":false,"context_lines":[{"line_number":236,"context_line":""},{"line_number":237,"context_line":"    def test_lockout_duration_failed_auth_cnt_resets(self):"},{"line_number":238,"context_line":"        # freeze time"},{"line_number":239,"context_line":"        with freezegun.freeze_time(datetime.datetime.now()) as frozen_time:"},{"line_number":240,"context_line":"            # lockout user"},{"line_number":241,"context_line":"            self._fail_auth_repeatedly(self.user[\u0027id\u0027], self.max_attempts)"},{"line_number":242,"context_line":"            self.assertRaises(exception.AccountLocked,"}],"source_content_type":"text/x-python","patch_set":39,"id":"bacf61ea_c0b8bb77","line":239,"in_reply_to":"bacf61ea_673489dd","updated":"2016-08-01 14:19:09.000000000","message":"Dam, my bad. I\u0027ll definitely pay closer attention to this.","commit_id":"6d9678f622e5272d946b023ca341938e06fba281"}],"test-requirements.txt":[{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"bd46088b97291ffdb69e45768ffce1caf7d735c8","unresolved":false,"context_lines":[{"line_number":7,"context_line":"flake8-docstrings\u003d\u003d0.2.1.post1 # MIT"},{"line_number":8,"context_line":"bashate\u003e\u003d0.2 # Apache-2.0"},{"line_number":9,"context_line":"os-testr\u003e\u003d0.7.0 # Apache-2.0"},{"line_number":10,"context_line":"freezegun # Apache-2.0"},{"line_number":11,"context_line":""},{"line_number":12,"context_line":"# Include drivers for opportunistic testing."},{"line_number":13,"context_line":"oslo.db[fixtures,mysql,postgresql]\u003e\u003d4.1.0 # Apache-2.0"}],"source_content_type":"text/plain","patch_set":25,"id":"fad55976_0ae750e5","line":10,"updated":"2016-07-15 19:33:07.000000000","message":"I think this might need an extra space to avoid the proposal bot re-updating it http://git.openstack.org/cgit/openstack/requirements/tree/global-requirements.txt#n300","commit_id":"561d9068e7e23764704716b57a3b99cb5729b81c"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"0c18a57b7bc33d121842769277b3d68ce355cf73","unresolved":false,"context_lines":[{"line_number":7,"context_line":"flake8-docstrings\u003d\u003d0.2.1.post1 # MIT"},{"line_number":8,"context_line":"bashate\u003e\u003d0.2 # Apache-2.0"},{"line_number":9,"context_line":"os-testr\u003e\u003d0.7.0 # Apache-2.0"},{"line_number":10,"context_line":"freezegun # Apache-2.0"},{"line_number":11,"context_line":""},{"line_number":12,"context_line":"# Include drivers for opportunistic testing."},{"line_number":13,"context_line":"oslo.db[fixtures,mysql,postgresql]\u003e\u003d4.1.0 # Apache-2.0"}],"source_content_type":"text/plain","patch_set":25,"id":"fad55976_6435fff5","line":10,"in_reply_to":"fad55976_0ae750e5","updated":"2016-07-16 15:07:42.000000000","message":"Done","commit_id":"561d9068e7e23764704716b57a3b99cb5729b81c"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"ce2381b20584ee5e595b38b4b73abeb795657598","unresolved":false,"context_lines":[{"line_number":7,"context_line":"flake8-docstrings\u003d\u003d0.2.1.post1 # MIT"},{"line_number":8,"context_line":"bashate\u003e\u003d0.2 # Apache-2.0"},{"line_number":9,"context_line":"os-testr\u003e\u003d0.7.0 # Apache-2.0"},{"line_number":10,"context_line":"freezegun # Apache-2.0"},{"line_number":11,"context_line":""},{"line_number":12,"context_line":"# Include drivers for opportunistic testing."},{"line_number":13,"context_line":"oslo.db[fixtures,mysql,postgresql]\u003e\u003d4.1.0 # Apache-2.0"}],"source_content_type":"text/plain","patch_set":25,"id":"fad55976_787ce320","line":10,"in_reply_to":"fad55976_0ae750e5","updated":"2016-07-15 20:10:40.000000000","message":"Hopefully this is fine; it did pass the requirements job.","commit_id":"561d9068e7e23764704716b57a3b99cb5729b81c"}]}
