[Grok-dev] Putting together the authentication plugin and a Session. Is that possible?

Hector Blanco white.lists at gmail.com
Tue Jan 4 16:53:26 EST 2011


Thanks!

For the moment I have only a couple of users (just for testing
purposes) but that number will grow when I start wroking for real, and
I'm sure it's good to have the cache implemented over something better
than a regular dict()... I'll definitely keep that in mind!

Thanks for the hint

2011/1/4 Sebastian Ware <sebastian at urbantalk.se>:
> If you intend to store large amounts of users in your cache you might want to use a grok.Container or a simple Btree. Every time you access the dict Zodb will fetch all items when accessing a dict, but only selected ones with a Btree based alternative.
>
> Not sure where the tipping point is for this, but it could be worth considering.
>
> Mvh Sebastian
>
> 4 jan 2011 kl. 00.45 skrev Hector Blanco:
>
>> Hello list...
>>
>> I have "fixed" it putting a very simple "cache" (...erm... ok, ok... a
>> dict() with the shape <userName, User()>, but "cache" sounds better )
>> in the "UserManager" class so if the user is not in the cache, queries
>> the database, but if it is in the dict, return the value from the
>> dict.
>>
>> It seems to work...
>>
>> 2010/12/28 Hector Blanco <white.lists at gmail.com>:
>>> Oh, I see... Actually, that's how I have it done (good to see I wasn't
>>> totally wrong)
>>>
>>> class MySessionCredentialsPlugin(grok.GlobalUtility, SessionCredentialsPlugin):
>>>    grok.provides(ICredentialsPlugin)
>>>    grok.name('credentials')
>>>
>>>    loginpagename = 'login'
>>>    loginfield = 'form.login'
>>>    passwordfield = 'form.hashedPwd'
>>>
>>> ... and ...
>>>
>>> class MyOwnPrincipalInfo(object):
>>>        grok.implements(IPrincipalInfo)
>>>
>>> The issue is that the getAccount() method seems to be called a lot of times
>>>
>>> class UserAuthenticatorPlugin(grok.GlobalUtility):
>>>        grok.provides(IAuthenticatorPlugin)
>>>        grok.name('users')
>>>        grok.context(Server)
>>>
>>>        def getAccount(self, login):
>>>                try:
>>>                        return grok.getSite()["UserManager"].getByName(login, allData=False)
>>>                except Exception, e:
>>>                        log.warn("::UserAuthenticatorPlugin > getAccount > Got exception %s " % e)
>>>                finally:
>>>                        Database.session.close()
>>>
>>>        def authenticateCredentials(self, credentials):
>>>                if isinstance(credentials, dict):
>>>                        if (("login" in credentials) and ("password" in credentials)):
>>>                                user = self.getAccount(credentials['login'])
>>>                                if user and (user.checkPassword(credentials['password'])):
>>>                                        log.debug("::UserAuthenticatorPlugin > authenticateCredentials >
>>>                                                   Credentials authenticated for user %s " % (user.userName))
>>>                                        return MyOwnPrincipalInfo.MyOwnPrincipalInfo(user)
>>>                return None
>>>
>>> And I don't know how to avoid that...
>>>
>>> For other views, I understand I can use the [self].request.principal.
>>> For instance:
>>>
>>> class OtherPage(grok.View):
>>>        grok.context(Server)
>>>        grok.require('server.ViewSite')
>>>
>>>        def update(self):
>>>                if self.request.principal.id == "peter":
>>>                                # do stuff
>>>
>>> , but I don't see how to access that information in the "getAccount"
>>> method (or in authenticateCredentials, which seems to be the method
>>> calling getAccount). In the "authenticateCredentials" itself, it'd be
>>> nice to check if the user has already been authenticated and then
>>> return the request.principal, instead of having to call getAccount()
>>> (access the database) and then instantiate a new MyOwnPrincipalInfo()
>>> object (which, if I understood properly, is in the request already
>>> once that the user has been authenticated once)
>>>
>>> Thanks!
>>>
>>> 2010/12/28 Jeffrey Peterson <bgpete at gmail.com>:
>>>> So you followed that tutorial.  In there it includes session based login.  it's outdated a bit but if you change a few imports still valid.
>>>>
>>>> Your Credentials utility needs to inherit from SessionCredentialsPlugin:  from zope.pluggableauth.plugins.session import SessionCredentialsPlugin
>>>>
>>>> MyOwnPrincipalInfo needs to implement IPrincipalInfo, and then the principal will be in the request:  self.request.principal it doesn't AFAIK access the DB multiple times.  The principal is in the request until logout, or session expiration.
>>>>
>>>> Jeff.
>>>> On Dec 27, 2010, at 6:14 PM, Hector Blanco wrote:
>>>>
>>>>> Hello list:
>>>>>
>>>>> I have set up a user authentication mechanism as explained in
>>>>> http://grok.zope.org/documentation/how-to/authentication-with-grok
>>>>>
>>>>> The users structure is serialized on a MySQL database.
>>>>>
>>>>> I have setup the "authenticateCredentials" and "getAccount" methods
>>>>> for the authenticator plugin like this
>>>>>
>>>>> def authenticateCredentials(self, credentials):
>>>>>       if isinstance(credentials, dict):
>>>>>               if (("login" in credentials) and ("password" in credentials)):
>>>>>                       user = self.getAccount(credentials['login'])
>>>>>                       if user and (user.checkPassword(credentials['password'])):
>>>>>                               log.debug("::UserAuthenticatorPlugin > authenticateCredentials >
>>>>>                                          Credentials authenticated for user %s " % (user.userName))
>>>>>                               return MyOwnPrincipalInfo.MyOwnPrincipalInfo(user)
>>>>>       return None
>>>>>
>>>>> def getAccount(self, login):
>>>>> try:
>>>>>       return grok.getSite()["UserManager"].getByName(login, allData=False)
>>>>> except Exception, e:
>>>>>       log.warn("::UserAuthenticatorPlugin > getAccount > Got exception %s " % e)
>>>>>       log.debug("::UserAuthenticatorPlugin > getAccount > Showing
>>>>> traceback:\n%s" % traceback.format_exc(limit=5))
>>>>> finally:
>>>>>       Database.session.close()
>>>>>
>>>>> The "UserManager" is just a bunch of static methods that access the
>>>>> database (using SqlAlchemy) and, in this case, tries to get the user
>>>>> whose "userName" is the same in "login". That means having to access
>>>>> the database many, many times.
>>>>>
>>>>> So here's the question:
>>>>> Is there any way of using the ISession object so I don't have to query
>>>>> the database so often?
>>>>>
>>>>> The idea would be putting "something" in the "authenticateCredentials"
>>>>> method so if userName and password are correct, a new entry for that
>>>>> user is created in the session object, so I can get it from there,
>>>>> instead of having to access the database that often.
>>>>>
>>>>> Something that would allow me to modify the getAccount() method to
>>>>> something like this:
>>>>>
>>>>> def getAccount(self, login):
>>>>> try:
>>>>>        if (ISession(self.request)['users'][self.request.principal.id]):
>>>>>                  return =
>>>>> ISession(self.request)['users'][self.request.principal.id]
>>>>>        else:
>>>>>                  return
>>>>> grok.getSite()["UserManager"].getByName(login, allData=False)
>>>>> except Exception, e:
>>>>>       log.warn("::UserAuthenticatorPlugin > getAccount > Got exception %s " % e)
>>>>>       log.debug("::UserAuthenticatorPlugin > getAccount > Showing
>>>>> traceback:\n%s" % traceback.format_exc(limit=5))
>>>>> finally:
>>>>>       Database.session.close()
>>>>>
>>>>> But that's the issue... in order to use the session, I need to have
>>>>> access to a .request, right? And in getAccount(self...), self is an
>>>>> instance of "UserAuthenticatorPlugin", which doesn't have any request
>>>>> associated (at least, not that I have seen)
>>>>>
>>>>> Is there any way to access the request from an instance of
>>>>> "UserAuthenticatorPlugin"?  The idea would be "registering" the user
>>>>> that is authenticated in the Session object so I don't have to access
>>>>> the database that many times...
>>>>>
>>>>> Thank you in advance!
>>>>> _______________________________________________
>>>>> Grok-dev mailing list
>>>>> Grok-dev at zope.org
>>>>> https://mail.zope.org/mailman/listinfo/grok-dev
>>>>
>>>>
>>>
>> _______________________________________________
>> Grok-dev mailing list
>> Grok-dev at zope.org
>> https://mail.zope.org/mailman/listinfo/grok-dev
>
>


More information about the Grok-dev mailing list