[Grok-dev] Make self.request.principal to be an instance of MyOwnPrincipalInfo (my own class)

Hector Blanco white.lists at gmail.com
Wed Jan 12 13:12:25 EST 2011


Thank you for your reply, J.W.

I tried your latest solution... with same results... Maybe I have to
register the "MyOwnPrincipalInfo" somewhere else...

I can always get workarounds so is not too vital... is just that it'd
be nice to get it working (mostly to understand a little bit better
how all that works... out of curiosity...)

Just in case, let me detail the tools involved in the authentication
(maybe it's just a little silly detail with a pretty straight-forward
solution).

In app.py I have:
# = = = = =   app.py   = = = = = = = = = = = = = = = = = = = = #

from backlib.user import MyOwnPrincipalInfo # <-- This is what I want :-)
from backlib.database import Database
import grok
# ... other imports...
from zope.authentication.interfaces import IAuthentication
from zope.authentication.interfaces import ILogout
from zope.authentication.interfaces import IUnauthenticatedPrincipal
from zope.interface import Interface
from zope.pluggableauth.authentication import PluggableAuthentication
from zope.pluggableauth.interfaces import IAuthenticatorPlugin
from zope.pluggableauth.interfaces import ICredentialsPlugin
from zope.pluggableauth.plugins.session import SessionCredentialsPlugin
from zope.security import checkPermission

def setup_authentication(pau):
    pau.credentialsPlugins = ['credentials']
    pau.authenticatorPlugins = ['myAuthenticatorPlugin']

class Server(grok.Application, grok.Container):
	grok.local_utility(
		PluggableAuthentication, provides=IAuthentication,
		setup=setup_authentication,
		)

	def __init__(self):
		super(Server, self).__init__()
		# ... yadda ... yadda ...
# End of class Server

class MySessionCredentialsPlugin(grok.GlobalUtility, SessionCredentialsPlugin):
    grok.provides(ICredentialsPlugin)
    grok.name('credentials')

    loginpagename = 'login'
    loginfield = 'form.login'
    passwordfield = 'form.hashedPwd'
# End of class MySessionCredentialsPlugin

class UserAuthenticatorPlugin(grok.GlobalUtility):
	grok.provides(IAuthenticatorPlugin)
	grok.name('myAuthenticatorPlugin')
	grok.context(Server)

	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'])):
					return MyOwnPrincipalInfo.MyOwnPrincipalInfo(user)
		return None

	def principalInfo(self, principalName):
		# May the answer be here ??
		return self.getAccount(principalName)

	def getAccount(self, login):
		if not(login.startswith("zope.") or login == "zope.manager"):
			try:
				return grok.getSite()["UserManager"].getByName(login)
			except Exception, e:
				log.warn("::UserAuthenticatorPlugin > getAccount > Got exception %s " % e)
			finally:
				Database.session.close()
		else:
			return None
# End of class UserAuthenticatorPlugin

class ILoginForm(Interface):
    login = schema.TextLine(title=u'Username', required=True)
    hashedPwd = schema.BytesLine(title=u'HashedPwd', required=True)

class Login(grok.Form):
    grok.context(Interface)
    grok.require('zope.Public')

    form_fields = grok.Fields(ILoginForm)

    @grok.action('login')
    def handle_login(self, ** data):
		if self.request.form.get('camefrom', ''):
			redirect = (self.request.form.get('camefrom', '')).split('/')[-1]
			self.redirect(self.url(redirect))
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

And the the MyOwnPrincipalInfo is in another .py file (in the
"backlib/user/" folder):

# = = = = =   MyOwnPrincipalInfo.py   = = = = = = = = = = = = = = = = #

from backlib.user import User
import grok
# ... other imports...
from zope.pluggableauth.interfaces import IPrincipalInfo
from zope.publisher.interfaces.browser import IBrowserRequest

class MyOwnPrincipalInfo(grok.MultiAdapter):
	grok.adapts(IPrincipalInfo, IBrowserRequest)
	grok.implements(IPrincipalInfo)
	
	def __init__(self, user):
		super(MyOwnPrincipalInfo, self).__init__()
		if isinstance(user, User.User) and (user.id):
			self.id = str(user.id)
			self.title = user.userName
			self.description = str(user.firstName) + " " + str(user.lastName)
		else:
			raise TypeError("Unable to provide a PrincipalInfo from a %s" % type(user))
	#End __init__

	def someOtherVeryCoolStuff(self):
		# do whatever
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

But still... if in a view (which are defined in app.py, by the way...
JIC) I try to access:
    self.request.principal.someOtherVeryCoolStuff()

(for instance:

class Test(grok.View):
	grok.context(Server)
	grok.require('server.ViewSite')

	def update(self):
		print "Type of the principal: %s\n" % type(self.request.principal)
		print "self.request.principal.someOtherVeryCoolStuff(): %s" %
		          self.request.principal.someOtherVeryCoolStuff()
)

I get the same exception:

Type of the principal: <class 'zope.pluggableauth.factories.Principal'>

2011-01-12 13:08:08,295 ERROR [SiteError] http://127.0.0.1:8080/myOwn-cms/test
Traceback (most recent call last):
  File "/home/ae/.buildout/eggs/zope.publisher-3.12.4-py2.6.egg/zope/publisher/publish.py",
line 132, in publish
    result = publication.callObject(request, obj)
  File "/home/ae/.buildout/eggs/grok-1.2.1-py2.6.egg/grok/publication.py",
line 90, in callObject
    return super(ZopePublicationSansProxy, self).callObject(request, ob)
  File "/home/ae/.buildout/eggs/zope.app.publication-3.12.0-py2.6.egg/zope/app/publication/zopepublication.py",
line 207, in callObject
    return mapply(ob, request.getPositionalArguments(), request)
  File "/home/ae/.buildout/eggs/zope.publisher-3.12.4-py2.6.egg/zope/publisher/publish.py",
line 107, in mapply
    return debug_call(obj, args)
  File "/home/ae/.buildout/eggs/zope.publisher-3.12.4-py2.6.egg/zope/publisher/publish.py",
line 113, in debug_call
    return obj(*args)
  File "/home/ae/.buildout/eggs/grokcore.view-1.13.5-py2.6.egg/grokcore/view/components.py",
line 92, in __call__
    mapply(self.update, (), self.request)
  File "/home/ae/.buildout/eggs/zope.publisher-3.12.4-py2.6.egg/zope/publisher/publish.py",
line 107, in mapply
    return debug_call(obj, args)
  File "/home/ae/.buildout/eggs/zope.publisher-3.12.4-py2.6.egg/zope/publisher/publish.py",
line 113, in debug_call
    return obj(*args)
  File "/home/ae/myOwn-cms/server/src/server/app.py", line 180, in update
    print "self.request.principal.someOtherVeryCoolStuff(): %s" %
self.request.principal.someOtherVeryCoolStuff()
AttributeError: 'Principal' object has no attribute 'someOtherVeryCoolStuff'

As I said, I can get some workarounds, but it'd be nice to get it
working so I could understand a bit better the authentication system.

Thank you!

2011/1/10 Hector Blanco <white.lists at gmail.com>:
> Hello!
>
> Thanks for all your replies
>
> 2011/1/10 Jan-Wijbrand Kolman <janwijbrand at gmail.com>:
>> On 1/9/11 21:57 PM, Hector Blanco wrote:
>>> --------------- (in app.py) ---------------
>>> 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'])):
>>>                               return MyOwnPrincipalInfo.MyOwnPrincipalInfo(user)
>>>       return None
>
>>
>> This "def authenticateCredentials()" method is implemented where in your
>> code? If you want to do this, you'd need to create your own
>> IAuthentication utility and register that for you site.
>>
>
> I put it in app.py
>
>> Another possibility, if you for some reason you cannot use the dolmen.*
>> packages that would provide features you are looking for, is to create
>> your own IAuthenticatedPrincipalFactory adapter.
>>
>> This adapter is looked up whenever the Pluggable Authentication Utility
>> creates an authenticated principal from the principal info that was
>> found. There you could hook in you own implementation, something like
>> (incomplete and untested, but I hope you get the idea!):
>>
>> class MyOwnPrincipalInfo(grok.MultiAdapter):
>>         grok.adapts(IPrincipalInfo, IBrowserRequest)
>>        grok.implements(IPrincipalInfo)
>>
>>        def someOtherVeryCoolStuff(self):
>>                # do whatever
>>
>> HTH
>>
>
> Gonna try that... Let's see what happens :)
>
>> regrrds, jw
>>
>
> Thanks again for all the hints
>


More information about the Grok-dev mailing list