Massimo,

If you are concern about possible backward compatibility issue that this
change could raise... Maybe we could find a way to let the ldap_auth return
validator error to form (to user)... I could live with that too... I just
didn't find a easy way to make it works from ldap_auth (mean a lot of
refactoring could be required and I don't want to screw up ldap_auth for
others, I am not equiped to test it properly over different ldap
implementation). I just have to change a single line in tools.py + add a
IS_NOT_EMAIL() validator, that was the easiest...

:)

Richard


On Tue, Aug 13, 2013 at 10:19 AM, Richard Vézina <
[email protected]> wrote:

> No problem!
>
> As long as there is a solution in the next version I will be happy...
> Curious to know what is bugging you though, adding a new validator? Maybe
> the IS_MAIL() could be hack in order that it usage could be reversed,
> something like this : IS_MAIL(..., complement=True), then it will return
> true if the string is not a email... So don't need a new validator.
>
> Richard
>
>
>
>
> On Tue, Aug 13, 2013 at 10:04 AM, Massimo Di Pierro <
> [email protected]> wrote:
>
>> I need to review this. I understand the problem but I am not convinced by
>> the solution. I will need one week.
>>
>>
>> On Monday, 12 August 2013 08:46:31 UTC-5, Richard wrote:
>>
>>> UP!
>>>
>>>
>>>
>>> On Fri, Aug 9, 2013 at 10:59 AM, Richard Vézina 
>>> <[email protected]>wrote:
>>>
>>>> Here the patch!!
>>>>
>>>> I have not been able to use the IS_NOT_EMAIL() validator from
>>>> validators.py didn't understand how validators are import in tools.py...
>>>>
>>>> NOTE :
>>>> About my precedent mail... the "auth_table.username.requires =
>>>> IS_NOT_IN_DB(db, auth_table.username" from the book is not require if the
>>>> user use the "auth.define_tables(username=**True)" and the recommended
>>>> auth_tables customization mechanism. So, I think the book should be revised
>>>> this way :
>>>>
>>>> "In case you use old style customizing auth_tables. Make sure your
>>>> username field definition looks like that :
>>>>  Field('username', 'string',
>>>>           notnull=True,
>>>>           required=True,
>>>>            requires=[IS_NOT_EMPTY(error_**message=T(auth.messages.is_**
>>>> empty)),
>>>>                     IS_NOT_IN_DB(db, 'auth_user.username'),
>>>> IS_NOT_EMAIL()]
>>>>           ),
>>>>
>>>> Where you make sure you use these validators in order to make sure
>>>> email is not used as username and there is no duplicated username in your
>>>> auth_user table."
>>>>
>>>> :)
>>>>
>>>> Richard
>>>>
>>>>
>>>>
>>>>
>>>> On Wed, Aug 7, 2013 at 1:48 PM, Richard Vézina 
>>>> <[email protected]>wrote:
>>>>
>>>>> I would also add this :
>>>>>
>>>>> tmpvalidator = [IS_NOT_EMPTY(error_message=se**lf.messages.is_empty), 
>>>>> IS_NOT_IN_DB(db,
>>>>> 'auth_user.username'), IS_NOT_EMAIL()]
>>>>>
>>>>> Since this line in the book :
>>>>>
>>>>> auth_table.username.requires = IS_NOT_IN_DB(db, auth_table.username)
>>>>>
>>>>>
>>>>> Doesn't seem to works and could be erase since who want a duplicated
>>>>> username in his auth_user??
>>>>>
>>>>>
>>>>> Richard
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> On Wed, Aug 7, 2013 at 1:35 PM, Richard Vézina 
>>>>> <[email protected]>wrote:
>>>>>
>>>>>>  Better then that I think :
>>>>>>
>>>>>> In gluon/tools.py in Auth login() near line 2006 :
>>>>>>
>>>>>> Replace :
>>>>>> tmpvalidator = IS_NOT_EMPTY(error_message=**self.messages.is_empty)
>>>>>>
>>>>>> With :
>>>>>>         if 'username' in table_user.fields or \
>>>>>>                 not self.settings.login_email_**validate:
>>>>>>             tmpvalidator = 
>>>>>> [IS_NOT_EMPTY(error_message=**self.messages.is_empty),
>>>>>> IS_NOT_EMAIL()]
>>>>>>
>>>>>> Will require to add this new validator though :
>>>>>>
>>>>>> class IS_NOT_EMAIL:
>>>>>>     def __init__(self, error_message='You can\'t use email as
>>>>>> username'):
>>>>>>         self.e = error_message
>>>>>>     def __call__(self, value):
>>>>>>         if not IS_EMAIL()(value)[1]:
>>>>>>             return (value, self.e)
>>>>>>         return (value, None)
>>>>>>
>>>>>> What you think about that??
>>>>>>
>>>>>> Richard
>>>>>>
>>>>>>
>>>>>> On Wed, Aug 7, 2013 at 1:23 PM, Richard Vézina <[email protected]
>>>>>> > wrote:
>>>>>>
>>>>>>> from gluon.validators import IS_EMAIL
>>>>>>>
>>>>>>>             if ldap_mode == 'ad':
>>>>>>>                 # Microsoft Active Directory
>>>>>>>                 if IS_EMAIL()(username)[1] is not None:
>>>>>>>                 #if '@' not in username:
>>>>>>>                     domain = []
>>>>>>>                     for x in ldap_basedn.split(','):
>>>>>>>                         if "DC=" in x.upper():
>>>>>>>                             domain.append(x.split('=')[-1]**)
>>>>>>>                     username = "%s@%s" % (username,
>>>>>>> '.'.join(domain))
>>>>>>>                 else:
>>>>>>>                     return False
>>>>>>>                 username_bare = username.split("@")[0]
>>>>>>>
>>>>>>>
>>>>>>> This prevent login to occure and new user to be inserted when email
>>>>>>> is used as username... however it not returning any advise to the 
>>>>>>> user... I
>>>>>>> will try to figure out how to implement validation from ldap_auth and 
>>>>>>> get
>>>>>>> back with a patch.
>>>>>>>
>>>>>>> Richard
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On Wed, Aug 7, 2013 at 10:56 AM, Richard Vézina <
>>>>>>> [email protected]> wrote:
>>>>>>>
>>>>>>>> Ok!
>>>>>>>>
>>>>>>>> :)
>>>>>>>>
>>>>>>>> Richard
>>>>>>>>
>>>>>>>>
>>>>>>>> On Wed, Aug 7, 2013 at 10:10 AM, Massimo Di Pierro <
>>>>>>>> [email protected]> wrote:
>>>>>>>>
>>>>>>>>> Please send me a patch when you test it. ;-)
>>>>>>>>>
>>>>>>>>> On Wednesday, 7 August 2013 07:51:58 UTC-5, Richard wrote:
>>>>>>>>>
>>>>>>>>>> No change... Auth seems to delegate entirely the validation on
>>>>>>>>>> username input field in case ldap_auth is used as authentication 
>>>>>>>>>> method.
>>>>>>>>>>
>>>>>>>>>> I guess this simple refactor (not tested) could do the tricks at
>>>>>>>>>> least for Active directory :
>>>>>>>>>>
>>>>>>>>>>                 if not IS_EMAIL()(username)[1]:
>>>>>>>>>>                     domain = []
>>>>>>>>>>                     for x in ldap_basedn.split(','):
>>>>>>>>>>                         if "DC=" in x.upper():
>>>>>>>>>>                             domain.append(x.split('=')[-1]****)
>>>>>>>>>>                      identifier = "%s@%s" % (username,
>>>>>>>>>> '.'.join(domain))
>>>>>>>>>>                 else: return ERROR...
>>>>>>>>>>                 username_bare = username.split("@")[0]
>>>>>>>>>>
>>>>>>>>>> Richard
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On Wed, Aug 7, 2013 at 8:42 AM, Richard Vézina <
>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>
>>>>>>>>>>> Hello,
>>>>>>>>>>>
>>>>>>>>>>> I was about to post this (I think I answer your question) :
>>>>>>>>>>>
>>>>>>>>>>> Hello,
>>>>>>>>>>>
>>>>>>>>>>> I think I found a flaw in the interaction between Auth and LDAP
>>>>>>>>>>> contrib (web2py 2.4.7).
>>>>>>>>>>>
>>>>>>>>>>> If I set LDAP as unique authentification method
>>>>>>>>>>> (auth.settings.login_methods = LDAP) as written in the book, web2py 
>>>>>>>>>>> should
>>>>>>>>>>> leaves LDAP to create user... The things is web2py Auth seems to 
>>>>>>>>>>> create
>>>>>>>>>>> user even if it LDAP that is responsible of doing it. I mean, I 
>>>>>>>>>>> carefully
>>>>>>>>>>> read the code of LDAP and the only way it could create a new user 
>>>>>>>>>>> is if
>>>>>>>>>>> manage_groups=True by calling do_manage_groups() since the other 
>>>>>>>>>>> place
>>>>>>>>>>> where LDAP is instert new user it set email, first_name and 
>>>>>>>>>>> last_name. In
>>>>>>>>>>> my case, if user use email instead of username (that should not be 
>>>>>>>>>>> email,
>>>>>>>>>>> but I can't enforce this with the custom IS_NOT_EMAIL() validator I 
>>>>>>>>>>> wrote)
>>>>>>>>>>> for login a new user get inserted like this : first_name = email 
>>>>>>>>>>> (or the
>>>>>>>>>>> content of username input that is an email), username = email and
>>>>>>>>>>> registration_id = email. As far as I can see the only way LDAP could
>>>>>>>>>>> produce this result is if the do_manage_groups method is called, 
>>>>>>>>>>> but it
>>>>>>>>>>> can't be call if manage_groups is set to False. So, the only 
>>>>>>>>>>> remaining
>>>>>>>>>>> possibility is that Auth is creating the new user because it 
>>>>>>>>>>> recieve a bad
>>>>>>>>>>> signal from LDAP.
>>>>>>>>>>>
>>>>>>>>>>> I make a couples tests and found that the insert new user base
>>>>>>>>>>> on the credentials of already existing user that log with it email 
>>>>>>>>>>> instead
>>>>>>>>>>> of it username occure at line 2147-2148. So I guess Auth recieve a 
>>>>>>>>>>> True
>>>>>>>>>>> flag from LDAP mean the user exist in directory, since web2py can't 
>>>>>>>>>>> match a
>>>>>>>>>>> existing user base on the wrong username (email) it insert a new 
>>>>>>>>>>> user with
>>>>>>>>>>> wrong setting.
>>>>>>>>>>>
>>>>>>>>>>> The origin of this is multifold. First, I think it could be
>>>>>>>>>>> prevent if there was a IS_NOT_EMAIL() validator on the username 
>>>>>>>>>>> field, for
>>>>>>>>>>> some reason I can't get it to work properly with LDAP because of 
>>>>>>>>>>> the way
>>>>>>>>>>> LDAP is working the validator seems to be skipped, and the username 
>>>>>>>>>>> is
>>>>>>>>>>> first check against directory. Maybe using IS_NOT_EMAIL() inside 
>>>>>>>>>>> ldap_auth
>>>>>>>>>>> contrib could solve this issue. Other possible origin is the way 
>>>>>>>>>>> ldap_auth
>>>>>>>>>>> is written. I mean it seems that for saving a variable "username" is
>>>>>>>>>>> re-used... I think that the issue is coming from line 8 of code 
>>>>>>>>>>> extract
>>>>>>>>>>> below :
>>>>>>>>>>>
>>>>>>>>>>>             if ldap_mode == 'ad':
>>>>>>>>>>>                 # Microsoft Active Directory
>>>>>>>>>>>                 if '@' not in username:
>>>>>>>>>>>                     domain = []
>>>>>>>>>>>                     for x in ldap_basedn.split(','):
>>>>>>>>>>>                         if "DC=" in x.upper():
>>>>>>>>>>>                             domain.append(x.split('=')[-1]****)
>>>>>>>>>>>                      username = "%s@%s" % (username,
>>>>>>>>>>> '.'.join(domain))
>>>>>>>>>>>                 username_bare = username.split("@")[0]
>>>>>>>>>>>                 con.set_option(ldap.OPT_**PROTOC**OL_VERSION, 3)
>>>>>>>>>>>                 # In cases where ForestDnsZones and
>>>>>>>>>>> DomainDnsZones are found,
>>>>>>>>>>>                 # result will look like the following:
>>>>>>>>>>>                 # ['ldap://ForestDnsZones.**domain**
>>>>>>>>>>> .com/DC=ForestDnsZones<http://ForestDnsZones.domain.com/DC=ForestDnsZones>
>>>>>>>>>>> ,
>>>>>>>>>>>                 #    DC=domain,DC=com']
>>>>>>>>>>>                 if ldap_binddn:
>>>>>>>>>>>                     # need to search directory with an admin
>>>>>>>>>>> account 1st
>>>>>>>>>>>                     con.simple_bind_s(ldap_binddn, ldap_bindpw)
>>>>>>>>>>>                 else:
>>>>>>>>>>>                     # credentials should be in the form of
>>>>>>>>>>> [email protected]
>>>>>>>>>>>                     con.simple_bind_s(username, password)
>>>>>>>>>>>                 # this will throw an index error if the account
>>>>>>>>>>> is not found
>>>>>>>>>>>                 # in the ldap_basedn
>>>>>>>>>>>                 requested_attrs = ['sAMAccountName']
>>>>>>>>>>>                 if manage_user:
>>>>>>>>>>>                     requested_attrs.extend([user_**f**
>>>>>>>>>>> irstname_attrib,
>>>>>>>>>>>                                            user_lastname_attrib,
>>>>>>>>>>>                                            user_mail_attrib])
>>>>>>>>>>>                 result = con.search_ext_s(
>>>>>>>>>>>                     ldap_basedn, ldap.SCOPE_SUBTREE,
>>>>>>>>>>>                     "(&(sAMAccountName=%s)(%s))" % (
>>>>>>>>>>>                                 ldap.filter.escape_filter_**char
>>>>>>>>>>> **s(username_bare),
>>>>>>>>>>>                                 filterstr),
>>>>>>>>>>>                     requested_attrs)[0][1]
>>>>>>>>>>>                 if not isinstance(result, dict):
>>>>>>>>>>>                     # result should be a dict in the form
>>>>>>>>>>>                     # {'sAMAccountName': [username_bare]}
>>>>>>>>>>>                     logger.warning('User [%s] not found!' %
>>>>>>>>>>> username)
>>>>>>>>>>>                     return False
>>>>>>>>>>>                 if ldap_binddn:
>>>>>>>>>>>                     # We know the user exists & is in the
>>>>>>>>>>> correct OU
>>>>>>>>>>>                     # so now we just check the password
>>>>>>>>>>>                     con.simple_bind_s(username, password)
>>>>>>>>>>>                 username = username_bare
>>>>>>>>>>>
>>>>>>>>>>> This peace of code is pretty unreliable : It start by
>>>>>>>>>>> re-creating a email and store it in username vars if username it 
>>>>>>>>>>> recieves
>>>>>>>>>>> from web2py is not a email before derive a username_bare from the 
>>>>>>>>>>> altered
>>>>>>>>>>> username var and at the end it finally set username = 
>>>>>>>>>>> username_bare... Why
>>>>>>>>>>> all this just to avoid create a var?!
>>>>>>>>>>>
>>>>>>>>>>> I propose to refator this using creating a new ID or identifier
>>>>>>>>>>> var to store connection "identifier" var instead reusing the 
>>>>>>>>>>> username for
>>>>>>>>>>> that. Then it will require to determine if the IS_NOT_EMAIL() 
>>>>>>>>>>> should go at
>>>>>>>>>>> Auth level or ldap_auth. I don't know so much LDAP in general and 
>>>>>>>>>>> even less
>>>>>>>>>>> the different implementation, so I don't know if some 
>>>>>>>>>>> implementation use
>>>>>>>>>>> email as an identifier or not. Since, the Auth class as mechanism 
>>>>>>>>>>> to create
>>>>>>>>>>> missing user I don't no if it intentional to allow the creation of 
>>>>>>>>>>> user
>>>>>>>>>>> with email as username or not... So, maybe it a option in to use
>>>>>>>>>>> IS_NOT_EMAIL() on username field in this case it will require that
>>>>>>>>>>> IS_NOT_EMAIL be at level of Auth. Maybe, I didn't be able to make 
>>>>>>>>>>> work my
>>>>>>>>>>> custom validator because of the order of validator (I had set 
>>>>>>>>>>> multiple
>>>>>>>>>>> validator on username), I will try to set only IS_NOT_EMAIL and 
>>>>>>>>>>> report here
>>>>>>>>>>> if it solve the problem I have with LDAP authentication.
>>>>>>>>>>>
>>>>>>>>>>> Thanks
>>>>>>>>>>>
>>>>>>>>>>> Richard
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> On Wed, Aug 7, 2013 at 7:22 AM, Massimo Di Pierro <
>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>
>>>>>>>>>>>> How would you change this?
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> On Monday, 5 August 2013 15:42:39 UTC-5, Richard wrote:
>>>>>>>>>>>>
>>>>>>>>>>>>> Hello,
>>>>>>>>>>>>>
>>>>>>>>>>>>> Is there a way to prevent user to log with there email? I set
>>>>>>>>>>>>> LDAP authentication, I create a username field on custom 
>>>>>>>>>>>>> auth_user model
>>>>>>>>>>>>> and set auth.define_tables(username=**Tr****ue)
>>>>>>>>>>>>>
>>>>>>>>>>>>> But I notice that I can still login with [email protected]. In
>>>>>>>>>>>>> this case, ldap_auth create a new user with first_name and 
>>>>>>>>>>>>> username =
>>>>>>>>>>>>> [email protected]
>>>>>>>>>>>>>
>>>>>>>>>>>>> So, I think there is a flaw here in ldap_auth :
>>>>>>>>>>>>>
>>>>>>>>>>>>> if ldap_mode == 'ad':
>>>>>>>>>>>>>                 # Microsoft Active Directory
>>>>>>>>>>>>>                 if '@' not in username:
>>>>>>>>>>>>>                     domain = []
>>>>>>>>>>>>>                     for x in ldap_basedn.split(','):
>>>>>>>>>>>>>                         if "DC=" in x.upper():
>>>>>>>>>>>>>                             domain.append(x.split('=')[-1]****
>>>>>>>>>>>>> **)
>>>>>>>>>>>>>                     username = "%s@%s" % (username,
>>>>>>>>>>>>> '.'.join(domain))
>>>>>>>>>>>>>                 username_bare = username.split("@")[0]
>>>>>>>>>>>>>
>>>>>>>>>>>>> Since it seems to recreate email as username...
>>>>>>>>>>>>>
>>>>>>>>>>>>> Thanks
>>>>>>>>>>>>>
>>>>>>>>>>>>> Richard
>>>>>>>>>>>>>
>>>>>>>>>>>>  --
>>>>>>>>>>>>
>>>>>>>>>>>> ---
>>>>>>>>>>>> You received this message because you are subscribed to the
>>>>>>>>>>>> Google Groups "web2py-users" group.
>>>>>>>>>>>> To unsubscribe from this group and stop receiving emails from
>>>>>>>>>>>> it, send an email to web2py+un...@**googlegroups.com.
>>>>>>>>>>>>
>>>>>>>>>>>> For more options, visit https://groups.google.com/**grou**
>>>>>>>>>>>> ps/opt_out <https://groups.google.com/groups/opt_out>.
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>  --
>>>>>>>>>
>>>>>>>>> ---
>>>>>>>>> You received this message because you are subscribed to the Google
>>>>>>>>> Groups "web2py-users" group.
>>>>>>>>> To unsubscribe from this group and stop receiving emails from it,
>>>>>>>>> send an email to web2py+un...@**googlegroups.com.
>>>>>>>>> For more options, visit 
>>>>>>>>> https://groups.google.com/**groups/opt_out<https://groups.google.com/groups/opt_out>
>>>>>>>>> .
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>  --
>>
>> ---
>> You received this message because you are subscribed to the Google Groups
>> "web2py-users" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to [email protected].
>> For more options, visit https://groups.google.com/groups/opt_out.
>>
>>
>>
>
>

-- 

--- 
You received this message because you are subscribed to the Google Groups 
"web2py-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to