Single Sign On In Windows Domains

This HowTo tells you how to integrate Zope, Plone and Apache in a Windows domain such that domain users are automatically logged into Plone. It's also a tutorial about getting Zope/Plone to run behind an Apache web server using FastCGI.

The original of this HowTo can be found at Diary Products.

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 …

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.

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.

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

Can't get mod_ntlm to work with RH9/Apache 2

Posted by Dennis Halladay at Dec 29, 2004 09:50 PM
I've tried following the instructions, and get an error
send_ntlm_challenge: no conn. handle...trouble communicating with PDC/BDC?
when I run the /ntlmtest to verify mod_ntlm

While searching for patches I've seen several buffer overflow
security warnings against this module along with comments that it is
no longer maintained. It does not appear on the apache site as an
'official' module. Are there other (maintained) options for NT
domain authentication?

Thanks,
 -Dennis

Error due to mod_ntlm paramaterer

Posted by Dennis Halladay at Dec 30, 2004 05:22 PM
I was using fully qualified names for NTLMServer and NTLMBackup. Once I dropped the domain name suffix from these parameters mod_ntlm worked as advertised.

tip to simplify the url

Posted by Fernando Martins at Sep 07, 2005 04:56 PM
Thanks a lot for the howto. I would like to add how to simplify the URLs which, as per the above, would be http://site/zope/intranet. I wanted to have http://site/intranet. For that I use mod_rewrite with a config similar to the next, put before the Location directives:<br>
<pre>
    RewriteEngine on
# don't change the URL if it starts already with /zope/ and stop rewriting
    RewriteRule ^/zope/.* - [PT,L]
# as an exception, the folder /subarea goes to Apache (not zope)
    RewriteRule ^/subarea/(.*) - [L]
# make URLs start with /zope to be sent through FastCGI
    RewriteRule ^(.*) http://site/zope$1 [PT]
    ProxyVia on
</pre>

Of course, you could also do something as http://intranet/

HTH someone,

Commercial Single Sign On

Posted by Alan Runyan at Mar 31, 2006 07:20 AM
Commercial Plug:

The commercial package, Enfold Server can get your single sign on solution up and running on Plone in less than 5 minutes. For people who want a supported Windows integration that is proven on LDAP directories of tens of thousands of users. Enfold Server is available for 30 day free trial.

A lot of people do not know there are commercial offerings for Plone with regards to SSO and getting this up and running without consulting can be daunting. This is why I'm adding this comment to bring attention for those who want Plone and have money and want a solution that Just Works.

OpenSource *and* Free NTLM SSO

Posted by Encolpe Degoute at Apr 11, 2006 10:54 AM
CMFNTLMSso is very similar to the configuration explain here with more security between proxy and Zope server. It is based on CMF cookie Crumbler the can works perfectly for Plone.

CMFNTLMSso and fastcgi

Posted by Encolpe Degoute at Apr 11, 2006 10:56 AM
CMFNTLMSso doesn't need Fast CGI configuration, Apache make the works.

note about where to put NTLM statements

Posted by Natalia Muravieva at Jun 28, 2006 01:15 PM
I use mod_ntlm in combination with TWiki installation under apache 1.3 and I found that the only way to force apache send non empty REMOTE_USER variable to TWiki is to put NTLM statments into <Location> directive. If I just add them to <Directory> directive authorization itself works (valid users get access to the resource) but REMOTE_USER variable which is used to connect users to their TWiki accounts is empty.

Apache/NTLM on Windows XP OS?

Posted by William Sears at Jul 06, 2006 01:09 AM
Is it possible to use this technique on a non-unix OS? I'm trying on Windows XP, but imagine I need an NTLM module that is compiled for Win 32? Any pointers for how I would go about that?

for win32 try mod_auth_sspi

Posted by matt wilkie at Aug 11, 2006 06:31 PM
it's a little old now, but this setup works for me on windows:

http://twiki.org/[…]/WindowsInstallModNTLM#mod_auth_sspi_Apache_2_x

Updated for using mod_rewrite rather than fastcgi

Posted by Michael Baltaks at Dec 10, 2006 10:54 PM
As of December 2006, Plone is at 2.5.1, Zope is 2.9.6 and Apache is 2.2.3. Zope 2.9 has depreciated fastcgi altogether, and apache 2.2 won't work nicely with mod_fastcgi (mod_fcgid works, but doesn't support the FastCgiExternalServer needed for zope with fastcgi). So I needed to keep using mod_ntlm, but use it with mod_rewrite rather than fastcgi. And I've made it work!

Assuming a plone site in zope called /plone, here is some apache 2.2 config that works with mod_rewrite, mod_proxy (and mod_proxy_http) and mod_headers.

<Location /zope/plone>
# Use this line instead (with the lines below) to have plone at the web site root.
#<Location /plone>
    AuthName "Active Directory Domain"
    AuthType NTLM
    NTLMAuth on
    NTLMAuthoritative on
    NTLMDomain domain
    NTLMServer domain-controller-1
    NTLMBackup domain-controller-2
    require valid-user
</Location>

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
RewriteEngine On
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule ^/zope/(.*) \
http://localhost:8080/VirtualHostBase/http/%{SERVER_NAME}:80/VirtualHostRoot/_vh_zope/$1 \
[L,P,E=RU:%1]
# Use these alternatives with the alternative Location above to put plone at the root.
#RewriteRule ^/(.*) \
#http://localhost:8080/VirtualHostBase/http/%{SERVER_NAME}:80/VirtualHostRoot/$1 \
#[L,P,E=RU:%1]
RequestHeader set X_REMOTE_USER %{RU}e

To make mod_ntlm work correctly with this reverse proxy config, I had to make some changes, which are now in the trunk of subversion at the source forge project. svn co https://modntlm.svn.sourceforge.net/svnroot/modntlm/trunk - this is the same code as found at http://modntlm.jamiekerwick.co.uk/ with a patch to fix reverse proxy auth.

On the zope/plone side, I had to install apachepas (http://dev.plone.org/[…]/apachepas, svn co http://svn.plone.org/svn/collective/PASPlugins/apachepas) into the products folder and add it to the acl_users folder for the plone instance. Make sure you put the contents of the trunk folder into a folder called "apachepas" in the products folder. I also needed LDAPMultiPlugins (http://www.dataflake.org/software/ldapmultiplugins) which might depend on LDAPUserFolder (http://www.dataflake.org/software/ldapuserfolder) - both just need to be copied into the products folder and then LDAPMultiPlugins added to the acl_users folder in the plone instance. Configuring the LDAPUserFolder within LDAPMultiPlugins is up to you, since it depends on your directory layout. I suggest talking to an (Active, e-, Open) Directory expert, and using an LDAP browser to get the settings right before going to the LDAPUserFolder.

As a starting point, here's the schema I used for Active Directory:
LDAP, Friendly name, maps to, multi
-----------------------------------
objectGUID, AD Object GUID, objectGUID, No
cn, Canonical Name, , No
dn, Distinguished Name, dn, No
givenName, First Name, first_name, No
memberOf, Group DNs, memberOf, Yes
sn, Last Name, last_name, No
sAMAccountName, Windows Login Name, windows_login_name, No
mail, Email address, email, No
displayName, Full Name, fullname, No

Then make Login Name Attribute and User ID Attribute use sAMAccountName.
Match all the Zope groups with LDAP groups, if required.
Activate all the plugins for all the types (Authentication, Extraction, etc)
Now you can search for users and add them to groups.
That was it.



For reference, I also made the fastcgi method work before I attempted this, using SharkbyteSSOPlugin (http://plone.org/[…]/sharkbytessoplugin-0-5-tar.gz) in place of apachepas. I had to set SharkbyteSSOPlugin to use REMOTE_USER, rather than X_REMOTE_USER, but all the other setup was the same. This was with Apache 1.3.37 and mod_fastcgi SNAP-0404142202 and my patched mod_ntlm, and patched FCGIServer.py for Zope.

--- /usr/local/zope/lib/python/ZServer/FCGIServer.py 2006-10-03 01:53:27.000000000 +1000
+++ ./FCGIServer.py 2006-11-22 23:01:19.000000000 +1100
@@ -466,6 +466,11 @@
                     user_name = '-'
                 else:
                     user_name = t[0]
+ if string.lower(http_authorization[:5]) == 'ntlm ':
+ # The user_name is set elsewhere
+ user_name = "ntlm user"
+ else:
+ user_name = "Unsupported HTTP Auth type"
         else:
             user_name='-'
         if self.addr:

Save the above to zope-fcgi-ntlm.patch then run:
patch -p0 $PREFIX/zope/lib/python/ZServer/FCGIServer.py zope-fcgi-ntlm.patch

Going in Circles

Posted by David L Ernstrom at Dec 20, 2006 10:09 PM
I have been chewing on this project for a number of weeks now without any success. It seems there are two avenues that seem potential for success but brickwalls wait me at the end of the path.

First, my setup:
Windows 2003 Domain Controller
Windows XP Pro acting as an Apache 2.2.3 Webserver (XAMPP package).
Python 2.4.3, Zope 2.9.5, and Plone 2.5.1 from binary package.

Avenue #1: mod_fastcgi.so
httpd.conf contains at least the following:
    LoadModule fastcgi_module modules/mod_fastcgi.so
    LoadModule sspi_auth_module modules/mod_auth_sspi.so

    FastCgiExternalServer "C:/Program Files/Plone 2/" -host localhost:8081 -pass-header Authorization

    <Location /plone>
        SetHandler fastcgi-script
        AuthType SSPI
        SSPIAuth On
        #SSPIAuthoritative On
        SSPIOfferBasic Off
        SSPIOmitDomain On
        SSPIUsernameCase upper
        SSPIBasicPreferred Off
        SSPIMSIE3HACK on
        Require valid-user
    </Location>
    <Directory "C:/Program Files/Plone 2/">
        Order allow,deny
        Allow from all
    </Directory>
    alias /plone "C:/Program Files/Plone 2/"

zope.conf (again contains at least the following):
    <fast-cgi>
        # valid key is "address"; the address may be hostname:port, port,
        # or a path for a Unix-domain socket
        address localhost:8081
    </fast-cgi>


This actually works the best, in that the NT Username is displayed as the logged on user. However, none of the CSS files load, i.e., there are no images or proper formatting of the plone site. Also, I end up with an error message near the bottom that says:
          Server error!
          The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there was an error in a CGI script.
          If you think this is a server error, please contact the webmaster.
          Error 1
Looking at the apache logs, it appears that the images are trying to load via the site root: /btn.gif rather than /plone/btn.gif so my assumption is that there should be more plone/zope configuration that could resolve the issue. Also, all hyperlinks on my default plone site reference my page as though it were at the domain root rather than the plone subfolder.

Avenue #2: mod_rewrite.so
This is my preferred method because I'd like to host several other html/php pages on the same machine accessed via a different url, however I haven't been at all successful.
I have attempted the following configuration in my httpd.conf:
NameVirtualHost *
<VirtualHost *:80>
    ServerName www.*****A.com
    ServerSignature On
    <IfModule mod_rewrite.c>
        RewriteEngine On
        RewriteLog logs/Rewrite.log
        RewriteLogLevel 9
        RewriteCond %{LA-U:REMOTE_USER} ^.+
        RewriteRule ^/(.*) http://localhost:8080/VirtualHostBase/http/%{SERVER_NAME}:80/Plone/VirtualHostRoot/$1 [L,P,E=RU:%1]
        RequestHeader set REMOTE_USER %{RU}e
    </IfModule>
</VirtualHost>
<VirtualHost *:80>
    ServerName www.*****B.com
</VirtualHost>
(I'm using the same SSPI setup as in option 1 without the cgi line)

In this avenue, I know that I am picking up the correct virtual host option because I can create/set arbitrary headers. If I change the + to a *, the redirect happens because regardless of the REMOTE_USER setting, the RewriteCond succeeds. However, I believe I need to have the + so that I only rewrite if the REMOTE_USER variable is set. I think that part of the problem here may be the process of apache authentication. I believe that when the initial request is made, apache returns an error effectively saying auth required. I actually show 2 auth required responses before a 200 code is logged. I assume that the 200 code is logged when the REMOTE_USER flag is finally set due to the client actually passing correct credentials.

I have tested functionality by commenting out the RewriteCond and RewriteRule lines and going to a phpinfo.php page which I dropped into the plone folder. The Apache header REMOTE_USER looks to be set to my domain username, so I can't figure out what is wrong.

If there is anybody who has the same configuration as I do that has a functioning setup, please guide me in the correct direction. I come back to this page about every day or so checking for further guidance, so I ought to respond fairly quickly to suggestions.

CSS Problem

Posted by Dominik Ruf at Dec 28, 2006 08:36 AM
For the CSS problem I think you should try to use the actual hostname instate of localhost.

access denied or logs in as "(null)"

Posted by John Fugazi at Jan 26, 2007 09:31 PM
i have tried your suggestion, but i always get "access denied". i am using the openSUSE 10.2 install of plone. i also have LDAPUserFolder and LDAPMultiPlugin configured correctly (i can log in as any user in my domain). i have also install apachepas and SharkbyteSSOPlugin. openSUSE installs plone at /var/opt/zope/default/ . this is what i have:
************************************
<VirtualHost 192.168.200.20:80>
    ServerName openSUSE

    ErrorLog /var/log/apache2/openSUSE-error_log
    CustomLog /var/log/apache2/openSUSE-access_log combined

    ServerSignature On

<Location "/var/opt/zope/default">

AuthName "Active Directory Domain"
AuthType NTLM
NTLMAuth on
NTLMAuthoritative on
NTLMDomain domain.com
NTLMServer ads

require valid-user
</Location>

RewriteEngine On
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule ^/var/opt/zope/(.*) \
http://localhost:8080/VirtualHostBase/http/%{SERVER_NAME}:80/\
VirtualHostRoot/plone_site/$1 [L,P,E=RU:%1]

RequestHeader set X_REMOTE_USER %{RU}e
</VirtualHost>
***********************************
this gives me a "Access Denied"
now if i was to comment out "RewriteCond %{LA-U:REMOTE_USER} (.+)" and replace my RewriteRule with "RewriteRule ^/(.*) \
http://localhost:8080/VirtualHostBase/http/%{SERVER_NAME}:80/\
plone_site/VirtualHostRoot/$1 [L,P,E=REMOTE_USER:%{LA-U:REMOTE_USER}]"

it will bring up the site and log on with "(null)" as the user.

any suggestions?????

Now with Apache VirtualHosts!

Posted by Michael Baltaks at Feb 07, 2007 01:38 AM
I've now got the same setup working using virtual hosts so I can have different sites using different host names on the same server (and same IP address).

NameVirtualHost *:80

<VirtualHost *:80>
    ServerName plone1.domain.com
    ServerAlias plone1

<IfModule mod_ntlm.c>
    <Location />
        AuthName "Active Directory Domain"
        AuthType NTLM
        NTLMAuth on
        NTLMAuthoritative on
        NTLMDomain domain
        NTLMServer domain-controller-1
        NTLMBackup domain-controller-2
        NTLMBasicAuth on
        NTLMBasicRealm AD
        require valid-user
    </Location>
</IfModule>

# Zope/Apache rewrite rules with virtualhost
ProxyRequests Off # Don't become a spam bot.
<Proxy *>
    Order deny,allow
    Allow from all
</Proxy>
RewriteEngine On
RewriteCond %{LA-U:REMOTE_USER} (.*)
RewriteRule ^/(.*) \
http://localhost:8080/VirtualHostBase/http/%{SERVER_NAME}:80/plone/VirtualHostRoot/$1 \
[L,P,E=RU:%1]
RequestHeader set X_REMOTE_USER %{RU}e

</VirtualHost>

SSO works

Posted by John Fugazi at Feb 08, 2007 07:21 PM
Thanks Michael Baltaks. But while I was trying to get this to work (I always got "(null)" to log in), I realize that if set the header with anything, like "yoyo-ma", it would log that person in. After I cut-and-paste Michael Baltaks conf, SSO worked on my intranet. So I reconfigured my LDAPMultiPlugin to only a few people (I have my users organized into separate OUs) and I was still able to log in users that were not listed in LDAPMultiPlugin. I guess apachepas does not verify members in acl_users.

Also, is there a way to get apache to only authenticate users using NTLM on the intranet and authenticate normally when a user is at home (extranet)?

Choosing auth method

Posted by Michael Baltaks at Feb 08, 2007 08:34 PM
If you have different IP addresses or even just different host names for intranet vs extranet then it shouldn't be too hard to create a separate VirtualHost with basic or some other auth method via the extranet. That is, just copy the entire VirtualHost for the intranet, and change the server name and auth sections.

apachepas and sharkbytessoplugin

Posted by John Fugazi at Feb 08, 2007 08:45 PM
thanks for the tip for the extranet.

but for these two plugins, i went and installed both and deleted my LDAPMultiPlugin. i activated one plugin at a time. they both allow the users (on the intranet) to log in even when the LDAPMultiPlugin folder is deleted. am i missing something?

Use Apache to control logins

Posted by Michael Baltaks at Feb 08, 2007 08:59 PM
When you use apachepas, you are accepting any user apache sends your way. So you need to use apache to block users if needed. Unfortunately with mod_ntlm, Windows groups don't seem to be supported, so you're left entering users individually, ie. change Require valid-user to Require user username (for as many users as you need). It's a pain, but I don't have time to add group support to mod_ntlm right now.

In my setup, anyone can view the site (so mod_ntlm has Require valid-user) but only those with permission can edit. I did this by making the default permission Anonymous, and then using the LDAP plugin for plone to give specific users the correct permission.

Problem with %{LA-U:REMOTE_USER}

Posted by Dominik Ruf at Feb 08, 2007 09:32 AM
I used the mod_auth_sspi module and it works with the apachepas plugin.
But I am always asked for username and password of my windows account.
I realized that when ever I use %{LA-U:REMOTE_USER} mod_auth_sspi asks me for username and password.
When I when I don't use %{LA-U:REMOTE_USER} mod_auth_sspi automatically takes the windows account.

Has anybody an idea how to solve this?

Finally

Posted by Dominik Ruf at Feb 09, 2007 08:37 AM
Hi,

I finally made it work :-)
I use:
http://dev.plone.org/[…]/apachepas
http://sourceforge.net/projects/mod-auth-sspi
Apache mod_rewrite, mod_headers
and some hacks :-)


First I installed apachepas as mentioned by Michael Baltaks (SharkbyteSSOPlugin and RemoteUserFolder didn't work for me) and configured SSPI and rewrite as mentioned by David L Ernstrom. But I had to use "RequestHeader set X_REMOTE_USER %{RU}e" instead of "RequestHeader set REMOTE_USER %{RU}e".

As I mentioned above in this configuration I am still been asked to insert username and password. But the reason why I am using SSPI is that the users are automatically logged in and do not have to insert anything. In the Apache manual (http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html) I found some thing to avoid this. If I move the RewriteRule from the httpd.conf to a .htaccess file I can use %{REMOTE_USER} instead of %{LA-U:REMOTE_USER}. So I moved the configuration to a .htaccess file in the DocumentRoot directory of the apache installation.

But that lead me to the next problem. Now the CSS files couldn't be loaded and my plone looks quite ugly :-(
I found out that the URLs with whitespaces(%20) don't work any more. I couldn't find out why so I rename the Skins from "Plone Default" to "Plone_Default" and from "Plone Tableless" to "Plone_Tableless" and now it works.

Another hack I made was to remove the domain from the username. I added the following to auth.py in the apachepas product just after the "if '@' in user_id" block :
    if '\\' in user_id:
        parts = user_id.split('\\')
        user_id = parts[1]

I am not happy with the situation that whitespaces don't work so if anybody has an advise for me why please let me know.

I hope this helps some people.

patched version of mod-ntlm2 for Apache 2.2

Posted by Kirk Fretwell at Dec 01, 2007 12:55 AM

Firefox 3

Posted by Clemens Steinkogler at Aug 01, 2008 11:03 AM
Is it possible that SSO with Firefox 3 doesn't work anymore even if the site is added to network.automatic-ntlm-auth.trusted-uris? Is there another possibility for SSO without the mod_ntlm?

Howto doesn't work

Posted by Devis Calio at Apr 22, 2009 03:12 PM
Hi All,

I followed the steps described in this howto, but with unsuccess.
I'm using a Debian Lenny, Apache 2.2.9, and Zope 2.10.
Apache's root is /var/www
Zope's root is /var/lib/zope2.10

NT Domain is a Samba Server without LDAP.

Anyone can help me?

Thx

Devis