Single-Sign-On for Zope & Plone in Windows Domains

Submitted by Hannes Schmidt on Sat, 12/18/2004 - 14:22.
Single-Sign-On for Zope & Plone in Windows Domains: SSO
Single-Sign-On for Zope & Plone in Windows Domains: Remote User Folder

One of my clients runs his own intranet for his employees. The intranet currently consists of a bunch of static HTML pages which are written and maintained by a single editor. This approach might have been sufficient five years ago but as the intranet grew it became apparent that the static HTML would become unmanageable in the near future. I therefore suggested replacing the existing solution with a community-oriented CMS. Due to certain requirements the set of contestants was cut down to two: Drupal and Plone. I favored Plone because a) I am slightly disappointed with the direction and pace that Drupal’s development has recently taken and b) I wanted to learn Zope and Plone anyway.

Table Of Contents

State Of The Art
Step 1 - NTLM authentication for Apache: mod_ntlm
Step 2 - Zope/Plone and Apache
Step 3 - FastCGI
Step 4 - Enable NTLM authentication for requests to Zope
Step 5 - Install Remote User Folder
Appendix 1 - Exempting the ZMI from NTLM authentication
Appendix 2 - Schizophrenia
Appendix 3 - Disabling Zope's http server
Appendix 4 - Virtual Host Monster (VHM)
Appendix 5 - What about Group User Folder?
Appendix 6 - Problems with mod_ntlm under load
Appendix 7 - Multiple Windows Domains
Appendix 8 - Kerberos

State Of The Art

The most important requirement was the integration of Plone’s user management into the client’s Windows domain. This requirement had two implications:

  1. Unified logon: Any domain user should automatically be a Plone user. There should not be any additional user administration in Plone.
  2. Seamless authentication: Users should only have to logon once. After a user is logged into the domain, Plone should not ask for a password a second time.

The above requirements are usually summarized as single-sign-on. This article describes how single-sign-on can be achieved by gluing together various pieces of software in addition to Zope/Plone; namely, Apache, mod_ntlm, mod_fastcgi, a Samba or Windows 2000 Server and Zope’s Remote User Folder.

In coming to my conclusions I examined several possible solutions:

  • LDAPUserFolder could be used to fulfill the unified logon requirement by integrating Active Directory (Microsoft’s extended LDAP directory implementation for Windows domains) with Plone. However, with LDAPUserFolder the user would need to login into the CMS separately. This is basically because there is no trust relationship between the Zope Server that Plone runs on and the Windows workstation that the client logs into. Currently, such trust can only be established using Microsoft’s own proprietary HTTP authentication protocol, called NTLM authentication. NTLM auth was initially supported by Internet Explorer (IE) and Microsoft’s web server, Internet Information Server (IIS). The NTLM authentication scheme is sneered at by many because it’s thought to be rather weak (I remember reading somewhere that there is a stronger Kerberos extension to it). Notwithstanding, it has been adopted by a variety of open source projects, probably because of user demand and usefulness. The Squid proxy server supports it, Firefox 1.0 supports it and for Apache there is mod_ntlm. I successfully used all of these in conjunction with NTLM authentication in my client’s intranet. The security risk imposed by NTLM authentication in a controlled LAN environment is acceptable.
  • The Plone product exUserFolder can authenticate against a windows domain but it doesn’t support NTLM authentication either.
  • The Plone product PluggableAuthService (PAS) looks very promising but I doubt that at the time of this writing it’s ready for production or that it even supports NTLM auth. There were posts on the corresponding mailing list that indicate someone is working on NTLM auth though.

This leaves us with one remaining option: Running Zope behind Apache with mod_ntlm installed. The remainder of this article focuses on the details of how to get Apache 2.0 to do the authentication and yet let Zope serve the content for the Plone CMS. The procedure for Version 1.3 of the Apache web server should be very similar but is not addressed in this article.

Step 1 – NTLM authentication for Apache: mod_ntlm

Update, Feb 1st, 2005: Read this section and then immediately read Appendix 6!

Apache’s mod_ntlm is available for Apache 1.3 and 2.0 and although still in beta it is pretty much usable as long as you use it in one domain only. I prefer loading it as a module, which is the default build setting. Download the modntlm2 source package [3] and compile and install it according to the instructions found either on the home page [4] or in the package itself. The compilation requires the Apache header files. The installation uses the apxs program to install the compiled module but that didn’t work on my Suse Linux system. If this is the case for your system too, there are two things you will have to do. First, you will need to copy the mod_ntlm.so file to the directory that contains the other Apache modules, e.g /usr/lib/apache2. Looking into httpd.conf for LoadModule statements of other modules should give you an idea.

LoadModule ntlm_module /usr/lib/apache2/mod_ntlm.so

The bold part will probably need to be adjusted to match your system’s module path. Restart Apache to see if it starts up correctly. Then add this to your httpd.conf:

<Location /ntlmtest>
  AuthType NTLM
  NTLMAuth on
  NTLMAuthoritative on
  NTLMDomain YOURDOMAIN
  NTLMServer yourDomainController
  NTLMBackup yourBackupDomainController
  Require valid-user
</Location> 

Instead of putting the above statements into a <Location> section, you can also put them into an existing <Directory> section. Point your browser to /ntlmtest on your server (http://yourserver/ntlmtest) or to the directory to which you added the above http.conf statements. If you get a password prompt or an “Authentication Required” error page, something isn’t working. If you get an “Object Not Found” 404-error page, that’s good. Note that you must use Mozilla Firefox 1.0 for Windows or Internet Explorer when you test this and that you have to be logged on as a domain user.

Firefoxies, read this: In order to use NTLM auth on direct HTTP connections (as opposed to proxy connections that support NTLM out of the box) you need to add your server to the list of trusted URIs. To do so, start Firefox, type about:config into the address text field, find the setting network.automatic-ntlm-auth.trusted-uris, double-click it and enter http://yourserver (no slash at the end). This might seem tedious but for security reasons it’s a good idea to limit the servers that a user agent exchanges NTLM challenges with because NTLM auth is susceptible to man-in-the-middle attacks. Better safe then sorry. If you want to be sorry, you can set the trusted URIs setting to http:// (two slashes at the end).

Also, check your server access logs (usually somewhere in /var/log) and see whether your test requests were logged with your user name. If not, something is not working properly or your log format is non-standard (unlikely). You need to fix this before you continue.

If you haven’t done so yet, you should install Zope and Plone now and setup up your Plone site. Don’t add any users yet. When install a Zope instance, you need to specify the credentials of the instance manager. The manager should be the only user available in Zope and Plone.

Step 2 – Zope/Plone and Apache

OK, we got NTLM authentication working and we have a functioning Plone and Zope installation. What’s left is chaining Apache and Zope such that

  • Apache forwards the requests to Zope,
  • Apache passes the authenticated user’s name to Zope and
  • Plone accepts that user as a member of the Plone site.

There are plenty of ways to run Zope behind Apache:

  • CGI -- For every request, Apache runs the python binary, passing the request headers in environment variables and the request body in a pipe (I think). The Zope response is sent back through a pipe. After this, the Zope process finishes. Extremely slow and not recommended.
  • FastCGI – Apache creates a socket connection to an already running Zope and passes the request info through that connection. Zope handles the request and sends the response back through that connection. The connection is closed and re-opened for every request but the Zope process continues to run. Much faster. Additional environment variables can be transferred through the socket connection.
  • mod_proxy alone – This is conceptually similar but technically different from FastCGI. Apache works as a proxy and forwards the HTTP requests to Zope. This method is as fast as FastCGI. No environment variables can be passed along with the forwarded request. The URLs that Apache receives have the same postfix as the ones that Apache sends to Zope but the prefix can be different.
  • mod_rewrite together with mod_proxy – Very similar to the previous solution but it allows for rewriting the URLs.

Although all of the above techniques have pros and cons, there is one killer requirement that rules out all but one technique: transferring the authenticated user from Apache over to Zope. So before we investigate how we are going to connect Apache and Zope, let’s have a look at the Zope authentication and permission system.

Disclaimer: I am more or less a Zope newbie so from here on out we will be moving into unknown territory. Don’t take everything I say for granted but don’t lose your faith either – the solution described in this article does actually work!

Zope (and hence Plone) organizes users in special folders called user folders. When added to an object, the user folder determines the available set of users for this object. Generally speaking, if a user folder is added to the Plone object, only the users in that user folder can access the Plone site. Well, not quite. Firstly, the Plone site can also be accessed by users of user folders further up in the hierarchical Zope database. For example, the users in the acl_users object at the Root Folder are granted access to the Plone site as well. Secondly, the users can be assigned Roles that further restrict the operations available to the users.

Different authentication mechanisms are added to Zope by adding specialized types of user folders to a Zope instance. The default user folder is acl_users at the Root Folder of any vanilla Zope instance. Another type of user folder is LDAP  user folder. This user folder type doesn’t store the users in the Zope database but in an LDAP directory such that LDAP user entries appear as Zope users. I also want to mention GRUF (Group User Folder) as it is a very common user folder for Plone sites. (See Appendix 5 – What about Group User Folder? )

Another type of user folder, the so-called Remote User Folder is of particular interest to us. It doesn’t contain any persistent user objects at all. Instead, it assumes that authentication has already been completed for an incoming HTTP request and it looks up the request’s authenticated user in its own list of users. A Remote User Folder obtains the name of the authenticated user from the REMOTE_USER environment variable. As mentioned earlier, environment variables are not part of a standard HTTP request. For this reason we cannot use either of the two mod_proxy solutions because mod_proxy uses HTTP only. We’ll have to stick to either CGI or FastCGI.

If the user isn’t present, a Remote User Folder will either reject the user (this is the default setting) or create a matching user entry automatically, provided that this feature is enabled. The on-the-fly creation of users is particularly helpful for our purposes, as it completely delegates authentication and the user management to some other instance. Finally, we have all the ingredients:

  1. The browser sends a request to the Apache web-server together with an invitation for NTLM authentication of the currently logged on user
  2. Apache receives the request
  3. The ntlm_auth module authenticates the request by mediating the NTLM challenge/response handshake between the user’s browser and the domain controller
  4. Once the user is authenticated, Apache dispatches the request to the Zope server, using the FastCGI protocol and including the authenticated user’s name in the REMOTE_USER environment variable
  5. Zope receives the request and - based on the path of the requested object – passes the request to the appropriate user folders for authorization
  6. The Remote User Folder obtains the user’s name from REMOTE_USER, scans its user list for that user name and adds an entry for the user if it is not yet present. Depending on the type of the requested object and the roles assigned to the user, the request is either denied with a 401 response or granted and executed.

Although this all sounds very lengthy, it is in fact rather easy to achieve.

Step 3 – FastCGI

Download mod_fastcgi package from the FastCGI homepage and follow the instructions in the INSTALL file (or INSTALL.AP2 for Apache 2). Compiling and installing FastCGI was a bit of headache for me because FastCGI uses Apache’s build system and I didn’t have a proper set of Apache headers and makefiles. My Apache installation is a backport RPM for my ancient Suse 7.1 so I think my difficulties are more the packager’s fault than FastCGI’s.

LoadModule fastcgi_module /usr/lib/apache2-prefork/mod_fastcgi.so
FastCgiExternalServer /usr/local/httpd/htdocs/zope -host localhost:8081 -pass-header Authorization
<Location /zope>
  SetHandler fastcgi-script
</Location>

The FastCgiExternalServer statement tells FastCGI which request paths should be handled by mod_fastcgi. I’m not sure why it’s specified as a file system path instead of a URL path but the file name is just a dummy and the file does not need to exist. You can choose any other name instead of zope but if you do that, you’ll need to adjust the following instructions accordingly. The Location statement tells Apache that requests to /zope are handled by FastCGI.

The -pass-header option tells Apache to send authorization information along with the requests. This doesn’t affect NTLM authentication because environment variable REMOTE_USER will be set regardless of this option. It only affects whether standard HTTP authentication headers will be handed over to Zope, thus enabling us to use the Zope management interface (ZMI) through Apache (see Appendix 1 – Exempting the ZMI from NTLM auth and Appendix 2 – Schizophrenia).

The -host option denotes the host name and port number to which FastCGI request will be sent. We need to enable Zope’s FastCGI server and configure it to listen on the given port. Add the following lines to the zope.conf configuration file which is usually located in the Zope instance’s /etc directory.

<fast-cgi>
address localhost:8081
</fast-cgi>

Restart Apache and the Zope instance.

Step 4 – Enable NTLM authentication for requests to Zope

You already tested NTLM auth. in Apache by adding a dummy /ntlmtest location section to Apache’s configuration file. Edit http.conf one more time and modify the <Location /ntlmtest> section we added earlier:

<Location /zope/intranet>
AuthType NTLM NTLMAuth on NTLMAuthoritative on NTLMDomain YOURDOMAIN NTLMServer yourDomainController NTLMBackup yourBackupDomainController Require valid-user </Location>

It is important that the intranet component of the location path matches the identity of the Plone site object. You can verify the identity using the ZMI.

Also note that we now have two Location sections: one with FastCGI for /zope and one with NTLM for /zope/intranet. Because /zope is a prefix of /zope/intranet, FastCGI and NTLM auth will be active for /zope/intranet. (For an explanation of why we do not use NTLM auth for /zope see Appendix 1 – Exempting the ZMI from NTLM auth)

Restart Apache. For the remainder of this article I will assume that you know the basics about ZMI, like creating and deleting objects or changing object properties. (In case you don’t, there is plenty of information about ZMI on the web.)

Step 5 – Install Remote User Folder

  1. Download and install the Remote User Folder product in your Zope instance directory.
  2. Point your browser to the ZMI and log in as manager. Use Zope’s HTTP port (default is 8080) because we are not quite ready to connect via Apache/FastCGI.
  3. Remove the existing user folder from the Plone site object.
  4. Add a Remote User Folder to the Plone site object. It will be called acl_users. Make sure to add it to the Plone site, not the Root Folder.
  5. Enable automatic creation of user objects in Plone. This option is called Auto  Add Users and can be found on the property tab of the acl_users folder that we just created.

Appendix 1 – Exempting the ZMI from NTLM authentication

In Step 3 – FastCGI ) and Step 4 – Enable NTLM authentication for requests to Zope ) we used distinct location sections, one for FastCGI and one for NTLM auth. We did this for one main reason: Although Apache wraps the entire Zope instance, NTLM auth should only be performed for URLs that point to the Plone site. It’s important that /zope and especially /zope/manage are exempt from NTLM auth because we do not want to lock out the Zope manager. The Zope manager should be able to login using standard HTTP authentication. Furthermore, there might be other Zope objects beside your Plone site for which NTLM auth would not be appropriate.

Theoretically speaking, it should be possible to add the Remote User Folder to the Zope instance root instead of the Plone site and to enable NTLM auth for the entire Zope instance but there’s a caveat. I wasn’t able to replace the default acl_users folder with a different one, say Remote User Folder (RUF) because after removing the acl_users folder, I couldn’t do anything at all because the manager (me) was locked out. There may be a trick to get around this, though.

Appendix 2 – Schizophrenia

When accessing the ZMI through Apache/FastCGI, you will notice that you’ll still have to enter the credentials of the manager. When you click on the intranet icon representing the Plone site in the tree view on the left hand side frame, you may notice that you turn from Zope manager into the Plone user that corresponds with your Windows domain account. This is because the Plone part of the ZMI also uses the /zope/intranet URL prefix for which NTLM authentication is enabled in Apache. For requests to this URL the browser sends NTLM authentication headers instead of HTTP authentication. I’m not quite sure as to why NTLM authentication overrides HTTP authentication, as there clearly is a conflict between the two. If your domain account is not assigned the Manager role in Plone, you will not get the management view of the Plone folder. Instead you will get the Plone home page. In order to fix this you need to connect to the ZMI directly via Zope’s HTTP port and assign the Manager role to the user object in Plone’s acl_users folder that corresponds to your Windows domain account.

Appendix 3 – Disabling Zope’s http server

Unless you already disabled the HTTP server in zope.conf, your Zope instance is listening on both the FastCGI and the HTTP ports. Using HTTP you should still be able to access everything in Zope including the management interface and excluding the Plone site. But because a Remote User Folder depends on the REMOTE_USER environment variable, access to the Plone site is only possible via FastCGI and thus through Apache. I recommend disabling the HTTP port in zope.conf because we don’t need it. The entire Zope site is accessible through Apache and FastCGI. Because HTTP is a more direct and robust way of connecting to your Zope instance, it might be necessary to temporarily enable the HTTP port for maintenance and debugging.

Appendix 4 – Virtual Host Monster (VHM) …

… is not needed apparently. VHM or SiteRoot objects are used whenever Zope runs behind something that disguises Zope’s internal URLs. VHM and SiteRoot make sure that URLs generated by Zope are mapped to the external URL format. Although this also applies to the solution described here, it seems that the URL mapping is taken care of by Zope’s FastCGI server.

Appendix 5 – What about Group User Folder?

Group User Folder (GRUF) can store users and groups. Instead of maintaining its own list of users and groups, it delegates the user and group storage to any number of user folders of any type. In that respect it is some kind of compound user folder, because it contains other user folders. The contained user folders are called sources. At the time of writing, Remote User Folder and GRUF are not compatible, i.e. Remote User Folder cannot be used as a source for GRUF. Stay tuned for updates on this issue …

Update, July 28th, 2005: Ok, you kept coming back, so here is an update ;-)

Apparently, GRUF doesn't implement validate() and thus never gives RemoteUserFolder any chance to do its work. This patch fixes GRUF when RemoteUserFolder is used as a source to a Group User Folder. The patch implements validate() in a way that I think should work in other cases as well. But who am I to promise you anything? Being a total Zope noob, I learned about Zope's acquisition today and am still gasping ...

Click here to download GroupUserFolder.py.patch

Apply the patch by doing

cd <your plone installation>/Products/GroupUserFolder
wget http://www.hannesschmidt.de/files/GroupUserFolder.py.patch
patch -b < GroupUserFolder.py.patch
zopectl restart

Click here to download GroupUserFolder.py-3.3.patch, which does the same thing to the new GRUF 3.3

Update, Oct 1st, 2005: Did more work to RUF:

I think there were a lot of things wrong with RUF. At least there was one obvious bug (RUF not assigning roles automatically from DOMAIN\*) and some things going on for which I saw no reason at all. So I went ahead, fixed the bug and removed the code that seemed unnecessary. Download my new version (see list of attachments below) and replace your existing RemoteUserFolder.py. With the patches to GRUF-3.3 and the fixed RUF installed, I have a perfectly working portal in production now. If you have done testing with previous versions of my patches, you better make sure that you delete any existing GRUF and RUF instances and Members before you apply the patches. Afterwards create vanilla RUF and GRUF instances.

Update, Oct 21st, 2005: RemoteUserFolder v0.5:

This version has a workaround for an error reported by jmarks. Searching for users in the sharing tab produces a SiteError when the wildcard user "*" is present in RUF. I could not find the cause for this but I was able to provide a workaround by overriding RUF's getUsers() to simply not return the wildcard user. This means that RUF must be used to assign roles to the wildcard user. For regular users both RUF and GRUF may be used.

Update, Nov 8th, 2005: RemoteUserFolder v0.5.1:

With the help of Joey (jmarks), I fixed two more bugs, an obvious one in the Kerberos/NTLM functionality I added to v0.5 and a not so obvious one. According to ZODB documentation, it is not possible to pickle objects with acquisition wrapper. Part of my first modifications to RUF was a refactoring of __of__( self ) into _doAddUser(). Unfortunately, that wasn't a good idea. _doAddUser should really just return a plain RemoteUser instance. GRUF on the other hand needs a wrapped instance of RemoteUser, such that it can get to the user folder that created the RemoteUser instance. So with this version I refactored __of__( self ) calls back to validate().

Appendix 6 - Problems with mod_ntlm under load

People have reported that repeatedly refreshing the page causes a basic authentication dialog to appear. I initially though that it was a browser problem so I tested both Firefox and Internet Explorer. I was able to reproduce that problem under both browsers. The forum and bugtracking area sourceforge project page contains numerous posts describing the same symptoms, so the problem must be in mod_ntlm. In this post, Michael Cai and Jamie Kerwick announce their own improved version of mod_ntlm and mod_ntlm2 [8], which supposedly fixes this and other issues. I tried it out and was not able to reproduce the problem anymore. The bottom line is that you shouldn't use the official version. Instead, use Michael Cai's unofficial MOD_NTLM Apache module.

Sidenote: The mod_ntlm project managers seems to have abondened their baby. The last sign of life from them was spotted in May 2004, announcing a new version to be due "in a few days". Since then, various people have attempted to fix/rewrite mod_ntlm (see the project forum [3]).

Appendix 7 - Multiple Windows Domains

The mod_ntlm version described in Appendix 6 has support for multiple domains. If anybody has tested this feature, I'd appreciate it if they could contact me.

Update, Nov 8th, 2005: Patch to Michael Cai's mod_ntlm

Apparently, Michael Cai's mod_ntlm authenticates against multiple domains but it doesn't pass the authenticated user's domain name to Apache. This means that further down the line, RUF and GRUF won't be able to distinguish users from multiple domains. I modified Michael's version of mod_ntlm (because that's the only one that works reliably) such that it passes the user information in the form DOMAIN\User. You'll find the patch for Apache 2 in the attachements section at the end of this article. Let me know if you need one for Apache 1.3. I don't have 1.3 so I have no way of testing it.

Note that you shouldn't enable RUF's Simple Usernames property if you use this patch in conjunction with GRUF. This is because GRUF is confused about user names and id's.

Appendix 8 - Kerberos

Andrew Bartlett has rewritten mod_ntlm_winbind and he claims that it's coded more cleanly than mod_ntlm and that

"It is also a very good base to add a SPENGO (Negotiate) module, that accepts NTLMSSP as well as kerberos".

There is no official homepage and it may only work with Samba3. You're on your own. Let me know if you succeed.

Update, Oct 21st, 2005: mod_auth_kerb:

Our user jmarks reportedly got this to work with mod_auth_kerb by tweaking RUF to use the User@Domain syntax instead of Domain\User. He posted his version of RUF in a comment to this article. Today I updated RUF such that it can be switched dynamically between the two syntaxes. This updated RUF can now be used with both mod_ntlm and mod_auth_kerb.

Resources

  1. Zope.org
  2. Plone.org
  3. mod_ntlm Sourceforge project page
  4. mod_ntlm project home page
  5. FastCGI.com - The FastCGI home page
  6. Remote User Folder
  7. Group User Folder (GRUF)
  8. Unofficial MOD_NTLM Apache Module
  9. mod_ntlm_winbind back alive
AttachmentSize
GroupUserFolder.py-3.3.patch.bz2697 bytes
GroupUserFolder.py.patch.bz2784 bytes
mod_ntlm.c-apache2.patch.bz2547 bytes
RemoteUserFolder-0.5.1.tar.bz27.29 KB
( categories: Zope/Plone | Webmaster )
Submitted by Anonymous on Fri, 08/11/2006 - 05:09.

I love, love, love it!

Submitted by Hannes Schmidt on Mon, 07/17/2006 - 14:56.

John contacted me with details about his setup which seems to work for him:

Plone 2.1.2, 
Zope (Zope 2.7.8-final, python 2.3.5, win32), 
Python 2.3.5 (#62, Feb 8 2005, 16:23:02) [MSC v.1200 32 bit (Intel)], 
PIL 1.1.4 
 
GRUF 3.5 (with your patch applied).
RUF (your version, 0.5.1, with class NameIsIdUser 
and methods 'getRolesInContext' and 'allowed' added).
 
Have attached my GroupUserFolder.py and RemoteUserFolder.py 
(only files changed in those products).

Thanks again,
John

-- Hannes

The user attached the following files to this comment. The files may contain malicious code. Use at your own risk.
AttachmentSize
RemoteUserFolder.py.txt12.27 KB
GroupUserFolder.py.txt104.7 KB
Submitted by Hannes Schmidt on Wed, 07/12/2006 - 11:23.

... but unfortunately I changed jobs last year and have not been able to access my production installation of Zope+Plone. For that reason, I am not able to verify what you say but I can perfectly imagine that putting NameIsIdUser fixes things for you. I took them out because that fixed things for me ;-). I can't remember exactly why. I hate to say though that the deeper I got into RUF+GRUF and also Plone in general the more I realized what a mess it all was. My biggest concern was Zope's acquisition mechanism. It really is the work of the devil because it is SO opaque and counter-intuitive to code against. In order to help other users that stumble upon this could you post the versions of Zope, Plone and GRUF and maybe even the sources to your RUF? If you register with this site I could give you permission to attach files to your comments. Or you could email it to me (dp hannesschmidt net).

-- Hannes

Submitted by Anonymous on Wed, 07/12/2006 - 02:08.

Sorry for another post on this, but simply changing to the latest GRUF didn't fix the problem - I had to add the class NameIsIdUser to RemoteUserFolder.py and the methods getRolesInContext and allowed to the RemoteUser class (all in the original RemoteUser product).
You removed them for some reason, for me it won't work without them.


Great tutorial though, and thanks for the patches :)

John

Submitted by Anonymous on Tue, 07/11/2006 - 09:29.

Hi,

Nevermind, I think I've sorted the problem.

For the curious:

When I saw that the GRUF patch on this page was for 3.3, I removed my current version (3.5) and applied the patch. I just tried applying the patch to 3.5 and reinstalling it and the problem seems to have gone away.

John

Submitted by Anonymous on Tue, 07/11/2006 - 07:11.

I should add that authentication is fine if I just use RUF as the acl_users (no GRUF), so data is being correctly passed from Apache.

John

Submitted by Anonymous on Tue, 07/11/2006 - 06:49.

Hi,

I'm using your SSO setup, with Gruf 3.3 (with your patch) and your RUF version, on Plone 2.1.2 and Zope 2.7.8.

I find that I am not always authenticated, and I can't figure out why. I've set the RUF as the user source in GRUF (removed acl_users and added a new one), can see the user accounts in GRUF and RUF.

I found that I was unable to access the site setup (plone_control_panel) or any of the forms within. I just got the following error and seemingly meaningless traceback:

Time 2006/07/11 14:09:53.703 GMT+1
User Name (User Id)
Anonymous User (None) Request URL

http://localhost/intranet/home/prefs_error_log_showEntry Exception Type
Unauthorized Exception Value
You are not authorized to access this resource. Traceback (innermost last):

Module ZPublisher.Publish, line 92, in publish
Module ZPublisher.BaseRequest, line 449, in traverse
Module ZPublisher.HTTPResponse, line 673, in unauthorized
Unauthorized: You are not authorized to access this resource.

The user account that I was using has the Manager role. I seem to be authenticated everywhere else in the site. Any suggestions?

Not much in the error log, just the traceback and a lot of lines of:

2006-07-11T14:09:53 INFO(0) RemoteUserFolder url is http://localhost/intranet/home
------

2006-07-11T14:09:53 INFO(0) RemoteUserFolder should be http://localhost/intranet/home

Sorry about the formatting, couldn't really seem to get paragraphs and new lines sorted properly in these comment boxes.

Thanks,
John

Submitted by Hannes Schmidt on Wed, 05/10/2006 - 19:13.

John, you're right - they were incredibly difficult to read. Thanks for pointing that out. The reason behind these captchas is not to require several tries, just to prevent scripted comment spam. Anyway, I use a bigger font size now and less obfuscation. Hope that makes it easier to read the captchas. -- Hannes

PS: I also enabled user registration again. I disabled it because I had a couple of suspicious user registrations a while ago. Registered users don't need to enter captchas when posting comments. They only need to fill out one captcha at registration, that's it.

Submitted by Anonymous on Wed, 05/10/2006 - 15:00.

I found your recipes, and the improved RemoteUserFolder and GRUF patch,
very useful. I am actually using mod_auth_pam on linux to do the authentication, but was getting nowhere before I read your pages.

My only complaint is that your "Verify comment authorship" hidden letters are the hardest to read I have ever seen. Often takes me several tries. (Or is that the point?) - John

Submitted by Anonymous on Thu, 01/26/2006 - 12:52.

Hi,

I'm using your solution with partial success (problems passing back pdf, doc, etc) and now FastCGI is deprecated. This thread (http://archives.free.net.ph/message/20051219.201229.41bd4824.en.html) discusses the problem. One post suggests to REMOTE_USER info from HTTP_X_FORWARDED_FOR (I doubt but it was already sometime ago since I last looked into the headers). Another post suggests "... what is happening is that Zope's HTTPRequest is grabbing the AUTHORISATION header and processing it, sticking the contents into the _auth attribute." This doesn't seem consistent with your claim that "environment variables are not part of a standard HTTP request...".

Any ideas?
regards,
Fernando Martins

Submitted by Anonymous on Sun, 01/15/2006 - 03:18.

HERE IS THE TRACKBACK for the the error when i click "share"

Traceback (innermost last):
Module ZPublisher.Publish, line 113, in publish
Module ZPublisher.mapply, line 88, in mapply
Module ZPublisher.Publish, line 40, in call_object
Module Shared.DC.Scripts.Bindings, line 311, in __call__
Module Shared.DC.Scripts.Bindings, line 348, in _bindAndExec
Module Products.CMFCore.FSPageTemplate, line 188, in _exec
Module Products.CMFCore.FSPageTemplate, line 127, in pt_render
Module Products.PageTemplates.PageTemplate, line 104, in pt_render
-
Module TAL.TALInterpreter, line 206, in __call__
Module TAL.TALInterpreter, line 250, in interpret
Module TAL.TALInterpreter, line 711, in do_useMacro
Module TAL.TALInterpreter, line 250, in interpret
Module TAL.TALInterpreter, line 426, in do_optTag_tal
Module TAL.TALInterpreter, line 411, in do_optTag
Module TAL.TALInterpreter, line 406, in no_tag
Module TAL.TALInterpreter, line 250, in interpret
Module TAL.TALInterpreter, line 742, in do_defineSlot
Module TAL.TALInterpreter, line 250, in interpret
Module TAL.TALInterpreter, line 426, in do_optTag_tal
Module TAL.TALInterpreter, line 411, in do_optTag
Module TAL.TALInterpreter, line 406, in no_tag
Module TAL.TALInterpreter, line 250, in interpret
Module TAL.TALInterpreter, line 690, in do_defineMacro
Module TAL.TALInterpreter, line 250, in interpret
Module TAL.TALInterpreter, line 734, in do_defineSlot
Module TAL.TALInterpreter, line 250, in interpret
Module TAL.TALInterpreter, line 477, in do_setLocal_tal
Module Products.PageTemplates.TALES, line 221, in evaluate
- URL: file:CMFPlone/skins/plone_forms/folder_localrole_form.pt
- Line 148, Column 20
- Expression:
- Names:
{'container': ,
'context': ,
'default': ,
'here': ,
'loop': ,
'modules': ,
'nothing': None,
'options': {'args': ()},
'repeat': ,
'request': ,
'root': ,
'template': ,
'traverse_subpath': [],
'user': john.doe}
Module Products.PageTemplates.ZRPythonExpr, line 47, in __call__
- __traceback_info__: putils.isLocalRoleAcquired(here)
Module Python expression "putils.isLocalRoleAcquired(here)", line 1, in
Module Products.CMFPlone.PloneTool, line 1153, in isLocalRoleAcquired
AttributeError: isLocalRoleAcquired

Submitted by sura on Sun, 01/15/2006 - 01:36.

I'm on Plone 2.1.1, Zope 2.8.4
I'm using the unofficial modntlm

I've installed RUF-0.5.1 from this page.

It all works in terms of NTLM!

Problem 1)
When I click on the "sharing" option on a folder, page etc.. I get this error

--
Site error

This site encountered an error trying to fulfill your request. The errors were:

Error Type
AttributeError
Error Value
isLocalRoleAcquired
--

Does any one know how to fix this!?

Submitted by jmarks on Tue, 11/08/2005 - 19:07.

The new module works like a charm. Thanks for the quick response! I just tried the search feature and got the traceback listed below. This is not a problem for me as I do not intend to use member folders and searches but if you need someone to test some changes you made I would be more than glad to help.

Traceback (innermost last):
  Module ZPublisher.Publish, line 113, in publish
  Module ZPublisher.mapply, line 88, in mapply
  Module ZPublisher.Publish, line 40, in call_object
  Module Shared.DC.Scripts.Bindings, line 311, in __call__
  Module Shared.DC.Scripts.Bindings, line 348, in _bindAndExec
  Module Products.CMFCore.FSPageTemplate, line 188, in _exec
  Module Products.CMFCore.FSPageTemplate, line 127, in pt_render
  Module Products.PageTemplates.PageTemplate, line 104, in pt_render
   - 
  Module TAL.TALInterpreter, line 206, in __call__
  Module TAL.TALInterpreter, line 250, in interpret
  Module TAL.TALInterpreter, line 711, in do_useMacro
  Module TAL.TALInterpreter, line 250, in interpret
  Module TAL.TALInterpreter, line 426, in do_optTag_tal
  Module TAL.TALInterpreter, line 411, in do_optTag
  Module TAL.TALInterpreter, line 406, in no_tag
  Module TAL.TALInterpreter, line 250, in interpret
  Module TAL.TALInterpreter, line 742, in do_defineSlot
  Module TAL.TALInterpreter, line 250, in interpret
  Module TAL.TALInterpreter, line 426, in do_optTag_tal
  Module TAL.TALInterpreter, line 411, in do_optTag
  Module TAL.TALInterpreter, line 406, in no_tag
  Module TAL.TALInterpreter, line 250, in interpret
  Module TAL.TALInterpreter, line 690, in do_defineMacro
  Module TAL.TALInterpreter, line 250, in interpret
  Module TAL.TALInterpreter, line 734, in do_defineSlot
  Module TAL.TALInterpreter, line 250, in interpret
  Module TAL.TALInterpreter, line 477, in do_setLocal_tal
  Module Products.PageTemplates.TALES, line 221, in evaluate
   - URL: file:CMFPlone/skins/plone_forms/member_search_results.pt
   - Line 148, Column 20
   - Expression: 
   - Names:
      {'container': ,
       'context': ,
       'default': ,
       'here': ,
       'loop': ,
       'modules': ,
       'nothing': None,
       'options': {'args': ()},
       'repeat': ,
       'request': ,
       'root': ,
       'template': ,
       'traverse_subpath': [],
       'user': jmarks}
  Module Products.PageTemplates.ZRPythonExpr, line 47, in __call__
   - __traceback_info__: mtool.searchForMembers(request)
  Module Python expression "mtool.searchForMembers(request)", line 1, in 
  Module Products.CMFPlone.MembershipTool, line 438, in searchForMembers
  Module Products.CMFCore.MembershipTool, line 124, in wrapUser
AttributeError: 'NoneType' object has no attribute '__of__'

Submitted by Hannes Schmidt on Tue, 11/08/2005 - 16:47.

Yeah, I figured that, too. I think though that RemoteUser objects need to be acquired by the RUF. Simply omitting __of__(self) breaks other things. Now, I am working on a version that has your fix AND returns a properly acquired object GRUF when needed. I also worked on multi-domain support for mod_ntlm and I fixed the other problem you mentioned (split given 3 instead of 2 parameters). That one was actually pretty stupid on my behalf.

I will upload my work in the next hour. Thanks, Joey.

Update: Did that just now. I'd be really interested to see if it fixes your problems. Could you also let me know whether it fixes the problem with user search?

Submitted by jmarks on Tue, 11/08/2005 - 13:28.

Sorry for jumping the gun earlier but I found the real cause of the problem with your _doAddUser function. It seems that it simply didn't like the .__of__(self) part at the end though I admit I have no idea what it is used for. Here is what I changed from your code:

Old line:
self.data[ name ] = RemoteUser( self, name, roles, domains ).__of__( self )^M
New line:
self.data[ name ] = RemoteUser( self, name, roles, domains )

Submitted by jmarks on Tue, 11/08/2005 - 10:51.

I recently upgraded my Plone and Zope to the most recent versions and encountered the problem mentioned by peppiv "TypeError: Can't pickle objects in acquisition wrappers." After trying many things to try and fix this I reached a point where I had just about given up. However while re-reading your conversation thread with peppiv I saw that he mentioned that the original RUF implementation did create users with no error. I compared the two versions and noticed that the old version had 2 declarations of the _doAddUser function but the newer one commented out the second. The first declaration used the RemoteUser object but the second used simply the User object. I tried commenting out the first declaration and uncommenting the second in your most recent RUF version (0.5) and suddenly I could create users both with the interface and with auto-create!

I am not certain yet if this could cause problems in other areas but at first glance I think this is usable. You might want to have a look yourself because I suspect that upgrading your Zope and Plone setup will cause this problem to rear it's ugly head again. Eventually we all want to upgrade don't we?

Joey

Submitted by jmarks on Tue, 11/08/2005 - 10:43.

I've recently had to do more work on this implementation due to my desire to upgrade my Plone to the latest 2.1.1 and generally update all components.

It seems that your patch to RUF that allows both kerberos and NTLM domain extensions is broken on the Kerberos side of things. I get the following error when RUF tries to auto-create a user:

Traceback (innermost last):
Module ZPublisher.Publish, line 104, in publish
Module ZPublisher.BaseRequest, line 445, in traverse
Module Products.GroupUserFolder.GroupUserFolder, line 1025, in validate
Module Products.RemoteUserFolder.RemoteUserFolder, line 177, in validate
Module Products.RemoteUserFolder.RemoteUserFolder, line 148, in normalizeName
Module Products.RemoteUserFolder.RemoteUserFolder, line 125, in splitName
TypeError: split() takes at most 2 arguments (3 given)

I have tried changing a few things on the affected line but with my near non-existent knowledge of Python I have not been able to get it to work.

Could you have a look at this and see if you can figure out why I am getting the error?

Thanks, Joey

Submitted by Hannes Schmidt on Thu, 10/27/2005 - 09:20.

... moved here.

Submitted by Hannes Schmidt on Thu, 10/27/2005 - 09:01.

... moved here.

Submitted by Hannes Schmidt on Fri, 10/21/2005 - 11:31.

Thanks for your support, jmarks. See my updates to Appendices 5 and 8.

Submitted by jmarks on Wed, 10/05/2005 - 11:40.

In my testing I encountered a problem with member searches when a wildcard user was present and wanted to share my discovery. This problem presents itself with an error in the search result page stating: "getUser() takes exactly 2 arguments (1 given)". I believe this could be resolved by somehow changing the user preferences for this user to not be listed in member search results but since I did not require member folders I simply removed them and did not attempt to resolve this.

I also noticed that user management is limited to certain interfaces and that others simply do not work. This is not much of an issue as the whole point of SSO is that we are not managing users in zope but zope group membership does still need to be managed. I found that the only way to effectively manage groups and users is using the ZMI and going directly to the RUF folder properties.

Submitted by jmarks on Wed, 10/05/2005 - 11:31.

As requested I am uploading my modified RUF module. Unfortunately I did not have the time to properly modify the module so that it accepts both the DOMAIN\user and user@DOMAIN.com syntax but I doubt there would be a need to support both at the same time anyways.

The user attached the following files to this comment. The files may contain malicious code. Use at your own risk.
AttachmentSize
RemoteUserFolder.py.bz23.54 KB
Submitted by Hannes Schmidt on Tue, 10/04/2005 - 01:13.

Many people have asked whether there is a way to do this SSO with Kerberos. I'm glad to hear that you got it working. Nice job! I granted you upload permissions so you can attach files to comments. Do you want to post your modified RUF?

Submitted by jmarks on Mon, 10/03/2005 - 11:56.

Absolutely beautiful. I applied your GRUF 3.3 patch which fixed some weird problems I had been having with my kludge, then I put in your RUF module which finally enabled role assignment.

After this though I ran into the problem that since I am using kerberos the usernames were being passed on to RUF in the form of user@domain.com. This of course completely broke the member folder creation due to the incompatible @ character. I then decided to modify the RUF module so that instead of searching for DOMAIN\user it now searches for user@domain.com. Having done that and enabled simple usernames I now have full functionality with member folders and the works.

I will keep working with this setup to see if I find any other problems but so far it looks great. Thanks for the great howto it really put me on the right track to get SSO working with our environment.

Submitted by Hannes Schmidt on Sat, 10/01/2005 - 01:21.

I'm so stupid. The upload module's default permissions don't allow users to view uploaded files. I fixed that. For future reference: always test your Drupal site as an anonymous user.

Also note my update to appendix 5. I wanted to publish my works on RUF more than a month ago but due to my relocation I didn't have enough time to work on these matters. Let me know how things work out for you, jmarks. So far it works for one guy (me) and doesn't for the other (peppiv).

Submitted by jmarks on Fri, 09/30/2005 - 11:27.

I'm trying to find the RUF patches you wrote about in your previous posts and your updated GRUF 3.3 patch (even though I hacked that one in from the info I found in previous posts). They are not posted with the article as mentioned.

I was also wondering if you had any updates on your work with this or you guys had given up. I am currently trying to get a very similar setup going but using mod_auth_kerb going against a Linux LDAP+ Kerberos setup instead of NTLM on Windows. I am running into the same problems as you with authentication working with RUF standalone but not with GRUF and would like to see how far I can go with this.

Submitted by Hannes Schmidt on Tue, 07/05/2005 - 14:30.

Sorry for the late reply. I had a quick look and it seems that you extend LDAPUserFolder and that you use a cookie that I didn't know of. Is it mod_ntlm that sends the cookie? You'd still need Apache (Version 2 only?) and NTLM for the actual authentication. I like the fact that you use LDAPuserFolder. That means that a lot more user info is available and that users are not created on the fly as in my solution. I will definitely try it out and maybe post an updated/alternative version of this HOWTO. Are you still maintaining your product?

Submitted by Anonymous on Fri, 07/01/2005 - 13:46.

I wrote this product last year:
http://svn.nuxeo.org/trac/pub/browser/CMFNtlmSso/

It seems more simple to me that this method.

What did you think of it ?

Submitted by Hannes Schmidt on Wed, 06/29/2005 - 02:36.

Hi Cecilia, I think using the version of NTLM described in Appendix 6 supports multiple domains. I think you also need to remove the NTLMDomain YOURDOMAIN line from httpd.conf. Could you let us know if it works? I've seen this question somewhere else also.

Submitted by Anonymous (not verified) on Mon, 05/02/2005 - 13:22.


I wasn’t able to replace the default acl_users folder with a different one, say Remote User Folder (RUF) because after removing the acl_users folder, I couldn’t do anything at all because the manager (me) was locked out. There may be a trick to get around this, though.

I had a similar problem once, and found you needed to use the Emergency User which is referred to in the Zope Book in the Users and Security section. One of the tasks of the Emergency User is administering User Folders.

Submitted by Hannes Schmidt on Wed, 04/13/2005 - 16:24.

No, Samba isn't necessary. Looks like there is simply a networking problem. Can you ping either of the domain controllers, i.e. does "ping 10.3.3.51" work? I notice that the domain controllers are in a different subnet as your web server. Is there a router or firewall between them that prevents access to port 139? What happens if you do a "telnet 10.3.3.51 139"?

Submitted by Kima (not verified) on Tue, 04/12/2005 - 06:06.

I have installed Plone on Red Hat.
I have Active Directory on Windows 2000 Server.

I get the next error:

[Tue Apr 12 14:00:44 2005] [error] 5336 - RFCNB_Call: RFCNB_IP_Connect to 10.3.3.50 and port 139 failed
[Tue Apr 12 14:00:44 2005] [error] 5336 - RFCNB_Call: RFCNB_IP_Connect to 10.3.3.51 and port 139 failed
[Tue Apr 12 14:00:44 2005] [error] [client 10.3.4.10] 135670304 5336 /ntlmtest - send_ntlm_challenge: no conn. handle...trouble communicating with PDC/BDC? returning internal server error

Is it necessary to install Samba on Red Hat?

Thanks!

Submitted by Jørgen Larsen (not verified) on Thu, 01/20/2005 - 14:49.

Hi, Do you have any advice on how to get Remote User Folder to work as a source for GRUF.

Submitted by Anonymous (not verified) on Thu, 01/20/2005 - 01:18.

Is there an existing solution to do an authentication with the kerberos apache module, Zope (Plone) against an Active Directory Domain ?

Submitted by Hannes Schmidt on Thu, 01/06/2005 - 09:57.

But here's my daisy cutter response. If you want flexibility, take Zope or Typo3. If you want a clean, extensible architecture take Zope. If you don't want to learn Zope and Python but need a website with similar flexibility, take Typo3. If you want a simple blog or a community oriented website that runs out of the box and doesn't require a lot of studying, take Drupal (or Plone if you are willing to go through the hassle of installing a recent version of Python and Zope). I know just enough about Mambo and Moveable Type to say that they are at least worth a look.

Submitted by Gleb (not verified) on Wed, 01/05/2005 - 18:19.

And what about typo3?
Do you think that typo is wors then those two?