)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"b04acc59315eab98aef754de7f5989136bec8706","unresolved":false,"context_lines":[{"line_number":15,"context_line":"present for user, otherwise expects totp passcode appended"},{"line_number":16,"context_line":"to the password."},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"Also fixing a byte\u003estr conversion bug present in the TOTP"},{"line_number":19,"context_line":"passcode generation function that was only present in python3."},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"Change-Id: Ia552b98002d83ec1ef2d127f11e98f2588692645"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":8,"id":"dada55a8_e444e647","line":18,"updated":"2016-07-27 13:21:51.000000000","message":"This should be in a separate review.","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":10420,"name":"Adrian Turjak","email":"devs+openstack@uncaught-exceptions.com","username":"adriant"},"change_message_id":"4d2dfb0460dc09d88771d45b03fbffdc0fee2943","unresolved":false,"context_lines":[{"line_number":15,"context_line":"present for user, otherwise expects totp passcode appended"},{"line_number":16,"context_line":"to the password."},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"Also fixing a byte\u003estr conversion bug present in the TOTP"},{"line_number":19,"context_line":"passcode generation function that was only present in python3."},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"Change-Id: Ia552b98002d83ec1ef2d127f11e98f2588692645"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":8,"id":"bacf61ea_a1f8df7d","line":18,"in_reply_to":"dada55a8_e444e647","updated":"2016-07-27 22:34:36.000000000","message":"Will be up soon, added here temporarily to check if it fixes my tests.","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"}],"doc/source/auth-totp.rst":[{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"59fac7b7a20434d4b719904a46c4e5fd61353303","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":13,"id":"ba5da102_c2c5a88e","updated":"2016-11-01 01:57:29.000000000","message":"nit: this can be done in a separate review","commit_id":"cd4c09c4ed47b4bde601c42a6a6168d7ead5a9f9"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"babd7229bfdb043358c5babdb404e249b3eff491","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":13,"id":"ba5da102_0fd7b6ed","in_reply_to":"ba5da102_c2c5a88e","updated":"2016-11-01 15:07:31.000000000","message":"++","commit_id":"cd4c09c4ed47b4bde601c42a6a6168d7ead5a9f9"}],"doc/source/index.rst":[{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"b04acc59315eab98aef754de7f5989136bec8706","unresolved":false,"context_lines":[{"line_number":68,"context_line":"   :maxdepth: 1"},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"   configure_tokenless_x509"},{"line_number":71,"context_line":"   password-totp"},{"line_number":72,"context_line":"   auth-totp"},{"line_number":73,"context_line":"   event_notifications"},{"line_number":74,"context_line":"   external-auth"}],"source_content_type":"text/x-rst","patch_set":8,"id":"dada55a8_24a0bef3","line":71,"updated":"2016-07-27 13:21:51.000000000","message":"Logically does this go after the totp introduction?","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":10420,"name":"Adrian Turjak","email":"devs+openstack@uncaught-exceptions.com","username":"adriant"},"change_message_id":"4d2dfb0460dc09d88771d45b03fbffdc0fee2943","unresolved":false,"context_lines":[{"line_number":68,"context_line":"   :maxdepth: 1"},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"   configure_tokenless_x509"},{"line_number":71,"context_line":"   password-totp"},{"line_number":72,"context_line":"   auth-totp"},{"line_number":73,"context_line":"   event_notifications"},{"line_number":74,"context_line":"   external-auth"}],"source_content_type":"text/x-rst","patch_set":8,"id":"bacf61ea_a1029f3c","line":71,"in_reply_to":"dada55a8_24a0bef3","updated":"2016-07-27 22:34:36.000000000","message":"Added before because unlike totp this was setup as a default auth method, and likely to be more common than raw totp.","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"}],"doc/source/password-totp.rst":[{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"b04acc59315eab98aef754de7f5989136bec8706","unresolved":false,"context_lines":[{"line_number":33,"context_line":"Disable V2 API"},{"line_number":34,"context_line":"--------------"},{"line_number":35,"context_line":""},{"line_number":36,"context_line":"Before doing this you should configure your identity endpoint to be"},{"line_number":37,"context_line":"versionless and setup all services to correctly use the V3 API."},{"line_number":38,"context_line":""},{"line_number":39,"context_line":"To fully disable the V2 api in Keystone, in the \u0027keystone-paste.ini\u0027"}],"source_content_type":"text/x-rst","patch_set":8,"id":"dada55a8_44d5f219","line":36,"updated":"2016-07-27 13:21:51.000000000","message":"Starting the sentence with \u0027Before doing this\u0027 doesn\u0027t sound right.","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":10420,"name":"Adrian Turjak","email":"devs+openstack@uncaught-exceptions.com","username":"adriant"},"change_message_id":"4d2dfb0460dc09d88771d45b03fbffdc0fee2943","unresolved":false,"context_lines":[{"line_number":33,"context_line":"Disable V2 API"},{"line_number":34,"context_line":"--------------"},{"line_number":35,"context_line":""},{"line_number":36,"context_line":"Before doing this you should configure your identity endpoint to be"},{"line_number":37,"context_line":"versionless and setup all services to correctly use the V3 API."},{"line_number":38,"context_line":""},{"line_number":39,"context_line":"To fully disable the V2 api in Keystone, in the \u0027keystone-paste.ini\u0027"}],"source_content_type":"text/x-rst","patch_set":8,"id":"bacf61ea_619f0704","line":36,"in_reply_to":"dada55a8_44d5f219","updated":"2016-07-27 22:34:36.000000000","message":"Done","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"b04acc59315eab98aef754de7f5989136bec8706","unresolved":false,"context_lines":[{"line_number":69,"context_line":"    /v3 \u003d api_v3"},{"line_number":70,"context_line":"    / \u003d admin_version_api"},{"line_number":71,"context_line":""},{"line_number":72,"context_line":"Following that restart Keystone, and confirm the API is inoperable."},{"line_number":73,"context_line":""},{"line_number":74,"context_line":"Configuring MFA for your user account"},{"line_number":75,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":8,"id":"dada55a8_84808af8","line":72,"updated":"2016-07-27 13:21:51.000000000","message":"s/Following that/Then/","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":10420,"name":"Adrian Turjak","email":"devs+openstack@uncaught-exceptions.com","username":"adriant"},"change_message_id":"4d2dfb0460dc09d88771d45b03fbffdc0fee2943","unresolved":false,"context_lines":[{"line_number":69,"context_line":"    /v3 \u003d api_v3"},{"line_number":70,"context_line":"    / \u003d admin_version_api"},{"line_number":71,"context_line":""},{"line_number":72,"context_line":"Following that restart Keystone, and confirm the API is inoperable."},{"line_number":73,"context_line":""},{"line_number":74,"context_line":"Configuring MFA for your user account"},{"line_number":75,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"}],"source_content_type":"text/x-rst","patch_set":8,"id":"bacf61ea_41a48356","line":72,"in_reply_to":"dada55a8_84808af8","updated":"2016-07-27 22:34:36.000000000","message":"Done","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"b04acc59315eab98aef754de7f5989136bec8706","unresolved":false,"context_lines":[{"line_number":71,"context_line":""},{"line_number":72,"context_line":"Following that restart Keystone, and confirm the API is inoperable."},{"line_number":73,"context_line":""},{"line_number":74,"context_line":"Configuring MFA for your user account"},{"line_number":75,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":76,"context_line":""},{"line_number":77,"context_line":"Create a TOTP secret"}],"source_content_type":"text/x-rst","patch_set":8,"id":"dada55a8_e4d4e6e9","line":74,"updated":"2016-07-27 13:21:51.000000000","message":"Why are we duplicating so much from the totp documentation?","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"d6444c431479fa1022b7c1b29bf4bad5bbec75e1","unresolved":false,"context_lines":[{"line_number":71,"context_line":""},{"line_number":72,"context_line":"Following that restart Keystone, and confirm the API is inoperable."},{"line_number":73,"context_line":""},{"line_number":74,"context_line":"Configuring MFA for your user account"},{"line_number":75,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":76,"context_line":""},{"line_number":77,"context_line":"Create a TOTP secret"}],"source_content_type":"text/x-rst","patch_set":8,"id":"bacf61ea_75c17d80","line":74,"in_reply_to":"bacf61ea_c41a416e","updated":"2016-07-27 23:53:53.000000000","message":"That\u0027s probably a good plan.","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":10420,"name":"Adrian Turjak","email":"devs+openstack@uncaught-exceptions.com","username":"adriant"},"change_message_id":"4d2dfb0460dc09d88771d45b03fbffdc0fee2943","unresolved":false,"context_lines":[{"line_number":71,"context_line":""},{"line_number":72,"context_line":"Following that restart Keystone, and confirm the API is inoperable."},{"line_number":73,"context_line":""},{"line_number":74,"context_line":"Configuring MFA for your user account"},{"line_number":75,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":76,"context_line":""},{"line_number":77,"context_line":"Create a TOTP secret"}],"source_content_type":"text/x-rst","patch_set":8,"id":"bacf61ea_c41a416e","line":74,"in_reply_to":"dada55a8_e4d4e6e9","updated":"2016-07-27 22:34:36.000000000","message":"There quite a few changes below, although I am tempted to move those changes to the totp-docs.\n\nBoth auth-totp and this plugin rely on setting up a totp credential, but then use it differently. Might be better to create a new \"setup-totp\" doc, have both plugins reference it, and only have the auth docs talk about setup and use.","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":1916,"name":"Guang Yee","email":"gyee@suse.com","username":"guang-yee"},"change_message_id":"065e7f5423f035e5136124a150e3a6a5700101e1","unresolved":false,"context_lines":[{"line_number":58,"context_line":"Disable V2 API"},{"line_number":59,"context_line":"--------------"},{"line_number":60,"context_line":""},{"line_number":61,"context_line":"To be fully secure your deployment of Keystone **must disable the V2 API** as"},{"line_number":62,"context_line":"it does not support MFA and regardless of a user having a \u0027totp\u0027 credential"},{"line_number":63,"context_line":"will only require username and password for authentication."},{"line_number":64,"context_line":""}],"source_content_type":"text/x-rst","patch_set":11,"id":"bacf61ea_f80fe485","line":61,"range":{"start_line":61,"start_character":49,"end_line":61,"end_character":73},"updated":"2016-07-29 00:44:11.000000000","message":"I like this requirement!","commit_id":"897369cf739a02c6f74bdc93e4eae4ef76ddf574"},{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"59fac7b7a20434d4b719904a46c4e5fd61353303","unresolved":false,"context_lines":[{"line_number":20,"context_line":""},{"line_number":21,"context_line":"Keystone supports Multi-Factor Auth (MFA) via a combination of TOTP and"},{"line_number":22,"context_line":"password authetication. This is disabled by default, but is easily"},{"line_number":23,"context_line":"enabled via a one line change in the \u0027keystone.conf\u0027 file."},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"Once your configuration is setup, activating MFA is done on a per user basis"},{"line_number":26,"context_line":"by associating a credential of type \u0027totp\u0027 with your user."}],"source_content_type":"text/x-rst","patch_set":13,"id":"ba5da102_02dde00d","line":23,"range":{"start_line":23,"start_character":37,"end_line":23,"end_character":52},"updated":"2016-11-01 01:57:29.000000000","message":"in general, just double backticks instead of single quotes:  `` vs \u0027","commit_id":"cd4c09c4ed47b4bde601c42a6a6168d7ead5a9f9"},{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"59fac7b7a20434d4b719904a46c4e5fd61353303","unresolved":false,"context_lines":[{"line_number":25,"context_line":"Once your configuration is setup, activating MFA is done on a per user basis"},{"line_number":26,"context_line":"by associating a credential of type \u0027totp\u0027 with your user."},{"line_number":27,"context_line":""},{"line_number":28,"context_line":"keystone.conf changes"},{"line_number":29,"context_line":"---------------------"},{"line_number":30,"context_line":""},{"line_number":31,"context_line":"Find the following section in \u0027keystone.conf\u0027"}],"source_content_type":"text/x-rst","patch_set":13,"id":"ba5da102_42051878","line":28,"range":{"start_line":28,"start_character":0,"end_line":28,"end_character":13},"updated":"2016-11-01 01:57:29.000000000","message":"wrap this in `` too","commit_id":"cd4c09c4ed47b4bde601c42a6a6168d7ead5a9f9"},{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"59fac7b7a20434d4b719904a46c4e5fd61353303","unresolved":false,"context_lines":[{"line_number":28,"context_line":"keystone.conf changes"},{"line_number":29,"context_line":"---------------------"},{"line_number":30,"context_line":""},{"line_number":31,"context_line":"Find the following section in \u0027keystone.conf\u0027"},{"line_number":32,"context_line":""},{"line_number":33,"context_line":"/etc/keystone/keystone.conf::"},{"line_number":34,"context_line":""}],"source_content_type":"text/x-rst","patch_set":13,"id":"ba5da102_c2f92882","line":31,"range":{"start_line":31,"start_character":9,"end_line":31,"end_character":18},"updated":"2016-11-01 01:57:29.000000000","message":"``[auth]``","commit_id":"cd4c09c4ed47b4bde601c42a6a6168d7ead5a9f9"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"babd7229bfdb043358c5babdb404e249b3eff491","unresolved":false,"context_lines":[{"line_number":28,"context_line":"keystone.conf changes"},{"line_number":29,"context_line":"---------------------"},{"line_number":30,"context_line":""},{"line_number":31,"context_line":"Find the following section in \u0027keystone.conf\u0027"},{"line_number":32,"context_line":""},{"line_number":33,"context_line":"/etc/keystone/keystone.conf::"},{"line_number":34,"context_line":""}],"source_content_type":"text/x-rst","patch_set":13,"id":"ba5da102_0f733616","line":31,"range":{"start_line":31,"start_character":9,"end_line":31,"end_character":18},"in_reply_to":"ba5da102_c2f92882","updated":"2016-11-01 15:07:31.000000000","message":"This seems so overly verbose compared to how the rest of the docs explain configuration changes.","commit_id":"cd4c09c4ed47b4bde601c42a6a6168d7ead5a9f9"},{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"59fac7b7a20434d4b719904a46c4e5fd61353303","unresolved":false,"context_lines":[{"line_number":30,"context_line":""},{"line_number":31,"context_line":"Find the following section in \u0027keystone.conf\u0027"},{"line_number":32,"context_line":""},{"line_number":33,"context_line":"/etc/keystone/keystone.conf::"},{"line_number":34,"context_line":""},{"line_number":35,"context_line":"    [auth]"},{"line_number":36,"context_line":""},{"line_number":37,"context_line":"    #"},{"line_number":38,"context_line":"    # From keystone"},{"line_number":39,"context_line":"    #"},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"    # Allowed authentication methods. (list value)"},{"line_number":42,"context_line":"    #methods \u003d external,password,token,oauth1"},{"line_number":43,"context_line":""},{"line_number":44,"context_line":"    # Entrypoint for the password auth plugin module in the keystone.auth.password"},{"line_number":45,"context_line":"    # namespace. (string value)"},{"line_number":46,"context_line":"    #password \u003d \u003cNone\u003e"},{"line_number":47,"context_line":""},{"line_number":48,"context_line":"And set the password auth plugin to be \u0027password_totp\u0027"},{"line_number":49,"context_line":""}],"source_content_type":"text/x-rst","patch_set":13,"id":"ba5da102_02f40084","line":46,"range":{"start_line":33,"start_character":0,"end_line":46,"end_character":22},"updated":"2016-11-01 01:57:29.000000000","message":"remove this and get to the point faster :)","commit_id":"cd4c09c4ed47b4bde601c42a6a6168d7ead5a9f9"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"babd7229bfdb043358c5babdb404e249b3eff491","unresolved":false,"context_lines":[{"line_number":115,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":116,"context_line":""},{"line_number":117,"context_line":"Once you have a valid application such as Google Authenticator setup with your"},{"line_number":118,"context_line":"secret, it will provide you with a 6 digit passcode that is valid for 30 seconds."},{"line_number":119,"context_line":""},{"line_number":120,"context_line":"Using your new TOTP credentials is done by simply appending your 6 digit passcode"},{"line_number":121,"context_line":"to your standard password on any interactions with OpenStack APIs."}],"source_content_type":"text/x-rst","patch_set":13,"id":"ba5da102_af796aca","line":118,"updated":"2016-11-01 15:07:31.000000000","message":"Why is 6 hardcoded? It\u0027s entirely possible that a token legth is different, should we account for that? How common is it to have different values? YubiKey for example can use 6 or 8.","commit_id":"cd4c09c4ed47b4bde601c42a6a6168d7ead5a9f9"}],"doc/source/totp-credentials.rst":[{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"f5ae4f391269809603573ac751863224ee7b094f","unresolved":false,"context_lines":[{"line_number":67,"context_line":""},{"line_number":68,"context_line":"To make use of your secret, you need to be able to generate a 6 digit passcode."},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"On a device install Google Authenticator and inside the app click on \u0027Set up"},{"line_number":71,"context_line":"account\u0027 and then click on \u0027Enter provided key\u0027. In the input fields enter"},{"line_number":72,"context_line":"account name and secret.  Optionally a QR code can be generated programatically"},{"line_number":73,"context_line":"to avoid having to type the information."}],"source_content_type":"text/x-rst","patch_set":12,"id":"bacf61ea_c6a59047","line":70,"range":{"start_line":70,"start_character":20,"end_line":70,"end_character":40},"updated":"2016-08-01 03:37:06.000000000","message":"include a hyperlink to: http://www.google.com/2step","commit_id":"afdfba5e19b6d4e707198a8afb36f0e9877c96f8"}],"keystone/auth/plugins/password.py":[{"author":{"_account_id":1916,"name":"Guang Yee","email":"gyee@suse.com","username":"guang-yee"},"change_message_id":"9932b35b1697aaa421533dae33984bed6394b973","unresolved":false,"context_lines":[{"line_number":12,"context_line":"# License for the specific language governing permissions and limitations"},{"line_number":13,"context_line":"# under the License."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"\"\"\"Password and Time-based One-time Password Algorithm (TOTP) auth plugin."},{"line_number":16,"context_line":""},{"line_number":17,"context_line":"The goal of this plugin is to combine username/password with a TOTP passcode"},{"line_number":18,"context_line":"as a 2-factor solution when a TOTP credential is present for a given user."}],"source_content_type":"text/x-python","patch_set":5,"id":"dada55a8_2cd5691b","line":15,"updated":"2016-07-20 22:00:47.000000000","message":"This need to be a separate plugin. We should not be mixing up Password and Password + TOTP in the same plugin.","commit_id":"c401a02099193276c6b387d21b4400a252ddfa7f"},{"author":{"_account_id":1916,"name":"Guang Yee","email":"gyee@suse.com","username":"guang-yee"},"change_message_id":"9932b35b1697aaa421533dae33984bed6394b973","unresolved":false,"context_lines":[{"line_number":50,"context_line":"LOG \u003d log.getLogger(__name__)"},{"line_number":51,"context_line":""},{"line_number":52,"context_line":""},{"line_number":53,"context_line":"def _generate_totp_passcode(secret):"},{"line_number":54,"context_line":"    \"\"\"Generate TOTP passcode."},{"line_number":55,"context_line":""},{"line_number":56,"context_line":"    :param bytes secret: A base32 encoded secret for the TOTP authentication"}],"source_content_type":"text/x-python","patch_set":5,"id":"dada55a8_0cc18554","line":53,"updated":"2016-07-20 22:00:47.000000000","message":"suggest refactoring the existing TOTP plugin to share code instead of duplicating code","commit_id":"c401a02099193276c6b387d21b4400a252ddfa7f"},{"author":{"_account_id":10420,"name":"Adrian Turjak","email":"devs+openstack@uncaught-exceptions.com","username":"adriant"},"change_message_id":"e8006ecfe7160062d6f0b6ff37ac86027dca76d2","unresolved":false,"context_lines":[{"line_number":50,"context_line":"LOG \u003d log.getLogger(__name__)"},{"line_number":51,"context_line":""},{"line_number":52,"context_line":""},{"line_number":53,"context_line":"def _generate_totp_passcode(secret):"},{"line_number":54,"context_line":"    \"\"\"Generate TOTP passcode."},{"line_number":55,"context_line":""},{"line_number":56,"context_line":"    :param bytes secret: A base32 encoded secret for the TOTP authentication"}],"source_content_type":"text/x-python","patch_set":5,"id":"dada55a8_9dd3e103","line":53,"in_reply_to":"dada55a8_0cc18554","updated":"2016-07-20 23:09:19.000000000","message":"Will likely move this function somewhere else, or import from totp.py","commit_id":"c401a02099193276c6b387d21b4400a252ddfa7f"},{"author":{"_account_id":1916,"name":"Guang Yee","email":"gyee@suse.com","username":"guang-yee"},"change_message_id":"9932b35b1697aaa421533dae33984bed6394b973","unresolved":false,"context_lines":[{"line_number":83,"context_line":""},{"line_number":84,"context_line":"        # First we check if the given user_id has totp credentials"},{"line_number":85,"context_line":"        credentials \u003d self.credential_api.list_credentials_for_user("},{"line_number":86,"context_line":"            user_info.user_id, type\u003d\u0027totp\u0027)"},{"line_number":87,"context_line":""},{"line_number":88,"context_line":"        try:"},{"line_number":89,"context_line":"            if credentials:"}],"source_content_type":"text/x-python","patch_set":5,"id":"dada55a8_8ca29597","line":86,"updated":"2016-07-20 22:00:47.000000000","message":"Currently, a given credential can scope to a project (i.e. project_id in cred ref). We may need to change the auth framework to check to see if the scope matches the credential as well.","commit_id":"c401a02099193276c6b387d21b4400a252ddfa7f"},{"author":{"_account_id":1916,"name":"Guang Yee","email":"gyee@suse.com","username":"guang-yee"},"change_message_id":"9932b35b1697aaa421533dae33984bed6394b973","unresolved":false,"context_lines":[{"line_number":86,"context_line":"            user_info.user_id, type\u003d\u0027totp\u0027)"},{"line_number":87,"context_line":""},{"line_number":88,"context_line":"        try:"},{"line_number":89,"context_line":"            if credentials:"},{"line_number":90,"context_line":"                # If the user has credentials, strip passcode from password"},{"line_number":91,"context_line":"                self.identity_api.authenticate("},{"line_number":92,"context_line":"                    request.context_dict,"}],"source_content_type":"text/x-python","patch_set":5,"id":"dada55a8_97974247","line":89,"updated":"2016-07-20 22:00:47.000000000","message":"this should be universally enforced instead of selectively enforced","commit_id":"c401a02099193276c6b387d21b4400a252ddfa7f"}],"keystone/auth/plugins/password_totp.py":[{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"75040187a5dfab9ae4ef2a55d3a9e10bf0bf9d06","unresolved":false,"context_lines":[{"line_number":62,"context_line":"                self.identity_api.authenticate("},{"line_number":63,"context_line":"                    request,"},{"line_number":64,"context_line":"                    user_id\u003duser_info.user_id,"},{"line_number":65,"context_line":"                    password\u003duser_info.password[:-6])"},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"                valid_passcode \u003d False"},{"line_number":68,"context_line":"                auth_passcode \u003d user_info.password[-6:]"}],"source_content_type":"text/x-python","patch_set":7,"id":"dada55a8_2dcc4c88","line":65,"range":{"start_line":65,"start_character":49,"end_line":65,"end_character":51},"updated":"2016-07-26 17:35:33.000000000","message":"Should this be configurable?","commit_id":"e9f8b4c624f0cfbb586f7489a288088070db02cb"},{"author":{"_account_id":10420,"name":"Adrian Turjak","email":"devs+openstack@uncaught-exceptions.com","username":"adriant"},"change_message_id":"cc45dbc18fcc46a13b8977aa57e260a4cd523bca","unresolved":false,"context_lines":[{"line_number":62,"context_line":"                self.identity_api.authenticate("},{"line_number":63,"context_line":"                    request,"},{"line_number":64,"context_line":"                    user_id\u003duser_info.user_id,"},{"line_number":65,"context_line":"                    password\u003duser_info.password[:-6])"},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"                valid_passcode \u003d False"},{"line_number":68,"context_line":"                auth_passcode \u003d user_info.password[-6:]"}],"source_content_type":"text/x-python","patch_set":7,"id":"dada55a8_d803a70e","line":65,"range":{"start_line":65,"start_character":49,"end_line":65,"end_character":51},"in_reply_to":"dada55a8_2dcc4c88","updated":"2016-07-26 23:30:19.000000000","message":"This can\u0027t become configurable unless this also is:\nhttps://github.com/openstack/keystone/blob/master/keystone/auth/plugins/totp.py#L64\nAs that\u0027s the passcode generation function I am using.\n\n6 digits with totp appears to be the commonly accepted default.","commit_id":"e9f8b4c624f0cfbb586f7489a288088070db02cb"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"b04acc59315eab98aef754de7f5989136bec8706","unresolved":false,"context_lines":[{"line_number":1,"context_line":"# Copyright 2013 OpenStack Foundation"},{"line_number":2,"context_line":"#"},{"line_number":3,"context_line":"# Licensed under the Apache License, Version 2.0 (the \"License\"); you may"},{"line_number":4,"context_line":"# not use this file except in compliance with the License. You may obtain"}],"source_content_type":"text/x-python","patch_set":8,"id":"dada55a8_447b32f5","line":1,"updated":"2016-07-27 13:21:51.000000000","message":"Why is this here? Was the code copied from foundation code?","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"d6444c431479fa1022b7c1b29bf4bad5bbec75e1","unresolved":false,"context_lines":[{"line_number":1,"context_line":"# Copyright 2013 OpenStack Foundation"},{"line_number":2,"context_line":"#"},{"line_number":3,"context_line":"# Licensed under the Apache License, Version 2.0 (the \"License\"); you may"},{"line_number":4,"context_line":"# not use this file except in compliance with the License. You may obtain"}],"source_content_type":"text/x-python","patch_set":8,"id":"bacf61ea_75485d2e","line":1,"in_reply_to":"bacf61ea_c431a1ee","updated":"2016-07-27 23:53:53.000000000","message":"If it\u0027s based on that code we should leave it.","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":10420,"name":"Adrian Turjak","email":"devs+openstack@uncaught-exceptions.com","username":"adriant"},"change_message_id":"4d2dfb0460dc09d88771d45b03fbffdc0fee2943","unresolved":false,"context_lines":[{"line_number":1,"context_line":"# Copyright 2013 OpenStack Foundation"},{"line_number":2,"context_line":"#"},{"line_number":3,"context_line":"# Licensed under the Apache License, Version 2.0 (the \"License\"); you may"},{"line_number":4,"context_line":"# not use this file except in compliance with the License. You may obtain"}],"source_content_type":"text/x-python","patch_set":8,"id":"bacf61ea_c431a1ee","line":1,"in_reply_to":"dada55a8_447b32f5","updated":"2016-07-27 22:34:36.000000000","message":"Code was based on the password.py module:\nhttps://github.com/openstack/keystone/blob/master/keystone/auth/plugins/password.py#L1\n\nWill update.","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"b04acc59315eab98aef754de7f5989136bec8706","unresolved":false,"context_lines":[{"line_number":48,"context_line":"@dependency.requires(\u0027credential_api\u0027)"},{"line_number":49,"context_line":"class PasswordTOTP(base.AuthMethodHandler):"},{"line_number":50,"context_line":""},{"line_number":51,"context_line":"    def authenticate(self, request, auth_payload, auth_context):"},{"line_number":52,"context_line":"        \"\"\"Try to authenticate against the identity backend and with TOTP.\"\"\""},{"line_number":53,"context_line":"        user_info \u003d plugins.UserAuthInfo.create(auth_payload, METHOD_NAME)"},{"line_number":54,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"dada55a8_04801a8a","line":51,"updated":"2016-07-27 13:21:51.000000000","message":"Is there any possibility of sharing more code?","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"d6444c431479fa1022b7c1b29bf4bad5bbec75e1","unresolved":false,"context_lines":[{"line_number":48,"context_line":"@dependency.requires(\u0027credential_api\u0027)"},{"line_number":49,"context_line":"class PasswordTOTP(base.AuthMethodHandler):"},{"line_number":50,"context_line":""},{"line_number":51,"context_line":"    def authenticate(self, request, auth_payload, auth_context):"},{"line_number":52,"context_line":"        \"\"\"Try to authenticate against the identity backend and with TOTP.\"\"\""},{"line_number":53,"context_line":"        user_info \u003d plugins.UserAuthInfo.create(auth_payload, METHOD_NAME)"},{"line_number":54,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"bacf61ea_b569358e","line":51,"in_reply_to":"bacf61ea_e46ca59e","updated":"2016-07-27 23:53:53.000000000","message":"It just seems like it would be nice for this to use the original Password plugin and the TOTP plugin instead of copying the code.... not sure if it\u0027s worth it, but wanted to bring it up.","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":10420,"name":"Adrian Turjak","email":"devs+openstack@uncaught-exceptions.com","username":"adriant"},"change_message_id":"4d2dfb0460dc09d88771d45b03fbffdc0fee2943","unresolved":false,"context_lines":[{"line_number":48,"context_line":"@dependency.requires(\u0027credential_api\u0027)"},{"line_number":49,"context_line":"class PasswordTOTP(base.AuthMethodHandler):"},{"line_number":50,"context_line":""},{"line_number":51,"context_line":"    def authenticate(self, request, auth_payload, auth_context):"},{"line_number":52,"context_line":"        \"\"\"Try to authenticate against the identity backend and with TOTP.\"\"\""},{"line_number":53,"context_line":"        user_info \u003d plugins.UserAuthInfo.create(auth_payload, METHOD_NAME)"},{"line_number":54,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"bacf61ea_e46ca59e","line":51,"in_reply_to":"dada55a8_04801a8a","updated":"2016-07-27 22:34:36.000000000","message":"with the other totp or password modules? Possibly the \"for credential in credentials:\" loop by breaking it into a function, but that just makes the code less clear without saving much on duplication.","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"b04acc59315eab98aef754de7f5989136bec8706","unresolved":false,"context_lines":[{"line_number":62,"context_line":"                self.identity_api.authenticate("},{"line_number":63,"context_line":"                    request,"},{"line_number":64,"context_line":"                    user_id\u003duser_info.user_id,"},{"line_number":65,"context_line":"                    password\u003duser_info.password[:-6])"},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"                valid_passcode \u003d False"},{"line_number":68,"context_line":"                auth_passcode \u003d user_info.password[-6:]"}],"source_content_type":"text/x-python","patch_set":8,"id":"dada55a8_a4866eb6","line":65,"updated":"2016-07-27 13:21:51.000000000","message":"The 6 needs to be configurable. Not all totp systems use 6 digits do they? I think the original code got this wrong.","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"d6444c431479fa1022b7c1b29bf4bad5bbec75e1","unresolved":false,"context_lines":[{"line_number":62,"context_line":"                self.identity_api.authenticate("},{"line_number":63,"context_line":"                    request,"},{"line_number":64,"context_line":"                    user_id\u003duser_info.user_id,"},{"line_number":65,"context_line":"                    password\u003duser_info.password[:-6])"},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"                valid_passcode \u003d False"},{"line_number":68,"context_line":"                auth_passcode \u003d user_info.password[-6:]"}],"source_content_type":"text/x-python","patch_set":8,"id":"bacf61ea_155e41e9","line":65,"in_reply_to":"bacf61ea_e455c5c6","updated":"2016-07-27 23:53:53.000000000","message":"I\u0027m OK with this being in a follow up.","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":10420,"name":"Adrian Turjak","email":"devs+openstack@uncaught-exceptions.com","username":"adriant"},"change_message_id":"4d2dfb0460dc09d88771d45b03fbffdc0fee2943","unresolved":false,"context_lines":[{"line_number":62,"context_line":"                self.identity_api.authenticate("},{"line_number":63,"context_line":"                    request,"},{"line_number":64,"context_line":"                    user_id\u003duser_info.user_id,"},{"line_number":65,"context_line":"                    password\u003duser_info.password[:-6])"},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"                valid_passcode \u003d False"},{"line_number":68,"context_line":"                auth_passcode \u003d user_info.password[-6:]"}],"source_content_type":"text/x-python","patch_set":8,"id":"bacf61ea_e455c5c6","line":65,"in_reply_to":"dada55a8_a4866eb6","updated":"2016-07-27 22:34:36.000000000","message":"6 seems to be the accepted default for totp across almost all devices and applications at present. Google Autheticator only does 6 digits:\nhttps://github.com/google/google-authenticator/wiki/Key-Uri-Format#digits\n\nMaybe we can do a follow up patch in future that changes both this an the other totp module to have it configurable?","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"b04acc59315eab98aef754de7f5989136bec8706","unresolved":false,"context_lines":[{"line_number":81,"context_line":""},{"line_number":82,"context_line":"        for credential in credentials:"},{"line_number":83,"context_line":"            try:"},{"line_number":84,"context_line":"                generated_passcode \u003d totp._generate_totp_passcode("},{"line_number":85,"context_line":"                    credential[\u0027blob\u0027])"},{"line_number":86,"context_line":"                if auth_passcode \u003d\u003d generated_passcode:"},{"line_number":87,"context_line":"                    valid_passcode \u003d True"}],"source_content_type":"text/x-python","patch_set":8,"id":"dada55a8_18e19e2a","line":84,"updated":"2016-07-27 13:21:51.000000000","message":"If you are going to reuse _generate_totp_passcode then you should rename it. The leading underscore implies it\u0027s private.","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":10420,"name":"Adrian Turjak","email":"devs+openstack@uncaught-exceptions.com","username":"adriant"},"change_message_id":"4d2dfb0460dc09d88771d45b03fbffdc0fee2943","unresolved":false,"context_lines":[{"line_number":81,"context_line":""},{"line_number":82,"context_line":"        for credential in credentials:"},{"line_number":83,"context_line":"            try:"},{"line_number":84,"context_line":"                generated_passcode \u003d totp._generate_totp_passcode("},{"line_number":85,"context_line":"                    credential[\u0027blob\u0027])"},{"line_number":86,"context_line":"                if auth_passcode \u003d\u003d generated_passcode:"},{"line_number":87,"context_line":"                    valid_passcode \u003d True"}],"source_content_type":"text/x-python","patch_set":8,"id":"bacf61ea_a472ad7a","line":84,"in_reply_to":"dada55a8_18e19e2a","updated":"2016-07-27 22:34:36.000000000","message":"Done","commit_id":"032f516a0f53fa695aec60dca995eb4a90d1af8d"},{"author":{"_account_id":1916,"name":"Guang Yee","email":"gyee@suse.com","username":"guang-yee"},"change_message_id":"065e7f5423f035e5136124a150e3a6a5700101e1","unresolved":false,"context_lines":[{"line_number":64,"context_line":"                    user_id\u003duser_info.user_id,"},{"line_number":65,"context_line":"                    password\u003duser_info.password[:-6])"},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"                valid_passcode \u003d False"},{"line_number":68,"context_line":"                auth_passcode \u003d user_info.password[-6:]"},{"line_number":69,"context_line":"            else:"},{"line_number":70,"context_line":"                # If the user has no TOTP credentials, skip TOTP."}],"source_content_type":"text/x-python","patch_set":11,"id":"bacf61ea_78f8144a","line":67,"range":{"start_line":67,"start_character":16,"end_line":67,"end_character":30},"updated":"2016-07-29 00:44:11.000000000","message":"no need for this, just raise an exception if passcode doesn\u0027t match","commit_id":"897369cf739a02c6f74bdc93e4eae4ef76ddf574"},{"author":{"_account_id":10420,"name":"Adrian Turjak","email":"devs+openstack@uncaught-exceptions.com","username":"adriant"},"change_message_id":"640818bdf524be60039de93df3742468027de166","unresolved":false,"context_lines":[{"line_number":64,"context_line":"                    user_id\u003duser_info.user_id,"},{"line_number":65,"context_line":"                    password\u003duser_info.password[:-6])"},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"                valid_passcode \u003d False"},{"line_number":68,"context_line":"                auth_passcode \u003d user_info.password[-6:]"},{"line_number":69,"context_line":"            else:"},{"line_number":70,"context_line":"                # If the user has no TOTP credentials, skip TOTP."}],"source_content_type":"text/x-python","patch_set":11,"id":"bacf61ea_003cfa2d","line":67,"range":{"start_line":67,"start_character":16,"end_line":67,"end_character":30},"in_reply_to":"bacf61ea_53e891e2","updated":"2016-07-29 06:57:16.000000000","message":"An exception is raised at L96, after the loop at L82.\n\nWe need the value as a flag since we can\u0027t throw an exception in the loop as a user can have multiple totp values and just one of those needs to be valid. This functionality is based on the other totp module.","commit_id":"897369cf739a02c6f74bdc93e4eae4ef76ddf574"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"436730b2da2a43617f4c79da5f82c225ecaf5803","unresolved":false,"context_lines":[{"line_number":64,"context_line":"                    user_id\u003duser_info.user_id,"},{"line_number":65,"context_line":"                    password\u003duser_info.password[:-6])"},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"                valid_passcode \u003d False"},{"line_number":68,"context_line":"                auth_passcode \u003d user_info.password[-6:]"},{"line_number":69,"context_line":"            else:"},{"line_number":70,"context_line":"                # If the user has no TOTP credentials, skip TOTP."}],"source_content_type":"text/x-python","patch_set":11,"id":"bacf61ea_53e891e2","line":67,"range":{"start_line":67,"start_character":16,"end_line":67,"end_character":30},"in_reply_to":"bacf61ea_78f8144a","updated":"2016-07-29 02:21:44.000000000","message":"++","commit_id":"897369cf739a02c6f74bdc93e4eae4ef76ddf574"},{"author":{"_account_id":1916,"name":"Guang Yee","email":"gyee@suse.com","username":"guang-yee"},"change_message_id":"065e7f5423f035e5136124a150e3a6a5700101e1","unresolved":false,"context_lines":[{"line_number":65,"context_line":"                    password\u003duser_info.password[:-6])"},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"                valid_passcode \u003d False"},{"line_number":68,"context_line":"                auth_passcode \u003d user_info.password[-6:]"},{"line_number":69,"context_line":"            else:"},{"line_number":70,"context_line":"                # If the user has no TOTP credentials, skip TOTP."},{"line_number":71,"context_line":"                self.identity_api.authenticate("}],"source_content_type":"text/x-python","patch_set":11,"id":"bacf61ea_98e6a8b2","line":68,"range":{"start_line":68,"start_character":16,"end_line":68,"end_character":55},"updated":"2016-07-29 00:44:11.000000000","message":"suggest moving this up to line 61 and use auth_passcode throughout","commit_id":"897369cf739a02c6f74bdc93e4eae4ef76ddf574"},{"author":{"_account_id":10420,"name":"Adrian Turjak","email":"devs+openstack@uncaught-exceptions.com","username":"adriant"},"change_message_id":"640818bdf524be60039de93df3742468027de166","unresolved":false,"context_lines":[{"line_number":65,"context_line":"                    password\u003duser_info.password[:-6])"},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"                valid_passcode \u003d False"},{"line_number":68,"context_line":"                auth_passcode \u003d user_info.password[-6:]"},{"line_number":69,"context_line":"            else:"},{"line_number":70,"context_line":"                # If the user has no TOTP credentials, skip TOTP."},{"line_number":71,"context_line":"                self.identity_api.authenticate("}],"source_content_type":"text/x-python","patch_set":11,"id":"bacf61ea_e0360651","line":68,"range":{"start_line":68,"start_character":16,"end_line":68,"end_character":55},"in_reply_to":"bacf61ea_13de193f","updated":"2016-07-29 06:57:16.000000000","message":"I\u0027m not sure what you mean by this. What does moving it to line 61 achieve?\nMaybe to make the following clearer?:\n\n\nif credentials:\n    password \u003d user_info.password[:-6]\n    auth_passcode \u003d user_info.password[-6:]\n    \n    self.identity_api.authenticate(\n        request, user_id\u003duser_info.user_id,\n        password\u003dpassword)\n\n    valid_passcode \u003d False\nelse:\n\n\nI have it below the authenticate as it isn\u0027t worth setting unless the authenticate passes.","commit_id":"897369cf739a02c6f74bdc93e4eae4ef76ddf574"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"436730b2da2a43617f4c79da5f82c225ecaf5803","unresolved":false,"context_lines":[{"line_number":65,"context_line":"                    password\u003duser_info.password[:-6])"},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"                valid_passcode \u003d False"},{"line_number":68,"context_line":"                auth_passcode \u003d user_info.password[-6:]"},{"line_number":69,"context_line":"            else:"},{"line_number":70,"context_line":"                # If the user has no TOTP credentials, skip TOTP."},{"line_number":71,"context_line":"                self.identity_api.authenticate("}],"source_content_type":"text/x-python","patch_set":11,"id":"bacf61ea_13de193f","line":68,"range":{"start_line":68,"start_character":16,"end_line":68,"end_character":55},"in_reply_to":"bacf61ea_98e6a8b2","updated":"2016-07-29 02:21:44.000000000","message":"++","commit_id":"897369cf739a02c6f74bdc93e4eae4ef76ddf574"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"436730b2da2a43617f4c79da5f82c225ecaf5803","unresolved":false,"context_lines":[{"line_number":95,"context_line":""},{"line_number":96,"context_line":"        if not valid_passcode:"},{"line_number":97,"context_line":"            # authentication failed because of invalid passcode"},{"line_number":98,"context_line":"            msg \u003d _(\u0027Invalid TOTP passcode\u0027)"},{"line_number":99,"context_line":"            raise exception.Unauthorized(msg)"},{"line_number":100,"context_line":""},{"line_number":101,"context_line":"        auth_context[\u0027user_id\u0027] \u003d user_info.user_id"}],"source_content_type":"text/x-python","patch_set":11,"id":"bacf61ea_339fdd51","line":98,"updated":"2016-07-29 02:21:44.000000000","message":"Do we want to make a distinction between invalid username/password and invalid passcode?","commit_id":"897369cf739a02c6f74bdc93e4eae4ef76ddf574"},{"author":{"_account_id":10420,"name":"Adrian Turjak","email":"devs+openstack@uncaught-exceptions.com","username":"adriant"},"change_message_id":"640818bdf524be60039de93df3742468027de166","unresolved":false,"context_lines":[{"line_number":95,"context_line":""},{"line_number":96,"context_line":"        if not valid_passcode:"},{"line_number":97,"context_line":"            # authentication failed because of invalid passcode"},{"line_number":98,"context_line":"            msg \u003d _(\u0027Invalid TOTP passcode\u0027)"},{"line_number":99,"context_line":"            raise exception.Unauthorized(msg)"},{"line_number":100,"context_line":""},{"line_number":101,"context_line":"        auth_context[\u0027user_id\u0027] \u003d user_info.user_id"}],"source_content_type":"text/x-python","patch_set":11,"id":"bacf61ea_a07a4eef","line":98,"in_reply_to":"bacf61ea_339fdd51","updated":"2016-07-29 06:57:16.000000000","message":"I don\u0027t think we lose anything by doing so, and it helps keep things clearer. Better UX, easier to debug.","commit_id":"897369cf739a02c6f74bdc93e4eae4ef76ddf574"},{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"59fac7b7a20434d4b719904a46c4e5fd61353303","unresolved":false,"context_lines":[{"line_number":1,"context_line":"# Copyright 2013 OpenStack Foundation"},{"line_number":2,"context_line":"#"},{"line_number":3,"context_line":"# Licensed under the Apache License, Version 2.0 (the \"License\"); you may"},{"line_number":4,"context_line":"# not use this file except in compliance with the License. You may obtain"}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5da102_4290b843","line":1,"range":{"start_line":1,"start_character":0,"end_line":1,"end_character":37},"updated":"2016-11-01 01:57:29.000000000","message":"remove this since you dont work for the foundation","commit_id":"cd4c09c4ed47b4bde601c42a6a6168d7ead5a9f9"},{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"59fac7b7a20434d4b719904a46c4e5fd61353303","unresolved":false,"context_lines":[{"line_number":12,"context_line":"# License for the specific language governing permissions and limitations"},{"line_number":13,"context_line":"# under the License."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"\"\"\"Password and Time-based One-time Password Algorithm (TOTP) auth plugin."},{"line_number":16,"context_line":""},{"line_number":17,"context_line":"The goal of this plugin is to combine username/password with a TOTP passcode"},{"line_number":18,"context_line":"as a 2-factor solution when a TOTP credential is present for a given user."}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5da102_a2b434d1","line":15,"range":{"start_line":15,"start_character":45,"end_line":15,"end_character":61},"updated":"2016-11-01 01:57:29.000000000","message":"nit: (TOTP) Algorithm","commit_id":"cd4c09c4ed47b4bde601c42a6a6168d7ead5a9f9"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"babd7229bfdb043358c5babdb404e249b3eff491","unresolved":false,"context_lines":[{"line_number":44,"context_line":"LOG \u003d log.getLogger(__name__)"},{"line_number":45,"context_line":""},{"line_number":46,"context_line":""},{"line_number":47,"context_line":"@dependency.requires(\u0027identity_api\u0027)"},{"line_number":48,"context_line":"@dependency.requires(\u0027credential_api\u0027)"},{"line_number":49,"context_line":"class PasswordTOTP(base.AuthMethodHandler):"},{"line_number":50,"context_line":""}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5da102_d26721e7","line":47,"updated":"2016-11-01 15:07:31.000000000","message":"@dependency.requires(\u0027credential_api\u0027, \u0027identity_api\u0027)","commit_id":"cd4c09c4ed47b4bde601c42a6a6168d7ead5a9f9"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"babd7229bfdb043358c5babdb404e249b3eff491","unresolved":false,"context_lines":[{"line_number":62,"context_line":"                self.identity_api.authenticate("},{"line_number":63,"context_line":"                    request,"},{"line_number":64,"context_line":"                    user_id\u003duser_info.user_id,"},{"line_number":65,"context_line":"                    password\u003duser_info.password[:-6])"},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"                valid_passcode \u003d False"},{"line_number":68,"context_line":"                auth_passcode \u003d user_info.password[-6:]"}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5da102_929cc95e","line":65,"updated":"2016-11-01 15:07:31.000000000","message":"If we were to take out the hard coded 6 you could do somthing like this before the authenticate call:\n\npossible_passwords \u003d []\nfor c in credentials:\n    generated_passcode \u003d ...\n    if user_info.password[:-len(generate_passcode)] \u003d\u003d generated_passcode:\n        possible_passwords.append(...)\n\nAnd then later to to auth for each possible password to see if any match.","commit_id":"cd4c09c4ed47b4bde601c42a6a6168d7ead5a9f9"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"babd7229bfdb043358c5babdb404e249b3eff491","unresolved":false,"context_lines":[{"line_number":68,"context_line":"                auth_passcode \u003d user_info.password[-6:]"},{"line_number":69,"context_line":"            else:"},{"line_number":70,"context_line":"                # If the user has no TOTP credentials, skip TOTP."},{"line_number":71,"context_line":"                self.identity_api.authenticate("},{"line_number":72,"context_line":"                    request,"},{"line_number":73,"context_line":"                    user_id\u003duser_info.user_id,"},{"line_number":74,"context_line":"                    password\u003duser_info.password)"}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5da102_b2cc6d6b","line":71,"updated":"2016-11-01 15:07:31.000000000","message":"The code can be factored more so the .authenticate() call only appears once in code.","commit_id":"cd4c09c4ed47b4bde601c42a6a6168d7ead5a9f9"},{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"7f2cb30995913821a5028c77901e077426026da9","unresolved":false,"context_lines":[{"line_number":41,"context_line":""},{"line_number":42,"context_line":"LOG \u003d log.getLogger(__name__)"},{"line_number":43,"context_line":""},{"line_number":44,"context_line":"PASSCODE_LENGTH \u003d 6"},{"line_number":45,"context_line":""},{"line_number":46,"context_line":""},{"line_number":47,"context_line":"@dependency.requires(\u0027credential_api\u0027, \u0027identity_api\u0027)"}],"source_content_type":"text/x-python","patch_set":14,"id":"ba5da102_575e9112","line":44,"range":{"start_line":44,"start_character":0,"end_line":44,"end_character":19},"updated":"2016-11-02 00:16:50.000000000","message":"do we want to bikeshed over whether this should be a config option or not?","commit_id":"812bcd4251556f30bb993e616233e70330c55679"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"c5ec3e69ec8cb8e44cccec814595eb83d65cd3d4","unresolved":false,"context_lines":[{"line_number":41,"context_line":""},{"line_number":42,"context_line":"LOG \u003d log.getLogger(__name__)"},{"line_number":43,"context_line":""},{"line_number":44,"context_line":"PASSCODE_LENGTH \u003d 6"},{"line_number":45,"context_line":""},{"line_number":46,"context_line":""},{"line_number":47,"context_line":"@dependency.requires(\u0027credential_api\u0027, \u0027identity_api\u0027)"}],"source_content_type":"text/x-python","patch_set":14,"id":"ba5da102_f56f9d28","line":44,"range":{"start_line":44,"start_character":0,"end_line":44,"end_character":19},"in_reply_to":"ba5da102_575e9112","updated":"2016-11-02 03:08:08.000000000","message":"I don\u0027t think it\u0027s a bikeshed. I think we have to ask ourselves what we want to support, draw a line in the sand and go. So far I\u0027ve asked that question a few times and so far just crickets. AWS calls out what they support for MFA and I think we should do the same.","commit_id":"812bcd4251556f30bb993e616233e70330c55679"},{"author":{"_account_id":10420,"name":"Adrian Turjak","email":"devs+openstack@uncaught-exceptions.com","username":"adriant"},"change_message_id":"f8bed21c7b5116e91c75243608e66a2be3c04243","unresolved":false,"context_lines":[{"line_number":41,"context_line":""},{"line_number":42,"context_line":"LOG \u003d log.getLogger(__name__)"},{"line_number":43,"context_line":""},{"line_number":44,"context_line":"PASSCODE_LENGTH \u003d 6"},{"line_number":45,"context_line":""},{"line_number":46,"context_line":""},{"line_number":47,"context_line":"@dependency.requires(\u0027credential_api\u0027, \u0027identity_api\u0027)"}],"source_content_type":"text/x-python","patch_set":14,"id":"ba5da102_953821f1","line":44,"range":{"start_line":44,"start_character":0,"end_line":44,"end_character":19},"in_reply_to":"ba5da102_f56f9d28","updated":"2016-11-02 03:20:50.000000000","message":"Seeing as the majority is doing 6 digits for 30sec, we may as well just stick with it, and if anyone cares beyond that they can submit a blueprint/patch. No one seems to be vehemently against it, or for it.","commit_id":"812bcd4251556f30bb993e616233e70330c55679"}],"keystone/tests/unit/test_v3_auth.py":[{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"436730b2da2a43617f4c79da5f82c225ecaf5803","unresolved":false,"context_lines":[{"line_number":5078,"context_line":"        self.assertTrue(reg.match(passcode))"},{"line_number":5079,"context_line":""},{"line_number":5080,"context_line":""},{"line_number":5081,"context_line":"class TestAuthPasswordTOTP(test_v3.RestfulTestCase, TokenAPITests):"},{"line_number":5082,"context_line":"    # NOTE(adriant): We extend TokenAPITests to ensure the Token API"},{"line_number":5083,"context_line":"    # still works fully as expected with password_totp exactly as it"},{"line_number":5084,"context_line":"    # would with default password auth."}],"source_content_type":"text/x-python","patch_set":11,"id":"bacf61ea_8ebf82fa","line":5081,"updated":"2016-07-29 02:21:44.000000000","message":"I\u0027m still not a fan of using TokenAPITests here because it makes it really hard to see if all the cases we care about are tested. I may try to cut this down to a smaller set of more focused tests in a followup review.","commit_id":"897369cf739a02c6f74bdc93e4eae4ef76ddf574"},{"author":{"_account_id":10420,"name":"Adrian Turjak","email":"devs+openstack@uncaught-exceptions.com","username":"adriant"},"change_message_id":"640818bdf524be60039de93df3742468027de166","unresolved":false,"context_lines":[{"line_number":5078,"context_line":"        self.assertTrue(reg.match(passcode))"},{"line_number":5079,"context_line":""},{"line_number":5080,"context_line":""},{"line_number":5081,"context_line":"class TestAuthPasswordTOTP(test_v3.RestfulTestCase, TokenAPITests):"},{"line_number":5082,"context_line":"    # NOTE(adriant): We extend TokenAPITests to ensure the Token API"},{"line_number":5083,"context_line":"    # still works fully as expected with password_totp exactly as it"},{"line_number":5084,"context_line":"    # would with default password auth."}],"source_content_type":"text/x-python","patch_set":11,"id":"bacf61ea_4146f4bf","line":5081,"in_reply_to":"bacf61ea_8ebf82fa","updated":"2016-07-29 06:57:16.000000000","message":"I fully agree. It\u0027s just we don\u0027t have a dedicated TestAuthPassword module. So it might be worth making one eventually and subclassing that one instead. \n\nAs it stands TokenAPITests has tests which fail because of conflicts caused when those testcases also change the config settings. Hence why those tests are overridden and skipped in this class.","commit_id":"897369cf739a02c6f74bdc93e4eae4ef76ddf574"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"babd7229bfdb043358c5babdb404e249b3eff491","unresolved":false,"context_lines":[{"line_number":5386,"context_line":"        self.v3_create_token(auth_data, expected_status\u003dhttp_client.CREATED)"},{"line_number":5387,"context_line":""},{"line_number":5388,"context_line":"    def test_bind_not_set_with_remote_user(self):"},{"line_number":5389,"context_line":"        self.skipTest(\"skipping test due to config update mismatch.\")"},{"line_number":5390,"context_line":""},{"line_number":5391,"context_line":"    def test_auth_with_bind_token(self):"},{"line_number":5392,"context_line":"        self.skipTest(\"skipping test due to config update mismatch.\")"}],"source_content_type":"text/x-python","patch_set":13,"id":"ba5da102_528071c0","line":5389,"updated":"2016-11-01 15:07:31.000000000","message":"What is a \u0027config update mismatch\u0027?","commit_id":"cd4c09c4ed47b4bde601c42a6a6168d7ead5a9f9"}]}
