)]}'
{"api-ref/source/v3/users.inc":[{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"3e630a3a68e09b996b292cf35f414ebbc34ebc4c","unresolved":false,"context_lines":[{"line_number":360,"context_line":""},{"line_number":361,"context_line":"Changes the password for a user."},{"line_number":362,"context_line":""},{"line_number":363,"context_line":".. note::"},{"line_number":364,"context_line":"    This API call does not require an authentication token in the"},{"line_number":365,"context_line":"    \u0027X-Auth-Token\u0027 request header."},{"line_number":366,"context_line":""},{"line_number":367,"context_line":"Response Codes"},{"line_number":368,"context_line":"--------------"}],"source_content_type":"text/x-c++src","patch_set":13,"id":"ba5201f7_09172c55","line":365,"range":{"start_line":363,"start_character":0,"end_line":365,"end_character":34},"updated":"2017-01-09 18:27:11.000000000","message":"++","commit_id":"3084a1e1a7a7600e3886cd1361e4561a4b8df787"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"68aa4a04e9f6d651206abdf8427d7c66ca1dd586","unresolved":false,"context_lines":[{"line_number":363,"context_line":".. note::"},{"line_number":364,"context_line":"    This API call does not require an authentication token in the"},{"line_number":365,"context_line":"    \u0027X-Auth-Token\u0027 request header if"},{"line_number":366,"context_line":"    ``[security_compliance] user_can_change_expired_password`` is set to"},{"line_number":367,"context_line":"    True in keystone.conf."},{"line_number":368,"context_line":""},{"line_number":369,"context_line":"Response Codes"}],"source_content_type":"text/x-c++src","patch_set":19,"id":"5a3905b3_0e947589","line":366,"range":{"start_line":366,"start_character":5,"end_line":366,"end_character":62},"updated":"2017-01-19 20:13:05.000000000","message":"See comment on config options.","commit_id":"915ab8ca03f62ba972cec09d958b66edae4bfff2"},{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"d0f799cfe8f825d93c674f39940196f8ec85eae2","unresolved":false,"context_lines":[{"line_number":363,"context_line":".. note::"},{"line_number":364,"context_line":"    This API call does not require an authentication token in the"},{"line_number":365,"context_line":"    \u0027X-Auth-Token\u0027 request header if"},{"line_number":366,"context_line":"    ``[security_compliance] user_can_change_expired_password`` is set to"},{"line_number":367,"context_line":"    True in keystone.conf."},{"line_number":368,"context_line":""},{"line_number":369,"context_line":"Response Codes"}],"source_content_type":"text/x-c++src","patch_set":19,"id":"5a3905b3_74ff8c01","line":366,"range":{"start_line":366,"start_character":5,"end_line":366,"end_character":62},"in_reply_to":"5a3905b3_0e947589","updated":"2017-01-19 20:40:30.000000000","message":"I don\u0027t see a need to mention any of this, a user shouldn\u0027t need to know about keystone.conf settings or specific headers (maybe)\n\nHow about just:\n\n\"This API can be called directly without authenticating and providing a token in the ``X-Auth-Token`` request header\"","commit_id":"915ab8ca03f62ba972cec09d958b66edae4bfff2"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"b6d18b8a0a32337895d997bfdaac528df0d88d60","unresolved":false,"context_lines":[{"line_number":363,"context_line":".. note::"},{"line_number":364,"context_line":"    This API call does not require an authentication token in the"},{"line_number":365,"context_line":"    \u0027X-Auth-Token\u0027 request header if"},{"line_number":366,"context_line":"    ``[security_compliance] user_can_change_expired_password`` is set to"},{"line_number":367,"context_line":"    True in keystone.conf."},{"line_number":368,"context_line":""},{"line_number":369,"context_line":"Response Codes"}],"source_content_type":"text/x-c++src","patch_set":19,"id":"5a3905b3_7e13b9b8","line":366,"in_reply_to":"5a3905b3_74ff8c01","updated":"2017-01-20 15:50:07.000000000","message":"I would replace \u0027and\u0027 with \u0027or\u0027","commit_id":"915ab8ca03f62ba972cec09d958b66edae4bfff2"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"c908b737d18b2cee6f88eed8ff28073f6df03ef0","unresolved":false,"context_lines":[{"line_number":361,"context_line":"Changes the password for a user."},{"line_number":362,"context_line":""},{"line_number":363,"context_line":".. note::"},{"line_number":364,"context_line":"    This API can be called directly without authenticating and providing a token in the"},{"line_number":365,"context_line":"    ``X-Auth-Token`` request header."},{"line_number":366,"context_line":""},{"line_number":367,"context_line":"Response Codes"}],"source_content_type":"text/x-c++src","patch_set":24,"id":"5a3905b3_d2de616c","line":364,"updated":"2017-01-20 16:05:00.000000000","message":"This still reads just a bit strange, and I think it is because of the \u0027and\u0027. I feel like we could make it simpler by omitting the \u0027authenticating and\u0027 piece.\n\nBut we can fix this later in a follow on patch when someone who is better at wordsmithing than I am takes a look at it.","commit_id":"88ba36a38841e9f66e741e53e13b877390195df1"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"776f641a12b985a328aea90bd92814d28d563e6d","unresolved":false,"context_lines":[{"line_number":361,"context_line":"Changes the password for a user."},{"line_number":362,"context_line":""},{"line_number":363,"context_line":".. note::"},{"line_number":364,"context_line":"    This API can be called directly without authenticating and providing a token in the"},{"line_number":365,"context_line":"    ``X-Auth-Token`` request header."},{"line_number":366,"context_line":""},{"line_number":367,"context_line":"Response Codes"}],"source_content_type":"text/x-c++src","patch_set":24,"id":"5a3905b3_5cde0012","line":364,"in_reply_to":"5a3905b3_d2de616c","updated":"2017-01-20 17:58:09.000000000","message":"yeah, could probably remove the \u0027authenticating and\u0027 part.","commit_id":"88ba36a38841e9f66e741e53e13b877390195df1"}],"doc/source/security_compliance.rst":[{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"d7d65d990bc41f581741ebab1b0ed0e8c3bed6aa","unresolved":false,"context_lines":[{"line_number":109,"context_line":""},{"line_number":110,"context_line":"If a user\u0027s password has expired, by default, an administrator would need to"},{"line_number":111,"context_line":"reset it. However, this can be changed to allow a user with an expired password"},{"line_number":112,"context_line":"to change it by setting ``password_expires_allow_user_change``:"},{"line_number":113,"context_line":""},{"line_number":114,"context_line":".. code-block:: ini"},{"line_number":115,"context_line":""}],"source_content_type":"text/x-rst","patch_set":19,"id":"5a3905b3_f3db96eb","line":112,"range":{"start_line":112,"start_character":26,"end_line":112,"end_character":60},"updated":"2017-01-19 19:58:27.000000000","message":"ditto","commit_id":"915ab8ca03f62ba972cec09d958b66edae4bfff2"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"68aa4a04e9f6d651206abdf8427d7c66ca1dd586","unresolved":false,"context_lines":[{"line_number":114,"context_line":".. code-block:: ini"},{"line_number":115,"context_line":""},{"line_number":116,"context_line":"    [security_compliance]"},{"line_number":117,"context_line":"    password_expires_allow_user_change \u003d True"},{"line_number":118,"context_line":""},{"line_number":119,"context_line":"Password Strength Requirements"},{"line_number":120,"context_line":"------------------------------"}],"source_content_type":"text/x-rst","patch_set":19,"id":"5a3905b3_6e825954","line":117,"range":{"start_line":117,"start_character":0,"end_line":117,"end_character":45},"updated":"2017-01-19 20:13:05.000000000","message":"Do not add more config options. This is not needed. Change policy and block the API if you want to disable. The proliferation of config options that can be easily mirrored in policy needs to stop.","commit_id":"915ab8ca03f62ba972cec09d958b66edae4bfff2"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"d7d65d990bc41f581741ebab1b0ed0e8c3bed6aa","unresolved":false,"context_lines":[{"line_number":114,"context_line":".. code-block:: ini"},{"line_number":115,"context_line":""},{"line_number":116,"context_line":"    [security_compliance]"},{"line_number":117,"context_line":"    password_expires_allow_user_change \u003d True"},{"line_number":118,"context_line":""},{"line_number":119,"context_line":"Password Strength Requirements"},{"line_number":120,"context_line":"------------------------------"}],"source_content_type":"text/x-rst","patch_set":19,"id":"5a3905b3_b3d10ed0","line":117,"range":{"start_line":117,"start_character":4,"end_line":117,"end_character":38},"updated":"2017-01-19 19:58:27.000000000","message":"Forgot to update this","commit_id":"915ab8ca03f62ba972cec09d958b66edae4bfff2"}],"keystone/auth/controllers.py":[{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"127608b88557c31e62d99e95f7accfcc9392317f","unresolved":false,"context_lines":[{"line_number":423,"context_line":"                parent_audit_id\u003dtoken_audit_id)"},{"line_number":424,"context_line":""},{"line_number":425,"context_line":"            if expired:"},{"line_number":426,"context_line":"                details \u003d self.base_url(request.context_dict,"},{"line_number":427,"context_line":"                                        path\u003d\u0027/users/\u0027 +"},{"line_number":428,"context_line":"                                        user_id +"},{"line_number":429,"context_line":"                                        \u0027/password/\u0027 +"},{"line_number":430,"context_line":"                                        token_id)"},{"line_number":431,"context_line":"                raise exception.PasswordExpired(user_id\u003duser_id,"},{"line_number":432,"context_line":"                                                detail\u003ddetails)"},{"line_number":433,"context_line":"            # NOTE(wanghong): We consume a trust use only when we are using"}],"source_content_type":"text/x-python","patch_set":6,"id":"1a6eadb0_6db690dd","line":430,"range":{"start_line":426,"start_character":0,"end_line":430,"end_character":49},"updated":"2016-12-20 18:02:33.000000000","message":"It was mentioned that we could return a URL if the user\u0027s password had expired so that they could use to change it. Wasn\u0027t sure about how to approach this though (tokenless?)","commit_id":"23a5cb10837ce26170d8db58108110849f5b4d1d"}],"keystone/common/controller.py":[{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"b74159f75b493739ff3729c7d33f7778c3ae9d13","unresolved":false,"context_lines":[{"line_number":95,"context_line":"    return False"},{"line_number":96,"context_line":""},{"line_number":97,"context_line":""},{"line_number":98,"context_line":"def protected(callback\u003dNone, check_auth\u003dNone):"},{"line_number":99,"context_line":"    \"\"\"Wrap API calls with role based access controls (RBAC)."},{"line_number":100,"context_line":""},{"line_number":101,"context_line":"    This handles both the protection of the API parameters as well as any"}],"source_content_type":"text/x-python","patch_set":15,"id":"7a3c09a3_4cbcbe6c","line":98,"updated":"2017-01-14 04:19:51.000000000","message":"I\u0027m not really a fan of doing this. The more i think about it the more I think we should try to do this a different way. A simple way to do this may be to create a new decorator \u0027protected_maybe\u0027 (or whatever) and have it call through to protected if it needs to.","commit_id":"983b52580f19af92aae82fcf3e95d2ffa0c4a8e8"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"c3fa70853132e779c204637a95892a75a191dc48","unresolved":false,"context_lines":[{"line_number":95,"context_line":"    return False"},{"line_number":96,"context_line":""},{"line_number":97,"context_line":""},{"line_number":98,"context_line":"def protected(callback\u003dNone, check_auth\u003dNone):"},{"line_number":99,"context_line":"    \"\"\"Wrap API calls with role based access controls (RBAC)."},{"line_number":100,"context_line":""},{"line_number":101,"context_line":"    This handles both the protection of the API parameters as well as any"}],"source_content_type":"text/x-python","patch_set":15,"id":"7a3c09a3_7f7e091a","line":98,"in_reply_to":"7a3c09a3_4cbcbe6c","updated":"2017-01-17 16:57:46.000000000","message":"Ok, I\u0027ll play around with setting up a separate \u0027protected_something\u0027 for this.","commit_id":"983b52580f19af92aae82fcf3e95d2ffa0c4a8e8"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"68aa4a04e9f6d651206abdf8427d7c66ca1dd586","unresolved":false,"context_lines":[{"line_number":80,"context_line":"    return context[\u0027environment\u0027].get(authorization.AUTH_CONTEXT_ENV, {})"},{"line_number":81,"context_line":""},{"line_number":82,"context_line":""},{"line_number":83,"context_line":"def _check_if_no_auth():"},{"line_number":84,"context_line":"    \"\"\"Check to see if protected auth should be bypassed."},{"line_number":85,"context_line":""},{"line_number":86,"context_line":"    One example is if users are configured to be able to change their own"},{"line_number":87,"context_line":"    password when it has expired, we want them to be able to authenticate"},{"line_number":88,"context_line":"    without needing a token. If other reasons arise in the future they"},{"line_number":89,"context_line":"    can be added here to be checked using \u0027protected_optional\u0027 wrapper."},{"line_number":90,"context_line":""},{"line_number":91,"context_line":"    \"\"\""},{"line_number":92,"context_line":"    if (CONF.security_compliance.password_expires_days and"},{"line_number":93,"context_line":"       CONF.security_compliance.user_can_change_expired_password):"},{"line_number":94,"context_line":"        return True"},{"line_number":95,"context_line":""},{"line_number":96,"context_line":"    return False"},{"line_number":97,"context_line":""},{"line_number":98,"context_line":""},{"line_number":99,"context_line":"def protected_optional(callback\u003dNone):"}],"source_content_type":"text/x-python","patch_set":19,"id":"5a3905b3_8e3ce594","line":96,"range":{"start_line":83,"start_character":0,"end_line":96,"end_character":16},"updated":"2017-01-19 20:13:05.000000000","message":"See info about config options. This whole method is not needed if you\u0027re only checking CONF.security_compliance.password_expires_days","commit_id":"915ab8ca03f62ba972cec09d958b66edae4bfff2"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"68aa4a04e9f6d651206abdf8427d7c66ca1dd586","unresolved":false,"context_lines":[{"line_number":96,"context_line":"    return False"},{"line_number":97,"context_line":""},{"line_number":98,"context_line":""},{"line_number":99,"context_line":"def protected_optional(callback\u003dNone):"},{"line_number":100,"context_line":"    \"\"\"Wrap API calls with (optional) role based access controls (RBAC)."},{"line_number":101,"context_line":""},{"line_number":102,"context_line":"    This checks a list of conditions where we do not want to apply RBAC."},{"line_number":103,"context_line":"    If the list of conditions is not met, we will call into protected()"},{"line_number":104,"context_line":"    below and continue RBAC checking as normal. Otherwise we will skip"},{"line_number":105,"context_line":"    any authentication checking here."},{"line_number":106,"context_line":""},{"line_number":107,"context_line":"    \"\"\""},{"line_number":108,"context_line":"    def wrapper(f):"},{"line_number":109,"context_line":"        @functools.wraps(f)"},{"line_number":110,"context_line":"        def inner(self, request, *args, **kwargs):"},{"line_number":111,"context_line":"            no_auth \u003d _check_if_no_auth()"},{"line_number":112,"context_line":"            if not no_auth:"},{"line_number":113,"context_line":"                return protected(callback)(f)(self, request, *args, **kwargs)"},{"line_number":114,"context_line":"            return f(self, request, *args, **kwargs)"},{"line_number":115,"context_line":"        return inner"},{"line_number":116,"context_line":"    return wrapper"},{"line_number":117,"context_line":""},{"line_number":118,"context_line":""},{"line_number":119,"context_line":"def protected(callback\u003dNone):"}],"source_content_type":"text/x-python","patch_set":19,"id":"5a3905b3_2e04d1be","line":116,"range":{"start_line":99,"start_character":0,"end_line":116,"end_character":18},"updated":"2017-01-19 20:13:05.000000000","message":"This is likely not needed at all, you can simply check in the controller method itself to see if the password change is needed. Drop this completely.\n\nThis is also adding a lot of complexity (the decorator pattern for security) is not a good one in general and we should be moving away from it not adding more especially for a limited use-case such as checking if a single API can be used.","commit_id":"915ab8ca03f62ba972cec09d958b66edae4bfff2"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"ea2788a66609d017bb3659b2a0b35696b6b0b13b","unresolved":false,"context_lines":[{"line_number":113,"context_line":"                return protected(callback)(f)(self, request, *args, **kwargs)"},{"line_number":114,"context_line":"            return f(self, request, *args, **kwargs)"},{"line_number":115,"context_line":"        return inner"},{"line_number":116,"context_line":"    return wrapper"},{"line_number":117,"context_line":""},{"line_number":118,"context_line":""},{"line_number":119,"context_line":"def protected(callback\u003dNone):"}],"source_content_type":"text/x-python","patch_set":19,"id":"5a3905b3_d473e0af","line":116,"in_reply_to":"5a3905b3_2e04d1be","updated":"2017-01-19 20:44:31.000000000","message":"I agree that a callback would be better here. When I suggested taking this logic out of the @protected decorator I wasn\u0027t thinking about callbacks at all. My primary motivation was not changing @protected for this.","commit_id":"915ab8ca03f62ba972cec09d958b66edae4bfff2"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"68aa4a04e9f6d651206abdf8427d7c66ca1dd586","unresolved":false,"context_lines":[{"line_number":132,"context_line":"    def wrapper(f):"},{"line_number":133,"context_line":"        @functools.wraps(f)"},{"line_number":134,"context_line":"        def inner(self, request, *args, **kwargs):"},{"line_number":135,"context_line":""},{"line_number":136,"context_line":"            request.assert_authenticated()"},{"line_number":137,"context_line":""},{"line_number":138,"context_line":"            if request.context.is_admin:"}],"source_content_type":"text/x-python","patch_set":19,"id":"5a3905b3_ee4ba929","line":135,"updated":"2017-01-19 20:13:05.000000000","message":"Unrelated change, revert","commit_id":"915ab8ca03f62ba972cec09d958b66edae4bfff2"}],"keystone/conf/security_compliance.py":[{"author":{"_account_id":11022,"name":"Rodrigo Duarte Sousa","email":"rodrigodsousa@gmail.com","username":"rodrigods"},"change_message_id":"b300a1116ee52eb3cfdaec8876b95c498a969c21","unresolved":false,"context_lines":[{"line_number":92,"context_line":"expires. This allows a user to change their own password without needing an"},{"line_number":93,"context_line":"administrator to reset it for them if it has expired. By default, this is"},{"line_number":94,"context_line":"disabled and a user will need to have an admin reset their password if it"},{"line_number":95,"context_line":"does expire. This feature will only be enabled if"},{"line_number":96,"context_line":"`[security_compliance] password_expires_days` is set."},{"line_number":97,"context_line":"\"\"\"))"},{"line_number":98,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ba5201f7_2ff4b385","line":95,"range":{"start_line":95,"start_character":18,"end_line":95,"end_character":25},"updated":"2017-01-03 21:48:18.000000000","message":"s/feature/setting\n\nwhat do you think?","commit_id":"7ee18fd641153fb005ad5e96077a7523486483e1"},{"author":{"_account_id":11022,"name":"Rodrigo Duarte Sousa","email":"rodrigodsousa@gmail.com","username":"rodrigods"},"change_message_id":"b300a1116ee52eb3cfdaec8876b95c498a969c21","unresolved":false,"context_lines":[{"line_number":91,"context_line":"If set to True, a user will be allowed to change their own password after it"},{"line_number":92,"context_line":"expires. This allows a user to change their own password without needing an"},{"line_number":93,"context_line":"administrator to reset it for them if it has expired. By default, this is"},{"line_number":94,"context_line":"disabled and a user will need to have an admin reset their password if it"},{"line_number":95,"context_line":"does expire. This feature will only be enabled if"},{"line_number":96,"context_line":"`[security_compliance] password_expires_days` is set."},{"line_number":97,"context_line":"\"\"\"))"},{"line_number":98,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ba5201f7_6fd79bed","line":95,"range":{"start_line":94,"start_character":8,"end_line":95,"end_character":11},"updated":"2017-01-03 21:48:18.000000000","message":"you can end the sentence here, think this is only repeating stuff that is already clear.","commit_id":"7ee18fd641153fb005ad5e96077a7523486483e1"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"713085e15fa2d37bd5de5b16cf061de9e08b2630","unresolved":false,"context_lines":[{"line_number":92,"context_line":"expires. This allows a user to change their own password without needing an"},{"line_number":93,"context_line":"administrator to reset it for them if it has expired. By default, this is"},{"line_number":94,"context_line":"disabled and a user will need to have an admin reset their password if it"},{"line_number":95,"context_line":"does expire. This feature will only be enabled if"},{"line_number":96,"context_line":"`[security_compliance] password_expires_days` is set."},{"line_number":97,"context_line":"\"\"\"))"},{"line_number":98,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ba5201f7_0f5fef41","line":95,"range":{"start_line":95,"start_character":18,"end_line":95,"end_character":25},"in_reply_to":"ba5201f7_2ff4b385","updated":"2017-01-03 21:58:32.000000000","message":"I think either works, I just copied that line from the one above.","commit_id":"7ee18fd641153fb005ad5e96077a7523486483e1"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"713085e15fa2d37bd5de5b16cf061de9e08b2630","unresolved":false,"context_lines":[{"line_number":91,"context_line":"If set to True, a user will be allowed to change their own password after it"},{"line_number":92,"context_line":"expires. This allows a user to change their own password without needing an"},{"line_number":93,"context_line":"administrator to reset it for them if it has expired. By default, this is"},{"line_number":94,"context_line":"disabled and a user will need to have an admin reset their password if it"},{"line_number":95,"context_line":"does expire. This feature will only be enabled if"},{"line_number":96,"context_line":"`[security_compliance] password_expires_days` is set."},{"line_number":97,"context_line":"\"\"\"))"},{"line_number":98,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ba5201f7_0f260fce","line":95,"range":{"start_line":94,"start_character":8,"end_line":95,"end_character":11},"in_reply_to":"ba5201f7_6fd79bed","updated":"2017-01-03 21:58:32.000000000","message":"Sure thing!","commit_id":"7ee18fd641153fb005ad5e96077a7523486483e1"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"521822a1462890614d929bd775450e33426af56d","unresolved":false,"context_lines":[{"line_number":88,"context_line":"    \u0027password_expires_allow_user_change\u0027,"},{"line_number":89,"context_line":"    default\u003dFalse,"},{"line_number":90,"context_line":"    help\u003dutils.fmt(\"\"\""},{"line_number":91,"context_line":"If set to True, a user will be allowed to change their own password after it"},{"line_number":92,"context_line":"expires. This allows a user to change their own password without needing an"},{"line_number":93,"context_line":"administrator to reset it for them if it has expired. By default, this is"},{"line_number":94,"context_line":"disabled. This feature will only be enabled if"},{"line_number":95,"context_line":"`[security_compliance] password_expires_days` is set."}],"source_content_type":"text/x-python","patch_set":11,"id":"ba5201f7_95c38d88","line":92,"range":{"start_line":91,"start_character":0,"end_line":92,"end_character":56},"updated":"2017-01-05 22:39:08.000000000","message":"This would allow users to change their password without an authentication token, right?","commit_id":"2d75668838f224d1fd678f029d6cc0524bb178d2"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"a4343422af35e6e2de82ef4917bbb3a26086ec13","unresolved":false,"context_lines":[{"line_number":88,"context_line":"    \u0027password_expires_allow_user_change\u0027,"},{"line_number":89,"context_line":"    default\u003dFalse,"},{"line_number":90,"context_line":"    help\u003dutils.fmt(\"\"\""},{"line_number":91,"context_line":"If set to True, a user will be allowed to change their own password after it"},{"line_number":92,"context_line":"expires. This allows a user to change their own password without needing an"},{"line_number":93,"context_line":"administrator to reset it for them if it has expired. By default, this is"},{"line_number":94,"context_line":"disabled. This feature will only be enabled if"},{"line_number":95,"context_line":"`[security_compliance] password_expires_days` is set."}],"source_content_type":"text/x-python","patch_set":11,"id":"ba5201f7_f5ef7984","line":92,"range":{"start_line":91,"start_character":0,"end_line":92,"end_character":56},"in_reply_to":"ba5201f7_95c38d88","updated":"2017-01-05 23:03:27.000000000","message":"This config setting will allow someone with an expired password to change it using the self-server change password api call. If it is set to False, then they will get the password expired response if a user tries to change a password that has expired.\n\nThe self-change password API call will no longer require a token in any situation.","commit_id":"2d75668838f224d1fd678f029d6cc0524bb178d2"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"d6eb264e3f4702d7c38302b3436ad9620b79bd15","unresolved":false,"context_lines":[{"line_number":89,"context_line":"    default\u003dFalse,"},{"line_number":90,"context_line":"    help\u003dutils.fmt(\"\"\""},{"line_number":91,"context_line":"If set to True, a user will be allowed to change their own password after it"},{"line_number":92,"context_line":"expires. This allows a user to change their own password without needing an"},{"line_number":93,"context_line":"administrator to reset it for them if it has expired. By default, this is"},{"line_number":94,"context_line":"disabled. This feature will only be enabled if"},{"line_number":95,"context_line":"`[security_compliance] password_expires_days` is set."}],"source_content_type":"text/x-python","patch_set":12,"id":"ba5201f7_f4383bd5","line":92,"updated":"2017-01-06 18:18:05.000000000","message":"Suggest: \"If set to True, a user will be able to change their own password after it expires without needing an administrator.\" Or something like that so that you can remove the second sentence since it\u0027s so similar to the first.","commit_id":"0318bb29c75455ca8a9b80ab0a398269202bee98"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"f15d0570ccb7852698115e12f94ecea7b8dcd8b2","unresolved":false,"context_lines":[{"line_number":89,"context_line":"    default\u003dFalse,"},{"line_number":90,"context_line":"    help\u003dutils.fmt(\"\"\""},{"line_number":91,"context_line":"If set to True, a user will be allowed to change their own password after it"},{"line_number":92,"context_line":"expires. This allows a user to change their own password without needing an"},{"line_number":93,"context_line":"administrator to reset it for them if it has expired. By default, this is"},{"line_number":94,"context_line":"disabled. This feature will only be enabled if"},{"line_number":95,"context_line":"`[security_compliance] password_expires_days` is set."}],"source_content_type":"text/x-python","patch_set":12,"id":"ba5201f7_6aa1c6f7","line":92,"in_reply_to":"ba5201f7_f4383bd5","updated":"2017-01-06 19:26:24.000000000","message":"Done","commit_id":"0318bb29c75455ca8a9b80ab0a398269202bee98"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"d6eb264e3f4702d7c38302b3436ad9620b79bd15","unresolved":false,"context_lines":[{"line_number":91,"context_line":"If set to True, a user will be allowed to change their own password after it"},{"line_number":92,"context_line":"expires. This allows a user to change their own password without needing an"},{"line_number":93,"context_line":"administrator to reset it for them if it has expired. By default, this is"},{"line_number":94,"context_line":"disabled. This feature will only be enabled if"},{"line_number":95,"context_line":"`[security_compliance] password_expires_days` is set."},{"line_number":96,"context_line":"\"\"\"))"},{"line_number":97,"context_line":""}],"source_content_type":"text/x-python","patch_set":12,"id":"ba5201f7_f1520d66","line":94,"updated":"2017-01-06 18:18:05.000000000","message":"I think everything after \"disabled.\" can be removed. It\u0027s redundant.","commit_id":"0318bb29c75455ca8a9b80ab0a398269202bee98"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"f15d0570ccb7852698115e12f94ecea7b8dcd8b2","unresolved":false,"context_lines":[{"line_number":91,"context_line":"If set to True, a user will be allowed to change their own password after it"},{"line_number":92,"context_line":"expires. This allows a user to change their own password without needing an"},{"line_number":93,"context_line":"administrator to reset it for them if it has expired. By default, this is"},{"line_number":94,"context_line":"disabled. This feature will only be enabled if"},{"line_number":95,"context_line":"`[security_compliance] password_expires_days` is set."},{"line_number":96,"context_line":"\"\"\"))"},{"line_number":97,"context_line":""}],"source_content_type":"text/x-python","patch_set":12,"id":"ba5201f7_8aa42a08","line":94,"in_reply_to":"ba5201f7_f1520d66","updated":"2017-01-06 19:26:24.000000000","message":"Done","commit_id":"0318bb29c75455ca8a9b80ab0a398269202bee98"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"3e630a3a68e09b996b292cf35f414ebbc34ebc4c","unresolved":false,"context_lines":[{"line_number":84,"context_line":"will only be enabled if `[security_compliance] password_expires_days` is set."},{"line_number":85,"context_line":"\"\"\"))"},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"password_expires_allow_user_change \u003d cfg.BoolOpt("},{"line_number":88,"context_line":"    \u0027password_expires_allow_user_change\u0027,"},{"line_number":89,"context_line":"    default\u003dFalse,"},{"line_number":90,"context_line":"    help\u003dutils.fmt(\"\"\""}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5201f7_8cdc0a76","line":87,"range":{"start_line":87,"start_character":0,"end_line":87,"end_character":34},"updated":"2017-01-09 18:27:11.000000000","message":"nit: I like \u0027user_can_change_expired_password\u0027","commit_id":"3084a1e1a7a7600e3886cd1361e4561a4b8df787"},{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"708eef0eadd63ab564fe692b3b57a7d6905d5808","unresolved":false,"context_lines":[{"line_number":86,"context_line":""},{"line_number":87,"context_line":"user_can_change_expired_password \u003d cfg.BoolOpt("},{"line_number":88,"context_line":"    \u0027user_can_change_expired_password\u0027,"},{"line_number":89,"context_line":"    default\u003dFalse,"},{"line_number":90,"context_line":"    help\u003dutils.fmt(\"\"\""},{"line_number":91,"context_line":"If set to True, a user will be able to change their password after it"},{"line_number":92,"context_line":"expires without needing a token for authentication. This removes the"}],"source_content_type":"text/x-python","patch_set":19,"id":"5a3905b3_597f29aa","line":89,"range":{"start_line":89,"start_character":12,"end_line":89,"end_character":17},"updated":"2017-01-19 20:38:30.000000000","message":"may as well set it to True. I can\u0027t imagine people will have \"password_expires_days\" and not want this -- if we go with the config option route","commit_id":"915ab8ca03f62ba972cec09d958b66edae4bfff2"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"68aa4a04e9f6d651206abdf8427d7c66ca1dd586","unresolved":false,"context_lines":[{"line_number":84,"context_line":"will only be enabled if `[security_compliance] password_expires_days` is set."},{"line_number":85,"context_line":"\"\"\"))"},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"user_can_change_expired_password \u003d cfg.BoolOpt("},{"line_number":88,"context_line":"    \u0027user_can_change_expired_password\u0027,"},{"line_number":89,"context_line":"    default\u003dFalse,"},{"line_number":90,"context_line":"    help\u003dutils.fmt(\"\"\""},{"line_number":91,"context_line":"If set to True, a user will be able to change their password after it"},{"line_number":92,"context_line":"expires without needing a token for authentication. This removes the"},{"line_number":93,"context_line":"need for an administrator to reset it. This feature will only be enabled"},{"line_number":94,"context_line":"if `[security_compliance] password_expires_days` is set. By default,"},{"line_number":95,"context_line":"this is disabled."},{"line_number":96,"context_line":"\"\"\"))"},{"line_number":97,"context_line":""},{"line_number":98,"context_line":"unique_last_password_count \u003d cfg.IntOpt("},{"line_number":99,"context_line":"    \u0027unique_last_password_count\u0027,"}],"source_content_type":"text/x-python","patch_set":19,"id":"5a3905b3_ce2b4d2f","line":96,"range":{"start_line":87,"start_character":0,"end_line":96,"end_character":5},"updated":"2017-01-19 20:13:05.000000000","message":"See other comment about config options. If the config option stays is use default this to True. Do not add this config option.","commit_id":"915ab8ca03f62ba972cec09d958b66edae4bfff2"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"68aa4a04e9f6d651206abdf8427d7c66ca1dd586","unresolved":false,"context_lines":[{"line_number":150,"context_line":"    lockout_ignored_user_ids,"},{"line_number":151,"context_line":"    password_expires_days,"},{"line_number":152,"context_line":"    password_expires_ignore_user_ids,"},{"line_number":153,"context_line":"    user_can_change_expired_password,"},{"line_number":154,"context_line":"    unique_last_password_count,"},{"line_number":155,"context_line":"    minimum_password_age,"},{"line_number":156,"context_line":"    password_regex,"}],"source_content_type":"text/x-python","patch_set":19,"id":"5a3905b3_ee20094c","line":153,"updated":"2017-01-19 20:13:05.000000000","message":"See above comment.","commit_id":"915ab8ca03f62ba972cec09d958b66edae4bfff2"}],"keystone/exception.py":[{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"3e630a3a68e09b996b292cf35f414ebbc34ebc4c","unresolved":false,"context_lines":[{"line_number":248,"context_line":""},{"line_number":249,"context_line":""},{"line_number":250,"context_line":"class PasswordExpired(Unauthorized):"},{"line_number":251,"context_line":"    message_format \u003d _(\"The password is expired and needs to be reset for \""},{"line_number":252,"context_line":"                       \"user: %(user_id)s.\")"},{"line_number":253,"context_line":""},{"line_number":254,"context_line":""}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5201f7_ecee76b3","line":251,"range":{"start_line":251,"start_character":64,"end_line":251,"end_character":69},"updated":"2017-01-09 18:27:11.000000000","message":"\u0027changed\u0027 to avoid confusion with admin reset","commit_id":"3084a1e1a7a7600e3886cd1361e4561a4b8df787"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"549ed4b828593d36e29b652122059857c4ca9044","unresolved":false,"context_lines":[{"line_number":248,"context_line":""},{"line_number":249,"context_line":""},{"line_number":250,"context_line":"class PasswordExpired(Unauthorized):"},{"line_number":251,"context_line":"    message_format \u003d _(\"The password is expired and needs to be reset for \""},{"line_number":252,"context_line":"                       \"user: %(user_id)s.\")"},{"line_number":253,"context_line":""},{"line_number":254,"context_line":""}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5201f7_994fb4bd","line":251,"range":{"start_line":251,"start_character":64,"end_line":251,"end_character":69},"in_reply_to":"ba5201f7_ecee76b3","updated":"2017-01-12 00:22:40.000000000","message":"Done","commit_id":"3084a1e1a7a7600e3886cd1361e4561a4b8df787"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"c908b737d18b2cee6f88eed8ff28073f6df03ef0","unresolved":false,"context_lines":[{"line_number":249,"context_line":""},{"line_number":250,"context_line":"class PasswordExpired(Unauthorized):"},{"line_number":251,"context_line":"    message_format \u003d _(\"The password is expired and needs to be changed for \""},{"line_number":252,"context_line":"                       \"user: %(user_id)s.\")"},{"line_number":253,"context_line":""},{"line_number":254,"context_line":""},{"line_number":255,"context_line":"class AuthPluginException(Unauthorized):"}],"source_content_type":"text/x-python","patch_set":24,"id":"5a3905b3_b2a9d5e1","line":252,"updated":"2017-01-20 16:05:00.000000000","message":"This is still either/or? If a password is expired it can either be reset by the user, or it can be rest by an administrator, right?","commit_id":"88ba36a38841e9f66e741e53e13b877390195df1"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"776f641a12b985a328aea90bd92814d28d563e6d","unresolved":false,"context_lines":[{"line_number":249,"context_line":""},{"line_number":250,"context_line":"class PasswordExpired(Unauthorized):"},{"line_number":251,"context_line":"    message_format \u003d _(\"The password is expired and needs to be changed for \""},{"line_number":252,"context_line":"                       \"user: %(user_id)s.\")"},{"line_number":253,"context_line":""},{"line_number":254,"context_line":""},{"line_number":255,"context_line":"class AuthPluginException(Unauthorized):"}],"source_content_type":"text/x-python","patch_set":24,"id":"5a3905b3_bc02846d","line":252,"in_reply_to":"5a3905b3_b2a9d5e1","updated":"2017-01-20 17:58:09.000000000","message":"yes, I changed this to be less specific about needing an administrator, with this change it\u0027s no longer needed but still can be done.","commit_id":"88ba36a38841e9f66e741e53e13b877390195df1"}],"keystone/identity/backends/sql.py":[{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"127608b88557c31e62d99e95f7accfcc9392317f","unresolved":false,"context_lines":[{"line_number":69,"context_line":"        # reset failed count if present, check expired password"},{"line_number":70,"context_line":"        if user_ref.local_user.failed_auth_count:"},{"line_number":71,"context_line":"            self._reset_failed_auth(user_id)"},{"line_number":72,"context_line":"        if self._is_password_expired_self_change(user_id, user_ref):"},{"line_number":73,"context_line":"            user_ref[\u0027expired\u0027] \u003d True"},{"line_number":74,"context_line":"        return base.filter_user(user_ref.to_dict())"},{"line_number":75,"context_line":""},{"line_number":76,"context_line":"    def _is_account_locked(self, user_id, user_ref):"}],"source_content_type":"text/x-python","patch_set":6,"id":"1a6eadb0_0d3b5c39","line":73,"range":{"start_line":72,"start_character":0,"end_line":73,"end_character":38},"updated":"2016-12-20 18:02:33.000000000","message":"Right now this allows a user to auth with an expired password, but bubbles up to only allow a unscoped token.","commit_id":"23a5cb10837ce26170d8db58108110849f5b4d1d"},{"author":{"_account_id":11022,"name":"Rodrigo Duarte Sousa","email":"rodrigodsousa@gmail.com","username":"rodrigods"},"change_message_id":"b300a1116ee52eb3cfdaec8876b95c498a969c21","unresolved":false,"context_lines":[{"line_number":65,"context_line":"            raise AssertionError(_(\u0027Invalid user / password\u0027))"},{"line_number":66,"context_line":"        elif not user_ref.enabled:"},{"line_number":67,"context_line":"            raise exception.UserDisabled(user_id\u003duser_id)"},{"line_number":68,"context_line":"        # Successful Auth (Password may be expired):"},{"line_number":69,"context_line":"        # Check expired password, reset failed count if present"},{"line_number":70,"context_line":"        if user_ref.password_is_expired:"},{"line_number":71,"context_line":"            raise exception.PasswordExpired(user_id\u003duser_id)"},{"line_number":72,"context_line":"        if user_ref.local_user.failed_auth_count:"},{"line_number":73,"context_line":"            self._reset_failed_auth(user_id)"}],"source_content_type":"text/x-python","patch_set":9,"id":"ba5201f7_af15039c","line":70,"range":{"start_line":68,"start_character":0,"end_line":70,"end_character":40},"updated":"2017-01-03 21:48:18.000000000","message":"this looks unrelated? don\u0027t see an actual change in the logic here.","commit_id":"7ee18fd641153fb005ad5e96077a7523486483e1"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"713085e15fa2d37bd5de5b16cf061de9e08b2630","unresolved":false,"context_lines":[{"line_number":65,"context_line":"            raise AssertionError(_(\u0027Invalid user / password\u0027))"},{"line_number":66,"context_line":"        elif not user_ref.enabled:"},{"line_number":67,"context_line":"            raise exception.UserDisabled(user_id\u003duser_id)"},{"line_number":68,"context_line":"        # Successful Auth (Password may be expired):"},{"line_number":69,"context_line":"        # Check expired password, reset failed count if present"},{"line_number":70,"context_line":"        if user_ref.password_is_expired:"},{"line_number":71,"context_line":"            raise exception.PasswordExpired(user_id\u003duser_id)"},{"line_number":72,"context_line":"        if user_ref.local_user.failed_auth_count:"},{"line_number":73,"context_line":"            self._reset_failed_auth(user_id)"}],"source_content_type":"text/x-python","patch_set":9,"id":"ba5201f7_6f023b0d","line":70,"range":{"start_line":68,"start_character":0,"end_line":70,"end_character":40},"in_reply_to":"ba5201f7_af15039c","updated":"2017-01-03 21:58:32.000000000","message":"Yeah, I moved it down for my own readability but you\u0027re right, the logic doesn\u0027t change so this is not really needed.","commit_id":"7ee18fd641153fb005ad5e96077a7523486483e1"}],"keystone/identity/controllers.py":[{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"99da3b86e221994aa06411dff56679b116598702","unresolved":false,"context_lines":[{"line_number":276,"context_line":"            user_id, initiator\u003drequest.audit_initiator"},{"line_number":277,"context_line":"        )"},{"line_number":278,"context_line":""},{"line_number":279,"context_line":"    def change_password(self, request, user_id, user):"},{"line_number":280,"context_line":"        original_password \u003d user.get(\u0027original_password\u0027)"},{"line_number":281,"context_line":"        if original_password is None:"},{"line_number":282,"context_line":"            raise exception.ValidationError(target\u003d\u0027user\u0027,"}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5201f7_e38143c4","line":279,"range":{"start_line":279,"start_character":4,"end_line":279,"end_character":54},"updated":"2017-01-09 05:28:45.000000000","message":"add a comment about why this is unprotected or someone will inevitably come around and add a @protected decorator","commit_id":"3084a1e1a7a7600e3886cd1361e4561a4b8df787"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"3e630a3a68e09b996b292cf35f414ebbc34ebc4c","unresolved":false,"context_lines":[{"line_number":276,"context_line":"            user_id, initiator\u003drequest.audit_initiator"},{"line_number":277,"context_line":"        )"},{"line_number":278,"context_line":""},{"line_number":279,"context_line":"    def change_password(self, request, user_id, user):"},{"line_number":280,"context_line":"        original_password \u003d user.get(\u0027original_password\u0027)"},{"line_number":281,"context_line":"        if original_password is None:"},{"line_number":282,"context_line":"            raise exception.ValidationError(target\u003d\u0027user\u0027,"}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5201f7_4c8222ca","line":279,"range":{"start_line":279,"start_character":4,"end_line":279,"end_character":54},"in_reply_to":"ba5201f7_e38143c4","updated":"2017-01-09 18:27:11.000000000","message":"++","commit_id":"3084a1e1a7a7600e3886cd1361e4561a4b8df787"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"304b7adb4be3f8dad872b2bff23f251899145c5a","unresolved":false,"context_lines":[{"line_number":276,"context_line":"            user_id, initiator\u003drequest.audit_initiator"},{"line_number":277,"context_line":"        )"},{"line_number":278,"context_line":""},{"line_number":279,"context_line":"    @controller.protected(check_auth\u003dTrue)"},{"line_number":280,"context_line":"    def change_password(self, request, user_id, user):"},{"line_number":281,"context_line":"        original_password \u003d user.get(\u0027original_password\u0027)"},{"line_number":282,"context_line":"        if original_password is None:"}],"source_content_type":"text/x-python","patch_set":15,"id":"7a3c09a3_a09fe901","line":279,"range":{"start_line":279,"start_character":4,"end_line":279,"end_character":42},"updated":"2017-01-13 23:21:14.000000000","message":"Added this back with the optional parameter to still require a token if one still does not wish to use the new feature.","commit_id":"983b52580f19af92aae82fcf3e95d2ffa0c4a8e8"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"68aa4a04e9f6d651206abdf8427d7c66ca1dd586","unresolved":false,"context_lines":[{"line_number":276,"context_line":"            user_id, initiator\u003drequest.audit_initiator"},{"line_number":277,"context_line":"        )"},{"line_number":278,"context_line":""},{"line_number":279,"context_line":"    @controller.protected_optional()"},{"line_number":280,"context_line":"    def change_password(self, request, user_id, user):"},{"line_number":281,"context_line":"        original_password \u003d user.get(\u0027original_password\u0027)"},{"line_number":282,"context_line":"        if original_password is None:"}],"source_content_type":"text/x-python","patch_set":19,"id":"5a3905b3_eece4982","line":279,"updated":"2017-01-19 20:13:05.000000000","message":"See other comment, revert, add the auth check directly in the controller bit. This API can be generally exempted from a token requirement by having no entry in the policy.json for it.\n\nSimply the API should be open without a token but should require (as it does) the current password and the new password. It should be blocked by policy.json if it is meant to be disabled.","commit_id":"915ab8ca03f62ba972cec09d958b66edae4bfff2"}],"keystone/identity/core.py":[{"author":{"_account_id":11022,"name":"Rodrigo Duarte Sousa","email":"rodrigodsousa@gmail.com","username":"rodrigods"},"change_message_id":"b300a1116ee52eb3cfdaec8876b95c498a969c21","unresolved":false,"context_lines":[{"line_number":1287,"context_line":"        try:"},{"line_number":1288,"context_line":"            self.authenticate(request, user_id, original_password)"},{"line_number":1289,"context_line":"        except exception.PasswordExpired:"},{"line_number":1290,"context_line":"            if CONF.security_compliance.password_expires_allow_user_change:"},{"line_number":1291,"context_line":"                pass"},{"line_number":1292,"context_line":"            else:"},{"line_number":1293,"context_line":"                raise"},{"line_number":1294,"context_line":"        except AssertionError:"},{"line_number":1295,"context_line":"            raise"},{"line_number":1296,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ba5201f7_0f6e0f2f","line":1293,"range":{"start_line":1290,"start_character":0,"end_line":1293,"end_character":21},"updated":"2017-01-03 21:48:18.000000000","message":"The following looks more concise to me:\n  \n  if not CONF.security_compliance.password_expires_allow_user_change:\n    raise","commit_id":"7ee18fd641153fb005ad5e96077a7523486483e1"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"713085e15fa2d37bd5de5b16cf061de9e08b2630","unresolved":false,"context_lines":[{"line_number":1287,"context_line":"        try:"},{"line_number":1288,"context_line":"            self.authenticate(request, user_id, original_password)"},{"line_number":1289,"context_line":"        except exception.PasswordExpired:"},{"line_number":1290,"context_line":"            if CONF.security_compliance.password_expires_allow_user_change:"},{"line_number":1291,"context_line":"                pass"},{"line_number":1292,"context_line":"            else:"},{"line_number":1293,"context_line":"                raise"},{"line_number":1294,"context_line":"        except AssertionError:"},{"line_number":1295,"context_line":"            raise"},{"line_number":1296,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ba5201f7_0121839f","line":1293,"range":{"start_line":1290,"start_character":0,"end_line":1293,"end_character":21},"in_reply_to":"ba5201f7_0f6e0f2f","updated":"2017-01-03 21:58:32.000000000","message":"It does. For some reason it was not working correctly without the else when I tested this, but I will try again.","commit_id":"7ee18fd641153fb005ad5e96077a7523486483e1"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"5c72a6e0d88be40489a20b386c3479ab1ce78d8a","unresolved":false,"context_lines":[{"line_number":1287,"context_line":"        try:"},{"line_number":1288,"context_line":"            self.authenticate(request, user_id, original_password)"},{"line_number":1289,"context_line":"        except exception.PasswordExpired:"},{"line_number":1290,"context_line":"            if CONF.security_compliance.password_expires_allow_user_change:"},{"line_number":1291,"context_line":"                pass"},{"line_number":1292,"context_line":"            else:"},{"line_number":1293,"context_line":"                raise"},{"line_number":1294,"context_line":"        except AssertionError:"},{"line_number":1295,"context_line":"            raise"},{"line_number":1296,"context_line":""}],"source_content_type":"text/x-python","patch_set":10,"id":"ba5201f7_ea942844","line":1293,"range":{"start_line":1290,"start_character":0,"end_line":1293,"end_character":21},"updated":"2017-01-04 22:20:19.000000000","message":"Removing the else causes this to not work properly:\n\nhttp://paste.openstack.org/show/593920/","commit_id":"a3a4c00d29c519fcd63dbac99e16f0dcadec1992"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"521822a1462890614d929bd775450e33426af56d","unresolved":false,"context_lines":[{"line_number":1291,"context_line":"                pass"},{"line_number":1292,"context_line":"            else:"},{"line_number":1293,"context_line":"                raise"},{"line_number":1294,"context_line":"        except AssertionError:"},{"line_number":1295,"context_line":"            raise"},{"line_number":1296,"context_line":""},{"line_number":1297,"context_line":"        domain_id, driver, entity_id \u003d ("},{"line_number":1298,"context_line":"            self._get_domain_driver_and_entity_id(user_id))"}],"source_content_type":"text/x-python","patch_set":11,"id":"ba5201f7_55f685f9","line":1295,"range":{"start_line":1294,"start_character":8,"end_line":1295,"end_character":17},"updated":"2017-01-05 22:39:08.000000000","message":"Do you need this? If you are not catching this exception, it will automatically be raised. Likewise, if exception.UserDisabled is thrown:\nhttps://github.com/openstack/keystone/blob/master/keystone/identity/backends/sql.py#L67","commit_id":"2d75668838f224d1fd678f029d6cc0524bb178d2"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"a4343422af35e6e2de82ef4917bbb3a26086ec13","unresolved":false,"context_lines":[{"line_number":1291,"context_line":"                pass"},{"line_number":1292,"context_line":"            else:"},{"line_number":1293,"context_line":"                raise"},{"line_number":1294,"context_line":"        except AssertionError:"},{"line_number":1295,"context_line":"            raise"},{"line_number":1296,"context_line":""},{"line_number":1297,"context_line":"        domain_id, driver, entity_id \u003d ("},{"line_number":1298,"context_line":"            self._get_domain_driver_and_entity_id(user_id))"}],"source_content_type":"text/x-python","patch_set":11,"id":"ba5201f7_b5fa5141","line":1295,"range":{"start_line":1294,"start_character":8,"end_line":1295,"end_character":17},"in_reply_to":"ba5201f7_55f685f9","updated":"2017-01-05 23:03:27.000000000","message":"Good point, I\u0027ll remove this and put the comment back.","commit_id":"2d75668838f224d1fd678f029d6cc0524bb178d2"},{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"99da3b86e221994aa06411dff56679b116598702","unresolved":false,"context_lines":[{"line_number":1284,"context_line":"    @domains_configured"},{"line_number":1285,"context_line":"    def change_password(self, request, user_id, original_password,"},{"line_number":1286,"context_line":"                        new_password, initiator\u003dNone):"},{"line_number":1287,"context_line":""},{"line_number":1288,"context_line":"        # authenticate() will raise an AssertionError if authentication fails"},{"line_number":1289,"context_line":"        self.authenticate(request, user_id, original_password)"},{"line_number":1290,"context_line":""}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5201f7_030e478b","side":"PARENT","line":1287,"updated":"2017-01-09 05:28:45.000000000","message":"undo the white space change","commit_id":"663865dfecb483f0ef6aa48749c0712779033dd7"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"549ed4b828593d36e29b652122059857c4ca9044","unresolved":false,"context_lines":[{"line_number":1284,"context_line":"    @domains_configured"},{"line_number":1285,"context_line":"    def change_password(self, request, user_id, original_password,"},{"line_number":1286,"context_line":"                        new_password, initiator\u003dNone):"},{"line_number":1287,"context_line":""},{"line_number":1288,"context_line":"        # authenticate() will raise an AssertionError if authentication fails"},{"line_number":1289,"context_line":"        self.authenticate(request, user_id, original_password)"},{"line_number":1290,"context_line":""}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5201f7_19cae41a","side":"PARENT","line":1287,"in_reply_to":"ba5201f7_030e478b","updated":"2017-01-12 00:22:40.000000000","message":"Done","commit_id":"663865dfecb483f0ef6aa48749c0712779033dd7"},{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"99da3b86e221994aa06411dff56679b116598702","unresolved":false,"context_lines":[{"line_number":1289,"context_line":"            self.authenticate(request, user_id, original_password)"},{"line_number":1290,"context_line":"        except exception.PasswordExpired:"},{"line_number":1291,"context_line":"            if CONF.security_compliance.password_expires_allow_user_change:"},{"line_number":1292,"context_line":"                pass"},{"line_number":1293,"context_line":"            else:"},{"line_number":1294,"context_line":"                raise"},{"line_number":1295,"context_line":""}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5201f7_e30a2378","line":1292,"range":{"start_line":1292,"start_character":16,"end_line":1292,"end_character":20},"updated":"2017-01-09 05:28:45.000000000","message":"add a comment about why we\u0027re passing and more importantly *why it\u0027s OK to pass*","commit_id":"3084a1e1a7a7600e3886cd1361e4561a4b8df787"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"549ed4b828593d36e29b652122059857c4ca9044","unresolved":false,"context_lines":[{"line_number":1289,"context_line":"            self.authenticate(request, user_id, original_password)"},{"line_number":1290,"context_line":"        except exception.PasswordExpired:"},{"line_number":1291,"context_line":"            if CONF.security_compliance.password_expires_allow_user_change:"},{"line_number":1292,"context_line":"                pass"},{"line_number":1293,"context_line":"            else:"},{"line_number":1294,"context_line":"                raise"},{"line_number":1295,"context_line":""}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5201f7_99d6d4c1","line":1292,"range":{"start_line":1292,"start_character":16,"end_line":1292,"end_character":20},"in_reply_to":"ba5201f7_cc57f224","updated":"2017-01-12 00:22:40.000000000","message":"Done, and will do!","commit_id":"3084a1e1a7a7600e3886cd1361e4561a4b8df787"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"3e630a3a68e09b996b292cf35f414ebbc34ebc4c","unresolved":false,"context_lines":[{"line_number":1289,"context_line":"            self.authenticate(request, user_id, original_password)"},{"line_number":1290,"context_line":"        except exception.PasswordExpired:"},{"line_number":1291,"context_line":"            if CONF.security_compliance.password_expires_allow_user_change:"},{"line_number":1292,"context_line":"                pass"},{"line_number":1293,"context_line":"            else:"},{"line_number":1294,"context_line":"                raise"},{"line_number":1295,"context_line":""}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5201f7_cc57f224","line":1292,"range":{"start_line":1292,"start_character":16,"end_line":1292,"end_character":20},"in_reply_to":"ba5201f7_e30a2378","updated":"2017-01-09 18:27:11.000000000","message":"This only works because password expired is the last check in authentication:\nhttps://github.com/openstack/keystone/blob/master/keystone/identity/backends/sql.py#L70\n\nHowever, if the order of this logic changes, e.g. we check password expired before checking if user is disabled, it could have unintended consequences. For example, we could allow a user to change their password even though their account is disabled or locked. Therefore, I think we need a test case to protect us from this scenario.","commit_id":"3084a1e1a7a7600e3886cd1361e4561a4b8df787"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"3e630a3a68e09b996b292cf35f414ebbc34ebc4c","unresolved":false,"context_lines":[{"line_number":1290,"context_line":"        except exception.PasswordExpired:"},{"line_number":1291,"context_line":"            if CONF.security_compliance.password_expires_allow_user_change:"},{"line_number":1292,"context_line":"                pass"},{"line_number":1293,"context_line":"            else:"},{"line_number":1294,"context_line":"                raise"},{"line_number":1295,"context_line":""},{"line_number":1296,"context_line":"        domain_id, driver, entity_id \u003d ("},{"line_number":1297,"context_line":"            self._get_domain_driver_and_entity_id(user_id))"}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5201f7_ec73d613","line":1294,"range":{"start_line":1293,"start_character":11,"end_line":1294,"end_character":21},"updated":"2017-01-09 18:27:11.000000000","message":"I\u0027m not clear why you need this raise","commit_id":"3084a1e1a7a7600e3886cd1361e4561a4b8df787"},{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"99da3b86e221994aa06411dff56679b116598702","unresolved":false,"context_lines":[{"line_number":1291,"context_line":"            if CONF.security_compliance.password_expires_allow_user_change:"},{"line_number":1292,"context_line":"                pass"},{"line_number":1293,"context_line":"            else:"},{"line_number":1294,"context_line":"                raise"},{"line_number":1295,"context_line":""},{"line_number":1296,"context_line":"        domain_id, driver, entity_id \u003d ("},{"line_number":1297,"context_line":"            self._get_domain_driver_and_entity_id(user_id))"}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5201f7_831a37c4","line":1294,"range":{"start_line":1294,"start_character":16,"end_line":1294,"end_character":21},"updated":"2017-01-09 05:28:45.000000000","message":"add a comment here about what will happen and why we do it","commit_id":"3084a1e1a7a7600e3886cd1361e4561a4b8df787"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"73978fe5b7e80cf35f14af85c67426f3aaff92d5","unresolved":false,"context_lines":[{"line_number":1290,"context_line":"        except exception.PasswordExpired:"},{"line_number":1291,"context_line":"            if CONF.security_compliance.password_expires_allow_user_change:"},{"line_number":1292,"context_line":"                pass"},{"line_number":1293,"context_line":"            else:"},{"line_number":1294,"context_line":"                raise"},{"line_number":1295,"context_line":""},{"line_number":1296,"context_line":"        domain_id, driver, entity_id \u003d ("},{"line_number":1297,"context_line":"            self._get_domain_driver_and_entity_id(user_id))"}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5201f7_9c29119e","line":1294,"range":{"start_line":1293,"start_character":11,"end_line":1294,"end_character":21},"in_reply_to":"ba5201f7_3af94cc9","updated":"2017-01-12 02:37:25.000000000","message":"Gotcha, sorry misread this. Makes sense.","commit_id":"3084a1e1a7a7600e3886cd1361e4561a4b8df787"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"549ed4b828593d36e29b652122059857c4ca9044","unresolved":false,"context_lines":[{"line_number":1290,"context_line":"        except exception.PasswordExpired:"},{"line_number":1291,"context_line":"            if CONF.security_compliance.password_expires_allow_user_change:"},{"line_number":1292,"context_line":"                pass"},{"line_number":1293,"context_line":"            else:"},{"line_number":1294,"context_line":"                raise"},{"line_number":1295,"context_line":""},{"line_number":1296,"context_line":"        domain_id, driver, entity_id \u003d ("},{"line_number":1297,"context_line":"            self._get_domain_driver_and_entity_id(user_id))"}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5201f7_3af94cc9","line":1294,"range":{"start_line":1293,"start_character":11,"end_line":1294,"end_character":21},"in_reply_to":"ba5201f7_ec73d613","updated":"2017-01-12 00:22:40.000000000","message":"If we don\u0027t want users changing their own expired passwords, then we will float the exception up and send back the 401","commit_id":"3084a1e1a7a7600e3886cd1361e4561a4b8df787"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"b74159f75b493739ff3729c7d33f7778c3ae9d13","unresolved":false,"context_lines":[{"line_number":1292,"context_line":"            # Allow a user to change their own password if it has expired"},{"line_number":1293,"context_line":"            # and the config is set to allow this"},{"line_number":1294,"context_line":"            # Otherwise, an admin will need to change it for the user"},{"line_number":1295,"context_line":"            if CONF.security_compliance.user_can_change_expired_password:"},{"line_number":1296,"context_line":"                pass"},{"line_number":1297,"context_line":"            else:"},{"line_number":1298,"context_line":"                raise"}],"source_content_type":"text/x-python","patch_set":15,"id":"7a3c09a3_2ca8521f","line":1295,"updated":"2017-01-14 04:19:51.000000000","message":"Why not simplify to \u0027if not ...\u0027 and not \u0027else\u0027?","commit_id":"983b52580f19af92aae82fcf3e95d2ffa0c4a8e8"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"c3fa70853132e779c204637a95892a75a191dc48","unresolved":false,"context_lines":[{"line_number":1292,"context_line":"            # Allow a user to change their own password if it has expired"},{"line_number":1293,"context_line":"            # and the config is set to allow this"},{"line_number":1294,"context_line":"            # Otherwise, an admin will need to change it for the user"},{"line_number":1295,"context_line":"            if CONF.security_compliance.user_can_change_expired_password:"},{"line_number":1296,"context_line":"                pass"},{"line_number":1297,"context_line":"            else:"},{"line_number":1298,"context_line":"                raise"}],"source_content_type":"text/x-python","patch_set":15,"id":"7a3c09a3_e4a8ac79","line":1295,"in_reply_to":"7a3c09a3_2ca8521f","updated":"2017-01-17 16:57:46.000000000","message":"Done","commit_id":"983b52580f19af92aae82fcf3e95d2ffa0c4a8e8"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"68aa4a04e9f6d651206abdf8427d7c66ca1dd586","unresolved":false,"context_lines":[{"line_number":1286,"context_line":"                        new_password, initiator\u003dNone):"},{"line_number":1287,"context_line":""},{"line_number":1288,"context_line":"        # authenticate() will raise an AssertionError if authentication fails"},{"line_number":1289,"context_line":"        try:"},{"line_number":1290,"context_line":"            self.authenticate(request, user_id, original_password)"},{"line_number":1291,"context_line":"        except exception.PasswordExpired:"},{"line_number":1292,"context_line":"            # Allow a user to change their own password if it has expired"},{"line_number":1293,"context_line":"            # and the config is set to allow this"},{"line_number":1294,"context_line":"            # Otherwise, an admin will need to change it for the user"},{"line_number":1295,"context_line":"            if not CONF.security_compliance.user_can_change_expired_password:"},{"line_number":1296,"context_line":"                raise"},{"line_number":1297,"context_line":""},{"line_number":1298,"context_line":"        domain_id, driver, entity_id \u003d ("},{"line_number":1299,"context_line":"            self._get_domain_driver_and_entity_id(user_id))"}],"source_content_type":"text/x-python","patch_set":19,"id":"5a3905b3_4eabdd74","line":1296,"range":{"start_line":1289,"start_character":0,"end_line":1296,"end_character":21},"updated":"2017-01-19 20:13:05.000000000","message":"See other comments about the additional config option. Without the config option less code is changed less to maintain.","commit_id":"915ab8ca03f62ba972cec09d958b66edae4bfff2"}],"keystone/tests/unit/test_v3_identity.py":[{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"3ad24b53f5e6c597ab1177949abcfdc503ca385b","unresolved":false,"context_lines":[{"line_number":836,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"},{"line_number":837,"context_line":"                                   password_expires_days\u003d2)"},{"line_number":838,"context_line":"        password \u003d uuid.uuid4().hex"},{"line_number":839,"context_line":"        # Create a datetime 3 days in the past that will expire in 2 days"},{"line_number":840,"context_line":"        time \u003d ("},{"line_number":841,"context_line":"            datetime.datetime.utcnow() -"},{"line_number":842,"context_line":"            datetime.timedelta("}],"source_content_type":"text/x-python","patch_set":11,"id":"ba5201f7_4a62943f","line":839,"range":{"start_line":839,"start_character":0,"end_line":839,"end_character":73},"updated":"2017-01-04 22:30:14.000000000","message":"Interestingly, I tried to use the already made user_ref in the setup() and moving time forward 3 days to expire the password, but that caused sqlite errors with these tests. Making a new user 3 days in the past avoids this (similar to the pci-dss notification tests)","commit_id":"2d75668838f224d1fd678f029d6cc0524bb178d2"},{"author":{"_account_id":11022,"name":"Rodrigo Duarte Sousa","email":"rodrigodsousa@gmail.com","username":"rodrigods"},"change_message_id":"7037a71ea7567bd6a23ef11edce333f487d9e4d7","unresolved":false,"context_lines":[{"line_number":836,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"},{"line_number":837,"context_line":"                                   password_expires_days\u003d2)"},{"line_number":838,"context_line":"        password \u003d uuid.uuid4().hex"},{"line_number":839,"context_line":"        # Create a datetime 3 days in the past that will expire in 2 days"},{"line_number":840,"context_line":"        time \u003d ("},{"line_number":841,"context_line":"            datetime.datetime.utcnow() -"},{"line_number":842,"context_line":"            datetime.timedelta("}],"source_content_type":"text/x-python","patch_set":11,"id":"ba5201f7_df18ebd5","line":839,"range":{"start_line":839,"start_character":0,"end_line":839,"end_character":73},"in_reply_to":"ba5201f7_4a62943f","updated":"2017-01-05 13:15:16.000000000","message":"this sounds like that some tests are leaving garbage behind.","commit_id":"2d75668838f224d1fd678f029d6cc0524bb178d2"},{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"99da3b86e221994aa06411dff56679b116598702","unresolved":false,"context_lines":[{"line_number":798,"context_line":"        # original token works"},{"line_number":799,"context_line":"        old_token_auth \u003d self.build_authentication_request(token\u003dtoken_id)"},{"line_number":800,"context_line":"        self.v3_create_token(old_token_auth)"},{"line_number":801,"context_line":""},{"line_number":802,"context_line":"        # change password"},{"line_number":803,"context_line":"        new_password \u003d uuid.uuid4().hex"},{"line_number":804,"context_line":"        self.change_password(password\u003dnew_password,"}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5201f7_63763307","side":"PARENT","line":801,"updated":"2017-01-09 05:28:45.000000000","message":"undo the white space change (and the others below)","commit_id":"663865dfecb483f0ef6aa48749c0712779033dd7"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"549ed4b828593d36e29b652122059857c4ca9044","unresolved":false,"context_lines":[{"line_number":798,"context_line":"        # original token works"},{"line_number":799,"context_line":"        old_token_auth \u003d self.build_authentication_request(token\u003dtoken_id)"},{"line_number":800,"context_line":"        self.v3_create_token(old_token_auth)"},{"line_number":801,"context_line":""},{"line_number":802,"context_line":"        # change password"},{"line_number":803,"context_line":"        new_password \u003d uuid.uuid4().hex"},{"line_number":804,"context_line":"        self.change_password(password\u003dnew_password,"}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5201f7_fab34408","side":"PARENT","line":801,"in_reply_to":"ba5201f7_63763307","updated":"2017-01-12 00:22:40.000000000","message":"Done","commit_id":"663865dfecb483f0ef6aa48749c0712779033dd7"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"b74159f75b493739ff3729c7d33f7778c3ae9d13","unresolved":false,"context_lines":[{"line_number":843,"context_line":"        )"},{"line_number":844,"context_line":"        password \u003d uuid.uuid4().hex"},{"line_number":845,"context_line":"        with freezegun.freeze_time(time):"},{"line_number":846,"context_line":"            user_ref \u003d unit.new_user_ref(domain_id\u003dself.domain_id,"},{"line_number":847,"context_line":"                                         password\u003dpassword)"},{"line_number":848,"context_line":"            self.user_ref \u003d self.identity_api.create_user(user_ref)"},{"line_number":849,"context_line":"        return password"}],"source_content_type":"text/x-python","patch_set":15,"id":"7a3c09a3_4c63de1a","line":846,"updated":"2017-01-14 04:19:51.000000000","message":"(nit) i don\u0027t think this needs to be in the context block.","commit_id":"983b52580f19af92aae82fcf3e95d2ffa0c4a8e8"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"c3fa70853132e779c204637a95892a75a191dc48","unresolved":false,"context_lines":[{"line_number":843,"context_line":"        )"},{"line_number":844,"context_line":"        password \u003d uuid.uuid4().hex"},{"line_number":845,"context_line":"        with freezegun.freeze_time(time):"},{"line_number":846,"context_line":"            user_ref \u003d unit.new_user_ref(domain_id\u003dself.domain_id,"},{"line_number":847,"context_line":"                                         password\u003dpassword)"},{"line_number":848,"context_line":"            self.user_ref \u003d self.identity_api.create_user(user_ref)"},{"line_number":849,"context_line":"        return password"}],"source_content_type":"text/x-python","patch_set":15,"id":"7a3c09a3_9f12d555","line":846,"in_reply_to":"7a3c09a3_4c63de1a","updated":"2017-01-17 16:57:46.000000000","message":"Done","commit_id":"983b52580f19af92aae82fcf3e95d2ffa0c4a8e8"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"68aa4a04e9f6d651206abdf8427d7c66ca1dd586","unresolved":false,"context_lines":[{"line_number":839,"context_line":"        expire_days \u003d CONF.security_compliance.password_expires_days"},{"line_number":840,"context_line":"        time \u003d ("},{"line_number":841,"context_line":"            datetime.datetime.utcnow() -"},{"line_number":842,"context_line":"            datetime.timedelta(expire_days + 1)"},{"line_number":843,"context_line":"        )"},{"line_number":844,"context_line":"        password \u003d uuid.uuid4().hex"},{"line_number":845,"context_line":"        user_ref \u003d unit.new_user_ref(domain_id\u003dself.domain_id,"}],"source_content_type":"text/x-python","patch_set":19,"id":"5a3905b3_8e094598","line":842,"range":{"start_line":842,"start_character":31,"end_line":842,"end_character":46},"updated":"2017-01-19 20:13:05.000000000","message":"Specify days\u003d in the constructor, be explicit to avoid oddities where possible.","commit_id":"915ab8ca03f62ba972cec09d958b66edae4bfff2"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"7e3d3224d74ad289bba9905e42858481ab0690f2","unresolved":false,"context_lines":[{"line_number":955,"context_line":"                             original_password\u003dpassword,"},{"line_number":956,"context_line":"                             expected_status\u003dhttp_client.NO_CONTENT)"},{"line_number":957,"context_line":""},{"line_number":958,"context_line":"    def test_changing_expired_password_fails(self):"},{"line_number":959,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"},{"line_number":960,"context_line":"                                   password_expires_days\u003d2)"},{"line_number":961,"context_line":"        _password \u003d self._create_user_with_expired_password()"}],"source_content_type":"text/x-python","patch_set":23,"id":"5a3905b3_c7c07d2d","line":958,"range":{"start_line":958,"start_character":8,"end_line":958,"end_character":44},"updated":"2017-01-20 06:06:04.000000000","message":"With removing the config setting, this test is really a duplicate of \"test_changing_password_with_incorrect_password_fails\"","commit_id":"2ec4045e3ca4ad074218210894ef506fd60ef3f4"},{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"82a5c1828e5655318f733c8de2b3fbfd20dfd335","unresolved":false,"context_lines":[{"line_number":989,"context_line":"        # Password changed, token should be invalid"},{"line_number":990,"context_line":"        self.change_password(password\u003duuid.uuid4().hex,"},{"line_number":991,"context_line":"                             original_password\u003dnew_password,"},{"line_number":992,"context_line":"                             expected_status\u003dhttp_client.UNAUTHORIZED)"},{"line_number":993,"context_line":""},{"line_number":994,"context_line":""},{"line_number":995,"context_line":"class PasswordValidationTestCase(ChangePasswordTestCase):"}],"source_content_type":"text/x-python","patch_set":23,"id":"5a3905b3_5148cf87","line":992,"range":{"start_line":992,"start_character":29,"end_line":992,"end_character":70},"updated":"2017-01-20 05:00:57.000000000","message":"hmm, this is now returning: 204 No Content -- i wonder if in the change to the controller based validation we are forgetting to invalidate user tokens?","commit_id":"2ec4045e3ca4ad074218210894ef506fd60ef3f4"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"852a4d4a08bbc5c83d26cb152b7bfc21da5627ca","unresolved":false,"context_lines":[{"line_number":989,"context_line":"        # Password changed, token should be invalid"},{"line_number":990,"context_line":"        self.change_password(password\u003duuid.uuid4().hex,"},{"line_number":991,"context_line":"                             original_password\u003dnew_password,"},{"line_number":992,"context_line":"                             expected_status\u003dhttp_client.UNAUTHORIZED)"},{"line_number":993,"context_line":""},{"line_number":994,"context_line":""},{"line_number":995,"context_line":"class PasswordValidationTestCase(ChangePasswordTestCase):"}],"source_content_type":"text/x-python","patch_set":23,"id":"5a3905b3_e72c994c","line":992,"range":{"start_line":992,"start_character":29,"end_line":992,"end_character":70},"in_reply_to":"5a3905b3_5148cf87","updated":"2017-01-20 06:01:24.000000000","message":"I think this test is me making redundant tests, checking for invalid tokens is done above [1] and with the newest changes, this doesn\u0027t check token validation.\n\n[1] https://github.com/openstack/keystone/blob/master/keystone/tests/unit/test_v3_identity.py#L838","commit_id":"2ec4045e3ca4ad074218210894ef506fd60ef3f4"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"c908b737d18b2cee6f88eed8ff28073f6df03ef0","unresolved":false,"context_lines":[{"line_number":953,"context_line":"        new_password \u003d uuid.uuid4().hex"},{"line_number":954,"context_line":"        self.change_password(password\u003dnew_password,"},{"line_number":955,"context_line":"                             original_password\u003dpassword,"},{"line_number":956,"context_line":"                             expected_status\u003dhttp_client.NO_CONTENT)"},{"line_number":957,"context_line":""},{"line_number":958,"context_line":"    def test_changing_expired_password_with_disabled_user_fails(self):"},{"line_number":959,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"}],"source_content_type":"text/x-python","patch_set":24,"id":"5a3905b3_12f46984","line":956,"updated":"2017-01-20 16:05:00.000000000","message":"We could add another assertion here to make sure the user can authenticate with the new password.","commit_id":"88ba36a38841e9f66e741e53e13b877390195df1"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"776f641a12b985a328aea90bd92814d28d563e6d","unresolved":false,"context_lines":[{"line_number":953,"context_line":"        new_password \u003d uuid.uuid4().hex"},{"line_number":954,"context_line":"        self.change_password(password\u003dnew_password,"},{"line_number":955,"context_line":"                             original_password\u003dpassword,"},{"line_number":956,"context_line":"                             expected_status\u003dhttp_client.NO_CONTENT)"},{"line_number":957,"context_line":""},{"line_number":958,"context_line":"    def test_changing_expired_password_with_disabled_user_fails(self):"},{"line_number":959,"context_line":"        self.config_fixture.config(group\u003d\u0027security_compliance\u0027,"}],"source_content_type":"text/x-python","patch_set":24,"id":"5a3905b3_5c19a087","line":956,"in_reply_to":"5a3905b3_12f46984","updated":"2017-01-20 17:58:09.000000000","message":"sure","commit_id":"88ba36a38841e9f66e741e53e13b877390195df1"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"c908b737d18b2cee6f88eed8ff28073f6df03ef0","unresolved":false,"context_lines":[{"line_number":968,"context_line":"        new_password \u003d uuid.uuid4().hex"},{"line_number":969,"context_line":"        self.change_password(password\u003dnew_password,"},{"line_number":970,"context_line":"                             original_password\u003dpassword,"},{"line_number":971,"context_line":"                             expected_status\u003dhttp_client.UNAUTHORIZED)"},{"line_number":972,"context_line":""},{"line_number":973,"context_line":""},{"line_number":974,"context_line":"class PasswordValidationTestCase(ChangePasswordTestCase):"}],"source_content_type":"text/x-python","patch_set":24,"id":"5a3905b3_92369950","line":971,"updated":"2017-01-20 16:05:00.000000000","message":"Same comment here","commit_id":"88ba36a38841e9f66e741e53e13b877390195df1"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"c908b737d18b2cee6f88eed8ff28073f6df03ef0","unresolved":false,"context_lines":[{"line_number":969,"context_line":"        self.change_password(password\u003dnew_password,"},{"line_number":970,"context_line":"                             original_password\u003dpassword,"},{"line_number":971,"context_line":"                             expected_status\u003dhttp_client.UNAUTHORIZED)"},{"line_number":972,"context_line":""},{"line_number":973,"context_line":""},{"line_number":974,"context_line":"class PasswordValidationTestCase(ChangePasswordTestCase):"},{"line_number":975,"context_line":""}],"source_content_type":"text/x-python","patch_set":24,"id":"5a3905b3_72cbed1e","line":972,"updated":"2017-01-20 16:05:00.000000000","message":"If a user attempts to change their password with the wrong original, they should get a straight up 401, right? I\u0027m sure we have tests for that somewhere, but we could document that behavior here, too.\n\n  def test_changing_expired_password_with_wrong_password_fails(self):\n      self.config_fixture.config(\n          group\u003d\u0027security_compliance\u0027,\n          password_expires_days\u003d2\n      )\n      password \u003d self._create_user_with_expired_password()\n      self.change_password(\n          password\u003duuid.uuid4().hex,\n          original_password\u003duuid.uuid4().hex,\n          expected_status\u003dhttp_client.UNAUTHORIZED\n      )","commit_id":"88ba36a38841e9f66e741e53e13b877390195df1"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"776f641a12b985a328aea90bd92814d28d563e6d","unresolved":false,"context_lines":[{"line_number":969,"context_line":"        self.change_password(password\u003dnew_password,"},{"line_number":970,"context_line":"                             original_password\u003dpassword,"},{"line_number":971,"context_line":"                             expected_status\u003dhttp_client.UNAUTHORIZED)"},{"line_number":972,"context_line":""},{"line_number":973,"context_line":""},{"line_number":974,"context_line":"class PasswordValidationTestCase(ChangePasswordTestCase):"},{"line_number":975,"context_line":""}],"source_content_type":"text/x-python","patch_set":24,"id":"5a3905b3_9c3ce8e3","line":972,"in_reply_to":"5a3905b3_72cbed1e","updated":"2017-01-20 17:58:09.000000000","message":"It\u0027s tested here:\nhttps://github.com/openstack/keystone/blob/master/keystone/tests/unit/test_v3_identity.py#L904\n\nAlthough we could add a (expired + incorrect) test as well.","commit_id":"88ba36a38841e9f66e741e53e13b877390195df1"}],"releasenotes/notes/user-can-change-expired-password-516709f9da3de26f.yaml":[{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"b74159f75b493739ff3729c7d33f7778c3ae9d13","unresolved":false,"context_lines":[{"line_number":2,"context_line":"features:"},{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    Allows a user to change their own expired password. Added configuration"},{"line_number":5,"context_line":"    setting ``user_can_change_expired_password`` that will cause token"},{"line_number":6,"context_line":"    authentication to be skipped if set to True and ``password_expires_days``"},{"line_number":7,"context_line":"    has been set. This removes the need for an administrator to reset"},{"line_number":8,"context_line":"    a user\u0027s password if it expires before they can change it."}],"source_content_type":"text/x-yaml","patch_set":15,"id":"7a3c09a3_ac7282e3","line":5,"updated":"2017-01-14 04:19:51.000000000","message":"Do we need to mention the section for these settings?","commit_id":"983b52580f19af92aae82fcf3e95d2ffa0c4a8e8"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"c3fa70853132e779c204637a95892a75a191dc48","unresolved":false,"context_lines":[{"line_number":2,"context_line":"features:"},{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    Allows a user to change their own expired password. Added configuration"},{"line_number":5,"context_line":"    setting ``user_can_change_expired_password`` that will cause token"},{"line_number":6,"context_line":"    authentication to be skipped if set to True and ``password_expires_days``"},{"line_number":7,"context_line":"    has been set. This removes the need for an administrator to reset"},{"line_number":8,"context_line":"    a user\u0027s password if it expires before they can change it."}],"source_content_type":"text/x-yaml","patch_set":15,"id":"7a3c09a3_ff3839a2","line":5,"in_reply_to":"7a3c09a3_ac7282e3","updated":"2017-01-17 16:57:46.000000000","message":"Yes, I\u0027ll add them, thanks for catching that.","commit_id":"983b52580f19af92aae82fcf3e95d2ffa0c4a8e8"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"68aa4a04e9f6d651206abdf8427d7c66ca1dd586","unresolved":false,"context_lines":[{"line_number":4,"context_line":"    Allows a user to change their own expired password. Added configuration"},{"line_number":5,"context_line":"    setting ``[security_compliance] minimum_password_age`` that can be used"},{"line_number":6,"context_line":"    to cause token authentication to be skipped if set to True and"},{"line_number":7,"context_line":"    ``[security_compliance] password_expires_days`` has been set. This"},{"line_number":8,"context_line":"    removes the need for an administrator to reset a user\u0027s password if it"},{"line_number":9,"context_line":"    expires before they can change it."}],"source_content_type":"text/x-yaml","patch_set":19,"id":"5a3905b3_6e1259b6","line":7,"range":{"start_line":7,"start_character":4,"end_line":7,"end_character":49},"updated":"2017-01-19 20:13:05.000000000","message":"see comment on config options.","commit_id":"915ab8ca03f62ba972cec09d958b66edae4bfff2"},{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"c49dda9dc7a7f8f70e50611d294a3da48d80a57d","unresolved":false,"context_lines":[{"line_number":1,"context_line":"---"},{"line_number":2,"context_line":"features:"},{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    Removes RBAC protected from change_user API call. A user is expected"},{"line_number":5,"context_line":"    to know their own password and can be authenticated as such. This"},{"line_number":6,"context_line":"    change is related to PCI-DSS features and allows a user with an"},{"line_number":7,"context_line":"    expired password to change it without the need of an"}],"source_content_type":"text/x-yaml","patch_set":21,"id":"5a3905b3_21fdbf3a","line":4,"range":{"start_line":4,"start_character":27,"end_line":4,"end_character":52},"updated":"2017-01-19 22:36:12.000000000","message":"from change_user API call -\u003e\n\nfrom the `Self-service change user password` API (``/v3/user/$user_id/password``)","commit_id":"26f147831510ac1d9cf103078576662427f7b094"},{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"c49dda9dc7a7f8f70e50611d294a3da48d80a57d","unresolved":false,"context_lines":[{"line_number":1,"context_line":"---"},{"line_number":2,"context_line":"features:"},{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    Removes RBAC protected from change_user API call. A user is expected"},{"line_number":5,"context_line":"    to know their own password and can be authenticated as such. This"},{"line_number":6,"context_line":"    change is related to PCI-DSS features and allows a user with an"},{"line_number":7,"context_line":"    expired password to change it without the need of an"}],"source_content_type":"text/x-yaml","patch_set":21,"id":"5a3905b3_a15a8f81","line":4,"range":{"start_line":4,"start_character":17,"end_line":4,"end_character":26},"updated":"2017-01-19 22:36:12.000000000","message":"protection*","commit_id":"26f147831510ac1d9cf103078576662427f7b094"}]}
