I would also add this : tmpvalidator = [IS_NOT_EMPTY(error_message=self.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_**PROTOCOL_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_**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]> 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/**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.

