Why basic Apache Authentication? Well, it's the basis on which things like Alfresco + CAS and Alfresco + Shibboleth work, it can be used for SSL client cert auth, it's fairly easy to setup, I know most of the pieces already (always a bonus!). My aim in this - get Alfresco Explorer and the /wcservices/ WebScripts trusting Apache provided authentication. I'm not looking at Share, that's a follow-on post.
So, what components do we need? Firstly, there's the Alfresco External Authentication Subsystem. Next there's Tomcat AJP-13. There's Apache mod_jk to talk AJP-13. Finally, there's the basic Apache Authentication. Because I just want to test, I'm using a simple file based Apache auth setup. You likely won't use that in production, but it'll get you most of the way to a working SSO setup, and is easy to test with.
Our first thing to do is tell Alfresco that it can trust the remote authentication from Apache. (The process for this is similar to enabling Header based external Authentication). To do this, we need to enable + configure another Authentication SubSystem, specifically the External Auth SubSystem. Create a directory
alfresco/extension/subsystems/Authenticain your usual customisation spot (typically a module or the Tomcat Shared Classes). Into this new directory, create
external-authentication.properties, and populate it with something like:
# Which users should be treated as an Admin? external.authentication.defaultAdministratorUserNames=admin,nick # Enable the External Authentication external.authentication.enabled=trueThat's not all though, you also need to add this new authentication subsystem to the active list. Somewhere, quite possibly in your
alfresco-global.propertiesfile you should have an
authentication.chainline. Prepend this with
external-apache:external, something like:
# This is what we used to have, LDAP + Built-in ##authentication.chain=ldap-main:ldap,alfrescoNtlm1:alfrescoNtlm # Try the External Auth if we can, otherwise the previous ones authentication.chain=external-apache:external,ldap-main:ldap,alfrescoNtlm1:alfrescoNtlmRestart Alfresco, and check that you can log in as before. You should also see (assuming the default logging settings) something like
INFO [org.alfresco.repo.management.subsystems.Cin your logs to show it was found and used.
hildApplicationContextFactory] Starting 'Authentication' subsystem, ID: [Authentication, managed, external-apache]
Next up, we need to enable AJP-13 in Tomcat, and tell it to trust Apache supplied Authentication. I'm assuming you have two Tomcats, one for Alfresco on port 8080, and one for Share on 8081. If you only have one, skip the Share/8081/8010 bits. Edit
[Tomcat Root]/conf/server.xml; for both Tomcats. Around line 90, you should come across an AJP Connector section, which may be commented out. Uncomment it, set the Alfresco one to port 8009 (default), and the share one to 8010. Finally, add the attribute
tomcatAuthentication="false"to the Connector. This should give you something on the Alfresco Tomcat looking like:
<!-- Define an AJP 1.3 Connector on port 8009 --> <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" tomcatAuthentication="false" />And for Share it'll be:
<!-- Define an AJP 1.3 Connector on port 8010 (Alternate Port) --> <Connector port="8010" protocol="AJP/1.3" redirectPort="8443" tomcatAuthentication="false" />Restart your tomcats, and ensure they come up without error. Check you can telnet to localhost 8009 and 8010 (there's no welcome banner) to ensure the Tomcats are listening and no local firewalling breaks.
If you haven't already, install a copy of Apache (latest 2.4, or perhaps even 2.5/2.6 if that's out by the time you read this!), and make sure you can get the welcome page up. If on a Unix, make sure you have the Apache developer tools package installed too, if you're doing a package install. If you can, install a packaged version of the Tomcat Connectors module. Failing that, grab the source code and build + install the module
There are two parts to configuring up mod_jk, the first is a JK specific file worker.properties, the second is the regular Apache config. For the former, create a new file somewhere sensible (but make sure it's not somewhere that Apache auto-loads config files from, or you'll get errors). FWIW, I created a new directory under /etc/apache2/ of conf.other and created it as
tomcat-workers.propertiesbut it'll depend on your distro. Assuming you setup your Tomcat AJP as above, create the file with:
# For communicating with Tomcat via AJP13 # We have two Tomcats, and we'd like status please worker.list=jkalfresco,jkshare,jkstatus # Enable the status worker worker.jkstatus.type=status # Alfresco is on 8080 (http) / 8009 (AJP) worker.jkalfresco.type=ajp13 worker.jkalfresco.host=localhost worker.jkalfresco.port=8009 worker.jkalfresco.connection_pool_timeout=600 worker.jkalfresco.socket_keepalive=1 # Share is on 8081 (http) / 8010 (AJP) worker.jkshare.type=ajp13 worker.jkshare.host=localhost worker.jkshare.port=8010 worker.jkshare.connection_pool_timeout=600 worker.jkshare.socket_keepalive=1
Now, define a new vhost to Apache, either by tacking it on the end of your httpd.conf, or putting it in a new file in conf.d, or in sites-enabled, or .... as appropriate for your setup. To start with, go for something like:
# Load the mod_jk module (your path to it may be different) LoadModule jk_module /usr/lib/apache2/modules/mod_jk.so # These paths may need changing for your setup too # Where the file we created above lives JkWorkersFile /etc/apache2/conf.other/tomcat-workers.properties # Where to put jk shared memory JkShmFile /var/log/apache2/mod_jk.shm # Where to put jk logs JkLogFile /var/log/apache2/mod_jk.log # Set the jk log level [debug/error/info] JkLogLevel info # Select the timestamp log format JkLogStampFormat "[%a %b %d %H:%M:%S %Y] " # Define the vhost that'll expose Tomcat <VirtualHost *:80> ServerAdmin webmaster@localhost ServerName local-alfresco JkMount /status jkstatus JkMount /alfresco jkalfresco JkMount /alfresco/* jkalfresco JkMount /share jkshare JkMount /share/* jkshare </VirtualHost>The ServerName needs to be unique, so either make it your machine name (only vhost), or create a new alias for 127.0.0.1 in your
/etc/hostsfile and use that. Restart apache, and try visiting [server name]/status to check that mod_jk is loaded and running. Then, visit [server name]/alfresco and check that you get explorer as guest.
Finally, before we consider about how it all fits together, we need to turn on Authentication in Apache, so it has some auth to pass to Tomcat. Full details on this are in the Apache docs, but basically you'll want to use htpasswd to create a digest password file, something like:
$ # Create the file, add admin $ htpasswd -c /etc/apache2/conf.other/alfresco.htpasswd admin admin $ # Create another user (don't use these passwords in production!) $ htpasswd /etc/apache2/conf.other/alfresco.htpasswd nick password
Now, add to our vhost some auth lines:
<Location /> AuthType Basic AuthName "Test Alfresco Access Auth" AuthBasicProvider file AuthUserFile /etc/apache2/conf.other/alfresco.htpasswd Require valid-user </Location>Restart Apache, and re-visit [server name]/alfresco . You should be prompted for a password. Specify admin and admin (as given to htpasswd), and you should be taken to Explorer logged in as admin automatically. We're basically there!
At this point, make sure you're only using a test server, have suitable firewalling etc in place. We're just trying to get some basics in place to test with, so we have a working base before making our changes. More is needed to make this production...
So, how does this all work? Apache is doing the authentication, and passing that through to Tomcat. We can see that Tomcat sees the username by creating a small test jsp somewhere in the Alfresco webapp, containing:
User: <%=request.getRemoteUser()%>Run that, and you'll see the username you gave to the Apache auth come through. That username is passed into the Servlet Request.
What does Alfresco do with it? When we enabled our External Authentication SubSystem, we effectively pulled in the external-filter-context.xml context file, along with partly overriding the default external-filter.properties. The webscriptAuthenticationFilter isn't really doing that much for us, the key bit is the
remoteUserMapper. This is configured up to use DefaultRemoteUserMapper
When the request comes in to Alfresco, for either Explorer or /wcservices/ (but not /services/ as that's different), the global Authentication Filter fires. In
getSessionUserwhich in turn checks for a Remote User Mapper. If one is found (and we've enabled one with our next Authentication SubSystem),
getRemoteUseris called. If you look at that method in DefaultRemoteUserMapper, we'll see it checks the Remote User on the request, and returns that. So, no login is needed at the Tomcat / Alfresco layer, because the value from Apache is trusted.
We can also see how we could do http header auth at this point if we wanted, and also see some of the security issues which mean you shouldn't blindly enable this in production...!
So, we can now use our test Apache auth setup to be auto logged-in to Alfresco Explorer and wcservices. In the next part, we'll see how we enable Share auto-login with the same setup, and how that actually works under the hood.