Login username fake ending character

139 views
Skip to first unread message

Bruce Wade

unread,
Mar 29, 2012, 2:09:44 PM3/29/12
to web...@googlegroups.com
Hi,

I need to be able to add a character to the end of a username that can be changed by us. This character is not actually stored in the database for the username however it must be entered for the username to validate.

For example:
username: 0000012 -> is stored in the database

Login with: 0000012 would fail
Login with: 0000012R would succeed

This is a business requirement so even if I don't like this idea I still need to program it. How to make this work with the current login system? Is there a way to capture the form submit before the handler actually processes it, pull the last character if it is valid pass the username without the character to the real login validator?

--
--
Regards,
Bruce Wade
http://ca.linkedin.com/in/brucelwade
http://www.wadecybertech.com
http://www.warplydesigned.com
http://www.fitnessfriendsfinder.com

Marin Pranjić

unread,
Mar 29, 2012, 2:22:43 PM3/29/12
to web...@googlegroups.com
Yes you can capture the form submit.
Instead of:

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

you can do:

def user():
.. #TODO validate submitted username
.. if request.args(0) == 'login' and request.post_vars.username:
.. .. request.post_vars.username = request.vars.username = request.post_vars.username[:-1] # remove last character
.. return dict(form=auth())


Note you should do things before calling auth().

Marin

Bruce Wade

unread,
Mar 29, 2012, 2:35:05 PM3/29/12
to web...@googlegroups.com
Thanks that works exactly how I need it to.

Anthony

unread,
Mar 29, 2012, 3:29:55 PM3/29/12
to web...@googlegroups.com
Maybe something like:

def check_username(form):
   
if not form.vars.username.endswith('R')
        form
.errors.username = 'Invalid username'

auth
.settings.login_onvalidation = [check_username]

Anthony

Anthony

unread,
Mar 29, 2012, 3:34:02 PM3/29/12
to web...@googlegroups.com
def user():
.. #TODO validate submitted username
.. if request.args(0) == 'login' and request.post_vars.username:
.. .. request.post_vars.username = request.vars.username = request.post_vars.username[:-1] # remove last character
.. return dict(form=auth())

That doesn't check whether the last character is correct, so 0000012R would succeed, but so would 0000012X or any character at the end of the username.

Anthony 

Bruce Wade

unread,
Mar 29, 2012, 3:56:08 PM3/29/12
to web...@googlegroups.com
I just used the following because I don't want their login to succeed if they enter no character IE: 0000012 the real username without the character should also fail. 

if request.args(0) == 'login' and request.post_vars.username:
        login_char = request.post_vars.username[-1]
        if login_char == 'R':
            request.post_vars.username = request.vars.username = request.post_vars.username[:-1]    # remove last character
        else:
            request.post_vars.username = request.vars.username = request.post_vars.username + 'X'

Anthony

unread,
Mar 29, 2012, 4:01:48 PM3/29/12
to web...@googlegroups.com
I just used the following because I don't want their login to succeed if they enter no character IE: 0000012 the real username without the character should also fail. 

if request.args(0) == 'login' and request.post_vars.username:
        login_char = request.post_vars.username[-1]
        if login_char == 'R':
            request.post_vars.username = request.vars.username = request.post_vars.username[:-1]    # remove last character
        else:
            request.post_vars.username = request.vars.username = request.post_vars.username + 'X'

Actually, Marin's original solution would already protect against entering the real username without the extra character because it stripped the last character, which would therefore not match the username in the db. The problem was that it would succeed with any extra character at the end, not just with 'R'. Your solution above handles that problem, though I think the onvalidation solution is simpler and more straightforward (and it enables you to emit a custom error message for the particular case where the last character is incorrect if desired).

Anthony
 

Bruce Wade

unread,
Mar 29, 2012, 4:11:13 PM3/29/12
to web...@googlegroups.com
Yes I think you are correct, your solution is cleaner and explains the problem. However the last character would still need to be removed so your solution would need to be changed to:

def check_username(form):
    
if not form.vars.username.endswith('R')
        form
.errors.username = 'Invalid username'
    else:
        form.vars.username = forms.vars.username[:-1]

auth
.settings.login_onvalidation = [check_username]

Or is there a different way to handle that?

Anthony

unread,
Mar 29, 2012, 4:46:44 PM3/29/12
to web...@googlegroups.com
Oops, right. In that case, I would reverse the if/else.

Marin Pranjić

unread,
Mar 29, 2012, 4:55:04 PM3/29/12
to web...@googlegroups.com
Is check_username triggered before or after the database validation? I am not able to check it now.

Marin

Marin Pranjić

unread,
Mar 29, 2012, 5:06:13 PM3/29/12
to web...@googlegroups.com
If i am correct this will not work because it should be:

1. check last character
2. remove last character
3. do db validation

I think onvalidation does db validation and then 1&2.
Db validation will not pass because usernames are stored without last character (as stated in first post).

Not sure if I am right but should be easy to check :)

Marin

Massimo Di Pierro

unread,
Mar 29, 2012, 5:27:40 PM3/29/12
to web...@googlegroups.com
class MyStrangeRequirement(object):
    def __init__(self,s='R',error_message='forgot the R?'):
         self.s=s
         self.error_message = error_message
    def __call__(self,value):
         if not (value and value.endswith(self.s)):
             return (value, self.error_message)
         return value[:-len(self.s)]

db.auth_user.username.requires.insert(0, MyStrangeRequirement())

Anthony

unread,
Mar 29, 2012, 10:28:22 PM3/29/12
to web...@googlegroups.com
If i am correct this will not work because it should be:

1. check last character
2. remove last character
3. do db validation

I think onvalidation does db validation and then 1&2.
Db validation will not pass because usernames are stored without last character (as stated in first post).

The form validation just checks the username field validator, which is temporarily changed to IS_NOT_EMPTY, so it is only checking that a username was submitted. In any case, even the regular username field validator wouldn't check that the submitted value matches what's in the database. The check for matching the submitted username with an existing db username happens after the form processing, so using onvalidation should work.

Anthony 

Bruce Wade

unread,
Mar 30, 2012, 2:29:51 PM3/30/12
to web...@googlegroups.com
Your correct your solution Anthony works.

Massimo, I am not sure I understand what db.auth_user.username.requires.insert(0, MyStrangeRequirement()) is doing?

Bruno Rocha

unread,
Mar 30, 2012, 3:51:33 PM3/30/12
to web...@googlegroups.com
 db.auth_user.username.requires.insert(0, MyStrangeRequirement())

is the same of

 db.auth_user.username.requires = [MyStrangeRequirement(), IS_NOT_EMPTY(), IS_NOT_IN_DB(..)]

MyStrangeRequirement() is your custom validator.

db.table.field.requires is a list of validators, so you can use "insert" method of list.


--

Anthony

unread,
Mar 30, 2012, 3:56:26 PM3/30/12
to web...@googlegroups.com
Your correct your solution Anthony works.

Massimo, I am not sure I understand what db.auth_user.username.requires.insert(0, MyStrangeRequirement()) is doing?

Massimo's solution does the same thing but by creating a custom validator and adding the validator to the "requires" attribute of the "username" field. See http://web2py.com/books/default/chapter/29/7#Custom-validators. A custom validator can be more convenient because once it is added to the field it will automatically be applied to any SQLFORM (you don't have to set an onvalidation function for every SQLFORM), and it will also be applied when records are inserted via the .validate_and_insert() method (onvalidation functions don't apply in that case, as it doesn't involve any form processing). In this case, though, we only want the validation to happen with login, not with other forms or inserts/updates that may include the username field, so a custom validator probably doesn't have any advantage over an onvalidation function in this case.

Anthony

Bruce Wade

unread,
Mar 30, 2012, 4:11:43 PM3/30/12
to web...@googlegroups.com
Yes I agree with this situation it is only on the login. Every other part of the site uses the real username. Thanks for the explanation of Massimo's example Bruno and Anthony.
Reply all
Reply to author
Forward
0 new messages