How to customize a new password hash algorithm (bcrypt)?

117 views
Skip to first unread message

Ray (a.k.a. Iceberg)

unread,
Sep 4, 2013, 3:39:53 PM9/4/13
to web2py-d...@googlegroups.com
Hi folks,

I've developed a restful api using http basic authentication. Everything works fine, until now I need to migrate some user accounts from an legacy system. That system uses bcrypt as password hash.

First I thought I could follow instructions here (http://web2py.com/books/default/chapter/29/09/access-control#Other-login-methods-and-login-forms) to use a gateway service for authentication.

    auth.settings.login_methods.append(
        basic_auth('https://basic.gateway.old_system.com'))

And then if I login via login-form, it partially works, except the password is not saved in my db.
And when I tried my api via http basic authentication,
it generates error ticket whenever I access auth.user_id in my source code
(because auth.user is a string rather than an object after auth.login_bare()



Now I wonder if it would be easier to dump the bcrypt hash into my db, but then how can I tweak web2py to use those bcrypt hash to authenticate?

FYI: one of the bcrypt password looks like this: $2a$10$hpnU4WpdzMgOCR/qVD1I5OHip3HXh8n5.EwIrPg7Y7sHK9XMsIGDq

Regards,
Ray

Michele Comitini

unread,
Sep 4, 2013, 4:51:56 PM9/4/13
to web2py-developers
Hi Ray,
The problem is that bcrypt is not supported in web2py. It can be added but requires a little modification to the authentication code in web2py itself.

Back to your first try:

#in the model:
auth.settings.update_fields=True


#in the controller
#after successful login
user_logged = db.auth_user(username=auth.user)
password_hash = user_logged.password

Now password_hash contains a pbkdf2 hashed password.  That same hash is stored in the database in the user record.
Now your users will be authenticated locally by web2py.  So you actually have the new password hash stored within local database.






2013/9/4 Ray (a.k.a. Iceberg) <ice...@qq.com>

--
-- mail from:GoogleGroups "web2py-developers" mailing list
make speech: web2py-d...@googlegroups.com
unsubscribe: web2py-develop...@googlegroups.com
details : http://groups.google.com/group/web2py-developers
the project: http://code.google.com/p/web2py/
official : http://www.web2py.com/
---
You received this message because you are subscribed to the Google Groups "web2py-developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to web2py-develop...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Ray (a.k.a. Iceberg)

unread,
Sep 5, 2013, 10:53:54 AM9/5/13
to web2py-d...@googlegroups.com
Thanks for trying to help, mcm. Unfortunately it doesn't seem to work either. On the one hand auth.settings.update_fields should be a list rather than a boolean, on the other hand I encounter same ticket even after I set auth.settings.update_fields=['password']

I am still seeking work around or something.

Regards,
Ray

Ray (a.k.a. Iceberg)

unread,
Sep 5, 2013, 12:38:54 PM9/5/13
to web2py-d...@googlegroups.com
Looks like I made it. Not really a patch for kernel, just my dirty hack as a workaround.

In db.py, change this line:

    auth = Auth(db, hmac_key=Auth.get_or_create_key())

into:

class MyAuth(Auth):
    # auto-record-new-password feature did not work when auth.settings.login_methods.append(basic_auth(...))
    def login_bare(self, username, password):
        ret = Auth.login_bare(self, username, password)  # Unless user exists and contains password, this calls 3rd authen method and returns a string
        if ret and isinstance(ret, str):  # Gonna fix it otherwise future auth.user_id results in error ticket
            ret = self.user = self.get_or_create_user({  # This function updates current record too
                "username": username,
                "password": self.settings.table_user[self.settings.password_field].validate(password)[0],  # hash it
                }, update_fields=['password'])  # A dirty hack, for web2py 2.5.1
        return ret
auth = MyAuth(db, hmac_key=Auth.get_or_create_key())
Reply all
Reply to author
Forward
0 new messages