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]<javascript:>
> > 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_PROTOCOL_VERSION, 3)
>>                 # In cases where ForestDnsZones and DomainDnsZones are 
>> found,
>>                 # result will look like the following:
>>                 # ['ldap://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_firstname_attrib,
>>                                            user_lastname_attrib,
>>                                            user_mail_attrib])
>>                 result = con.search_ext_s(
>>                     ldap_basedn, ldap.SCOPE_SUBTREE,
>>                     "(&(sAMAccountName=%s)(%s))" % (
>>                                 
>> ldap.filter.escape_filter_chars(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]<javascript:>
>> > 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=**True)
>>>>
>>>> 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 [email protected] <javascript:>.
>>> 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