)]}'
{"keystone/conf/credential.py":[{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"ea7a73d98d58b7b9fd0b03fb3c05c78bcfa1ca41","unresolved":false,"context_lines":[{"line_number":51,"context_line":"    default\u003dTrue,"},{"line_number":52,"context_line":"    help\u003dutils.fmt(\"\"\""},{"line_number":53,"context_line":"Toggle for credential caching. This has no effect unless global caching is"},{"line_number":54,"context_line":"enabled."},{"line_number":55,"context_line":"\"\"\"))"},{"line_number":56,"context_line":""},{"line_number":57,"context_line":"cache_time \u003d cfg.IntOpt("}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_113e16da","line":54,"updated":"2019-02-20 15:48:27.000000000","message":"I suppose we could say here that this only applies to fetching a specific credential and not listing credentials.","commit_id":"6aa21ef974763c39ddba62258a30d0a40e9ff355"}],"keystone/credential/core.py":[{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"bd15f479f3f796ed919cdf514db864a7a5471f91","unresolved":false,"context_lines":[{"line_number":92,"context_line":"            credential \u003d self._decrypt_credential(credential)"},{"line_number":93,"context_line":"        return credentials"},{"line_number":94,"context_line":""},{"line_number":95,"context_line":"    def list_credentials_for_user(self, user_id, type\u003dNone):"},{"line_number":96,"context_line":"        \"\"\"List credentials for a specific user.\"\"\""},{"line_number":97,"context_line":"        credentials \u003d self.driver.list_credentials_for_user(user_id, type\u003dtype)"},{"line_number":98,"context_line":"        for credential in credentials:"}],"source_content_type":"text/x-python","patch_set":1,"id":"9fdfeff1_0f12d862","line":95,"updated":"2019-02-14 21:16:33.000000000","message":"This could be done in a separate patch, but we could optimize this if we refactor the kwarg out of the method signature.\n\n  @MEMOIZE\n  def list_credentials_for_user(self, user_id):","commit_id":"a1bb10967e7380d4d57da818241c91bb69325e87"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"a9425280999594214bb2f4598661639dde641112","unresolved":false,"context_lines":[{"line_number":148,"context_line":"            ref[\u0027blob\u0027] \u003d credential[\u0027blob\u0027]"},{"line_number":149,"context_line":"        else:"},{"line_number":150,"context_line":"            ref[\u0027blob\u0027] \u003d existing_blob"},{"line_number":151,"context_line":"        if MEMOIZE.should_cache(ref):"},{"line_number":152,"context_line":"            self.get_credential.set(ref, self, credential_id)"},{"line_number":153,"context_line":"            self.list_credentials_for_user.invalidate(self,"},{"line_number":154,"context_line":"                                                      ref[\u0027user_id\u0027],"}],"source_content_type":"text/x-python","patch_set":2,"id":"9fdfeff1_31000cac","line":151,"updated":"2019-02-19 20:36:46.000000000","message":"Interesting - we don\u0027t typically use this pattern. We usually just perform an invalidation.","commit_id":"a12daf6fe802b3abe1aa38f85a4970d1811b83cf"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"ea7a73d98d58b7b9fd0b03fb3c05c78bcfa1ca41","unresolved":false,"context_lines":[{"line_number":99,"context_line":"        return self._list_credentials_for_user(user_id, \u0027totp\u0027)"},{"line_number":100,"context_line":""},{"line_number":101,"context_line":"    @MEMOIZE"},{"line_number":102,"context_line":"    def _list_credentials_for_user(self, user_id, type):"},{"line_number":103,"context_line":"        \"\"\"List credentials for a specific user.\"\"\""},{"line_number":104,"context_line":"        credentials \u003d self.driver.list_credentials_for_user(user_id, type)"},{"line_number":105,"context_line":"        for credential in credentials:"}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_71a9a222","line":102,"range":{"start_line":102,"start_character":8,"end_line":102,"end_character":34},"updated":"2019-02-20 15:48:27.000000000","message":"This probably should have been made a private method initially. It appears that it\u0027s only used within keystone for fetching a users credentials, and not wired up publicly.\n\nThat said, we are now requiring the type for getting a users credentials to be either ec2 or totp even though it is possible for users to create credentials of whatever type they want.\n\nWe should either open up this to be a public API that isn\u0027t cacheable or just document somewhere that fetching credentials for a user outside of \u0027ec2\u0027 and \u0027totp\u0027 won\u0027t be cached.\n\nBut, again, since this is an internal method to keystone for the most part, it might make sense as a comment in the code.","commit_id":"6aa21ef974763c39ddba62258a30d0a40e9ff355"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"d650a5bb739fbd53271a99b48c27237aee0ef57b","unresolved":false,"context_lines":[{"line_number":100,"context_line":"        \"\"\"List credentials for a specific user.\"\"\""},{"line_number":101,"context_line":"        credentials \u003d self.driver.list_credentials_for_user(user_id, type)"},{"line_number":102,"context_line":"        for credential in credentials:"},{"line_number":103,"context_line":"            credential \u003d self._decrypt_credential(credential)"},{"line_number":104,"context_line":"        return credentials"},{"line_number":105,"context_line":""},{"line_number":106,"context_line":"    @MEMOIZE"}],"source_content_type":"text/x-python","patch_set":5,"id":"dfbec78f_9ec2a833","line":103,"updated":"2019-05-13 21:57:58.000000000","message":"Keep in mind this puts DECRYPTED [plain text] credentials in the cache (potentially external, e.g. memcache with less guarding that keystone\u0027s config/internal runtime)\n\nThe decrypting *may* meed to be in the uncached version. This is likely a security issue that should not be introduced. We make effort to cache un-hashed passwords. These elements are equivalent to unhashed password and results in exposed plaintext secure data.","commit_id":"cd5729c2719eea381828dcb6cc2af99ef98e7655"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"2ff87626c125d04661f50c440813ac5a6274d5cd","unresolved":false,"context_lines":[{"line_number":100,"context_line":"        \"\"\"List credentials for a specific user.\"\"\""},{"line_number":101,"context_line":"        credentials \u003d self.driver.list_credentials_for_user(user_id, type)"},{"line_number":102,"context_line":"        for credential in credentials:"},{"line_number":103,"context_line":"            credential \u003d self._decrypt_credential(credential)"},{"line_number":104,"context_line":"        return credentials"},{"line_number":105,"context_line":""},{"line_number":106,"context_line":"    @MEMOIZE"}],"source_content_type":"text/x-python","patch_set":5,"id":"dfbec78f_0c1680f2","line":103,"in_reply_to":"dfbec78f_9ec2a833","updated":"2019-05-14 16:43:09.000000000","message":"should have said \"NEVER cache unhashed passwords\"","commit_id":"cd5729c2719eea381828dcb6cc2af99ef98e7655"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"d650a5bb739fbd53271a99b48c27237aee0ef57b","unresolved":false,"context_lines":[{"line_number":117,"context_line":"        ref.pop(\u0027encrypted_blob\u0027, None)"},{"line_number":118,"context_line":"        ref[\u0027blob\u0027] \u003d credential[\u0027blob\u0027]"},{"line_number":119,"context_line":"        if MEMOIZE.should_cache(ref):"},{"line_number":120,"context_line":"            self.get_credential.set(ref, self, credential_id)"},{"line_number":121,"context_line":"        return ref"},{"line_number":122,"context_line":""},{"line_number":123,"context_line":"    def _validate_credential_update(self, credential_id, credential):"}],"source_content_type":"text/x-python","patch_set":5,"id":"dfbec78f_dea3409d","line":120,"updated":"2019-05-13 21:57:58.000000000","message":"You need to invalidate the lists here too.","commit_id":"cd5729c2719eea381828dcb6cc2af99ef98e7655"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"d650a5bb739fbd53271a99b48c27237aee0ef57b","unresolved":false,"context_lines":[{"line_number":154,"context_line":"        if MEMOIZE.should_cache(ref):"},{"line_number":155,"context_line":"            self.get_credential.set(ref, self, credential_id)"},{"line_number":156,"context_line":"            self._list_credentials_for_user.invalidate(self,"},{"line_number":157,"context_line":"                                                       ref[\u0027user_id\u0027],"},{"line_number":158,"context_line":"                                                       ref[\u0027type\u0027])"},{"line_number":159,"context_line":"        return ref"},{"line_number":160,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"dfbec78f_1e96b83f","line":157,"updated":"2019-05-13 21:57:58.000000000","message":"See note below about list invalidation","commit_id":"cd5729c2719eea381828dcb6cc2af99ef98e7655"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"d650a5bb739fbd53271a99b48c27237aee0ef57b","unresolved":false,"context_lines":[{"line_number":162,"context_line":"        \"\"\"Delete a credential.\"\"\""},{"line_number":163,"context_line":"        cred \u003d self.get_credential(credential_id)"},{"line_number":164,"context_line":"        self.get_credential.invalidate(self, credential_id)"},{"line_number":165,"context_line":"        self._list_credentials_for_user.invalidate(self,"},{"line_number":166,"context_line":"                                                   cred[\u0027user_id\u0027],"},{"line_number":167,"context_line":"                                                   cred[\u0027type\u0027])"},{"line_number":168,"context_line":"        self.driver.delete_credential(credential_id)"}],"source_content_type":"text/x-python","patch_set":5,"id":"dfbec78f_fe92c456","line":165,"updated":"2019-05-13 21:57:58.000000000","message":"You need to invalidate the bare list as well. This is because the way you have this implemented the raw list_credentials may be type_none, so you cache all of the creds for the user and the type cache is only invalidated.\n\nYou need to add this line as well:\n\n    self._list_credentials_for_user.invalidate(self, cred[\u0027user_id\u0027], None)","commit_id":"cd5729c2719eea381828dcb6cc2af99ef98e7655"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"d650a5bb739fbd53271a99b48c27237aee0ef57b","unresolved":false,"context_lines":[{"line_number":165,"context_line":"        self._list_credentials_for_user.invalidate(self,"},{"line_number":166,"context_line":"                                                   cred[\u0027user_id\u0027],"},{"line_number":167,"context_line":"                                                   cred[\u0027type\u0027])"},{"line_number":168,"context_line":"        self.driver.delete_credential(credential_id)"},{"line_number":169,"context_line":""},{"line_number":170,"context_line":"    def delete_credentials_for_project(self, project_id):"},{"line_number":171,"context_line":"        \"\"\"Delete all credentials for a project.\"\"\""}],"source_content_type":"text/x-python","patch_set":5,"id":"dfbec78f_1e81d8fb","line":168,"updated":"2019-05-13 21:57:58.000000000","message":"Deletion must happen BEFORE invalidation otherwise a race could re-populate the list/get before the delete occurs. Move this line above 164.","commit_id":"cd5729c2719eea381828dcb6cc2af99ef98e7655"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"d650a5bb739fbd53271a99b48c27237aee0ef57b","unresolved":false,"context_lines":[{"line_number":176,"context_line":"        self.driver.delete_credentials_for_project(project_id)"},{"line_number":177,"context_line":"        for cred in creds:"},{"line_number":178,"context_line":"            self.get_credential.invalidate(self, cred[\u0027id\u0027])"},{"line_number":179,"context_line":"            self._list_credentials_for_user.invalidate(self,"},{"line_number":180,"context_line":"                                                       cred[\u0027user_id\u0027],"},{"line_number":181,"context_line":"                                                       cred[\u0027type\u0027])"},{"line_number":182,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"dfbec78f_3e861c15","line":179,"updated":"2019-05-13 21:57:58.000000000","message":"See above note about list invalidation.","commit_id":"cd5729c2719eea381828dcb6cc2af99ef98e7655"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"d650a5bb739fbd53271a99b48c27237aee0ef57b","unresolved":false,"context_lines":[{"line_number":186,"context_line":"        self.driver.delete_credentials_for_user(user_id)"},{"line_number":187,"context_line":"        for cred in creds:"},{"line_number":188,"context_line":"            self.get_credential.invalidate(self, cred[\u0027id\u0027])"},{"line_number":189,"context_line":"            self._list_credentials_for_user.invalidate(self,"},{"line_number":190,"context_line":"                                                       user_id,"},{"line_number":191,"context_line":"                                                       cred[\u0027type\u0027])"}],"source_content_type":"text/x-python","patch_set":5,"id":"dfbec78f_fe7ba424","line":189,"updated":"2019-05-13 21:57:58.000000000","message":"See above note about list invalidation","commit_id":"cd5729c2719eea381828dcb6cc2af99ef98e7655"}],"keystone/tests/unit/test_backend_sql.py":[{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"a9425280999594214bb2f4598661639dde641112","unresolved":false,"context_lines":[{"line_number":1102,"context_line":""},{"line_number":1103,"context_line":"    def test_list_credentials_for_user(self):"},{"line_number":1104,"context_line":"        credentials \u003d PROVIDERS.credential_api.list_credentials_for_user("},{"line_number":1105,"context_line":"            self.user_foo[\u0027id\u0027], None)"},{"line_number":1106,"context_line":"        self._validateCredentialList(credentials, self.user_credentials)"},{"line_number":1107,"context_line":""},{"line_number":1108,"context_line":"    def test_list_credentials_for_user_and_type(self):"}],"source_content_type":"text/x-python","patch_set":2,"id":"9fdfeff1_911c5814","line":1105,"range":{"start_line":1105,"start_character":33,"end_line":1105,"end_character":37},"updated":"2019-02-19 20:36:46.000000000","message":"I\u0027m not a big fan of passing None in as a parameter. We should at least name it as a variable before passing it into the method.\n\nOtherwise, we could try and remove any ambiguity in the code so that we can always assume type is going to be present. One way we could do that would be to implement methods specifically for the credential types we support.\n\n  def list_ec2_credentials_for_user(self, user_id):\n\n  def list_totp_credentials_for_user(self, user_id):","commit_id":"a12daf6fe802b3abe1aa38f85a4970d1811b83cf"}],"keystone/tests/unit/test_v3_credential.py":[{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"d650a5bb739fbd53271a99b48c27237aee0ef57b","unresolved":false,"context_lines":[{"line_number":84,"context_line":"        # once we delete all credentials for self.project_id"},{"line_number":85,"context_line":"        self.assertRaises(exception.CredentialNotFound,"},{"line_number":86,"context_line":"                          PROVIDERS.credential_api.get_credential,"},{"line_number":87,"context_line":"                          self.credential[\u0027id\u0027])"},{"line_number":88,"context_line":""},{"line_number":89,"context_line":"    def test_credential_api_delete_credentials_for_user(self):"},{"line_number":90,"context_line":"        PROVIDERS.credential_api.delete_credentials_for_user(self.user_id)"}],"source_content_type":"text/x-python","patch_set":5,"id":"dfbec78f_9ea9487d","line":87,"updated":"2019-05-13 21:57:58.000000000","message":"Why was this changed? This shouldn\u0027t need to be changed.","commit_id":"cd5729c2719eea381828dcb6cc2af99ef98e7655"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"d650a5bb739fbd53271a99b48c27237aee0ef57b","unresolved":false,"context_lines":[{"line_number":92,"context_line":"        # once we delete all credentials for self.user_id"},{"line_number":93,"context_line":"        self.assertRaises(exception.CredentialNotFound,"},{"line_number":94,"context_line":"                          PROVIDERS.credential_api.get_credential,"},{"line_number":95,"context_line":"                          self.credential[\u0027id\u0027])"},{"line_number":96,"context_line":""},{"line_number":97,"context_line":"    def test_list_credentials(self):"},{"line_number":98,"context_line":"        \"\"\"Call ``GET /credentials``.\"\"\""}],"source_content_type":"text/x-python","patch_set":5,"id":"dfbec78f_bea68caa","line":95,"updated":"2019-05-13 21:57:58.000000000","message":"Same as above.","commit_id":"cd5729c2719eea381828dcb6cc2af99ef98e7655"}],"keystone/tests/unit/test_v3_resource.py":[{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"d650a5bb739fbd53271a99b48c27237aee0ef57b","unresolved":false,"context_lines":[{"line_number":1587,"context_line":"        # that reference this project"},{"line_number":1588,"context_line":"        self.assertRaises(exception.CredentialNotFound,"},{"line_number":1589,"context_line":"                          PROVIDERS.credential_api.get_credential,"},{"line_number":1590,"context_line":"                          credential[\u0027id\u0027])"},{"line_number":1591,"context_line":"        # But the credential for project2 is unaffected"},{"line_number":1592,"context_line":"        r \u003d PROVIDERS.credential_api.get_credential(credential2[\u0027id\u0027])"},{"line_number":1593,"context_line":"        self.assertDictEqual(credential2, r)"}],"source_content_type":"text/x-python","patch_set":5,"id":"dfbec78f_7ebed4b4","line":1590,"updated":"2019-05-13 21:57:58.000000000","message":"See previous comment on this.","commit_id":"cd5729c2719eea381828dcb6cc2af99ef98e7655"}],"releasenotes/notes/bug-1815771-ae0e4118c552f01e.yaml":[{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"a9425280999594214bb2f4598661639dde641112","unresolved":false,"context_lines":[{"line_number":1,"context_line":"---"},{"line_number":2,"context_line":"features:"},{"line_number":3,"context_line":"  - Allows to cache credentials to avoid lookups on the database. This"},{"line_number":4,"context_line":"    operation can be turned on/off through the configuration parameter of"},{"line_number":5,"context_line":"    [credential] caching"}],"source_content_type":"text/x-yaml","patch_set":2,"id":"9fdfeff1_f1d0442e","line":3,"range":{"start_line":3,"start_character":4,"end_line":3,"end_character":13},"updated":"2019-02-19 20:36:46.000000000","message":"Allows operators","commit_id":"a12daf6fe802b3abe1aa38f85a4970d1811b83cf"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"a9425280999594214bb2f4598661639dde641112","unresolved":false,"context_lines":[{"line_number":2,"context_line":"features:"},{"line_number":3,"context_line":"  - Allows to cache credentials to avoid lookups on the database. This"},{"line_number":4,"context_line":"    operation can be turned on/off through the configuration parameter of"},{"line_number":5,"context_line":"    [credential] caching"}],"source_content_type":"text/x-yaml","patch_set":2,"id":"9fdfeff1_5116f0f3","line":5,"range":{"start_line":5,"start_character":4,"end_line":5,"end_character":24},"updated":"2019-02-19 20:36:46.000000000","message":"nit:\n\n  ``keystone.conf [credential] caching``.","commit_id":"a12daf6fe802b3abe1aa38f85a4970d1811b83cf"},{"author":{"_account_id":8482,"name":"Colleen Murphy","email":"colleen@gazlene.net","username":"krinkle"},"change_message_id":"725a524c63bf329789c43ce44ac91c049b8047d3","unresolved":false,"context_lines":[{"line_number":1,"context_line":"---"},{"line_number":2,"context_line":"features:"},{"line_number":3,"context_line":"  - Allows operators to cache credentials to avoid lookups on the database."},{"line_number":4,"context_line":"    This operation can be turned on/off through the configuration parameter of"},{"line_number":5,"context_line":"    keystone.conf [credential] caching."}],"source_content_type":"text/x-yaml","patch_set":5,"id":"dfbec78f_de8ca5d8","line":2,"updated":"2019-05-13 17:39:22.000000000","message":"Could you link the bug report?","commit_id":"cd5729c2719eea381828dcb6cc2af99ef98e7655"}]}
