exUserFolder and PAM - caching?
All, Just a recipe for exUserFolder with PAM authentication that works for me. 1) Download the PyPAM module from http://www.pangalactic.org/PyPAM/PyPAM-0.4.2.tar.gz 2) Edit the PAMmodule.c file so it includes the "python2.1/Python.h" rather than the "python1.5/Python.h" 3) Compile it: gcc -DPACKAGE=1 -DVERSION=1 -I. -I. -I/usr/include/python2.1 -I/usr/lib/python2.1/config -fpic -g -O2 -c PAMmodule.c gcc -shared -o PAMmodule.so PAMmodule.o -lpam -lpam_misc 4) Make sure it works by running python2.1 and "import PAM" 5) Copy PAMmodule.so to /usr/local/Zope/lib/python 6) Create the file /usr/local/Zope/Extensions/passwd.py with the contents: import PAM class Checker: def __init__(self,username,password): self.username = username self.password = password def pam_conv(self, auth, query_list): resp = [] for query,type in query_list: if type == PAM.PAM_PROMPT_ECHO_ON: resp.append((self.username, 0)) elif type == PAM.PAM_PROMPT_ECHO_OFF: resp.append((self.password, 0)) elif type == PAM.PAM_PROMPT_ERROR_MSG or type == PAM.PAM_PROMPT_TEXT_INFO: resp.append(('', 0)); else: return None return resp def check(username,password): ckr = Checker(username,password) auth = PAM.pam() auth.start('zope') auth.set_item(PAM.PAM_USER, username) auth.set_item(PAM.PAM_CONV, ckr.pam_conv) try: auth.authenticate() except PAM.error, (resp, code): return (1, 'No: (%s)' % resp) except: return (1, 'Internal error') else: return (0, 'Yes') 7) Download and install exUserFolder>=0.7.2 8) cd /usr/local/Zope/lib/python/Products/exUserFolder/usAuthSource 9) vim usAuthSource.py <comment out line 134> <uncomment lines 136-139> <ESC>!wq 10) Create a test folder 11) Put an exUserFolder in it with a Null property source, a Null membership source, and a user-supplied auth source 12) In the managment interface, go into the exUserFolder, then contents, then usAuthSource 13) Create an external method called "check_password", module "password", function "check" 14) Create the following PythonScripts: x_usGetUsers: <no parameters> us = [] us.append({'username':'uname','password':'x','roles':['role1','role2']}) return us x_usListOneUser: username return [{'username':'uname','password':'x','roles':['role1','role2']},] # return [] for no such user x_usListUsers: <no parameters> return [ {'username':'uname',}, {'username':'uname2',}, {'username':'uname3',} ] x_usRemoteAuthMethod: username,password code,msg = container.check_password(username,password) if code: return None return 1 Clearly the data returned from these methods can be from SQL/LDAP queries or whatever. Beware - the usRemoteAuthMethod in particular will need a proxy role that can run the external method, since the logging in user doesn't have any roles... 14a) Give the appropriate proxy roles to each python script so it can be executed in the context of a logging-in user 15) Create the /etc/pam.d/zope file with the appropriate PAM configuration 16) Remove permissions for Anonymous on the folder so that you have to login 17) Copy your test folder (parent of the exUserFolder) to somewhere safe in case it's going to go wrong 18) Batch rename the x_* method to remove the leading x_ 19) Try logging in - watch /var/log/messages to see the output of the PAM module The one problem is that the usRemoteAuthMethod gets called on every page request, it isn't cached, which means for remote auth methods (e.g. Kerberos/LDAP/SMB PAM modules) the load might be quite high. Any ideas, let me know. Regards, Phil +------------------------------------------+ | Phil Mayers | | Network & Infrastructure Group | | Information & Communication Technologies | | Imperial College | +------------------------------------------+
+-------[ Mayers, Philip J ]---------------------- | All, | | Just a recipe for exUserFolder with PAM authentication that works for me. [snip] | The one problem is that the usRemoteAuthMethod gets called on every page | request, it isn't cached, which means for remote auth methods (e.g. This is the zope mechanism, and indeed the http mechanism. Basic Auth is sent for every page as well. | Kerberos/LDAP/SMB PAM modules) the load might be quite high. Any ideas, let | me know. That's why remote things are best done with persistent sources ala an PAM AuthSource, where you can cache user stuff (the IMAP/POP sources also do this). You could also I guess set a property on yourself or dummy object with username as the key and the last time checked, so you can avoid the overhead if last checked was within 5 minutes say. It's trivial to convert one of the other AuthSources, if you've already got an External Method to do the hard work, then you don't even need have proxy roles d;) Actually converting usAuthSource would be the easiest, since it's basically empty already, and it heavily commented. -- Totally Holistic Enterprises Internet| | Andrew Milton The Internet (Aust) Pty Ltd | | ACN: 082 081 472 ABN: 83 082 081 472 | M:+61 416 022 411 | Carpe Daemon PO Box 837 Indooroopilly QLD 4068 |akm@theinternet.com.au|
participants (2)
-
Andrew Kenneth Milton -
Mayers, Philip J