)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"59bd7156d788eb192c6930a1bbb248d5f3a3df4a","unresolved":false,"context_lines":[{"line_number":7,"context_line":"Check that the user is dumb moved to the common method"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"It\u0027s not enough to compare a DN of a member as a string to"},{"line_number":10,"context_line":"filter a dumb meqmber. In some cases we can get member with"},{"line_number":11,"context_line":"DN \u0027CN\u003ddumb,DC\u003dnonexistent\u0027 instead of \u0027cn\u003ddumb,dc\u003dnonexistent\u0027."},{"line_number":12,"context_line":"In this case comparison in string form will be incorrect."},{"line_number":13,"context_line":""}],"source_content_type":"text/x-gerrit-commit-message","patch_set":10,"id":"7adec928_caf850c7","line":10,"updated":"2014-05-07 21:21:20.000000000","message":"member*","commit_id":"df5e5698132b237f459cb2a76f74cd6e592da1a3"},{"author":{"_account_id":9569,"name":"Sergey Nikitin","email":"nikitinserv@gmail.com","username":"snikitin"},"change_message_id":"1c106ab9af531a937a97fcda7f0b88967f9c82bf","unresolved":false,"context_lines":[{"line_number":7,"context_line":"Check that the user is dumb moved to the common method"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"It\u0027s not enough to compare a DN of a member as a string to"},{"line_number":10,"context_line":"filter a dumb meqmber. In some cases we can get member with"},{"line_number":11,"context_line":"DN \u0027CN\u003ddumb,DC\u003dnonexistent\u0027 instead of \u0027cn\u003ddumb,dc\u003dnonexistent\u0027."},{"line_number":12,"context_line":"In this case comparison in string form will be incorrect."},{"line_number":13,"context_line":""}],"source_content_type":"text/x-gerrit-commit-message","patch_set":10,"id":"7adec928_a13b22ea","line":10,"in_reply_to":"7adec928_caf850c7","updated":"2014-05-08 04:58:16.000000000","message":"yep","commit_id":"df5e5698132b237f459cb2a76f74cd6e592da1a3"},{"author":{"_account_id":6486,"name":"Brant Knudson","email":"blk@acm.org","username":"blk-u"},"change_message_id":"e3dfb13208b4c4870db3cda5ad10b6e3b0cccf83","unresolved":false,"context_lines":[{"line_number":15,"context_line":"to lowercase values of cn and dc will be corrupted. That\u0027s why"},{"line_number":16,"context_line":"we should compare DNs ignoring a case of keys, not values."},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"Also some minor changes were made."},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"Change-Id: I61720d4b9ddeaf860578f76bc524fbda14984535"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":11,"id":"7adec928_e079cfc8","line":18,"updated":"2014-05-19 23:53:27.000000000","message":"Put these in a separate commit.","commit_id":"31a7e8d72517f5a3a7d9ad7fffa463d5ffc90c75"},{"author":{"_account_id":6486,"name":"Brant Knudson","email":"blk@acm.org","username":"blk-u"},"change_message_id":"a1cf6b873109bbe0a747d33fb30b32c006937551","unresolved":false,"context_lines":[{"line_number":8,"context_line":""},{"line_number":9,"context_line":"The code which checks if a user is the dumb member"},{"line_number":10,"context_line":"was moved to a new method to remove duplication of code."},{"line_number":11,"context_line":""},{"line_number":12,"context_line":"Change-Id: I61720d4b9ddeaf860578f76bc524fbda14984535"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":16,"id":"3ae8d1ca_bf78b32c","line":11,"updated":"2014-05-27 00:39:45.000000000","message":"Since this change is fixing a bug, that in some cases the \"dumb\" member was being returned, a bug should be filed and this should be marked Closes-Bug: #","commit_id":"6d5d7a8ec46bf5feab0406d32f113f1048b7830a"}],"keystone/assignment/backends/ldap.py":[{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"unresolved":false,"context_lines":[{"line_number":667,"context_line":"                # insensitive comparison since attribute names will be upper"},{"line_number":668,"context_line":"                # case for AD. We already do this elsewhere in the LDAP"},{"line_number":669,"context_line":"                # driver, so it\u0027s OK until we decide to become syntax aware."},{"line_number":670,"context_line":"                if not self._is_dumb_member(user_dn, True):"},{"line_number":671,"context_line":"                    res.append(UserRoleAssociation("},{"line_number":672,"context_line":"                               user_dn\u003duser_dn,"},{"line_number":673,"context_line":"                               role_dn\u003drole_dn,"}],"source_content_type":"text/x-python","patch_set":2,"id":"AAAAXH%2F%2FAic%3D","line":670,"updated":"2014-04-24 17:37:18.000000000","message":"pass True as a kwarg since it\u0027s optional (and not obvious what True means here)","commit_id":"3d57fd85342b4c6d3ed36b2b2c0137affdd6089d"},{"author":{"_account_id":9569,"name":"Sergey Nikitin","email":"nikitinserv@gmail.com","username":"snikitin"},"change_message_id":"d0f4a90ec5de73d494a68d5a51692ea8f35558fa","unresolved":false,"context_lines":[{"line_number":667,"context_line":"                # insensitive comparison since attribute names will be upper"},{"line_number":668,"context_line":"                # case for AD. We already do this elsewhere in the LDAP"},{"line_number":669,"context_line":"                # driver, so it\u0027s OK until we decide to become syntax aware."},{"line_number":670,"context_line":"                if not self._is_dumb_member(user_dn, True):"},{"line_number":671,"context_line":"                    res.append(UserRoleAssociation("},{"line_number":672,"context_line":"                               user_dn\u003duser_dn,"},{"line_number":673,"context_line":"                               role_dn\u003drole_dn,"}],"source_content_type":"text/x-python","patch_set":2,"id":"AAAAXX%2F%2F8Io%3D","line":670,"in_reply_to":"AAAAXH%2F%2FAic%3D","updated":"2014-04-28 09:38:34.000000000","message":"Ok","commit_id":"3d57fd85342b4c6d3ed36b2b2c0137affdd6089d"},{"author":{"_account_id":6486,"name":"Brant Knudson","email":"blk@acm.org","username":"blk-u"},"change_message_id":"51fd6802e77e097911e23ccdae5022eed07d16a4","unresolved":false,"context_lines":[{"line_number":450,"context_line":"        if not role_dn:"},{"line_number":451,"context_line":"            # Get users who have default tenant mapping"},{"line_number":452,"context_line":"            for user_dn in tenant[1].get(self.member_attribute, []):"},{"line_number":453,"context_line":"                if not self._is_dumb_member(user_dn):"},{"line_number":454,"context_line":"                    res.add(user_dn)"},{"line_number":455,"context_line":""},{"line_number":456,"context_line":"        # Get users who are explicitly mapped via a tenant"}],"source_content_type":"text/x-python","patch_set":14,"id":"7adec928_ed57a324","line":453,"updated":"2014-05-22 22:21:49.000000000","message":"I prefer to leave it \"if self._is_dumb_member(user_dn): continue\"\n\n1) then we use a positive check rather than a negative one\n2) it removes a level of indentation for the following code.\n\nThis also applies to the rest of these changes.","commit_id":"bbd988e3f00dd1d48d84c83041af463f62df57f3"},{"author":{"_account_id":9569,"name":"Sergey Nikitin","email":"nikitinserv@gmail.com","username":"snikitin"},"change_message_id":"f2d6acfa5c9e7d34394835aa96e2d1f5217e52fe","unresolved":false,"context_lines":[{"line_number":450,"context_line":"        if not role_dn:"},{"line_number":451,"context_line":"            # Get users who have default tenant mapping"},{"line_number":452,"context_line":"            for user_dn in tenant[1].get(self.member_attribute, []):"},{"line_number":453,"context_line":"                if not self._is_dumb_member(user_dn):"},{"line_number":454,"context_line":"                    res.add(user_dn)"},{"line_number":455,"context_line":""},{"line_number":456,"context_line":"        # Get users who are explicitly mapped via a tenant"}],"source_content_type":"text/x-python","patch_set":14,"id":"7adec928_a3359cdc","line":453,"in_reply_to":"7adec928_ed57a324","updated":"2014-05-23 11:37:49.000000000","message":"ok","commit_id":"bbd988e3f00dd1d48d84c83041af463f62df57f3"}],"keystone/common/ldap/core.py":[{"author":{"_account_id":4,"name":"Dolph Mathews","email":"dolph.mathews@gmail.com","username":"dolph"},"unresolved":false,"context_lines":[{"line_number":752,"context_line":"            mapping[ldap_attr] \u003d attr_map"},{"line_number":753,"context_line":"        return mapping"},{"line_number":754,"context_line":""},{"line_number":755,"context_line":"    def _is_dumb_member(self, member_dn, ignore_case\u003dFalse):"},{"line_number":756,"context_line":"        if self.use_dumb_member:"},{"line_number":757,"context_line":"            if ignore_case:"},{"line_number":758,"context_line":"                return member_dn.lower() \u003d\u003d self.dumb_member.lower()"}],"source_content_type":"text/x-python","patch_set":2,"id":"AAAAXH%2F%2FAiQ%3D","line":755,"updated":"2014-04-24 17:37:18.000000000","message":"docstr would be appreciated","commit_id":"3d57fd85342b4c6d3ed36b2b2c0137affdd6089d"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"0229c03dc2262be01a5012c9b6d50274f8d59ae8","unresolved":false,"context_lines":[{"line_number":752,"context_line":"            mapping[ldap_attr] \u003d attr_map"},{"line_number":753,"context_line":"        return mapping"},{"line_number":754,"context_line":""},{"line_number":755,"context_line":"    def _is_dumb_member(self, member_dn, ignore_case\u003dFalse):"},{"line_number":756,"context_line":"        if self.use_dumb_member:"},{"line_number":757,"context_line":"            if ignore_case:"},{"line_number":758,"context_line":"                return member_dn.lower() \u003d\u003d self.dumb_member.lower()"}],"source_content_type":"text/x-python","patch_set":2,"id":"AAAAXX%2F%2F%2F9U%3D","line":755,"in_reply_to":"AAAAXH%2F%2FAiQ%3D","updated":"2014-04-24 20:05:56.000000000","message":"++","commit_id":"3d57fd85342b4c6d3ed36b2b2c0137affdd6089d"},{"author":{"_account_id":9569,"name":"Sergey Nikitin","email":"nikitinserv@gmail.com","username":"snikitin"},"change_message_id":"d0f4a90ec5de73d494a68d5a51692ea8f35558fa","unresolved":false,"context_lines":[{"line_number":752,"context_line":"            mapping[ldap_attr] \u003d attr_map"},{"line_number":753,"context_line":"        return mapping"},{"line_number":754,"context_line":""},{"line_number":755,"context_line":"    def _is_dumb_member(self, member_dn, ignore_case\u003dFalse):"},{"line_number":756,"context_line":"        if self.use_dumb_member:"},{"line_number":757,"context_line":"            if ignore_case:"},{"line_number":758,"context_line":"                return member_dn.lower() \u003d\u003d self.dumb_member.lower()"}],"source_content_type":"text/x-python","patch_set":2,"id":"AAAAXX%2F%2F8Iw%3D","line":755,"in_reply_to":"AAAAXX%2F%2F%2F9U%3D","updated":"2014-04-28 09:38:34.000000000","message":"Yea, docstring would be helpful","commit_id":"3d57fd85342b4c6d3ed36b2b2c0137affdd6089d"},{"author":{"_account_id":9098,"name":"Nathan Kinder","email":"nkinder@redhat.com","username":"nkinder"},"change_message_id":"cc00afa306b8f04380686659571d2a6f54671c40","unresolved":false,"context_lines":[{"line_number":755,"context_line":"                and self._is_dns_equal(member_dn, self.dumb_member))"},{"line_number":756,"context_line":""},{"line_number":757,"context_line":"    @staticmethod"},{"line_number":758,"context_line":"    def _is_dns_equal(first_dn, second_dn):"},{"line_number":759,"context_line":"        \"\"\"Checks that DNs are equal. When comparing the case of"},{"line_number":760,"context_line":"        keys (cn, ou, etc) ignored."},{"line_number":761,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"bad4c104_5be24da0","line":758,"updated":"2014-04-29 15:51:19.000000000","message":"It would be nice to add a comment to point out that this is not a fully \"Distinguished Name\" syntax aware comparison.  You can probably just use my comment that you removed from keystone/assignment/backends/ldap.py here.","commit_id":"1fc045158b0ab32bac5327b9a2750a5b9188d8a9"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"unresolved":false,"context_lines":[{"line_number":768,"context_line":"        if len(first_parsed_dn) !\u003d len(second_parsed_dn):"},{"line_number":769,"context_line":"            return False"},{"line_number":770,"context_line":""},{"line_number":771,"context_line":"        for i in xrange(len(first_parsed_dn)):"},{"line_number":772,"context_line":"            first_tuple \u003d first_parsed_dn[i][0]"},{"line_number":773,"context_line":"            second_tuple \u003d second_parsed_dn[i][0]"},{"line_number":774,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"bad4c104_db3add35","line":771,"updated":"2014-04-29 15:56:48.000000000","message":"xrange isn\u0027t available in Python3. Just use range as there really isn\u0027t that great of a performance advantage for a small iterable.","commit_id":"1fc045158b0ab32bac5327b9a2750a5b9188d8a9"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"unresolved":false,"context_lines":[{"line_number":775,"context_line":"            if first_tuple[0].lower() !\u003d second_tuple[0].lower():"},{"line_number":776,"context_line":"                return False"},{"line_number":777,"context_line":""},{"line_number":778,"context_line":"            for j in xrange(1, len(first_tuple)):"},{"line_number":779,"context_line":"                if first_tuple[j] !\u003d second_tuple[j]:"},{"line_number":780,"context_line":"                    return False"},{"line_number":781,"context_line":"        return True"}],"source_content_type":"text/x-python","patch_set":5,"id":"bad4c104_db03bd71","line":778,"updated":"2014-04-29 15:56:48.000000000","message":"Same here.","commit_id":"1fc045158b0ab32bac5327b9a2750a5b9188d8a9"},{"author":{"_account_id":9098,"name":"Nathan Kinder","email":"nkinder@redhat.com","username":"nkinder"},"change_message_id":"cc00afa306b8f04380686659571d2a6f54671c40","unresolved":false,"context_lines":[{"line_number":758,"context_line":"                and self._is_dns_equal(member_dn, self.dumb_member))"},{"line_number":759,"context_line":""},{"line_number":760,"context_line":"    @staticmethod"},{"line_number":761,"context_line":"    def _is_dns_equal(first_dn, second_dn):"},{"line_number":762,"context_line":"        \"\"\"Checks that DNs are equal. When comparing the case of"},{"line_number":763,"context_line":"        keys (cn, ou, etc) ignored."},{"line_number":764,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"bad4c104_61ba02e3","line":761,"updated":"2014-04-29 16:27:15.000000000","message":"It would be nice to add a comment to point out that this is not a fully \"Distinguished Name\" syntax aware comparison. You can probably just use my comment that you removed from keystone/assignment/backends/ldap.py here.","commit_id":"f5713671a8a70348ab281ebde9246b16f6b4d3cc"},{"author":{"_account_id":9098,"name":"Nathan Kinder","email":"nkinder@redhat.com","username":"nkinder"},"change_message_id":"f705873f3f78fabec6e234fcb8e9613e22158912","unresolved":false,"context_lines":[{"line_number":758,"context_line":"                and self._is_dns_equal(member_dn, self.dumb_member))"},{"line_number":759,"context_line":""},{"line_number":760,"context_line":"    @staticmethod"},{"line_number":761,"context_line":"    def _is_dns_equal(first_dn, second_dn):"},{"line_number":762,"context_line":"        \"\"\"Checks that DNs are equal. When comparing the case of"},{"line_number":763,"context_line":"        keys (cn, ou, etc) ignored."},{"line_number":764,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"9ad9bd40_701727ee","line":761,"in_reply_to":"9ad9bd40_d28805c9","updated":"2014-05-06 14:39:05.000000000","message":"A correct syntax aware DN comparison has to deal with a lot more than just case-sensitivity.  For example, characters may be escaped or multi-part RDNs may be specified in different orders.\n\nThe following DNs are all equal according to the RFC 4514:\n\n  cn\u003dfoo+cn\u003dbar,dc\u003dexample,dc\u003dcom\n  cn\u003dFoo+cn\u003dbar,dc\u003dexample,dc\u003dcom\n  cn\u003dbar+cn\u003dfoo,dc\u003dexample,dc\u003dcom\n  cn\u003d\\66\\6f\\6f+cn\u003dbar,dc\u003dexample,dc\u003dcom\n\nAlso, case-sensitivity of LDAP attribute values is dependent on the actual attribute as defined in the schema (and it\u0027s matching rule).  In general, values are not case-sensitive with most standard attributes (though most LDAP servers are case-preserving).  Here is an example showing this:\n\n  [nkinder@localhost]$ ldapsearch -x -D \"cn\u003ddirectory manager\" -W -b \"dc\u003dexample,dc\u003dcom\" \"cn\u003dfoo\" dn\n  dn: cn\u003dbar+cn\u003dfoo,dc\u003dexample,dc\u003dcom\n  \n  [nkinder@localhost KDS]$ ldapmodify -x -D \"cn\u003ddirectory manager\" -W\n  dn: cn\u003dFoo+cn\u003dbar,dc\u003dexample,dc\u003dcom\n  changetype: add\n  cn: Foo\n  cn: bar\n  objectclass: inetorgperson\n  sn: user\n  \n  adding new entry \"cn\u003dFoo+cn\u003dbar,dc\u003dexample,dc\u003dcom\"\n  ldap_add: Already exists (68)\n\nI am not suggesting that you make this function be truly syntax aware, as that is a large undertaking that is not necessary for the \"dumb member\" check.  I would merely like to see a comment so others know that this is not performing a true DN comparison that takes syntaxes and standards around DN string representation into account.","commit_id":"f5713671a8a70348ab281ebde9246b16f6b4d3cc"},{"author":{"_account_id":9569,"name":"Sergey Nikitin","email":"nikitinserv@gmail.com","username":"snikitin"},"change_message_id":"5f943ba3c54a3f9a916df10d745c8adc4f112083","unresolved":false,"context_lines":[{"line_number":758,"context_line":"                and self._is_dns_equal(member_dn, self.dumb_member))"},{"line_number":759,"context_line":""},{"line_number":760,"context_line":"    @staticmethod"},{"line_number":761,"context_line":"    def _is_dns_equal(first_dn, second_dn):"},{"line_number":762,"context_line":"        \"\"\"Checks that DNs are equal. When comparing the case of"},{"line_number":763,"context_line":"        keys (cn, ou, etc) ignored."},{"line_number":764,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"9ad9bd40_d28805c9","line":761,"in_reply_to":"bad4c104_61ba02e3","updated":"2014-04-30 10:56:22.000000000","message":"Why it\u0027s not a fully \"Distinguished Name\" syntax aware comparison? You wrote in your comment: \"We still need to do a case insensitive comparison since attribute names will be upper case for AD.\" But here we ignoring a case of keys. Is it not the solution?","commit_id":"f5713671a8a70348ab281ebde9246b16f6b4d3cc"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"unresolved":false,"context_lines":[{"line_number":759,"context_line":""},{"line_number":760,"context_line":"    @staticmethod"},{"line_number":761,"context_line":"    def _is_dns_equal(first_dn, second_dn):"},{"line_number":762,"context_line":"        \"\"\"Checks that DNs are equal. When comparing the case of"},{"line_number":763,"context_line":"        keys (cn, ou, etc) ignored."},{"line_number":764,"context_line":""},{"line_number":765,"context_line":"        :param first_dn: DN of first member to be compared."}],"source_content_type":"text/x-python","patch_set":6,"id":"bad4c104_21771a04","line":762,"updated":"2014-04-29 16:35:01.000000000","message":"Can you provide a few tests for this method? It\u0027s unclear to me what the parsed_dn[12] data looks like and the new implementation looks much different than the original.","commit_id":"f5713671a8a70348ab281ebde9246b16f6b4d3cc"},{"author":{"_account_id":9098,"name":"Nathan Kinder","email":"nkinder@redhat.com","username":"nkinder"},"change_message_id":"cc00afa306b8f04380686659571d2a6f54671c40","unresolved":false,"context_lines":[{"line_number":759,"context_line":""},{"line_number":760,"context_line":"    @staticmethod"},{"line_number":761,"context_line":"    def _is_dns_equal(first_dn, second_dn):"},{"line_number":762,"context_line":"        \"\"\"Checks that DNs are equal. When comparing the case of"},{"line_number":763,"context_line":"        keys (cn, ou, etc) ignored."},{"line_number":764,"context_line":""},{"line_number":765,"context_line":"        :param first_dn: DN of first member to be compared."}],"source_content_type":"text/x-python","patch_set":6,"id":"bad4c104_87047616","line":762,"in_reply_to":"bad4c104_21771a04","updated":"2014-04-29 17:14:23.000000000","message":"A parsed DN of \"uid\u003dfoo,dc\u003dexample,dc\u003dcom\" should look like this:\n\n  [[(\u0027uid\u0027, \u0027foo\u0027, 1)], [(\u0027dc\u0027, \u0027example\u0027, 1)], [(\u0027dc\u0027, \u0027com\u0027, 1)]]\n\nI agree that tests would be good here.  I think at a minimum we want a positive and negative test.  Something like the following would cover this:\n\nEvaluate that the following compare as equal:\n\n  \"uid\u003dfoo,dc\u003dexample,dc\u003dcom\"\n  \"UID\u003dfoo,DC\u003dexample,DC\u003dcom\"\n\nEvaluate that the following compare as NOT equal:\n\n  \"uid\u003dfoo,dc\u003dexample,dc\u003dcom\"\n  \"uid\u003dFOO,dc\u003dEXAMPLE,dc\u003dCOM\"","commit_id":"f5713671a8a70348ab281ebde9246b16f6b4d3cc"},{"author":{"_account_id":9569,"name":"Sergey Nikitin","email":"nikitinserv@gmail.com","username":"snikitin"},"change_message_id":"5f943ba3c54a3f9a916df10d745c8adc4f112083","unresolved":false,"context_lines":[{"line_number":759,"context_line":""},{"line_number":760,"context_line":"    @staticmethod"},{"line_number":761,"context_line":"    def _is_dns_equal(first_dn, second_dn):"},{"line_number":762,"context_line":"        \"\"\"Checks that DNs are equal. When comparing the case of"},{"line_number":763,"context_line":"        keys (cn, ou, etc) ignored."},{"line_number":764,"context_line":""},{"line_number":765,"context_line":"        :param first_dn: DN of first member to be compared."}],"source_content_type":"text/x-python","patch_set":6,"id":"9ad9bd40_de0f342d","line":762,"in_reply_to":"bad4c104_87047616","updated":"2014-04-30 10:56:22.000000000","message":"Ok. I\u0027am agree with you - tests would be helpful","commit_id":"f5713671a8a70348ab281ebde9246b16f6b4d3cc"},{"author":{"_account_id":8116,"name":"John Dennis","email":"jdennis@redhat.com","username":"jdennis"},"change_message_id":"d45abe4f347e4479e6cdb873a448f9fe63f7abc0","unresolved":false,"context_lines":[{"line_number":758,"context_line":"                and self._is_dns_equal(member_dn, self.dumb_member))"},{"line_number":759,"context_line":""},{"line_number":760,"context_line":"    @staticmethod"},{"line_number":761,"context_line":"    def _is_dns_equal(first_dn, second_dn):"},{"line_number":762,"context_line":"        \"\"\"Checks that DNs are equal. When comparing the case of"},{"line_number":763,"context_line":"        keys (cn, ou, etc) ignored. Ideally, this comparison would be"},{"line_number":764,"context_line":"        aware of the Distinguished Name LDAP syntax. Since Keystone"}],"source_content_type":"text/x-python","patch_set":11,"id":"7adec928_b80a8925","line":761,"updated":"2014-05-20 19:29:30.000000000","message":"The claim the values in an AVA should match with case sensitivity is not correct. I realize it\u0027s very hard to find the RFC\u0027s which specify this, I know because I\u0027ve written DN utilities in the past and spent a long time researching this. Here is a short abbreviated summary:\n\nYou need to apply the distinguishedMatchRule [1]\n\nYou need to compare individual AVA\u0027s (for now I\u0027ll ignore the fact you don\u0027t check for multiple AVA\u0027s in a single RDN). An AVA is composed of an attribute type and an attribute value. Because attribute types when expressed as a string alias [2] map to a numeric OID it\u0027s obvious a string representation of an OID alias needs to ignore case when comparing (ignoring for the moment it\u0027s legitimate to specify the attributeType as a numeric OID instead of an alias). Except for some corner cases you\u0027re correct, the attributeType comparison is case insensitive.\n\nThe RFC 4517 goes on to say \" Two AVAs with the same attribute type are the same if their values are equal according to the equality matching rule of the attribute type.\"\n\nThis means you have have to determine the matching rule for the attribute type in each AVA in order to perform the comparison. Does that mean we need a lookup table? Yuck! Fortunately no, If we research all the defined attribute types that can appear in an AVA [3] we\u0027ll discover virtually all derive their syntax from the \u0027name\u0027 atribute type (OID 2.5.4.41) whose EQUALITY MATCH RULE is caseIgnoreMatch. [4].\n\nTherefore the value comparison also must be case insensitive. [5].\n\nDoes that mean we don\u0027t have to parse the DN string with str2dn and just do a straight case insensitive match on the whole DN string? No, we still must decompose the DN into it\u0027s constituent parts. Why? Because RFC 4514 permits multiple escaping rules and formats which can map to the same canonical value. The str2dn function normalizes the different representations into one canonical form. (the str2dn decomposition would also allow one to properly handle mutli-valued RDN\u0027s which you currently ignore).\n\nI think for the near term if you just lower case the value components as well the function will be fine. I have written a Python class for DN\u0027s which permits comparisons,  indexing, slices, concatenation, construction, escaping, etc. on DN\u0027s for another Python project that heavily used LDAP (e.g. IPA). At some pont we need to get that class into OpenStack, we learned the hard way in IPA that DN\u0027s are anything but simple strings and got burned on a lot of corner cases, it really helps to have a DN object which is \"smart\".\n\n[1] http://www.ietf.org/rfc/rfc4517.txt, section 4.2.15\n\n[2] http://www.ietf.org/rfc/rfc4514.txt, end of section 3 (actually these aliases are defined in several different RFC\u0027s)\n\n[3] http://tools.ietf.org/html/rfc4519\n\n[4] With some exceptions such as DC whose matching rule is caseIgnoreIA5Match, hence is also case insensitive.\n\n[5] Assuming only predefined attribute types are used, which is a reasonable assumption.","commit_id":"31a7e8d72517f5a3a7d9ad7fffa463d5ffc90c75"}],"keystone/identity/backends/ldap.py":[{"author":{"_account_id":9569,"name":"Sergey Nikitin","email":"nikitinserv@gmail.com","username":"snikitin"},"change_message_id":"96f1d05d994c8492f76aa51e25b989c9646ab12a","unresolved":false,"context_lines":[{"line_number":329,"context_line":"        \"\"\"Return a list of groups for which the user is a member.\"\"\""},{"line_number":330,"context_line":""},{"line_number":331,"context_line":"        user_dn_esc \u003d ldap.filter.escape_filter_chars(user_dn)"},{"line_number":332,"context_line":"        query \u003d \u0027(\u0026(%s\u003d%s)%s)\u0027 % (self.member_attribute,"},{"line_number":333,"context_line":"                                  user_dn_esc,"},{"line_number":334,"context_line":"                                  self.ldap_filter or \u0027\u0027)"},{"line_number":335,"context_line":"        return self.get_all(query)"}],"source_content_type":"text/x-python","patch_set":2,"id":"AAAAXH%2F%2FsY4%3D","line":332,"updated":"2014-04-18 06:52:57.000000000","message":"objectClass was removed because it will be added to the query string in LdapBase._ldap_get_all.","commit_id":"3d57fd85342b4c6d3ed36b2b2c0137affdd6089d"},{"author":{"_account_id":9098,"name":"Nathan Kinder","email":"nkinder@redhat.com","username":"nkinder"},"change_message_id":"48367d014da6f9d36b3f0bcc743be50baeb11f16","unresolved":false,"context_lines":[{"line_number":351,"context_line":"        for dn, member in attrs:"},{"line_number":352,"context_line":"            user_dns \u003d member.get(self.member_attribute, [])"},{"line_number":353,"context_line":"            for user_dn in user_dns:"},{"line_number":354,"context_line":"                if not self._is_dumb_member(user_dn):"},{"line_number":355,"context_line":"                    users.append(user_dn)"},{"line_number":356,"context_line":"        return users"}],"source_content_type":"text/x-python","patch_set":2,"id":"AAAAXX%2F%2F%2BWU%3D","line":354,"updated":"2014-04-24 22:38:25.000000000","message":"Nice catch!  I missed this comparison in my earlier patch... :(\n\nThere are two other areas when you should call _is_dumb_member() in keystone/assignment/backends/ldap.py:\n\n  get_user_dns()\n  get_role_assignments()\n\nIt would also be great if you can add tests for each function that uses _is_dumb_member() to ensure that the dumb member is filtered out when the case is different between what fakeldap returns and what the config defines.","commit_id":"3d57fd85342b4c6d3ed36b2b2c0137affdd6089d"},{"author":{"_account_id":9569,"name":"Sergey Nikitin","email":"nikitinserv@gmail.com","username":"snikitin"},"change_message_id":"d0f4a90ec5de73d494a68d5a51692ea8f35558fa","unresolved":false,"context_lines":[{"line_number":325,"context_line":"        \"\"\"Return a list of groups for which the user is a member.\"\"\""},{"line_number":326,"context_line":""},{"line_number":327,"context_line":"        user_dn_esc \u003d ldap.filter.escape_filter_chars(user_dn)"},{"line_number":328,"context_line":"        query \u003d \u0027(\u0026(%s\u003d%s)%s)\u0027 % (self.member_attribute,"},{"line_number":329,"context_line":"                                  user_dn_esc,"},{"line_number":330,"context_line":"                                  self.ldap_filter or \u0027\u0027)"},{"line_number":331,"context_line":"        return self.get_all(query)"}],"source_content_type":"text/x-python","patch_set":5,"id":"bad4c104_58c5f359","line":328,"updated":"2014-04-29 15:05:35.000000000","message":"objectClass was removed because it will be added to the query string in LdapBase._ldap_get_all.","commit_id":"1fc045158b0ab32bac5327b9a2750a5b9188d8a9"},{"author":{"_account_id":6486,"name":"Brant Knudson","email":"blk@acm.org","username":"blk-u"},"change_message_id":"51fd6802e77e097911e23ccdae5022eed07d16a4","unresolved":false,"context_lines":[{"line_number":357,"context_line":"        for dn, member in attrs:"},{"line_number":358,"context_line":"            user_dns \u003d member.get(self.member_attribute, [])"},{"line_number":359,"context_line":"            for user_dn in user_dns:"},{"line_number":360,"context_line":"                if not self._is_dumb_member(user_dn):"},{"line_number":361,"context_line":"                    users.append(user_dn)"},{"line_number":362,"context_line":"        return users"},{"line_number":363,"context_line":""}],"source_content_type":"text/x-python","patch_set":14,"id":"7adec928_ad24bbc6","line":360,"updated":"2014-05-22 22:21:49.000000000","message":"same comment here, keep the positive check.","commit_id":"bbd988e3f00dd1d48d84c83041af463f62df57f3"},{"author":{"_account_id":9569,"name":"Sergey Nikitin","email":"nikitinserv@gmail.com","username":"snikitin"},"change_message_id":"f2d6acfa5c9e7d34394835aa96e2d1f5217e52fe","unresolved":false,"context_lines":[{"line_number":357,"context_line":"        for dn, member in attrs:"},{"line_number":358,"context_line":"            user_dns \u003d member.get(self.member_attribute, [])"},{"line_number":359,"context_line":"            for user_dn in user_dns:"},{"line_number":360,"context_line":"                if not self._is_dumb_member(user_dn):"},{"line_number":361,"context_line":"                    users.append(user_dn)"},{"line_number":362,"context_line":"        return users"},{"line_number":363,"context_line":""}],"source_content_type":"text/x-python","patch_set":14,"id":"7adec928_c33468e0","line":360,"in_reply_to":"7adec928_ad24bbc6","updated":"2014-05-23 11:37:49.000000000","message":"Done","commit_id":"bbd988e3f00dd1d48d84c83041af463f62df57f3"}],"keystone/tests/test_backend_ldap.py":[{"author":{"_account_id":6486,"name":"Brant Knudson","email":"blk@acm.org","username":"blk-u"},"change_message_id":"51fd6802e77e097911e23ccdae5022eed07d16a4","unresolved":false,"context_lines":[{"line_number":398,"context_line":"        dumb_id \u003d common_ldap.BaseLdap._dn_to_id(CONF.ldap.dumb_member)"},{"line_number":399,"context_line":"        self.assertNotIn(dumb_id, assignment_ids)"},{"line_number":400,"context_line":""},{"line_number":401,"context_line":"    def test_list_user_ids_for_project_dumb_member(self):"},{"line_number":402,"context_line":"        self.config_fixture.config(group\u003d\u0027ldap\u0027, use_dumb_member\u003dTrue)"},{"line_number":403,"context_line":"        self.clear_database()"},{"line_number":404,"context_line":"        self.load_backends()"}],"source_content_type":"text/x-python","patch_set":14,"id":"7adec928_6d12b363","line":401,"updated":"2014-05-22 22:21:49.000000000","message":"I didn\u0027t think this was fixing a bug? were there no tests before?","commit_id":"bbd988e3f00dd1d48d84c83041af463f62df57f3"},{"author":{"_account_id":9569,"name":"Sergey Nikitin","email":"nikitinserv@gmail.com","username":"snikitin"},"change_message_id":"f2d6acfa5c9e7d34394835aa96e2d1f5217e52fe","unresolved":false,"context_lines":[{"line_number":398,"context_line":"        dumb_id \u003d common_ldap.BaseLdap._dn_to_id(CONF.ldap.dumb_member)"},{"line_number":399,"context_line":"        self.assertNotIn(dumb_id, assignment_ids)"},{"line_number":400,"context_line":""},{"line_number":401,"context_line":"    def test_list_user_ids_for_project_dumb_member(self):"},{"line_number":402,"context_line":"        self.config_fixture.config(group\u003d\u0027ldap\u0027, use_dumb_member\u003dTrue)"},{"line_number":403,"context_line":"        self.clear_database()"},{"line_number":404,"context_line":"        self.load_backends()"}],"source_content_type":"text/x-python","patch_set":14,"id":"7adec928_6348f487","line":401,"in_reply_to":"7adec928_6d12b363","updated":"2014-05-23 11:37:49.000000000","message":"see my comment below","commit_id":"bbd988e3f00dd1d48d84c83041af463f62df57f3"},{"author":{"_account_id":6486,"name":"Brant Knudson","email":"blk@acm.org","username":"blk-u"},"change_message_id":"51fd6802e77e097911e23ccdae5022eed07d16a4","unresolved":false,"context_lines":[{"line_number":1086,"context_line":"        dn \u003d \u0027cn\u003ddumb,dc\u003dnonexistent\u0027"},{"line_number":1087,"context_line":"        self.assertTrue(self.identity_api.driver.user._is_dumb_member(dn))"},{"line_number":1088,"context_line":""},{"line_number":1089,"context_line":"    def test_is_dumb_member_upper_case_keys(self):"},{"line_number":1090,"context_line":"        self.config_fixture.config(group\u003d\u0027ldap\u0027,"},{"line_number":1091,"context_line":"                                   use_dumb_member\u003dTrue)"},{"line_number":1092,"context_line":"        self.load_backends()"}],"source_content_type":"text/x-python","patch_set":14,"id":"7adec928_18ffaf02","line":1089,"updated":"2014-05-22 22:21:49.000000000","message":"this test seems excessive, but I\u0027m ok with it as is.","commit_id":"bbd988e3f00dd1d48d84c83041af463f62df57f3"},{"author":{"_account_id":9569,"name":"Sergey Nikitin","email":"nikitinserv@gmail.com","username":"snikitin"},"change_message_id":"f2d6acfa5c9e7d34394835aa96e2d1f5217e52fe","unresolved":false,"context_lines":[{"line_number":1086,"context_line":"        dn \u003d \u0027cn\u003ddumb,dc\u003dnonexistent\u0027"},{"line_number":1087,"context_line":"        self.assertTrue(self.identity_api.driver.user._is_dumb_member(dn))"},{"line_number":1088,"context_line":""},{"line_number":1089,"context_line":"    def test_is_dumb_member_upper_case_keys(self):"},{"line_number":1090,"context_line":"        self.config_fixture.config(group\u003d\u0027ldap\u0027,"},{"line_number":1091,"context_line":"                                   use_dumb_member\u003dTrue)"},{"line_number":1092,"context_line":"        self.load_backends()"}],"source_content_type":"text/x-python","patch_set":14,"id":"7adec928_838980cc","line":1089,"in_reply_to":"7adec928_18ffaf02","updated":"2014-05-23 11:37:49.000000000","message":"It was added because in some cases method list_user_ids_for_project returns dumb member. It\u0027s happened because sometimes members returning in the follow form:\n\n {\u0027member\u0027: [u\u0027CN\u003ddumb,DC\u003dnonexistent\u0027, u\u0027CN\u003dd26520a7dbb64bb791d1b1c6759fddf6,OU\u003dUsers,CN\u003dexample,CN\u003dcom\u0027]}\n\nin this case member is dumb.\n\nand I added this test and test_list_user_ids_for_project_dumb_member to ensure that such members will be missed","commit_id":"bbd988e3f00dd1d48d84c83041af463f62df57f3"}]}
