Search code examples
passwordsweb2py

web2py check password in form


I am trying to create a change password form in web2py. I am using db.auth_user table. I want to create a form with fields ['current_password', 'new_password', 'repeat_password']

Form should give a warning to user if the password is not entered correctly.

My code is:

request.vars.current_password = request.vars.current_password if request.vars.current_password else 'xxx'

user_password_form = SQLFORM.factory(Field('current_password', 'password', 
                                           requires=IS_EQUAL_TO(db(db.auth_user.id == auth.user_id).select('password').first().password)(
                                                                str(db.auth_user.password.validate(request.vars.current_password)[0]))),
                                     Field('new_password', 'password'),
                                     Field('repeat_password', 'password',
                                           requires=IS_EQUAL_TO(request.vars.new_password,
                                                                'Passwords do not match')))

I have tested the validation for the following code and it sets a=1 if password is entered correctly. But on the form validation I couldn't figure it out how to implement it

if request.vars.current_password:
        if db.auth_user.password.validate(request.vars.current_password)[0] == db(
                        db.auth_user.id == auth.user_id).select('password').first().password:
            a=1

Any ideas how password validation can be achieved?


Solution

  • The web2py Auth system includes a built-in password change action. If you are using the default user action in the default.py controller, you access this form via /myapp/default/user/change_password.

    If you prefer to create a separate controller action just for this purpose, you can simply do:

    def change_password():
        return dict(form=auth.change_password())
    

    and in the associated view:

    {{=form}}
    

    Regarding your custom code, you cannot use the IS_EQUAL_TO validator alone, as it takes an expression that must be equal to the value submitted with the form (you cannot call the validator with a transformed value as you have, as that will return a tuple, but the requires attribute must be a callable object that takes a field and a value).

    Instead, you could use the CRYPT validator followed by the IS_EQUAL_TO validator in a list -- the first validator will transform the submitted password to a hash, and the second will then test for equality with the stored password hash.

    Alternatively, you could use:

    def check_password(password):
        new_hash = db.auth_user.password.validate(password)[0]
        return new_hash == auth.user.password
    
    form = SQLFORM.factory(Field('current_password', 'password')
                                 requires=IS_EXPR(check_password)),
                           ...)
    

    The IS_EXPR validator can take a function that will be passed the value, and the function should return True or False (note, this usage is not documented -- the book only shows the alternative usage, where you provide Python code as a string, which will be exec'ed).