)]}'
{"keystone/conf/security_compliance.py":[{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"17ca654ca67f61e11ebc0f8557fa6188fc9c5085","unresolved":false,"context_lines":[{"line_number":54,"context_line":"    help\u003dutils.fmt(\"\"\""},{"line_number":55,"context_line":"Number of latest password iterations for which the password must be unique."},{"line_number":56,"context_line":"Thus when set, validation will be added to ensure that new passwords do not"},{"line_number":57,"context_line":"match the previous passwords. This feature is disabled by default. Note: this"},{"line_number":58,"context_line":"feature is only supported via the SQL backend driver for identity."},{"line_number":59,"context_line":"\"\"\"))"},{"line_number":60,"context_line":""}],"source_content_type":"text/x-python","patch_set":30,"id":"1aa78d24_8af0e3fe","line":57,"updated":"2016-07-11 18:56:16.000000000","message":"This says the feature is disabled by default but the default is 1. This is because the password depth is determined by the length of the password list and the list will always be at least 2, right?","commit_id":"d3df651a93d3e8626e390670483d3b125bdfe6dc"},{"author":{"_account_id":6460,"name":"Brad Topol","email":"btopol@us.ibm.com","username":"btopol"},"change_message_id":"abe485dc0bd19883568d2c4e128d183fc6da1928","unresolved":false,"context_lines":[{"line_number":54,"context_line":"    help\u003dutils.fmt(\"\"\""},{"line_number":55,"context_line":"Number of latest password iterations for which the password must be unique."},{"line_number":56,"context_line":"Thus when set, validation will be added to ensure that new passwords do not"},{"line_number":57,"context_line":"match the previous passwords. This feature is disabled by default. Note: this"},{"line_number":58,"context_line":"feature is only supported via the SQL backend driver for identity."},{"line_number":59,"context_line":"\"\"\"))"},{"line_number":60,"context_line":""}],"source_content_type":"text/x-python","patch_set":30,"id":"1aa78d24_d5c56c8e","line":57,"in_reply_to":"1aa78d24_8af0e3fe","updated":"2016-07-11 19:24:38.000000000","message":"So 1 is the default and the value must be greater than or equal to 1?  All of this should be made more clear.","commit_id":"d3df651a93d3e8626e390670483d3b125bdfe6dc"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"e2305fecd85237bbc1e6efdede3a136420f4ee43","unresolved":false,"context_lines":[{"line_number":54,"context_line":"    help\u003dutils.fmt(\"\"\""},{"line_number":55,"context_line":"Number of latest password iterations for which the password must be unique."},{"line_number":56,"context_line":"Thus when set, validation will be added to ensure that new passwords do not"},{"line_number":57,"context_line":"match the previous passwords. This feature is disabled by default. Note: this"},{"line_number":58,"context_line":"feature is only supported via the SQL backend driver for identity."},{"line_number":59,"context_line":"\"\"\"))"},{"line_number":60,"context_line":""}],"source_content_type":"text/x-python","patch_set":30,"id":"1aa78d24_44d6ef4f","line":57,"in_reply_to":"1aa78d24_d5c56c8e","updated":"2016-07-11 20:12:30.000000000","message":"Reworded this so that greater than 1 indicates that the feature is enabled.","commit_id":"d3df651a93d3e8626e390670483d3b125bdfe6dc"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"c4421ed333037a70226b75aaa9f6337fe69591f8","unresolved":false,"context_lines":[{"line_number":71,"context_line":"This controls the number of previous user password iterations to keep in"},{"line_number":72,"context_line":"history, in order to enforce that newly created passwords are unique. Setting"},{"line_number":73,"context_line":"the value to one (the default) disables this feature. Thus, to enable this"},{"line_number":74,"context_line":"feature, values must be greater than 1. This feature depends on the `sql`"},{"line_number":75,"context_line":"backend for the `[identity] driver`."},{"line_number":76,"context_line":"\"\"\"))"},{"line_number":77,"context_line":""}],"source_content_type":"text/x-python","patch_set":41,"id":"bacf61ea_08b71587","line":74,"updated":"2016-07-28 19:55:27.000000000","message":"Why did we move away from 0 for disabling this feature? What if the cloud really does want to say it has to be different that the last password?","commit_id":"27850103adb8d1e3fc25d19ebd7f37249364a73a"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"84e181fdc2355ba54ac3c12c89c3441e6a00bbba","unresolved":false,"context_lines":[{"line_number":71,"context_line":"This controls the number of previous user password iterations to keep in"},{"line_number":72,"context_line":"history, in order to enforce that newly created passwords are unique. Setting"},{"line_number":73,"context_line":"the value to one (the default) disables this feature. Thus, to enable this"},{"line_number":74,"context_line":"feature, values must be greater than 1. This feature depends on the `sql`"},{"line_number":75,"context_line":"backend for the `[identity] driver`."},{"line_number":76,"context_line":"\"\"\"))"},{"line_number":77,"context_line":""}],"source_content_type":"text/x-python","patch_set":41,"id":"bacf61ea_eb5d5b7a","line":74,"in_reply_to":"bacf61ea_08b71587","updated":"2016-07-28 20:04:53.000000000","message":"We moved away from 0 to simplify truncating the extra passwords. One indicates having single password in your password history. So if you want the password to be different than the last password, you would set it to 2.","commit_id":"27850103adb8d1e3fc25d19ebd7f37249364a73a"}],"keystone/exception.py":[{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a393f1078cb77d6500a39a0122ca0d6fa6c1f8e","unresolved":false,"context_lines":[{"line_number":94,"context_line":""},{"line_number":95,"context_line":""},{"line_number":96,"context_line":"class PasswordValidationError(ValidationError):"},{"line_number":97,"context_line":"    message_format \u003d _(\"%(detail)s\")"},{"line_number":98,"context_line":""},{"line_number":99,"context_line":""},{"line_number":100,"context_line":"class SchemaValidationError(ValidationError):"}],"source_content_type":"text/x-python","patch_set":13,"id":"7aa08908_b113c1b6","line":97,"updated":"2016-06-16 16:22:03.000000000","message":"Wasn\u0027t this in another review as well?","commit_id":"db7b6631967cf4f110fa635bba0237cb332143d6"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"591d249b6fd260eb87c0b603f814ba5e3ca0572e","unresolved":false,"context_lines":[{"line_number":94,"context_line":""},{"line_number":95,"context_line":""},{"line_number":96,"context_line":"class PasswordValidationError(ValidationError):"},{"line_number":97,"context_line":"    message_format \u003d _(\"%(detail)s\")"},{"line_number":98,"context_line":""},{"line_number":99,"context_line":""},{"line_number":100,"context_line":"class SchemaValidationError(ValidationError):"}],"source_content_type":"text/x-python","patch_set":13,"id":"3aaa91ec_4c033f10","line":97,"in_reply_to":"7aa08908_b113c1b6","updated":"2016-06-21 16:57:24.000000000","message":"Yes: https://review.openstack.org/#/c/320586/42/keystone/exception.py\n\nI\u0027ll prefix it with \"Invalid password: \" for both patches.","commit_id":"db7b6631967cf4f110fa635bba0237cb332143d6"}],"keystone/identity/backends/sql.py":[{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"7214cc5e6ee2753bd92da3a906e0bf886445880e","unresolved":false,"context_lines":[{"line_number":256,"context_line":""},{"line_number":257,"context_line":""},{"line_number":258,"context_line":"class PasswordHistoryValidator(object):"},{"line_number":259,"context_line":"    def validate(self, password, user_ref):"},{"line_number":260,"context_line":"        cnt \u003d 0"},{"line_number":261,"context_line":"        max_cnt \u003d (CONF.security_compliance.unique_last_password_count if"},{"line_number":262,"context_line":"                   CONF.security_compliance.unique_last_password_count else 0)"}],"source_content_type":"text/x-python","patch_set":7,"id":"7aa08908_fdf4acf1","line":259,"updated":"2016-06-13 18:54:49.000000000","message":"We should probably think about removing passwords as they are added so you don\u0027t have to do the math here and we can make sure that we don\u0027t have a continuously growing table.","commit_id":"c0e2ea8d95b593611219d2da8accb9470bb72693"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"40f6ab20262b7bc9f82d31b934f59c06b993816c","unresolved":false,"context_lines":[{"line_number":256,"context_line":""},{"line_number":257,"context_line":""},{"line_number":258,"context_line":"class PasswordHistoryValidator(object):"},{"line_number":259,"context_line":"    def validate(self, password, user_ref):"},{"line_number":260,"context_line":"        cnt \u003d 0"},{"line_number":261,"context_line":"        max_cnt \u003d (CONF.security_compliance.unique_last_password_count if"},{"line_number":262,"context_line":"                   CONF.security_compliance.unique_last_password_count else 0)"}],"source_content_type":"text/x-python","patch_set":7,"id":"7aa08908_b8c192e6","line":259,"in_reply_to":"7aa08908_fdf4acf1","updated":"2016-06-13 19:33:22.000000000","message":"++ that\u0027s a good point. Pruning the old passwords would be a good idea.","commit_id":"c0e2ea8d95b593611219d2da8accb9470bb72693"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"5e91d217f7de82f0dd1e90b612904c1ddd341a2d","unresolved":false,"context_lines":[{"line_number":268,"context_line":"            elif utils.check_password(password, password_ref.password):"},{"line_number":269,"context_line":"                detail \u003d _(\u0027Invalid password: matches value in history\u0027)"},{"line_number":270,"context_line":"                raise exception.PasswordValidationError(detail\u003ddetail)"},{"line_number":271,"context_line":"            cnt \u003d cnt + 1"}],"source_content_type":"text/x-python","patch_set":7,"id":"7aa08908_c24d8b73","line":271,"updated":"2016-06-13 18:43:05.000000000","message":"nit: shorthand\n\n    cnt +\u003d1","commit_id":"c0e2ea8d95b593611219d2da8accb9470bb72693"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"aaac80debd191b0ab0c816f8b7e0a5eb9cda1564","unresolved":false,"context_lines":[{"line_number":106,"context_line":"        with sql.session_for_write() as session:"},{"line_number":107,"context_line":"            user_ref \u003d self._get_user(session, user_id)"},{"line_number":108,"context_line":"            if user.get(\u0027password\u0027) is not None:"},{"line_number":109,"context_line":"                PasswordHistoryValidator().validate(user[\u0027password\u0027], user_ref)"},{"line_number":110,"context_line":"            old_user_dict \u003d user_ref.to_dict()"},{"line_number":111,"context_line":"            user \u003d utils.hash_user_password(user)"},{"line_number":112,"context_line":"            for k in user:"}],"source_content_type":"text/x-python","patch_set":13,"id":"7aa08908_1425635b","line":109,"updated":"2016-06-16 16:45:21.000000000","message":"So I don\u0027t get the order of operations with regards to truncation. Will the truncation using -1 in local passwords lead to having 2 passwords even when the unique_last_password_count is 0?","commit_id":"db7b6631967cf4f110fa635bba0237cb332143d6"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"33d2e46f2a174a877f019cdcfb0f7ce083b61ca4","unresolved":false,"context_lines":[{"line_number":106,"context_line":"        with sql.session_for_write() as session:"},{"line_number":107,"context_line":"            user_ref \u003d self._get_user(session, user_id)"},{"line_number":108,"context_line":"            if user.get(\u0027password\u0027) is not None:"},{"line_number":109,"context_line":"                PasswordHistoryValidator().validate(user[\u0027password\u0027], user_ref)"},{"line_number":110,"context_line":"            old_user_dict \u003d user_ref.to_dict()"},{"line_number":111,"context_line":"            user \u003d utils.hash_user_password(user)"},{"line_number":112,"context_line":"            for k in user:"}],"source_content_type":"text/x-python","patch_set":13,"id":"3aaa91ec_5e5bd354","line":109,"in_reply_to":"3aaa91ec_9890b297","updated":"2016-06-21 20:51:25.000000000","message":"The one exception would be if no password is supplied when the user is created. In that case, there would only be one password after the update.","commit_id":"db7b6631967cf4f110fa635bba0237cb332143d6"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"03055ed2eb03ec88151cbb870607f22bec635768","unresolved":false,"context_lines":[{"line_number":106,"context_line":"        with sql.session_for_write() as session:"},{"line_number":107,"context_line":"            user_ref \u003d self._get_user(session, user_id)"},{"line_number":108,"context_line":"            if user.get(\u0027password\u0027) is not None:"},{"line_number":109,"context_line":"                PasswordHistoryValidator().validate(user[\u0027password\u0027], user_ref)"},{"line_number":110,"context_line":"            old_user_dict \u003d user_ref.to_dict()"},{"line_number":111,"context_line":"            user \u003d utils.hash_user_password(user)"},{"line_number":112,"context_line":"            for k in user:"}],"source_content_type":"text/x-python","patch_set":13,"id":"3aaa91ec_9890b297","line":109,"in_reply_to":"7aa08908_1425635b","updated":"2016-06-21 20:44:51.000000000","message":"Yes, it will always only have 2 passwords even if unique_last_password_count is set to zero. In the validation, I\u0027m not assuming that the password will actually get saved successfully even though it is part of the same transaction.","commit_id":"db7b6631967cf4f110fa635bba0237cb332143d6"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"8a393f1078cb77d6500a39a0122ca0d6fa6c1f8e","unresolved":false,"context_lines":[{"line_number":258,"context_line":"class PasswordHistoryValidator(object):"},{"line_number":259,"context_line":"    def validate(self, password, user_ref):"},{"line_number":260,"context_line":"        max_cnt \u003d (CONF.security_compliance.unique_last_password_count if"},{"line_number":261,"context_line":"                   CONF.security_compliance.unique_last_password_count else 0)"},{"line_number":262,"context_line":"        self._truncate_passwords(max_cnt, user_ref)"},{"line_number":263,"context_line":"        if max_cnt \u003e 0:"},{"line_number":264,"context_line":"            for password_ref in user_ref.local_user.passwords:"}],"source_content_type":"text/x-python","patch_set":13,"id":"7aa08908_b4a28fab","line":261,"updated":"2016-06-16 16:22:03.000000000","message":"If you set unique_last_password_count to -1, this looks like it\u0027ll have some wonky behaviors. In fact, I don\u0027t see any use case for the configuration value to be set to anything less than two. Disabled should be None / null / not set / set to whitespace, not zero.\n\nkeystone.conf should be revised similar to the following, and you won\u0027t have to handle so many edge cases here:\n\n  http://cdn.pasteraw.com/mwo41c5yhzxgxj2gqqv6a541zhtix0z","commit_id":"db7b6631967cf4f110fa635bba0237cb332143d6"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"591d249b6fd260eb87c0b603f814ba5e3ca0572e","unresolved":false,"context_lines":[{"line_number":258,"context_line":"class PasswordHistoryValidator(object):"},{"line_number":259,"context_line":"    def validate(self, password, user_ref):"},{"line_number":260,"context_line":"        max_cnt \u003d (CONF.security_compliance.unique_last_password_count if"},{"line_number":261,"context_line":"                   CONF.security_compliance.unique_last_password_count else 0)"},{"line_number":262,"context_line":"        self._truncate_passwords(max_cnt, user_ref)"},{"line_number":263,"context_line":"        if max_cnt \u003e 0:"},{"line_number":264,"context_line":"            for password_ref in user_ref.local_user.passwords:"}],"source_content_type":"text/x-python","patch_set":13,"id":"3aaa91ec_2f4b452d","line":261,"in_reply_to":"7aa08908_b4a28fab","updated":"2016-06-21 16:57:24.000000000","message":"Done","commit_id":"db7b6631967cf4f110fa635bba0237cb332143d6"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"aaac80debd191b0ab0c816f8b7e0a5eb9cda1564","unresolved":false,"context_lines":[{"line_number":263,"context_line":"        if max_cnt \u003e 0:"},{"line_number":264,"context_line":"            for password_ref in user_ref.local_user.passwords:"},{"line_number":265,"context_line":"                if utils.check_password(password, password_ref.password):"},{"line_number":266,"context_line":"                    detail \u003d _(\u0027Invalid password: matches value in history\u0027)"},{"line_number":267,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"},{"line_number":268,"context_line":""},{"line_number":269,"context_line":"    def _truncate_passwords(self, max_cnt, user_ref):"}],"source_content_type":"text/x-python","patch_set":13,"id":"7aa08908_74178745","line":266,"updated":"2016-06-16 16:45:21.000000000","message":"check_password can fail for other reasons too","commit_id":"db7b6631967cf4f110fa635bba0237cb332143d6"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"591d249b6fd260eb87c0b603f814ba5e3ca0572e","unresolved":false,"context_lines":[{"line_number":263,"context_line":"        if max_cnt \u003e 0:"},{"line_number":264,"context_line":"            for password_ref in user_ref.local_user.passwords:"},{"line_number":265,"context_line":"                if utils.check_password(password, password_ref.password):"},{"line_number":266,"context_line":"                    detail \u003d _(\u0027Invalid password: matches value in history\u0027)"},{"line_number":267,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"},{"line_number":268,"context_line":""},{"line_number":269,"context_line":"    def _truncate_passwords(self, max_cnt, user_ref):"}],"source_content_type":"text/x-python","patch_set":13,"id":"3aaa91ec_4f17b1ed","line":266,"in_reply_to":"7aa08908_74178745","updated":"2016-06-21 16:57:24.000000000","message":"But if it does fail, it means the passwords don\u0027t match, right?","commit_id":"db7b6631967cf4f110fa635bba0237cb332143d6"},{"author":{"_account_id":5707,"name":"Henry Nash","email":"henryn@linux.vnet.ibm.com","username":"henry-nash"},"change_message_id":"c37a21b7dedc3729d6f8ab55f3cda43488274409","unresolved":false,"context_lines":[{"line_number":269,"context_line":"    def _truncate_passwords(self, max_cnt, user_ref):"},{"line_number":270,"context_line":"        n \u003d len(user_ref.local_user.passwords)"},{"line_number":271,"context_line":"        if max_cnt \u003d\u003d 0:"},{"line_number":272,"context_line":"            user_ref.local_user.passwords \u003d [user_ref.local_user.passwords[-1]]"},{"line_number":273,"context_line":"        elif n \u003e max_cnt:"},{"line_number":274,"context_line":"            n -\u003d max_cnt"},{"line_number":275,"context_line":"            del user_ref.local_user.passwords[:n]"}],"source_content_type":"text/x-python","patch_set":13,"id":"7aa08908_8ddcba75","line":272,"range":{"start_line":272,"start_character":45,"end_line":272,"end_character":79},"updated":"2016-06-16 11:15:36.000000000","message":"so password is (I think) an optional attribute, so if the user_ref doesn\u0027t have a password, which might cause this is error? In fact, I\u0027m not sure how we handle having no password if unique_last_password_count is set? Is that even a valid scenario (but not sure we prevent it)?","commit_id":"db7b6631967cf4f110fa635bba0237cb332143d6"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"6e8993f49785d27f0852788707ee2222b07df802","unresolved":false,"context_lines":[{"line_number":269,"context_line":"    def _truncate_passwords(self, max_cnt, user_ref):"},{"line_number":270,"context_line":"        n \u003d len(user_ref.local_user.passwords)"},{"line_number":271,"context_line":"        if max_cnt \u003d\u003d 0:"},{"line_number":272,"context_line":"            user_ref.local_user.passwords \u003d [user_ref.local_user.passwords[-1]]"},{"line_number":273,"context_line":"        elif n \u003e max_cnt:"},{"line_number":274,"context_line":"            n -\u003d max_cnt"},{"line_number":275,"context_line":"            del user_ref.local_user.passwords[:n]"}],"source_content_type":"text/x-python","patch_set":13,"id":"7aa08908_4fc9145a","line":272,"in_reply_to":"7aa08908_2e4ad127","updated":"2016-06-16 16:33:16.000000000","message":"I wrote a test for that locally here http://cdn.pasteraw.com/c742f35crl7h6cfp0wcnemudfu89dof","commit_id":"db7b6631967cf4f110fa635bba0237cb332143d6"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"aaac80debd191b0ab0c816f8b7e0a5eb9cda1564","unresolved":false,"context_lines":[{"line_number":269,"context_line":"    def _truncate_passwords(self, max_cnt, user_ref):"},{"line_number":270,"context_line":"        n \u003d len(user_ref.local_user.passwords)"},{"line_number":271,"context_line":"        if max_cnt \u003d\u003d 0:"},{"line_number":272,"context_line":"            user_ref.local_user.passwords \u003d [user_ref.local_user.passwords[-1]]"},{"line_number":273,"context_line":"        elif n \u003e max_cnt:"},{"line_number":274,"context_line":"            n -\u003d max_cnt"},{"line_number":275,"context_line":"            del user_ref.local_user.passwords[:n]"}],"source_content_type":"text/x-python","patch_set":13,"id":"7aa08908_f18429d4","line":272,"range":{"start_line":272,"start_character":45,"end_line":272,"end_character":79},"in_reply_to":"7aa08908_2e4ad127","updated":"2016-06-16 16:45:21.000000000","message":"If you can get into a situation where a  user has no passwords then this line would raise an IndexError. The tests mask this issue because they always create a user with a password.\n\n+    def test_truncate_passwords_when_max_is_zero(self):\n+        expected_length \u003d 1\n+        max_cnt \u003d 0\n+        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,\n+                                   unique_last_password_count\u003dmax_cnt)\n+        #user \u003d self._create_user(uuid.uuid4().hex)\n+        user \u003d {\n+            \u0027name\u0027: uuid.uuid4().hex,\n+            \u0027domain_id\u0027: \u0027default\u0027,\n+            \u0027enabled\u0027: True,\n+        }\n+        user \u003d self.identity_api.create_user(user)\n+        self._add_passwords(user, 1)\n+","commit_id":"db7b6631967cf4f110fa635bba0237cb332143d6"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"595fef8cbe0ea566b20703f7b631206a37c7b2b0","unresolved":false,"context_lines":[{"line_number":269,"context_line":"    def _truncate_passwords(self, max_cnt, user_ref):"},{"line_number":270,"context_line":"        n \u003d len(user_ref.local_user.passwords)"},{"line_number":271,"context_line":"        if max_cnt \u003d\u003d 0:"},{"line_number":272,"context_line":"            user_ref.local_user.passwords \u003d [user_ref.local_user.passwords[-1]]"},{"line_number":273,"context_line":"        elif n \u003e max_cnt:"},{"line_number":274,"context_line":"            n -\u003d max_cnt"},{"line_number":275,"context_line":"            del user_ref.local_user.passwords[:n]"}],"source_content_type":"text/x-python","patch_set":13,"id":"7aa08908_fa9d2b0b","line":272,"range":{"start_line":272,"start_character":45,"end_line":272,"end_character":79},"in_reply_to":"7aa08908_8ddcba75","updated":"2016-06-16 14:05:02.000000000","message":"If the password is not set, the password value would be None, so we would always have a password record to compare.","commit_id":"db7b6631967cf4f110fa635bba0237cb332143d6"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"591d249b6fd260eb87c0b603f814ba5e3ca0572e","unresolved":false,"context_lines":[{"line_number":269,"context_line":"    def _truncate_passwords(self, max_cnt, user_ref):"},{"line_number":270,"context_line":"        n \u003d len(user_ref.local_user.passwords)"},{"line_number":271,"context_line":"        if max_cnt \u003d\u003d 0:"},{"line_number":272,"context_line":"            user_ref.local_user.passwords \u003d [user_ref.local_user.passwords[-1]]"},{"line_number":273,"context_line":"        elif n \u003e max_cnt:"},{"line_number":274,"context_line":"            n -\u003d max_cnt"},{"line_number":275,"context_line":"            del user_ref.local_user.passwords[:n]"}],"source_content_type":"text/x-python","patch_set":13,"id":"3aaa91ec_cf71e1e2","line":272,"range":{"start_line":272,"start_character":45,"end_line":272,"end_character":79},"in_reply_to":"7aa08908_f18429d4","updated":"2016-06-21 16:57:24.000000000","message":"Thanks lbragstad and dstanek, I\u0027ll add this test and make the necessary changes in the next patch.","commit_id":"db7b6631967cf4f110fa635bba0237cb332143d6"},{"author":{"_account_id":5707,"name":"Henry Nash","email":"henryn@linux.vnet.ibm.com","username":"henry-nash"},"change_message_id":"6496b10b7a4435a6e9f37cb6f0ac2607a609a949","unresolved":false,"context_lines":[{"line_number":269,"context_line":"    def _truncate_passwords(self, max_cnt, user_ref):"},{"line_number":270,"context_line":"        n \u003d len(user_ref.local_user.passwords)"},{"line_number":271,"context_line":"        if max_cnt \u003d\u003d 0:"},{"line_number":272,"context_line":"            user_ref.local_user.passwords \u003d [user_ref.local_user.passwords[-1]]"},{"line_number":273,"context_line":"        elif n \u003e max_cnt:"},{"line_number":274,"context_line":"            n -\u003d max_cnt"},{"line_number":275,"context_line":"            del user_ref.local_user.passwords[:n]"}],"source_content_type":"text/x-python","patch_set":13,"id":"7aa08908_2e4ad127","line":272,"range":{"start_line":272,"start_character":45,"end_line":272,"end_character":79},"in_reply_to":"7aa08908_fa9d2b0b","updated":"2016-06-16 15:01:23.000000000","message":"...I guess my concern is whether that would cause this method to be called when len(user_ref.local_user.passwords) is zero....which would result in this line throwing an error.  Maybe worth having a test for a user with no password?","commit_id":"db7b6631967cf4f110fa635bba0237cb332143d6"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"1b5554bd920be0cbc93cb65432f28f540b7f65d6","unresolved":false,"context_lines":[{"line_number":272,"context_line":"            user_ref.local_user.passwords \u003d [user_ref.local_user.passwords[-1]]"},{"line_number":273,"context_line":"        elif n \u003e max_cnt:"},{"line_number":274,"context_line":"            n -\u003d max_cnt"},{"line_number":275,"context_line":"            del user_ref.local_user.passwords[:n]"}],"source_content_type":"text/x-python","patch_set":13,"id":"7aa08908_2fd76850","line":275,"updated":"2016-06-16 16:30:26.000000000","message":"This could be simplified to:\n\n  del user_ref.local_user.passwords[:-max_cnt]\n\nAnd you wouldn\u0027t need the elif, either. Perform the truncation unconditionally.","commit_id":"db7b6631967cf4f110fa635bba0237cb332143d6"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"551bc891c03c542fbc0c18e586f947fd853b3967","unresolved":false,"context_lines":[{"line_number":272,"context_line":"            user_ref.local_user.passwords \u003d [user_ref.local_user.passwords[-1]]"},{"line_number":273,"context_line":"        elif n \u003e max_cnt:"},{"line_number":274,"context_line":"            n -\u003d max_cnt"},{"line_number":275,"context_line":"            del user_ref.local_user.passwords[:n]"}],"source_content_type":"text/x-python","patch_set":13,"id":"3aaa91ec_984b9259","line":275,"in_reply_to":"3aaa91ec_2f0ce541","updated":"2016-06-21 20:17:59.000000000","message":"Made this change, but test cases failed and it hurt my brain to try to figure out why :)","commit_id":"db7b6631967cf4f110fa635bba0237cb332143d6"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"591d249b6fd260eb87c0b603f814ba5e3ca0572e","unresolved":false,"context_lines":[{"line_number":272,"context_line":"            user_ref.local_user.passwords \u003d [user_ref.local_user.passwords[-1]]"},{"line_number":273,"context_line":"        elif n \u003e max_cnt:"},{"line_number":274,"context_line":"            n -\u003d max_cnt"},{"line_number":275,"context_line":"            del user_ref.local_user.passwords[:n]"}],"source_content_type":"text/x-python","patch_set":13,"id":"3aaa91ec_2f0ce541","line":275,"in_reply_to":"7aa08908_2fd76850","updated":"2016-06-21 16:57:24.000000000","message":"Done","commit_id":"db7b6631967cf4f110fa635bba0237cb332143d6"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"b8ac7a51c6a619a069060ed328024267b7f13518","unresolved":false,"context_lines":[{"line_number":256,"context_line":""},{"line_number":257,"context_line":""},{"line_number":258,"context_line":"class PasswordHistoryValidator(object):"},{"line_number":259,"context_line":"    def validate(self, password, user_ref):"},{"line_number":260,"context_line":"        max_cnt \u003d (CONF.security_compliance.unique_last_password_count if"},{"line_number":261,"context_line":"                   CONF.security_compliance.unique_last_password_count else 0)"},{"line_number":262,"context_line":"        self._truncate_passwords(max_cnt, user_ref)"}],"source_content_type":"text/x-python","patch_set":19,"id":"3aaa91ec_79d470bc","line":259,"updated":"2016-06-23 16:58:00.000000000","message":"maybe move this all up to the update_user method to tie this logic closer to the whole overall operation?","commit_id":"e926b4a5ce24748e4a803e65678b618a8bae43fa"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"b8ac7a51c6a619a069060ed328024267b7f13518","unresolved":false,"context_lines":[{"line_number":269,"context_line":"    def _truncate_passwords(self, max_cnt, user_ref):"},{"line_number":270,"context_line":"        n \u003d len(user_ref.local_user.passwords)"},{"line_number":271,"context_line":"        if max_cnt \u003d\u003d 0 and n \u003e 0:"},{"line_number":272,"context_line":"            user_ref.local_user.passwords \u003d [user_ref.local_user.passwords[-1]]"},{"line_number":273,"context_line":"        elif n \u003e max_cnt:"},{"line_number":274,"context_line":"            n -\u003d max_cnt"},{"line_number":275,"context_line":"            del user_ref.local_user.passwords[:n]"}],"source_content_type":"text/x-python","patch_set":19,"id":"3aaa91ec_5991b446","line":272,"updated":"2016-06-23 16:58:00.000000000","message":"so in this case we only ever keep the last, or most recent password.","commit_id":"e926b4a5ce24748e4a803e65678b618a8bae43fa"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"b7b7ba5458abdf08680c26f0d1772d1b5f3ed58c","unresolved":false,"context_lines":[{"line_number":255,"context_line":"            session.delete(ref)"},{"line_number":256,"context_line":""},{"line_number":257,"context_line":""},{"line_number":258,"context_line":"class PasswordHistoryValidator(object):"},{"line_number":259,"context_line":"    def validate(self, password, user_ref):"},{"line_number":260,"context_line":"        max_cnt \u003d (CONF.security_compliance.unique_last_password_count if"},{"line_number":261,"context_line":"                   CONF.security_compliance.unique_last_password_count else 0)"}],"source_content_type":"text/x-python","patch_set":21,"id":"3aaa91ec_b4a25649","line":258,"updated":"2016-06-23 19:32:47.000000000","message":"Did we want to move this up under the `update_user` method?","commit_id":"eafe85a235a71bab5e94113a12d07e406a41ac55"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"0433147f1458f1b8a96ff1a938b92541b3e98ee8","unresolved":false,"context_lines":[{"line_number":255,"context_line":"            session.delete(ref)"},{"line_number":256,"context_line":""},{"line_number":257,"context_line":""},{"line_number":258,"context_line":"class PasswordHistoryValidator(object):"},{"line_number":259,"context_line":"    def validate(self, password, user_ref):"},{"line_number":260,"context_line":"        max_cnt \u003d (CONF.security_compliance.unique_last_password_count if"},{"line_number":261,"context_line":"                   CONF.security_compliance.unique_last_password_count else 0)"}],"source_content_type":"text/x-python","patch_set":21,"id":"3aaa91ec_12aa0f19","line":258,"in_reply_to":"3aaa91ec_b4a25649","updated":"2016-06-25 15:55:39.000000000","message":"Done","commit_id":"eafe85a235a71bab5e94113a12d07e406a41ac55"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"0ca25140f92c30c27f60d1e2fbfab1613f4144eb","unresolved":false,"context_lines":[{"line_number":255,"context_line":"            session.delete(ref)"},{"line_number":256,"context_line":""},{"line_number":257,"context_line":""},{"line_number":258,"context_line":"class PasswordHistoryValidator(object):"},{"line_number":259,"context_line":"    def validate(self, password, user_ref):"},{"line_number":260,"context_line":"        max_cnt \u003d (CONF.security_compliance.unique_last_password_count if"},{"line_number":261,"context_line":"                   CONF.security_compliance.unique_last_password_count else 0)"}],"source_content_type":"text/x-python","patch_set":21,"id":"3aaa91ec_420254b5","line":258,"in_reply_to":"3aaa91ec_b4a25649","updated":"2016-06-23 20:06:39.000000000","message":"My preference is that we not move this up. While I understand the reason for wanting to move it, there is an argument for keeping it here as well.","commit_id":"eafe85a235a71bab5e94113a12d07e406a41ac55"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"957a5374c1e3cc42e198413baff0746cfe07d00f","unresolved":false,"context_lines":[{"line_number":12,"context_line":"# License for the specific language governing permissions and limitations"},{"line_number":13,"context_line":"# under the License."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"from oslo_config import cfg"},{"line_number":16,"context_line":"import sqlalchemy"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"from keystone.common import driver_hints"}],"source_content_type":"text/x-python","patch_set":26,"id":"3aaa91ec_0f667eec","line":15,"updated":"2016-06-30 16:11:13.000000000","message":"There is a new way to get this. Checkout the keystone.conf.CONF -\u003e http://git.openstack.org/cgit/openstack/keystone/tree/keystone/identity/controllers.py#n29","commit_id":"b7b35d482747418395cb458be4755b793d5c4a1d"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"3deefe62085b8ab6176a6ad8554c93dee632dcd6","unresolved":false,"context_lines":[{"line_number":12,"context_line":"# License for the specific language governing permissions and limitations"},{"line_number":13,"context_line":"# under the License."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"from oslo_config import cfg"},{"line_number":16,"context_line":"import sqlalchemy"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"from keystone.common import driver_hints"}],"source_content_type":"text/x-python","patch_set":26,"id":"3aaa91ec_ef07b215","line":15,"updated":"2016-06-30 18:38:40.000000000","message":"nit: import keystone.conf","commit_id":"b7b35d482747418395cb458be4755b793d5c4a1d"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"3bf9caa0fdfee79cb528a39ba7563e23a9da1a46","unresolved":false,"context_lines":[{"line_number":12,"context_line":"# License for the specific language governing permissions and limitations"},{"line_number":13,"context_line":"# under the License."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"from oslo_config import cfg"},{"line_number":16,"context_line":"import sqlalchemy"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"from keystone.common import driver_hints"}],"source_content_type":"text/x-python","patch_set":26,"id":"3aaa91ec_89cf0728","line":15,"in_reply_to":"3aaa91ec_0f667eec","updated":"2016-06-30 18:05:51.000000000","message":"Done","commit_id":"b7b35d482747418395cb458be4755b793d5c4a1d"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"75e60a52e4f456ff994740c88eee2371506ce3bd","unresolved":false,"context_lines":[{"line_number":12,"context_line":"# License for the specific language governing permissions and limitations"},{"line_number":13,"context_line":"# under the License."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"from oslo_config import cfg"},{"line_number":16,"context_line":"import sqlalchemy"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"from keystone.common import driver_hints"}],"source_content_type":"text/x-python","patch_set":26,"id":"3aaa91ec_20a6e0c0","line":15,"in_reply_to":"3aaa91ec_ef07b215","updated":"2016-06-30 19:09:37.000000000","message":"Done","commit_id":"b7b35d482747418395cb458be4755b793d5c4a1d"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"3deefe62085b8ab6176a6ad8554c93dee632dcd6","unresolved":false,"context_lines":[{"line_number":24,"context_line":"from keystone.identity.backends import sql_model as model"},{"line_number":25,"context_line":""},{"line_number":26,"context_line":""},{"line_number":27,"context_line":"CONF \u003d cfg.CONF"},{"line_number":28,"context_line":""},{"line_number":29,"context_line":""},{"line_number":30,"context_line":"class Identity(base.IdentityDriverV8):"}],"source_content_type":"text/x-python","patch_set":26,"id":"3aaa91ec_0f115e52","line":27,"updated":"2016-06-30 18:38:40.000000000","message":"nit: CONF \u003d keystone.conf.CONF","commit_id":"b7b35d482747418395cb458be4755b793d5c4a1d"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"75e60a52e4f456ff994740c88eee2371506ce3bd","unresolved":false,"context_lines":[{"line_number":24,"context_line":"from keystone.identity.backends import sql_model as model"},{"line_number":25,"context_line":""},{"line_number":26,"context_line":""},{"line_number":27,"context_line":"CONF \u003d cfg.CONF"},{"line_number":28,"context_line":""},{"line_number":29,"context_line":""},{"line_number":30,"context_line":"class Identity(base.IdentityDriverV8):"}],"source_content_type":"text/x-python","patch_set":26,"id":"3aaa91ec_80a99492","line":27,"in_reply_to":"3aaa91ec_0f115e52","updated":"2016-06-30 19:09:37.000000000","message":"Done","commit_id":"b7b35d482747418395cb458be4755b793d5c4a1d"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"957a5374c1e3cc42e198413baff0746cfe07d00f","unresolved":false,"context_lines":[{"line_number":126,"context_line":"        if max_cnt \u003e 0:"},{"line_number":127,"context_line":"            for password_ref in user_ref.local_user.passwords:"},{"line_number":128,"context_line":"                if utils.check_password(password, password_ref.password):"},{"line_number":129,"context_line":"                    detail \u003d _(\u0027Invalid password: matches value in history\u0027)"},{"line_number":130,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"},{"line_number":131,"context_line":""},{"line_number":132,"context_line":"    def _truncate_passwords(self, max_cnt, user_ref):"}],"source_content_type":"text/x-python","patch_set":26,"id":"3aaa91ec_8fa6eebe","line":129,"updated":"2016-06-30 16:11:13.000000000","message":"Strange output when this runs. \"Invalid password: Invalid password: matches value in history\"","commit_id":"b7b35d482747418395cb458be4755b793d5c4a1d"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"3deefe62085b8ab6176a6ad8554c93dee632dcd6","unresolved":false,"context_lines":[{"line_number":126,"context_line":"        if max_cnt \u003e 0:"},{"line_number":127,"context_line":"            for password_ref in user_ref.local_user.passwords:"},{"line_number":128,"context_line":"                if utils.check_password(password, password_ref.password):"},{"line_number":129,"context_line":"                    detail \u003d _(\u0027Invalid password: matches value in history\u0027)"},{"line_number":130,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"},{"line_number":131,"context_line":""},{"line_number":132,"context_line":"    def _truncate_passwords(self, max_cnt, user_ref):"}],"source_content_type":"text/x-python","patch_set":26,"id":"3aaa91ec_6f8f4275","line":129,"updated":"2016-06-30 18:38:40.000000000","message":"The UX on this error message could be improved... \"matches value in history\" makes sense to developers reading this code, but from a user perspective, something along the lines of \"You are not allowed to reuse recent passwords\" would make more sense.","commit_id":"b7b35d482747418395cb458be4755b793d5c4a1d"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"75e60a52e4f456ff994740c88eee2371506ce3bd","unresolved":false,"context_lines":[{"line_number":126,"context_line":"        if max_cnt \u003e 0:"},{"line_number":127,"context_line":"            for password_ref in user_ref.local_user.passwords:"},{"line_number":128,"context_line":"                if utils.check_password(password, password_ref.password):"},{"line_number":129,"context_line":"                    detail \u003d _(\u0027Invalid password: matches value in history\u0027)"},{"line_number":130,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"},{"line_number":131,"context_line":""},{"line_number":132,"context_line":"    def _truncate_passwords(self, max_cnt, user_ref):"}],"source_content_type":"text/x-python","patch_set":26,"id":"3aaa91ec_009e4462","line":129,"in_reply_to":"3aaa91ec_6f8f4275","updated":"2016-06-30 19:09:37.000000000","message":"Done","commit_id":"b7b35d482747418395cb458be4755b793d5c4a1d"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"3bf9caa0fdfee79cb528a39ba7563e23a9da1a46","unresolved":false,"context_lines":[{"line_number":126,"context_line":"        if max_cnt \u003e 0:"},{"line_number":127,"context_line":"            for password_ref in user_ref.local_user.passwords:"},{"line_number":128,"context_line":"                if utils.check_password(password, password_ref.password):"},{"line_number":129,"context_line":"                    detail \u003d _(\u0027Invalid password: matches value in history\u0027)"},{"line_number":130,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"},{"line_number":131,"context_line":""},{"line_number":132,"context_line":"    def _truncate_passwords(self, max_cnt, user_ref):"}],"source_content_type":"text/x-python","patch_set":26,"id":"3aaa91ec_cc6f5d29","line":129,"in_reply_to":"3aaa91ec_8fa6eebe","updated":"2016-06-30 18:05:51.000000000","message":"Done","commit_id":"b7b35d482747418395cb458be4755b793d5c4a1d"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"3deefe62085b8ab6176a6ad8554c93dee632dcd6","unresolved":false,"context_lines":[{"line_number":135,"context_line":"            user_ref.local_user.passwords \u003d [user_ref.local_user.passwords[-1]]"},{"line_number":136,"context_line":"        elif n \u003e max_cnt:"},{"line_number":137,"context_line":"            n -\u003d max_cnt"},{"line_number":138,"context_line":"            del user_ref.local_user.passwords[:n]"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    def add_user_to_group(self, user_id, group_id):"},{"line_number":141,"context_line":"        with sql.session_for_write() as session:"}],"source_content_type":"text/x-python","patch_set":26,"id":"3aaa91ec_fa9da766","line":138,"updated":"2016-06-30 18:38:40.000000000","message":"I *think* this can be simplified to a one-liner: https://review.openstack.org/#/c/328339/26/keystone/identity/backends/sql.py","commit_id":"b7b35d482747418395cb458be4755b793d5c4a1d"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"75e60a52e4f456ff994740c88eee2371506ce3bd","unresolved":false,"context_lines":[{"line_number":135,"context_line":"            user_ref.local_user.passwords \u003d [user_ref.local_user.passwords[-1]]"},{"line_number":136,"context_line":"        elif n \u003e max_cnt:"},{"line_number":137,"context_line":"            n -\u003d max_cnt"},{"line_number":138,"context_line":"            del user_ref.local_user.passwords[:n]"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    def add_user_to_group(self, user_id, group_id):"},{"line_number":141,"context_line":"        with sql.session_for_write() as session:"}],"source_content_type":"text/x-python","patch_set":26,"id":"3aaa91ec_808074f8","line":138,"in_reply_to":"3aaa91ec_fa9da766","updated":"2016-06-30 19:09:37.000000000","message":"Nice simplification!  Thanks Dolph :)","commit_id":"b7b35d482747418395cb458be4755b793d5c4a1d"},{"author":{"_account_id":6460,"name":"Brad Topol","email":"btopol@us.ibm.com","username":"btopol"},"change_message_id":"abe485dc0bd19883568d2c4e128d183fc6da1928","unresolved":false,"context_lines":[{"line_number":125,"context_line":"        user_ref.local_user.passwords \u003d ("},{"line_number":126,"context_line":"            user_ref.local_user.passwords[-max_cnt:])"},{"line_number":127,"context_line":"        # Validate the new password against the remaining passwords."},{"line_number":128,"context_line":"        if max_cnt \u003e 1:"},{"line_number":129,"context_line":"            for password_ref in user_ref.local_user.passwords:"},{"line_number":130,"context_line":"                if utils.check_password(password, password_ref.password):"},{"line_number":131,"context_line":"                    detail \u003d _(\u0027The new password cannot be identical to a \u0027"}],"source_content_type":"text/x-python","patch_set":30,"id":"1aa78d24_d5d28cff","line":128,"updated":"2016-07-11 19:24:38.000000000","message":"so if max_cnt is -1 no exception for invalid value is thrown?","commit_id":"d3df651a93d3e8626e390670483d3b125bdfe6dc"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"e1c20637e43a8bca2dd7eab4e9db25574c658d8c","unresolved":false,"context_lines":[{"line_number":125,"context_line":"        user_ref.local_user.passwords \u003d ("},{"line_number":126,"context_line":"            user_ref.local_user.passwords[-max_cnt:])"},{"line_number":127,"context_line":"        # Validate the new password against the remaining passwords."},{"line_number":128,"context_line":"        if max_cnt \u003e 1:"},{"line_number":129,"context_line":"            for password_ref in user_ref.local_user.passwords:"},{"line_number":130,"context_line":"                if utils.check_password(password, password_ref.password):"},{"line_number":131,"context_line":"                    detail \u003d _(\u0027The new password cannot be identical to a \u0027"}],"source_content_type":"text/x-python","patch_set":30,"id":"1aa78d24_842297a1","line":128,"in_reply_to":"1aa78d24_d5d28cff","updated":"2016-07-11 20:11:22.000000000","message":"max_cnt cannot be -1.  this is handled in the configuration, min\u003d1.","commit_id":"d3df651a93d3e8626e390670483d3b125bdfe6dc"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"17ca654ca67f61e11ebc0f8557fa6188fc9c5085","unresolved":false,"context_lines":[{"line_number":131,"context_line":"                    detail \u003d _(\u0027The new password cannot be identical to a \u0027"},{"line_number":132,"context_line":"                               \u0027previous password. Number of previous \u0027"},{"line_number":133,"context_line":"                               \u0027passwords: \u0027"},{"line_number":134,"context_line":"                               \u0027%(message)s\u0027) % {\u0027message\u0027: max_cnt}"},{"line_number":135,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"},{"line_number":136,"context_line":""},{"line_number":137,"context_line":"    def add_user_to_group(self, user_id, group_id):"}],"source_content_type":"text/x-python","patch_set":30,"id":"1aa78d24_4a2d5b45","line":134,"updated":"2016-07-11 18:56:16.000000000","message":"What if CONF.security_compliance.unique_last_password_count is 10, but the user has only changed their password once?\n\n Number of previous passwords: 10\n\nThis may seem confusing to a user since they\u0027ve only ever had two passwords. Not sure if there is a better way to word this though.","commit_id":"d3df651a93d3e8626e390670483d3b125bdfe6dc"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"44f3ea4242256c52b0dc1efeb86ce1b7043b37d0","unresolved":false,"context_lines":[{"line_number":131,"context_line":"                    detail \u003d _(\u0027The new password cannot be identical to a \u0027"},{"line_number":132,"context_line":"                               \u0027previous password. Number of previous \u0027"},{"line_number":133,"context_line":"                               \u0027passwords: \u0027"},{"line_number":134,"context_line":"                               \u0027%(message)s\u0027) % {\u0027message\u0027: max_cnt}"},{"line_number":135,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"},{"line_number":136,"context_line":""},{"line_number":137,"context_line":"    def add_user_to_group(self, user_id, group_id):"}],"source_content_type":"text/x-python","patch_set":31,"id":"1aa78d24_dd1720ec","line":134,"updated":"2016-07-12 15:30:19.000000000","message":"See comment from patch set 30. Thoughts?","commit_id":"08c500f8365b066e8b96b2a32014511f0fcfd45b"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"a2a89b818300251cad42a42197a100394237e4b6","unresolved":false,"context_lines":[{"line_number":131,"context_line":"                    detail \u003d _(\u0027The new password cannot be identical to a \u0027"},{"line_number":132,"context_line":"                               \u0027previous password. Number of previous \u0027"},{"line_number":133,"context_line":"                               \u0027passwords: \u0027"},{"line_number":134,"context_line":"                               \u0027%(message)s\u0027) % {\u0027message\u0027: max_cnt}"},{"line_number":135,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"},{"line_number":136,"context_line":""},{"line_number":137,"context_line":"    def add_user_to_group(self, user_id, group_id):"}],"source_content_type":"text/x-python","patch_set":31,"id":"1aa78d24_b63fce85","line":134,"in_reply_to":"1aa78d24_dd1720ec","updated":"2016-07-12 17:45:32.000000000","message":"Sorry, missed that.  Reworded so that it makes more sense.","commit_id":"08c500f8365b066e8b96b2a32014511f0fcfd45b"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"f8ae65a174382217427d80d12cfbebfae2a5146d","unresolved":false,"context_lines":[{"line_number":125,"context_line":""},{"line_number":126,"context_line":"    def _validate_password_history(self, password, user_ref):"},{"line_number":127,"context_line":"        max_cnt \u003d CONF.security_compliance.unique_last_password_count"},{"line_number":128,"context_line":"        # Slice off all of the extra passwords."},{"line_number":129,"context_line":"        user_ref.local_user.passwords \u003d ("},{"line_number":130,"context_line":"            user_ref.local_user.passwords[-max_cnt:])"},{"line_number":131,"context_line":"        # Validate the new password against the remaining passwords."}],"source_content_type":"text/x-python","patch_set":35,"id":"fad55976_36c71d47","line":128,"updated":"2016-07-15 19:44:44.000000000","message":"s/extra/previous/","commit_id":"330c68c2b4c6e4d3062a92837d7ca508de0b0923"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"f8ae65a174382217427d80d12cfbebfae2a5146d","unresolved":false,"context_lines":[{"line_number":134,"context_line":"                if utils.check_password(password, password_ref.password):"},{"line_number":135,"context_line":"                    detail \u003d _(\u0027The new password cannot be identical to a \u0027"},{"line_number":136,"context_line":"                               \u0027previous password. Maximum number of unique\u0027"},{"line_number":137,"context_line":"                               \u0027previous passwords required: \u0027"},{"line_number":138,"context_line":"                               \u0027%(message)s\u0027) % {\u0027message\u0027: max_cnt}"},{"line_number":139,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"},{"line_number":140,"context_line":""}],"source_content_type":"text/x-python","patch_set":35,"id":"fad55976_761d15bd","line":137,"updated":"2016-07-15 19:44:44.000000000","message":"++","commit_id":"330c68c2b4c6e4d3062a92837d7ca508de0b0923"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"a154a822f60c8b71fa0ef2ac99e11c5d82ce41cc","unresolved":false,"context_lines":[{"line_number":133,"context_line":"            for password_ref in user_ref.local_user.passwords:"},{"line_number":134,"context_line":"                if utils.check_password(password, password_ref.password):"},{"line_number":135,"context_line":"                    detail \u003d _(\u0027The new password cannot be identical to a \u0027"},{"line_number":136,"context_line":"                               \u0027previous password. Maximum number of unique\u0027"},{"line_number":137,"context_line":"                               \u0027previous passwords required: \u0027"},{"line_number":138,"context_line":"                               \u0027%(message)s\u0027) % {\u0027message\u0027: max_cnt}"},{"line_number":139,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"}],"source_content_type":"text/x-python","patch_set":40,"id":"bacf61ea_f69550e4","line":136,"updated":"2016-07-28 14:59:43.000000000","message":"Missing a space after `unique`","commit_id":"42ee42d7fbc07c33806ef3fb0c32d8112f830b40"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"d3db176d44653c105abecd3b7e70adb4a43e4f09","unresolved":false,"context_lines":[{"line_number":133,"context_line":"            for password_ref in user_ref.local_user.passwords:"},{"line_number":134,"context_line":"                if utils.check_password(password, password_ref.password):"},{"line_number":135,"context_line":"                    detail \u003d _(\u0027The new password cannot be identical to a \u0027"},{"line_number":136,"context_line":"                               \u0027previous password. Maximum number of unique\u0027"},{"line_number":137,"context_line":"                               \u0027previous passwords required: \u0027"},{"line_number":138,"context_line":"                               \u0027%(message)s\u0027) % {\u0027message\u0027: max_cnt}"},{"line_number":139,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"}],"source_content_type":"text/x-python","patch_set":40,"id":"bacf61ea_2aec9b8e","line":136,"in_reply_to":"bacf61ea_f69550e4","updated":"2016-07-28 15:59:07.000000000","message":"Done","commit_id":"42ee42d7fbc07c33806ef3fb0c32d8112f830b40"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"a154a822f60c8b71fa0ef2ac99e11c5d82ce41cc","unresolved":false,"context_lines":[{"line_number":135,"context_line":"                    detail \u003d _(\u0027The new password cannot be identical to a \u0027"},{"line_number":136,"context_line":"                               \u0027previous password. Maximum number of unique\u0027"},{"line_number":137,"context_line":"                               \u0027previous passwords required: \u0027"},{"line_number":138,"context_line":"                               \u0027%(message)s\u0027) % {\u0027message\u0027: max_cnt}"},{"line_number":139,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"},{"line_number":140,"context_line":""},{"line_number":141,"context_line":"    def add_user_to_group(self, user_id, group_id):"}],"source_content_type":"text/x-python","patch_set":40,"id":"bacf61ea_f6eef089","line":138,"updated":"2016-07-28 14:59:43.000000000","message":"This message is suppressed if you use the python-keystoneclient to update your password. For example, I did the following:\n\n- created a user with password\u003d\u0027password\u0027\n- used osc to update my password to \u0027password2\u0027\n- used osc to update my password to \u0027password\u0027\n\nThe error that I got back was \n\n Old password and new password must be different.\n\nBecause of:\n\nhttps://github.com/openstack/python-keystoneclient/blob/master/keystoneclient/v3/users.py#L220-L222\n\nIf I do the following:\n\n- created a user with password\u003d\u0027password\u0027\n- used osc to update my password to \u0027password2\u0027\n- used osc to update my password to \u0027password3\u0027\n- used osc to update my password to \u0027password\u0027\n\nI get:\n\n Invalid password: The new password cannot be identical to a previous password. Maximum number of uniqueprevious passwords required: 3 (HTTP 400) (Request-ID: req-e88d0239-72b0-4583-a795-9fb4c55ef7fc)\n\n\nWhich is definitely more informative. I wonder if we should patch the client to give this information in the first case, too?","commit_id":"42ee42d7fbc07c33806ef3fb0c32d8112f830b40"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"d3db176d44653c105abecd3b7e70adb4a43e4f09","unresolved":false,"context_lines":[{"line_number":135,"context_line":"                    detail \u003d _(\u0027The new password cannot be identical to a \u0027"},{"line_number":136,"context_line":"                               \u0027previous password. Maximum number of unique\u0027"},{"line_number":137,"context_line":"                               \u0027previous passwords required: \u0027"},{"line_number":138,"context_line":"                               \u0027%(message)s\u0027) % {\u0027message\u0027: max_cnt}"},{"line_number":139,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"},{"line_number":140,"context_line":""},{"line_number":141,"context_line":"    def add_user_to_group(self, user_id, group_id):"}],"source_content_type":"text/x-python","patch_set":40,"id":"bacf61ea_8ab14792","line":138,"in_reply_to":"bacf61ea_f6eef089","updated":"2016-07-28 15:59:07.000000000","message":"I think this is a bug; I\u0027ll add it in launchpad and fix this in a separate patch.","commit_id":"42ee42d7fbc07c33806ef3fb0c32d8112f830b40"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"c4421ed333037a70226b75aaa9f6337fe69591f8","unresolved":false,"context_lines":[{"line_number":135,"context_line":"                    detail \u003d _(\u0027The new password cannot be identical to a \u0027"},{"line_number":136,"context_line":"                               \u0027previous password. Maximum number of unique \u0027"},{"line_number":137,"context_line":"                               \u0027previous passwords required: \u0027"},{"line_number":138,"context_line":"                               \u0027%(message)s\u0027) % {\u0027message\u0027: max_cnt}"},{"line_number":139,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"},{"line_number":140,"context_line":""},{"line_number":141,"context_line":"    def add_user_to_group(self, user_id, group_id):"}],"source_content_type":"text/x-python","patch_set":41,"id":"bacf61ea_28fe5938","line":138,"updated":"2016-07-28 19:55:27.000000000","message":"(nit) %(...)d","commit_id":"27850103adb8d1e3fc25d19ebd7f37249364a73a"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"e55f12952f61571ebd9af009f106228fe524f11c","unresolved":false,"context_lines":[{"line_number":134,"context_line":"                if utils.check_password(password, password_ref.password):"},{"line_number":135,"context_line":"                    detail \u003d _(\u0027The new password cannot be identical to a \u0027"},{"line_number":136,"context_line":"                               \u0027previous password. Maximum number of unique \u0027"},{"line_number":137,"context_line":"                               \u0027previous passwords required: \u0027"},{"line_number":138,"context_line":"                               \u0027%(message)s\u0027) % {\u0027message\u0027: max_cnt}"},{"line_number":139,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"},{"line_number":140,"context_line":""}],"source_content_type":"text/x-python","patch_set":42,"id":"bacf61ea_1f3394f7","line":137,"updated":"2016-07-29 18:03:15.000000000","message":"\"Maximum number of unique passwords required\" is sort of ambiguous to me as an end user. I\u0027m not sure what you\u0027re saying is a problem here (or not). It sounds like I\u0027m supposed to provide a whole bunch of unique passwords at once, or something, but I didn\u0027t.","commit_id":"baacc717dec8b161d496ae23df8911dc566a6038"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"723afeaf7e51e06fdee1298255c36b3bf9aed545","unresolved":false,"context_lines":[{"line_number":134,"context_line":"                if utils.check_password(password, password_ref.password):"},{"line_number":135,"context_line":"                    detail \u003d _(\u0027The new password cannot be identical to a \u0027"},{"line_number":136,"context_line":"                               \u0027previous password. Maximum number of unique \u0027"},{"line_number":137,"context_line":"                               \u0027previous passwords required: \u0027"},{"line_number":138,"context_line":"                               \u0027%(message)s\u0027) % {\u0027message\u0027: max_cnt}"},{"line_number":139,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"},{"line_number":140,"context_line":""}],"source_content_type":"text/x-python","patch_set":42,"id":"bacf61ea_4267f34c","line":137,"in_reply_to":"bacf61ea_1f3394f7","updated":"2016-07-29 18:49:22.000000000","message":"Done","commit_id":"baacc717dec8b161d496ae23df8911dc566a6038"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"e55f12952f61571ebd9af009f106228fe524f11c","unresolved":false,"context_lines":[{"line_number":135,"context_line":"                    detail \u003d _(\u0027The new password cannot be identical to a \u0027"},{"line_number":136,"context_line":"                               \u0027previous password. Maximum number of unique \u0027"},{"line_number":137,"context_line":"                               \u0027previous passwords required: \u0027"},{"line_number":138,"context_line":"                               \u0027%(message)s\u0027) % {\u0027message\u0027: max_cnt}"},{"line_number":139,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"},{"line_number":140,"context_line":""},{"line_number":141,"context_line":"    def add_user_to_group(self, user_id, group_id):"}],"source_content_type":"text/x-python","patch_set":42,"id":"bacf61ea_ff5de015","line":138,"updated":"2016-07-29 18:03:15.000000000","message":"max_cnt is not a \"message\" at all -- use a more appropriate string format label.","commit_id":"baacc717dec8b161d496ae23df8911dc566a6038"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"723afeaf7e51e06fdee1298255c36b3bf9aed545","unresolved":false,"context_lines":[{"line_number":135,"context_line":"                    detail \u003d _(\u0027The new password cannot be identical to a \u0027"},{"line_number":136,"context_line":"                               \u0027previous password. Maximum number of unique \u0027"},{"line_number":137,"context_line":"                               \u0027previous passwords required: \u0027"},{"line_number":138,"context_line":"                               \u0027%(message)s\u0027) % {\u0027message\u0027: max_cnt}"},{"line_number":139,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"},{"line_number":140,"context_line":""},{"line_number":141,"context_line":"    def add_user_to_group(self, user_id, group_id):"}],"source_content_type":"text/x-python","patch_set":42,"id":"bacf61ea_825d6b7b","line":138,"in_reply_to":"bacf61ea_ff5de015","updated":"2016-07-29 18:49:22.000000000","message":"Done","commit_id":"baacc717dec8b161d496ae23df8911dc566a6038"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"804519930e4ac9343bfd917afe4eed9e08a01b26","unresolved":false,"context_lines":[{"line_number":135,"context_line":"                    detail \u003d _(\u0027The new password cannot be identical to a \u0027"},{"line_number":136,"context_line":"                               \u0027previous password. The number of previous \u0027"},{"line_number":137,"context_line":"                               \u0027passwords that must be unique is: \u0027"},{"line_number":138,"context_line":"                               \u0027%(unique_cnt)s\u0027) % {\u0027unique_cnt\u0027: unique_cnt}"},{"line_number":139,"context_line":"                    raise exception.PasswordValidationError(detail\u003ddetail)"},{"line_number":140,"context_line":""},{"line_number":141,"context_line":"    def add_user_to_group(self, user_id, group_id):"}],"source_content_type":"text/x-python","patch_set":43,"id":"bacf61ea_fdb28b05","line":138,"updated":"2016-08-02 14:23:03.000000000","message":"nit: %(..)d - since unique_cnt is an integer type.\n\nFrom David\u0027s comment on patch set 41.","commit_id":"6bc3a74909b548208a35673a4573f00af74b4f49"}],"keystone/tests/unit/identity/backends/test_sql.py":[{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"b8ac7a51c6a619a069060ed328024267b7f13518","unresolved":false,"context_lines":[{"line_number":102,"context_line":"        user \u003d self._create_user(uuid.uuid4().hex)"},{"line_number":103,"context_line":"        self._add_passwords(user, 4)"},{"line_number":104,"context_line":"        user_ref \u003d self._get_user_ref(user[\u0027id\u0027])"},{"line_number":105,"context_line":"        self.assertTrue(len(user_ref.local_user.passwords) \u003d\u003d (max_cnt + 1))"},{"line_number":106,"context_line":""},{"line_number":107,"context_line":"    def test_truncate_passwords_when_max_is_zero(self):"},{"line_number":108,"context_line":"        expected_length \u003d 2"}],"source_content_type":"text/x-python","patch_set":19,"id":"3aaa91ec_393828ef","line":105,"updated":"2016-06-23 16:58:00.000000000","message":"Could use assertGreater here","commit_id":"e926b4a5ce24748e4a803e65678b618a8bae43fa"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"b8ac7a51c6a619a069060ed328024267b7f13518","unresolved":false,"context_lines":[{"line_number":125,"context_line":"                                   unique_last_password_count\u003dmax_cnt)"},{"line_number":126,"context_line":"        self._add_passwords(user, 1)"},{"line_number":127,"context_line":"        user_ref \u003d self._get_user_ref(user[\u0027id\u0027])"},{"line_number":128,"context_line":"        self.assertTrue(len(user_ref.local_user.passwords) \u003d\u003d expected_length)"},{"line_number":129,"context_line":""},{"line_number":130,"context_line":"    def test_truncate_passwords_when_max_is_zero_and_no_password(self):"},{"line_number":131,"context_line":"        expected_length \u003d 1"}],"source_content_type":"text/x-python","patch_set":19,"id":"3aaa91ec_3c2db695","line":128,"updated":"2016-06-23 16:58:00.000000000","message":"Could use assertEqual here","commit_id":"e926b4a5ce24748e4a803e65678b618a8bae43fa"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"b8ac7a51c6a619a069060ed328024267b7f13518","unresolved":false,"context_lines":[{"line_number":140,"context_line":"        user \u003d self.identity_api.create_user(user)"},{"line_number":141,"context_line":"        self._add_passwords(user, 1)"},{"line_number":142,"context_line":"        user_ref \u003d self._get_user_ref(user[\u0027id\u0027])"},{"line_number":143,"context_line":"        self.assertTrue(len(user_ref.local_user.passwords) \u003d\u003d expected_length)"},{"line_number":144,"context_line":""},{"line_number":145,"context_line":"    def _create_user(self, password):"},{"line_number":146,"context_line":"        user \u003d {"}],"source_content_type":"text/x-python","patch_set":19,"id":"3aaa91ec_7c23bea7","line":143,"updated":"2016-06-23 16:58:00.000000000","message":"Could use assertEqual here","commit_id":"e926b4a5ce24748e4a803e65678b618a8bae43fa"}],"keystone/tests/unit/identity/test_backend_sql.py":[{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"957a5374c1e3cc42e198413baff0746cfe07d00f","unresolved":false,"context_lines":[{"line_number":112,"context_line":""},{"line_number":113,"context_line":"    def _add_passwords(self, user, n):"},{"line_number":114,"context_line":"        count \u003d 0"},{"line_number":115,"context_line":"        while (count \u003c n):"},{"line_number":116,"context_line":"            user[\u0027password\u0027] \u003d uuid.uuid4().hex"},{"line_number":117,"context_line":"            self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":118,"context_line":"            count +\u003d 1"}],"source_content_type":"text/x-python","patch_set":26,"id":"3aaa91ec_6fc3c238","line":115,"updated":"2016-06-30 16:11:13.000000000","message":"Instead of using a could a more pythonic way would be \"for _ in range(n):\"","commit_id":"b7b35d482747418395cb458be4755b793d5c4a1d"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"3bf9caa0fdfee79cb528a39ba7563e23a9da1a46","unresolved":false,"context_lines":[{"line_number":112,"context_line":""},{"line_number":113,"context_line":"    def _add_passwords(self, user, n):"},{"line_number":114,"context_line":"        count \u003d 0"},{"line_number":115,"context_line":"        while (count \u003c n):"},{"line_number":116,"context_line":"            user[\u0027password\u0027] \u003d uuid.uuid4().hex"},{"line_number":117,"context_line":"            self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":118,"context_line":"            count +\u003d 1"}],"source_content_type":"text/x-python","patch_set":26,"id":"3aaa91ec_2f041313","line":115,"in_reply_to":"3aaa91ec_6fc3c238","updated":"2016-06-30 18:05:51.000000000","message":"Thanks David :)","commit_id":"b7b35d482747418395cb458be4755b793d5c4a1d"},{"author":{"_account_id":6460,"name":"Brad Topol","email":"btopol@us.ibm.com","username":"btopol"},"change_message_id":"abe485dc0bd19883568d2c4e128d183fc6da1928","unresolved":false,"context_lines":[{"line_number":75,"context_line":"        user_ref \u003d self._get_user_ref(user[\u0027id\u0027])"},{"line_number":76,"context_line":"        self.assertEqual(len(user_ref.local_user.passwords), (max_cnt + 1))"},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"    def test_truncate_passwords_when_max_is_default(self):"},{"line_number":79,"context_line":"        expected_length \u003d 2"},{"line_number":80,"context_line":"        max_cnt \u003d 1"},{"line_number":81,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"}],"source_content_type":"text/x-python","patch_set":30,"id":"1aa78d24_b5f6e08c","line":78,"updated":"2016-07-11 19:24:38.000000000","message":"I think you need a test for when max_cnt is -1","commit_id":"d3df651a93d3e8626e390670483d3b125bdfe6dc"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"e1c20637e43a8bca2dd7eab4e9db25574c658d8c","unresolved":false,"context_lines":[{"line_number":75,"context_line":"        user_ref \u003d self._get_user_ref(user[\u0027id\u0027])"},{"line_number":76,"context_line":"        self.assertEqual(len(user_ref.local_user.passwords), (max_cnt + 1))"},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"    def test_truncate_passwords_when_max_is_default(self):"},{"line_number":79,"context_line":"        expected_length \u003d 2"},{"line_number":80,"context_line":"        max_cnt \u003d 1"},{"line_number":81,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"}],"source_content_type":"text/x-python","patch_set":30,"id":"1aa78d24_64ea0b11","line":78,"in_reply_to":"1aa78d24_b5f6e08c","updated":"2016-07-11 20:11:22.000000000","message":"This should be handled in the configuration.  -1 is not a valid config value.","commit_id":"d3df651a93d3e8626e390670483d3b125bdfe6dc"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"17ca654ca67f61e11ebc0f8557fa6188fc9c5085","unresolved":false,"context_lines":[{"line_number":123,"context_line":"        return self.identity_api.create_user(user)"},{"line_number":124,"context_line":""},{"line_number":125,"context_line":"    def _add_passwords(self, user, n):"},{"line_number":126,"context_line":"        for i in range(n):"},{"line_number":127,"context_line":"            user[\u0027password\u0027] \u003d uuid.uuid4().hex"},{"line_number":128,"context_line":"            self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":129,"context_line":""}],"source_content_type":"text/x-python","patch_set":30,"id":"1aa78d24_ef009904","line":126,"updated":"2016-07-11 18:56:16.000000000","message":"Does \n\n    for _ in range(n):\n\nnot work here?","commit_id":"d3df651a93d3e8626e390670483d3b125bdfe6dc"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"ac6ea63a681cb74ba79269d23bba7e13b5539a54","unresolved":false,"context_lines":[{"line_number":123,"context_line":"        return self.identity_api.create_user(user)"},{"line_number":124,"context_line":""},{"line_number":125,"context_line":"    def _add_passwords(self, user, n):"},{"line_number":126,"context_line":"        for i in range(n):"},{"line_number":127,"context_line":"            user[\u0027password\u0027] \u003d uuid.uuid4().hex"},{"line_number":128,"context_line":"            self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":129,"context_line":""}],"source_content_type":"text/x-python","patch_set":31,"id":"1aa78d24_5a3856ee","line":126,"updated":"2016-07-12 15:25:00.000000000","message":"Does: \n\n    for _ in range(n):\n\nnot work? I think having the underscore would be more pythonic here because we\u0027re not actually using i for anything (i\u0027ll assume dstanek can keep me correct since he made the original comment).","commit_id":"08c500f8365b066e8b96b2a32014511f0fcfd45b"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"a2a89b818300251cad42a42197a100394237e4b6","unresolved":false,"context_lines":[{"line_number":123,"context_line":"        return self.identity_api.create_user(user)"},{"line_number":124,"context_line":""},{"line_number":125,"context_line":"    def _add_passwords(self, user, n):"},{"line_number":126,"context_line":"        for i in range(n):"},{"line_number":127,"context_line":"            user[\u0027password\u0027] \u003d uuid.uuid4().hex"},{"line_number":128,"context_line":"            self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":129,"context_line":""}],"source_content_type":"text/x-python","patch_set":31,"id":"1aa78d24_56a66ac1","line":126,"in_reply_to":"1aa78d24_5a3856ee","updated":"2016-07-12 17:45:32.000000000","message":"Got it.  Thx.","commit_id":"08c500f8365b066e8b96b2a32014511f0fcfd45b"},{"author":{"_account_id":5707,"name":"Henry Nash","email":"henryn@linux.vnet.ibm.com","username":"henry-nash"},"change_message_id":"444f133d055742065368dddd04b764a7349f5cf7","unresolved":false,"context_lines":[{"line_number":189,"context_line":"        second_password \u003d user_ref.password"},{"line_number":190,"context_line":"        self.assertNotEqual(first_password, second_password)"},{"line_number":191,"context_line":""},{"line_number":192,"context_line":"    def test_disabled_validate_password_history_and_repeat_same_password(self):"},{"line_number":193,"context_line":"        password \u003d \u0027samepassword1\u0027"},{"line_number":194,"context_line":"        user \u003d self._create_user(password)"},{"line_number":195,"context_line":"        # update the same password and test"},{"line_number":196,"context_line":"        user[\u0027password\u0027] \u003d password"},{"line_number":197,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":198,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":199,"context_line":"        # repeat"},{"line_number":200,"context_line":"        user[\u0027password\u0027] \u003d password"},{"line_number":201,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":202,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":203,"context_line":""},{"line_number":204,"context_line":"    def test_truncate_passwords(self):"},{"line_number":205,"context_line":"        max_cnt \u003d 2"}],"source_content_type":"text/x-python","patch_set":35,"id":"dada55a8_93ffa800","line":202,"range":{"start_line":192,"start_character":0,"end_line":202,"end_character":52},"updated":"2016-07-25 14:40:53.000000000","message":"I think it would be good to have another test that shows that if we ARE validating password history, and I issue an update with the same password, then this is also fine.","commit_id":"330c68c2b4c6e4d3062a92837d7ca508de0b0923"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"37f858e1191957bea3f16b023ef1ab71589cfa0e","unresolved":false,"context_lines":[{"line_number":189,"context_line":"        second_password \u003d user_ref.password"},{"line_number":190,"context_line":"        self.assertNotEqual(first_password, second_password)"},{"line_number":191,"context_line":""},{"line_number":192,"context_line":"    def test_disabled_validate_password_history_and_repeat_same_password(self):"},{"line_number":193,"context_line":"        password \u003d \u0027samepassword1\u0027"},{"line_number":194,"context_line":"        user \u003d self._create_user(password)"},{"line_number":195,"context_line":"        # update the same password and test"},{"line_number":196,"context_line":"        user[\u0027password\u0027] \u003d password"},{"line_number":197,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":198,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":199,"context_line":"        # repeat"},{"line_number":200,"context_line":"        user[\u0027password\u0027] \u003d password"},{"line_number":201,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":202,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":203,"context_line":""},{"line_number":204,"context_line":"    def test_truncate_passwords(self):"},{"line_number":205,"context_line":"        max_cnt \u003d 2"}],"source_content_type":"text/x-python","patch_set":35,"id":"dada55a8_509b50c9","line":202,"range":{"start_line":192,"start_character":0,"end_line":202,"end_character":52},"in_reply_to":"dada55a8_93ffa800","updated":"2016-07-25 21:21:12.000000000","message":"Good suggestion.  I\u0027ve added a test_validate_password_history_with_valid_password test case to show reusing an existing password.","commit_id":"330c68c2b4c6e4d3062a92837d7ca508de0b0923"},{"author":{"_account_id":5707,"name":"Henry Nash","email":"henryn@linux.vnet.ibm.com","username":"henry-nash"},"change_message_id":"444f133d055742065368dddd04b764a7349f5cf7","unresolved":false,"context_lines":[{"line_number":219,"context_line":"        self._add_passwords(user, 4)"},{"line_number":220,"context_line":"        user_ref \u003d self._get_user_ref(user[\u0027id\u0027])"},{"line_number":221,"context_line":"        self.assertEqual(len(user_ref.local_user.passwords), expected_length)"},{"line_number":222,"context_line":"        # start with multiple passwords and then change max_cnt to zero"},{"line_number":223,"context_line":"        max_cnt \u003d 4"},{"line_number":224,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"},{"line_number":225,"context_line":"                                   unique_last_password_count\u003dmax_cnt)"}],"source_content_type":"text/x-python","patch_set":35,"id":"dada55a8_904afe81","line":222,"range":{"start_line":222,"start_character":67,"end_line":222,"end_character":71},"updated":"2016-07-25 14:40:53.000000000","message":"nit: I think you mean to one","commit_id":"330c68c2b4c6e4d3062a92837d7ca508de0b0923"},{"author":{"_account_id":5707,"name":"Henry Nash","email":"henryn@linux.vnet.ibm.com","username":"henry-nash"},"change_message_id":"90169955570e1e0248ddf3cd6507514d0d1ccacb","unresolved":false,"context_lines":[{"line_number":170,"context_line":"                          user[\u0027id\u0027],"},{"line_number":171,"context_line":"                          user)"},{"line_number":172,"context_line":""},{"line_number":173,"context_line":"    def test_validate_password_history_with_valid_password(self):"},{"line_number":174,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"},{"line_number":175,"context_line":"                                   unique_last_password_count\u003d2)"},{"line_number":176,"context_line":"        first_password \u003d \u0027mypassword1\u0027"},{"line_number":177,"context_line":"        user \u003d self._create_user(first_password)"},{"line_number":178,"context_line":"        user[\u0027password\u0027] \u003d \u0027mypassword2\u0027"},{"line_number":179,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":180,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":181,"context_line":"        user[\u0027password\u0027] \u003d \u0027mypassword3\u0027"},{"line_number":182,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":183,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":184,"context_line":"        # Now you should be able to change the password to the match first"},{"line_number":185,"context_line":"        # password because the password history only contains the 2nd and 3rd"},{"line_number":186,"context_line":"        # passwords."},{"line_number":187,"context_line":"        user[\u0027password\u0027] \u003d first_password"},{"line_number":188,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":189,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":190,"context_line":"        self.identity_api.authenticate(context\u003d{},"},{"line_number":191,"context_line":"                                       user_id\u003duser[\u0027id\u0027],"},{"line_number":192,"context_line":"                                       password\u003dfirst_password)"},{"line_number":193,"context_line":""},{"line_number":194,"context_line":"    def test_validate_password_history_with_no_password(self):"},{"line_number":195,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"}],"source_content_type":"text/x-python","patch_set":37,"id":"dada55a8_b059ec5d","line":192,"range":{"start_line":173,"start_character":0,"end_line":192,"end_character":63},"updated":"2016-07-25 21:35:05.000000000","message":"while this is a good test, the one I think we need to check is if a user executes an update_user but includes a password that actually matches the current version - i.e. they are not changing it...but our code does not check that the password passed does not actually represent a change..it still goes ahead and validates it agains the list. This should be allowed and the number of passwords in the history should not be increased.","commit_id":"82a9384ef29adec403066bbb6930c4f6292d9ace"},{"author":{"_account_id":5707,"name":"Henry Nash","email":"henryn@linux.vnet.ibm.com","username":"henry-nash"},"change_message_id":"3466bf71ed7cbfa60621dd3096c6b9412307e669","unresolved":false,"context_lines":[{"line_number":170,"context_line":"                          user[\u0027id\u0027],"},{"line_number":171,"context_line":"                          user)"},{"line_number":172,"context_line":""},{"line_number":173,"context_line":"    def test_validate_password_history_with_valid_password(self):"},{"line_number":174,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"},{"line_number":175,"context_line":"                                   unique_last_password_count\u003d2)"},{"line_number":176,"context_line":"        first_password \u003d \u0027mypassword1\u0027"},{"line_number":177,"context_line":"        user \u003d self._create_user(first_password)"},{"line_number":178,"context_line":"        user[\u0027password\u0027] \u003d \u0027mypassword2\u0027"},{"line_number":179,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":180,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":181,"context_line":"        user[\u0027password\u0027] \u003d \u0027mypassword3\u0027"},{"line_number":182,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":183,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":184,"context_line":"        # Now you should be able to change the password to the match first"},{"line_number":185,"context_line":"        # password because the password history only contains the 2nd and 3rd"},{"line_number":186,"context_line":"        # passwords."},{"line_number":187,"context_line":"        user[\u0027password\u0027] \u003d first_password"},{"line_number":188,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":189,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":190,"context_line":"        self.identity_api.authenticate(context\u003d{},"},{"line_number":191,"context_line":"                                       user_id\u003duser[\u0027id\u0027],"},{"line_number":192,"context_line":"                                       password\u003dfirst_password)"},{"line_number":193,"context_line":""},{"line_number":194,"context_line":"    def test_validate_password_history_with_no_password(self):"},{"line_number":195,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"}],"source_content_type":"text/x-python","patch_set":37,"id":"dada55a8_dd18f477","line":192,"range":{"start_line":173,"start_character":0,"end_line":192,"end_character":63},"in_reply_to":"dada55a8_4488b122","updated":"2016-07-25 22:55:30.000000000","message":"...although that\u0027s not true for other parameters....I can include them (as long as they are the current values) with no impact....for other attributes, we check to see if the value is the same as the old one, and if so, ignore that attribute","commit_id":"82a9384ef29adec403066bbb6930c4f6292d9ace"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"7efd58d05ad8da644191e28f325a4ef846dc67da","unresolved":false,"context_lines":[{"line_number":170,"context_line":"                          user[\u0027id\u0027],"},{"line_number":171,"context_line":"                          user)"},{"line_number":172,"context_line":""},{"line_number":173,"context_line":"    def test_validate_password_history_with_valid_password(self):"},{"line_number":174,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"},{"line_number":175,"context_line":"                                   unique_last_password_count\u003d2)"},{"line_number":176,"context_line":"        first_password \u003d \u0027mypassword1\u0027"},{"line_number":177,"context_line":"        user \u003d self._create_user(first_password)"},{"line_number":178,"context_line":"        user[\u0027password\u0027] \u003d \u0027mypassword2\u0027"},{"line_number":179,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":180,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":181,"context_line":"        user[\u0027password\u0027] \u003d \u0027mypassword3\u0027"},{"line_number":182,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":183,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":184,"context_line":"        # Now you should be able to change the password to the match first"},{"line_number":185,"context_line":"        # password because the password history only contains the 2nd and 3rd"},{"line_number":186,"context_line":"        # passwords."},{"line_number":187,"context_line":"        user[\u0027password\u0027] \u003d first_password"},{"line_number":188,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":189,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":190,"context_line":"        self.identity_api.authenticate(context\u003d{},"},{"line_number":191,"context_line":"                                       user_id\u003duser[\u0027id\u0027],"},{"line_number":192,"context_line":"                                       password\u003dfirst_password)"},{"line_number":193,"context_line":""},{"line_number":194,"context_line":"    def test_validate_password_history_with_no_password(self):"},{"line_number":195,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"}],"source_content_type":"text/x-python","patch_set":37,"id":"dada55a8_4488b122","line":192,"range":{"start_line":173,"start_character":0,"end_line":192,"end_character":63},"in_reply_to":"dada55a8_b059ec5d","updated":"2016-07-25 21:48:58.000000000","message":"The API states that the \u0027password\u0027 in the request represents the \u0027new\u0027 password for the user:\nhttp://developer.openstack.org/api-ref/identity/v3/index.html?expanded\u003dupdate-user-detail#update-user\n\nThus, if the password is included in the request, I think we have to assume the user is attempting change the password and validate against the history.","commit_id":"82a9384ef29adec403066bbb6930c4f6292d9ace"},{"author":{"_account_id":5707,"name":"Henry Nash","email":"henryn@linux.vnet.ibm.com","username":"henry-nash"},"change_message_id":"cca8460d8e2f8bfeb16310567cbeda66829706c0","unresolved":false,"context_lines":[{"line_number":170,"context_line":"                          user[\u0027id\u0027],"},{"line_number":171,"context_line":"                          user)"},{"line_number":172,"context_line":""},{"line_number":173,"context_line":"    def test_validate_password_history_with_valid_password(self):"},{"line_number":174,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"},{"line_number":175,"context_line":"                                   unique_last_password_count\u003d2)"},{"line_number":176,"context_line":"        first_password \u003d \u0027mypassword1\u0027"},{"line_number":177,"context_line":"        user \u003d self._create_user(first_password)"},{"line_number":178,"context_line":"        user[\u0027password\u0027] \u003d \u0027mypassword2\u0027"},{"line_number":179,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":180,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":181,"context_line":"        user[\u0027password\u0027] \u003d \u0027mypassword3\u0027"},{"line_number":182,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":183,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":184,"context_line":"        # Now you should be able to change the password to the match first"},{"line_number":185,"context_line":"        # password because the password history only contains the 2nd and 3rd"},{"line_number":186,"context_line":"        # passwords."},{"line_number":187,"context_line":"        user[\u0027password\u0027] \u003d first_password"},{"line_number":188,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":189,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":190,"context_line":"        self.identity_api.authenticate(context\u003d{},"},{"line_number":191,"context_line":"                                       user_id\u003duser[\u0027id\u0027],"},{"line_number":192,"context_line":"                                       password\u003dfirst_password)"},{"line_number":193,"context_line":""},{"line_number":194,"context_line":"    def test_validate_password_history_with_no_password(self):"},{"line_number":195,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"}],"source_content_type":"text/x-python","patch_set":37,"id":"dada55a8_9d9e7c52","line":192,"range":{"start_line":173,"start_character":0,"end_line":192,"end_character":63},"in_reply_to":"dada55a8_dd18f477","updated":"2016-07-25 23:10:03.000000000","message":"However, I guess this pretty much a corner case - I think we can worry about it later.","commit_id":"82a9384ef29adec403066bbb6930c4f6292d9ace"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"6fa875be1f5925b0231da441cb12102a27b3fc02","unresolved":false,"context_lines":[{"line_number":240,"context_line":"        self._add_passwords(user, 4)"},{"line_number":241,"context_line":"        user_ref \u003d self._get_user_ref(user[\u0027id\u0027])"},{"line_number":242,"context_line":"        self.assertEqual(len(user_ref.local_user.passwords), expected_length)"},{"line_number":243,"context_line":"        # start with multiple passwords and then change max_cnt to zero"},{"line_number":244,"context_line":"        max_cnt \u003d 4"},{"line_number":245,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"},{"line_number":246,"context_line":"                                   unique_last_password_count\u003dmax_cnt)"}],"source_content_type":"text/x-python","patch_set":39,"id":"dada55a8_c4df2267","line":243,"updated":"2016-07-27 12:59:54.000000000","message":"From Henry\u0027s comment on patch set 35 - don\u0027t we mean to change max_cnt to one?","commit_id":"239de194186f19168d8db5516a83d84c67f162cc"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"4a4c438bcfeb656da5bb2900a49231386450f89f","unresolved":false,"context_lines":[{"line_number":240,"context_line":"        self._add_passwords(user, 4)"},{"line_number":241,"context_line":"        user_ref \u003d self._get_user_ref(user[\u0027id\u0027])"},{"line_number":242,"context_line":"        self.assertEqual(len(user_ref.local_user.passwords), expected_length)"},{"line_number":243,"context_line":"        # start with multiple passwords and then change max_cnt to zero"},{"line_number":244,"context_line":"        max_cnt \u003d 4"},{"line_number":245,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"},{"line_number":246,"context_line":"                                   unique_last_password_count\u003dmax_cnt)"}],"source_content_type":"text/x-python","patch_set":39,"id":"bacf61ea_b05640d0","line":243,"in_reply_to":"dada55a8_c4df2267","updated":"2016-07-28 14:21:15.000000000","message":"Done","commit_id":"239de194186f19168d8db5516a83d84c67f162cc"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"c4421ed333037a70226b75aaa9f6337fe69591f8","unresolved":false,"context_lines":[{"line_number":152,"context_line":"            return user_ref"},{"line_number":153,"context_line":""},{"line_number":154,"context_line":""},{"line_number":155,"context_line":"class PasswordHistoryValidationTests(test_backend_sql.SqlTests):"},{"line_number":156,"context_line":"    def test_validate_password_history_with_invalid_password(self):"},{"line_number":157,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"},{"line_number":158,"context_line":"                                   unique_last_password_count\u003d4)"}],"source_content_type":"text/x-python","patch_set":41,"id":"bacf61ea_eb443b1c","line":155,"updated":"2016-07-28 19:55:27.000000000","message":"(nit) instead of hard coding password values it would be more inline with the other tests if these were uuids","commit_id":"27850103adb8d1e3fc25d19ebd7f37249364a73a"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"31f217666746e3930958238893df62ae6b733719","unresolved":false,"context_lines":[{"line_number":152,"context_line":"            return user_ref"},{"line_number":153,"context_line":""},{"line_number":154,"context_line":""},{"line_number":155,"context_line":"class PasswordHistoryValidationTests(test_backend_sql.SqlTests):"},{"line_number":156,"context_line":"    def test_validate_password_history_with_invalid_password(self):"},{"line_number":157,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"},{"line_number":158,"context_line":"                                   unique_last_password_count\u003d4)"}],"source_content_type":"text/x-python","patch_set":41,"id":"bacf61ea_7372f54a","line":155,"in_reply_to":"bacf61ea_eb443b1c","updated":"2016-07-29 01:09:41.000000000","message":"Done","commit_id":"27850103adb8d1e3fc25d19ebd7f37249364a73a"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"c4421ed333037a70226b75aaa9f6337fe69591f8","unresolved":false,"context_lines":[{"line_number":202,"context_line":"        self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":203,"context_line":"        user_ref \u003d self._get_user_ref(user[\u0027id\u0027])"},{"line_number":204,"context_line":"        first_password \u003d user_ref.password"},{"line_number":205,"context_line":"        self.assertIsNotNone(user_ref.password)"},{"line_number":206,"context_line":"        user[\u0027password\u0027] \u003d \u0027mypassword3\u0027"},{"line_number":207,"context_line":"        self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":208,"context_line":"        user_ref \u003d self._get_user_ref(user[\u0027id\u0027])"}],"source_content_type":"text/x-python","patch_set":41,"id":"bacf61ea_2babf3d7","line":205,"updated":"2016-07-28 19:55:27.000000000","message":"If we are going to assert anything we should probably be explicit about the value that we expect.","commit_id":"27850103adb8d1e3fc25d19ebd7f37249364a73a"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"31f217666746e3930958238893df62ae6b733719","unresolved":false,"context_lines":[{"line_number":202,"context_line":"        self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":203,"context_line":"        user_ref \u003d self._get_user_ref(user[\u0027id\u0027])"},{"line_number":204,"context_line":"        first_password \u003d user_ref.password"},{"line_number":205,"context_line":"        self.assertIsNotNone(user_ref.password)"},{"line_number":206,"context_line":"        user[\u0027password\u0027] \u003d \u0027mypassword3\u0027"},{"line_number":207,"context_line":"        self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":208,"context_line":"        user_ref \u003d self._get_user_ref(user[\u0027id\u0027])"}],"source_content_type":"text/x-python","patch_set":41,"id":"bacf61ea_f39c255f","line":205,"in_reply_to":"bacf61ea_0b454f6f","updated":"2016-07-29 01:09:41.000000000","message":"Haven\u0027t looked at these tests for a while; agree with many of your comments. Therefore, decided to bite the bullet and clean these up.","commit_id":"27850103adb8d1e3fc25d19ebd7f37249364a73a"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"2e03283309f19a6c142e28ed844e3ec5b81def8b","unresolved":false,"context_lines":[{"line_number":202,"context_line":"        self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":203,"context_line":"        user_ref \u003d self._get_user_ref(user[\u0027id\u0027])"},{"line_number":204,"context_line":"        first_password \u003d user_ref.password"},{"line_number":205,"context_line":"        self.assertIsNotNone(user_ref.password)"},{"line_number":206,"context_line":"        user[\u0027password\u0027] \u003d \u0027mypassword3\u0027"},{"line_number":207,"context_line":"        self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":208,"context_line":"        user_ref \u003d self._get_user_ref(user[\u0027id\u0027])"}],"source_content_type":"text/x-python","patch_set":41,"id":"bacf61ea_0b454f6f","line":205,"in_reply_to":"bacf61ea_2babf3d7","updated":"2016-07-28 20:17:05.000000000","message":"At that point the password is hashed, which is why just checking not none. To be honest, this test came out of one of our review sessions (weeks ago) and brought to light a edge case that was missed.","commit_id":"27850103adb8d1e3fc25d19ebd7f37249364a73a"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"c4421ed333037a70226b75aaa9f6337fe69591f8","unresolved":false,"context_lines":[{"line_number":208,"context_line":"        user_ref \u003d self._get_user_ref(user[\u0027id\u0027])"},{"line_number":209,"context_line":"        self.assertIsNotNone(user_ref.password)"},{"line_number":210,"context_line":"        second_password \u003d user_ref.password"},{"line_number":211,"context_line":"        self.assertNotEqual(first_password, second_password)"},{"line_number":212,"context_line":""},{"line_number":213,"context_line":"    def test_disabled_validate_password_history_and_repeat_same_password(self):"},{"line_number":214,"context_line":"        password \u003d \u0027samepassword1\u0027"}],"source_content_type":"text/x-python","patch_set":41,"id":"bacf61ea_4b4c6742","line":211,"updated":"2016-07-28 19:55:27.000000000","message":"Why are we doing this check?","commit_id":"27850103adb8d1e3fc25d19ebd7f37249364a73a"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"2e03283309f19a6c142e28ed844e3ec5b81def8b","unresolved":false,"context_lines":[{"line_number":208,"context_line":"        user_ref \u003d self._get_user_ref(user[\u0027id\u0027])"},{"line_number":209,"context_line":"        self.assertIsNotNone(user_ref.password)"},{"line_number":210,"context_line":"        second_password \u003d user_ref.password"},{"line_number":211,"context_line":"        self.assertNotEqual(first_password, second_password)"},{"line_number":212,"context_line":""},{"line_number":213,"context_line":"    def test_disabled_validate_password_history_and_repeat_same_password(self):"},{"line_number":214,"context_line":"        password \u003d \u0027samepassword1\u0027"}],"source_content_type":"text/x-python","patch_set":41,"id":"bacf61ea_cb185787","line":211,"in_reply_to":"bacf61ea_4b4c6742","updated":"2016-07-28 20:17:05.000000000","message":"I think verifying that the password did actually save and is not the same as the original password. The gist of this test is to test the history when a user is created with None password.","commit_id":"27850103adb8d1e3fc25d19ebd7f37249364a73a"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"31f217666746e3930958238893df62ae6b733719","unresolved":false,"context_lines":[{"line_number":208,"context_line":"        user_ref \u003d self._get_user_ref(user[\u0027id\u0027])"},{"line_number":209,"context_line":"        self.assertIsNotNone(user_ref.password)"},{"line_number":210,"context_line":"        second_password \u003d user_ref.password"},{"line_number":211,"context_line":"        self.assertNotEqual(first_password, second_password)"},{"line_number":212,"context_line":""},{"line_number":213,"context_line":"    def test_disabled_validate_password_history_and_repeat_same_password(self):"},{"line_number":214,"context_line":"        password \u003d \u0027samepassword1\u0027"}],"source_content_type":"text/x-python","patch_set":41,"id":"bacf61ea_d3dda115","line":211,"in_reply_to":"bacf61ea_cb185787","updated":"2016-07-29 01:09:41.000000000","message":"Changed this test, please re-review.","commit_id":"27850103adb8d1e3fc25d19ebd7f37249364a73a"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"c4421ed333037a70226b75aaa9f6337fe69591f8","unresolved":false,"context_lines":[{"line_number":216,"context_line":"        # update the same password and test"},{"line_number":217,"context_line":"        user[\u0027password\u0027] \u003d password"},{"line_number":218,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":219,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":220,"context_line":"        # repeat"},{"line_number":221,"context_line":"        user[\u0027password\u0027] \u003d password"},{"line_number":222,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"}],"source_content_type":"text/x-python","patch_set":41,"id":"bacf61ea_2b6e5396","line":219,"updated":"2016-07-28 19:55:27.000000000","message":"Why are we doing this check?","commit_id":"27850103adb8d1e3fc25d19ebd7f37249364a73a"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"2e03283309f19a6c142e28ed844e3ec5b81def8b","unresolved":false,"context_lines":[{"line_number":216,"context_line":"        # update the same password and test"},{"line_number":217,"context_line":"        user[\u0027password\u0027] \u003d password"},{"line_number":218,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":219,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":220,"context_line":"        # repeat"},{"line_number":221,"context_line":"        user[\u0027password\u0027] \u003d password"},{"line_number":222,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"}],"source_content_type":"text/x-python","patch_set":41,"id":"bacf61ea_3642363f","line":219,"in_reply_to":"bacf61ea_2b6e5396","updated":"2016-07-28 20:17:05.000000000","message":"Confirming the user that was updated is the actually the same user created.","commit_id":"27850103adb8d1e3fc25d19ebd7f37249364a73a"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"31f217666746e3930958238893df62ae6b733719","unresolved":false,"context_lines":[{"line_number":216,"context_line":"        # update the same password and test"},{"line_number":217,"context_line":"        user[\u0027password\u0027] \u003d password"},{"line_number":218,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":219,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":220,"context_line":"        # repeat"},{"line_number":221,"context_line":"        user[\u0027password\u0027] \u003d password"},{"line_number":222,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"}],"source_content_type":"text/x-python","patch_set":41,"id":"bacf61ea_53cb7153","line":219,"in_reply_to":"bacf61ea_3642363f","updated":"2016-07-29 01:09:41.000000000","message":"Changed this test, please re-review.","commit_id":"27850103adb8d1e3fc25d19ebd7f37249364a73a"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"c4421ed333037a70226b75aaa9f6337fe69591f8","unresolved":false,"context_lines":[{"line_number":220,"context_line":"        # repeat"},{"line_number":221,"context_line":"        user[\u0027password\u0027] \u003d password"},{"line_number":222,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":223,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":224,"context_line":""},{"line_number":225,"context_line":"    def test_truncate_passwords(self):"},{"line_number":226,"context_line":"        max_cnt \u003d 2"}],"source_content_type":"text/x-python","patch_set":41,"id":"bacf61ea_8b6dbf9a","line":223,"updated":"2016-07-28 19:55:27.000000000","message":"... or this check....or the others above","commit_id":"27850103adb8d1e3fc25d19ebd7f37249364a73a"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"2e03283309f19a6c142e28ed844e3ec5b81def8b","unresolved":false,"context_lines":[{"line_number":220,"context_line":"        # repeat"},{"line_number":221,"context_line":"        user[\u0027password\u0027] \u003d password"},{"line_number":222,"context_line":"        user_ret \u003d self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":223,"context_line":"        self.assertEqual(user[\u0027id\u0027], user_ret[\u0027id\u0027])"},{"line_number":224,"context_line":""},{"line_number":225,"context_line":"    def test_truncate_passwords(self):"},{"line_number":226,"context_line":"        max_cnt \u003d 2"}],"source_content_type":"text/x-python","patch_set":41,"id":"bacf61ea_969e82b6","line":223,"in_reply_to":"bacf61ea_8b6dbf9a","updated":"2016-07-28 20:17:05.000000000","message":"same as above...","commit_id":"27850103adb8d1e3fc25d19ebd7f37249364a73a"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"e55f12952f61571ebd9af009f106228fe524f11c","unresolved":false,"context_lines":[{"line_number":159,"context_line":"                          uuid.uuid4().hex,"},{"line_number":160,"context_line":"                          uuid.uuid4().hex,"},{"line_number":161,"context_line":"                          uuid.uuid4().hex]"},{"line_number":162,"context_line":"        self.max_cnt \u003d 3"},{"line_number":163,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"},{"line_number":164,"context_line":"                                   unique_last_password_count\u003dself.max_cnt)"},{"line_number":165,"context_line":""}],"source_content_type":"text/x-python","patch_set":42,"id":"bacf61ea_ffb4c035","line":162,"updated":"2016-07-29 18:03:15.000000000","message":"Seems unnecessary to have this as an instance attribute.","commit_id":"baacc717dec8b161d496ae23df8911dc566a6038"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"723afeaf7e51e06fdee1298255c36b3bf9aed545","unresolved":false,"context_lines":[{"line_number":159,"context_line":"                          uuid.uuid4().hex,"},{"line_number":160,"context_line":"                          uuid.uuid4().hex,"},{"line_number":161,"context_line":"                          uuid.uuid4().hex]"},{"line_number":162,"context_line":"        self.max_cnt \u003d 3"},{"line_number":163,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"},{"line_number":164,"context_line":"                                   unique_last_password_count\u003dself.max_cnt)"},{"line_number":165,"context_line":""}],"source_content_type":"text/x-python","patch_set":42,"id":"bacf61ea_3554b7fd","line":162,"in_reply_to":"bacf61ea_ffb4c035","updated":"2016-07-29 18:49:22.000000000","message":"My preference is to use the variable instead of using the long CONF.security_compliance.unique_last_password_count every time. Just easier to read in my opinion.","commit_id":"baacc717dec8b161d496ae23df8911dc566a6038"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"e55f12952f61571ebd9af009f106228fe524f11c","unresolved":false,"context_lines":[{"line_number":211,"context_line":"        self._add_passwords_to_history(user, n\u003d4)"},{"line_number":212,"context_line":"        user_ref \u003d self._get_user_ref(user[\u0027id\u0027])"},{"line_number":213,"context_line":"        self.assertEqual("},{"line_number":214,"context_line":"            len(user_ref.local_user.passwords), (self.max_cnt + 1))"},{"line_number":215,"context_line":""},{"line_number":216,"context_line":"    def test_truncate_passwords_when_max_is_default(self):"},{"line_number":217,"context_line":"        self.max_cnt \u003d 1"}],"source_content_type":"text/x-python","patch_set":42,"id":"bacf61ea_5feb4c13","line":214,"updated":"2016-07-29 18:03:15.000000000","message":"CONF.security_compliance.unique_last_password_count + 1","commit_id":"baacc717dec8b161d496ae23df8911dc566a6038"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"723afeaf7e51e06fdee1298255c36b3bf9aed545","unresolved":false,"context_lines":[{"line_number":211,"context_line":"        self._add_passwords_to_history(user, n\u003d4)"},{"line_number":212,"context_line":"        user_ref \u003d self._get_user_ref(user[\u0027id\u0027])"},{"line_number":213,"context_line":"        self.assertEqual("},{"line_number":214,"context_line":"            len(user_ref.local_user.passwords), (self.max_cnt + 1))"},{"line_number":215,"context_line":""},{"line_number":216,"context_line":"    def test_truncate_passwords_when_max_is_default(self):"},{"line_number":217,"context_line":"        self.max_cnt \u003d 1"}],"source_content_type":"text/x-python","patch_set":42,"id":"bacf61ea_d5439b40","line":214,"in_reply_to":"bacf61ea_5feb4c13","updated":"2016-07-29 18:49:22.000000000","message":"See comment above...","commit_id":"baacc717dec8b161d496ae23df8911dc566a6038"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"e55f12952f61571ebd9af009f106228fe524f11c","unresolved":false,"context_lines":[{"line_number":261,"context_line":"        }"},{"line_number":262,"context_line":"        return self.identity_api.create_user(user)"},{"line_number":263,"context_line":""},{"line_number":264,"context_line":"    def _assert_valid_password_update(self, user, new_password):"},{"line_number":265,"context_line":"        user[\u0027password\u0027] \u003d new_password"},{"line_number":266,"context_line":"        self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":267,"context_line":"        self.identity_api.authenticate(self.make_request(),"}],"source_content_type":"text/x-python","patch_set":42,"id":"bacf61ea_bfc36888","line":264,"updated":"2016-07-29 18:03:15.000000000","message":"Assert methods should follow the unittest convention -- there\u0027s no reason for this to be a private method, and it should actuallyBeCamelCased.","commit_id":"baacc717dec8b161d496ae23df8911dc566a6038"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"723afeaf7e51e06fdee1298255c36b3bf9aed545","unresolved":false,"context_lines":[{"line_number":261,"context_line":"        }"},{"line_number":262,"context_line":"        return self.identity_api.create_user(user)"},{"line_number":263,"context_line":""},{"line_number":264,"context_line":"    def _assert_valid_password_update(self, user, new_password):"},{"line_number":265,"context_line":"        user[\u0027password\u0027] \u003d new_password"},{"line_number":266,"context_line":"        self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":267,"context_line":"        self.identity_api.authenticate(self.make_request(),"}],"source_content_type":"text/x-python","patch_set":42,"id":"bacf61ea_02f85b48","line":264,"in_reply_to":"bacf61ea_bfc36888","updated":"2016-07-29 18:49:22.000000000","message":"Done","commit_id":"baacc717dec8b161d496ae23df8911dc566a6038"},{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"change_message_id":"e55f12952f61571ebd9af009f106228fe524f11c","unresolved":false,"context_lines":[{"line_number":275,"context_line":""},{"line_number":276,"context_line":"    def _get_user_ref(self, user_id):"},{"line_number":277,"context_line":"        with sql.session_for_read() as session:"},{"line_number":278,"context_line":"            return self.identity_api._get_user(session, user_id)"}],"source_content_type":"text/x-python","patch_set":42,"id":"bacf61ea_1f6b9486","line":278,"updated":"2016-07-29 18:03:15.000000000","message":"Call the public .get_user() method, and skip creating your own session here?","commit_id":"baacc717dec8b161d496ae23df8911dc566a6038"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"723afeaf7e51e06fdee1298255c36b3bf9aed545","unresolved":false,"context_lines":[{"line_number":275,"context_line":""},{"line_number":276,"context_line":"    def _get_user_ref(self, user_id):"},{"line_number":277,"context_line":"        with sql.session_for_read() as session:"},{"line_number":278,"context_line":"            return self.identity_api._get_user(session, user_id)"}],"source_content_type":"text/x-python","patch_set":42,"id":"bacf61ea_8270cbdd","line":278,"in_reply_to":"bacf61ea_1f6b9486","updated":"2016-07-29 18:49:22.000000000","message":"The public get_user() method returns a dictionary; I need the user model here.","commit_id":"baacc717dec8b161d496ae23df8911dc566a6038"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"804519930e4ac9343bfd917afe4eed9e08a01b26","unresolved":false,"context_lines":[{"line_number":261,"context_line":"        }"},{"line_number":262,"context_line":"        return self.identity_api.create_user(user)"},{"line_number":263,"context_line":""},{"line_number":264,"context_line":"    def assertValidPasswordUpdate(self, user, new_password):"},{"line_number":265,"context_line":"        user[\u0027password\u0027] \u003d new_password"},{"line_number":266,"context_line":"        self.identity_api.update_user(user[\u0027id\u0027], user)"},{"line_number":267,"context_line":"        self.identity_api.authenticate(self.make_request(),"}],"source_content_type":"text/x-python","patch_set":43,"id":"bacf61ea_ddb347e8","line":264,"updated":"2016-08-02 14:23:03.000000000","message":"I like the assertion.","commit_id":"6bc3a74909b548208a35673a4573f00af74b4f49"}]}
