Confluence as CAS Client

Replaced by Soulwing CAS Client

I have developed a replacement solution for Confluence and JIRA. You're welcome to continue to using
this crufty little number if you like, but I no longer support it. Visit http://www.soulwing.org for a better solution.
– Carl Harris, 12 April 2007

Version Compatibility

This client supports Confluence 2.1 and 2.2. For earlier versions of Confluence you'll probably want to refer to Seraph as CAS Client.

Disclaimer

Confluence is the name of a product by Atlassian. This client package is not a product of Atlassian. It was developed by Carl Harris at Virginia Tech. Please contact Carl (or simply add a comment to this page) for support, if needed.

Acknowledgements

The author of this client package wishes to acknowledge those responsible for the Yale Java CAS client and the Seraph Authenticator for CAS from which this work was derived.

Overview

Confluence 2.1 wiki software from Atlassian can be easily integrated with CAS. The client package described here provides a complete Confluence CAS solution including optional support for the following in addition to the basic CAS login authentication:

  • CAS bypass for any selected Confluence paths; e.g. the SOAP/XML-RPC interface path /rpc can bypass CAS.
  • Ability to support non-CAS login via the /login.action path.
  • Global CAS logout via the /logout.action path.

Using this client package is a simple matter of installing a couple of jar files into your Confluence installation, and modifying a couple of configuration files.

Background

CAS authentication in Confluence requires two components:

  1. A servlet filter that examines every request made to Confluence to check for an existing CAS receipt in the session attributes. If no valid receipt exists, this filter performs the CAS authentication by redirecting the user's browser to the CAS server in the usual manner. This filter also sets the CAS_FILTER_USER session attribute containing the authenticated user's login name. This filter is placed in the chain just before the normal Confluence login filter.
  2. A subclass of com.atlassian.confluence.user.ConfluenceAuthenticator. This subclass overrides the getUser, login, and logout methods of ConfluenceAuthenticator. For getUser and login it checks for the existence of the CAS_FILTER_USER session attribute. If this attribute doesn't exist our class delegates authentication to the superclass (ConfluenceAuthenticator). If CAS_FILTER_USER does exist, the authenticator subclass sets the Confluence LOGGED_IN_KEY and LOGGED_OUT_KEY attributes in the manner prescribed for ConfluenceAuthenticator. When the normal Confluence login filter sees these attributes, it assumes that the user has already been authenticated. In the logout method, the authenticator subclass updates the LOGGED_IN_KEY and LOGGED_OUT_KEY attributes in an appropriate manner to end the user's Confluence session.

The CASFilter provided by the Yale Java Client provides the basis for our servlet filter. It checks for the CAS receipt in the session attributes, redirects the user to the CAS server for authentication. It sets the CAS_FILTER_USER attribute to the authenticated user's login name. However, by extending the basic CASFilter, we can improve the integration of CAS with Confluence as discussed below.

The CasSeraphAuthenticator Java class described in Seraph as CAS Client extends the Seraph DefaultAuthenticator class used by Confluence versions prior to 2.1. In Confluence 2.1, Atlassian integrated the new Atlassian-user functionality. Because of this change, integrating CAS with Confluence 2.1 requires a class that extends com.atlassian.confluence.user.ConfluenceAuthenticator. The ConfluenceCasAuthenticator provided in this package was derived from the CasSeraphAuthenticator class but it extends ConfluenceAuthenticator instead of DefaultAuthenticator.

In Confluence, there are some paths that you really don't want to use with CAS. The SOAP/XML-RPC interface, for example is located at path /rpc. SOAP and XML-RPC client programs can't CAS-authenticate, so applying CAS to this path makes the API inaccessible. The Java servlet specification doesn't provide a means to apply a filter to all URLs except those matching a pattern. This makes it difficult to apply a filter like CASFilter to only some of the paths in Confluence. It seems unwise and manageable to try to identify all of the paths that should use CAS and apply the CASFilter only to those paths.

Providing an easy-to-configure CAS bypass capability was accomplished by subclassing CASFilter. The ConfluenceCasFilter provided in this package uses filter initialization parameters to identify paths (e.g. /rpc) that should bypass CAS. When a request is made for a URL that matches one of the defined bypass prefixes, ConfluenceCasFilter sets the CAS_FILTER_BYPASS attribute in the session context and bypasses the CASFilter. For all other requests, ConfluenceCasFilter delegates the real authentication work to CASFilter.

No-CAS Paths

These paths should be configured to bypass CAS:

  • /rpc — SOAP/XML RPC interface
  • /images — icons and other image content, linked-to in Confluence HTML e-mail
  • /createrssfeed.action — RSS feeds (few readers can deal with CAS redirects)

CAS is also bypassed for the /login.action path in Confluence. This allows users without accounts in your CAS service to login to Confluence via the Atlassian-user model, using locally configured usernames or LDAP. The CAS_BYPASS_FLAG ensures that ConfluenceCasFilter will continue to bypass CAS for a user who has authenticated via /login.action for the duration of the user's session.

To implement global logout, ConfluenceCasFilter looks for a requested path that matches the configured logout path (typically this is /logout.action). When this path is matched, if the CAS_FILTER_BYPASS session attribute is not set, the filter redirects the browser to the configured CAS global logout URL with the user's ticket appended as a parameter. The filter also removes all CAS-related session attributes when the logout path is requested.

Installing the Confluence CAS Package

Installation requires you to install a couple of jar files, edit the seraph-config.xml configuration file, and edit the web.xml deployment descriptor.

Making changes to the deployed Confluence application may cause the application server to try to reinitialize Confluence. This is definitely the case for the "standalone" Confluence running under Tomcat. It's best to shut down Confluence while making these changes.

Installing the Jar Files

  1. Download the Yale Java CAS Client from the JA-SIG CAS Downloads page. Copy casclient.jar from the dist directory of the client distribution into the confluence/WEB-INF/lib directory of your Confluence installation.
  2. Download the CAS:Confluence CAS Client package from the attachments section of this page. Copy confluence-cas.jar from the dist directory of the client distribution into the confluence/WEB-INF/lib directory of your Confluence installation.

Configuring Seraph

To replace the default ConfluenceAuthenticator with our ConfluenceCasAuthenticator, we need to
edit the confluence/WEB-INF/classes/seraph-config.xml file in your Confluence installation. It's a very good idea to make a copy of this file before you begin to edit it. Find the existing <authenticator> element and wrap it in XML comment markers. Then add a new <authenticator> element that identifies our ConfluenceCasAuthenticator. It should look like this when you're done.

<!--
   <authenticator class="com.atlassian.confluence.user.ConfluenceAuthenticator"/>
 -->
<authenticator class="org.soulwing.confluence.cas.ConfluenceCasAuthenticator"/>

Configuring web.xml

We need to edit the confluence/WEB-INF/web.xml file in your Confluence installation. It's a very good idea to make a copy of this file before you begin to edit it. Add the following configuration elements with the other <filter> elements in the file. Note that this configuration is similar but not identical to what is used with Yale's CASFilter. The name of the filter class used here is different, and there are a couple of extra initialization parameters. You'll need to replace the values specified for the CASFilter parameters with settings that are appropriate for your CAS service.

<filter>
    <filter-name>ConfluenceCasFilter</filter-name>
    <filter-class>org.soulwing.confluence.cas.ConfluenceCasFilter</filter-class>
    <!--
      These are the usual CASFilter parameters
    -->
    <init-param>
        <param-name>edu.yale.its.tp.cas.client.filter.loginUrl</param-name>
        <param-value>https://YOUR_CAS_SERVER_HOST/login</param-value>
    </init-param>
    <init-param>
        <param-name>edu.yale.its.tp.cas.client.filter.validateUrl</param-name>
        <param-value>https://YOUR_CAS_SERVER_HOST/serviceValidate</param-value>
    </init-param>
    <!-- Change this to the server that the CAS client is running on
         NOTE: This is REQUIRED. If there is a comma/space delimited list, this is automatically 
         matched from the HTTP Host header. If no match is found, the first entry is used. If only
         a single entry is present, that is always used.  -->
    <init-param>
        <param-name>edu.yale.its.tp.cas.client.filter.serverName</param-name>
        <param-value>YOUR_CONFLUENCE_SERVER:PORT</param-value>
    </init-param>
    <!--
      These are parameters specific to the ConfluenceCasFilter    
    -->
    <init-param>
       <!-- 
         This parameter specifies the Confluence path used for login.  If this 
         parameter is set, a user can navigate to the normal Confluence login 
         page to bypass CAS and be authenticated via Atlassian-user.
       -->
       <param-name>org.soulwing.confluence.cas.filter.loginPath</param-name>
       <param-value>/login.action</param-value>
    </init-param>
    <init-param>
       <!-- 
         This parameter specifies the Confluence path used for logout.  If this 
         parameter and the next parameter is set, clicking the Log Out link in 
         Confluence causes a global CAS logout.
       -->
       <param-name>org.soulwing.confluence.cas.filter.logoutPath</param-name>
       <param-value>/logout.action</param-value>
    </init-param>
    <init-param>
       <!-- 
         This parameter specifies the global logout URL for your CAS service.  It's
         used only if the previous logoutPath parameter is also configured.
       -->
       <param-name>org.soulwing.confluence.cas.filter.logoutUrl</param-name>
       <param-value>https://YOUR_CAS_SERVER/logout</param-value>
    </init-param>
    <init-param>
       <!-- 
         This parameter specifies a comma-delimited list of other Confluence paths that 
         should bypass CAS authentication.  The value shown here bypassses CAS for the 
         SOAP/XML-RPC API.
       -->
       <param-name>org.soulwing.confluence.cas.filter.bypassPrefixes</param-name>
       <param-value>/rpc, /images, /createrssfeed.action</param-value> 
    </init-param>
</filter>

Find the <filter-mapping> element containing <filter-name>login</filter-name>. This element sends all URL paths through the Atlassian-user filter for normal Confluence authentication. We want CAS authentication to occur just before the normal authentication filter gains control, so add the following element just above the existing filter mapping for the login filter:

<filter-mapping>
    <filter-name>ConfluenceCasFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

About Certificates

Many CAS installations are using certificates signed by their own CAs or even self-signed certificates. You need to make sure that the Java Runtime Environment used by your Confluence installation is properly configured to trust the certificates used by your CAS server. Typically this involves adding trusted CA certificates or a trusted certificate (for self-signers) into the JRE's trust keystore.

If you see javax.net.ssl exceptions in your application server's log file after configuring Confluence CAS authentication, it's a sure sign that you've got certificate trust problems.

Confluence CAS-ified

With the jar files in place and the configuration files edited, you're ready to restart Confluence and see the magic of CAS: