Technical description

Integrating Testlab with AD using CAS

This document is a guide for setting up Meliora Testlab for MS Active Directory authentication. To enable this, Testlab connects to CAS Enterprise Single Sign-On which should be installed and set up according to the instructions in this guide.

CAS SSO support in Testlab has been superseded with a SAML 2.0 based SSO. This guide is kept in place as a legacy reference.

  • Introduction

    Many organizations centralize their authentication with a centralized user directory to manage the accounts and passwords. For enterprises, Microsoft’s Active Directory does just that. To communicate with user directories, Meliora Testlab uses Jasig CAS (Centralized Authentication Service) which in turn is integrated with AD. The role of CAS is to act as a Single Sign-On ticket broker which performs the actual authentication from CAS and grants Testlab a ticket that can be used to verify the user identity later on.

    CAS supports various authentication backends and methods but this guide is for setting up Active Directory compatible configuration.

    We highly recommend that you read through this guide before proceeding to get a grasp on the requirements for installation.

  • How it works

    CAS is a simple Java-based web application run in Apache Tomcat. The CAS application is configured to connect to AD. Keep in mind, that Testlab won’t directly communicate with the AD server – it tells the CAS to authenticate and expects a ticket back from CAS if the authentication succeeds.

    Technically, the flow for authentication works as follows:

    • When an unauthenticated user tries to access Testlab, he/she gets redirected to CAS-server’s /cas/login URL
    • CAS presents a login page for which the user enters the credentials for authentication
    • CAS uses the credentials provided and asks AD to authenticate the user
      • If authentication fails, CAS informs the user and asks for a re-try
      • If authentication succeeds,
        • CAS creates and remembers a 10-hour long ticket for this user,
        • redirects user back to Testlab passing the ticket identifier to Testlab as a parameter,
        • Testlab picks up the ticket and makes a verification call back to CAS to validate the provided ticket.
          • If the ticket is reported to be valid, Testlab logs in the user normally and asks for the project to log on.
          • If the ticket is invalid, Testlab redirects the user back to CAS for login.

    Keep in mind, that when the user logs out from Testlab only the session in Testlab is invalidated. The (by default 10 hours long) SSO ticket in CAS is preserved for easy re-login. If for some reason the SSO ticket should also be invalidated, this can be done by invalidating the SSO session in CAS-server’s /cas/logout URL. The ticket expiration time can be configured in CAS configuration.

  • Pre-setup Apache Tomcat

    Jasig CAS is installed as a web application on top of Apache Tomcat. To install Tomcat for running the CAS application follow the steps below. The instructions will install Tomcat to port 18433 with SSL enabled and a self-signed SSL certificate. We highly recommend setting up Tomcat with a real SSL certificate if possible.

    1. Download latest Apache Tomcat 7 from https://tomcat.apache.org/download-70.cgi

    2. Add a non-privileged user to the server you intend to run CAS in

    # adduser cas --disabled-login --disabled-password
    ...

    3. Unzip Tomcat distribution to CAS user’s home directory

    # su - cas
    cas@testlab:~$ unzip apache-tomcat-7.0.62.zip

    4. Remove not-needed applications from Tomcat

    cas@testlab:~$ cd apache-tomcat-7.0.62/webapps/
    cas@testlab:~$ rm -rf *

    5. Configure a minimal HTTPS listener to CAS by replacing the default server.xml

    cas@testlab:~$ cd ../conf
    cas@testlab:~$ cp server.xml server.xml_old
    cas@testlab:~$ nano -w server.xml
    <?xml version='1.0' encoding='utf-8'?>
    <Server port="-1" shutdown="SHUTDOWN">
     <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
     <Listener className="org.apache.catalina.core.JasperListener" />
     <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
     <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
     <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
     <GlobalNamingResources>
     </GlobalNamingResources>
     <Service name="Catalina">
       <Connector port="18443" protocol="HTTP/1.1" SSLEnabled="true"
                  maxThreads="150" scheme="https" secure="true"
                  clientAuth="false" sslProtocol="TLS" 
                  keystoreFile="conf/.keystore"
                  keystorePass="changeit"
       />
       <Engine name="Catalina" defaultHost="localhost">
         <Host name="localhost"  appBase="webapps"
               unpackWARs="true" autoDeploy="false">
           <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
                  prefix="localhost_access_log." suffix=".txt"
                  pattern="%h %l %u %t &quot;%r&quot; %s %b" />
           <Context path="/cas" docBase="cas.war" useHttpOnly="true"/>
         </Host>
       </Engine>
     </Service>
    </Server>

    5. Generate a self-signed SSL certificate for Tomcat

    cas@testlab:~$ cd ~/apache-tomcat-7.0.62/
    cas@testlab:~$ keytool -genkey -alias tomcat -keyalg RSA -keystore conf/.keystore
    Enter keystore password: changeit
    Re-enter new password: changeit
    What is your first and last name?
     [Unknown]: mycompanycas 
    What is the name of your organizational unit?
     [Unknown]:  
    What is the name of your organization?
     [Unknown]:  
    What is the name of your City or Locality?
     [Unknown]:  
    What is the name of your State or Province?
     [Unknown]:  
    What is the two-letter country code for this unit?
     [Unknown]:  
    Is CN=mycompanycas, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct?
     [no]:  yes
     
    Enter key password for 
    (RETURN if same as keystore password): enter

    Please make sure to generate a valid certificate by entering a hostname matching to your CAS server (= the full hostname used when accessing the CAS server with a browser – must also include a domain if any) to the CN-field (When asked for “first and last name”). In the example above, the hostname of the server is “mycompanycas”.

    Note: This same certificate is exported and imported to Glassfish’s cacerts.jks keystore later on during Testlab configuration.

  • Creating a customized CAS application

    Jasig CAS is configured by building a customized cas.war application. This war application is deployed to run on Apache Tomcat we just set up.

    To configure and build a customized CAS application a WAR overlay method is used. This requires setting up a simple Maven-based Java project which is used to package the WAR application after the needed configurations are done. Make sure the workstation you are configuring CAS with has Java and Maven available.

    Note: We will first create a simple CAS application with fixed username and password authentication which will verify that the Tomcat + CAS + Testlab set up works as expected. When verified, as a last step we will configure the actual AD connection from CAS to AD.

    1. Create a project directory for a new CAS setup

    # cd ~
    # mkdir caswar

    We will refer to this directory as PROJECTHOME later on.

    2. Download provided Maven overlay helper package. Unzip the package to PROJECTHOME.

    # cd ~/caswar
    # unzip testlab-cas-maven-overlay.zip

    The package contains few overlay files which we will use to configure CAS:

    • src/main/webapp/WEB-INF/deployerConfigContext.xml: Contains the central configuration of CAS and all authenticators. Maybe the most important of all.
    • src/main/webapp/WEB-INF/spring-configuration/ticketExpirationPolicies.xml: Ticket expiration policies for CAS. Pre-configured to 10 hours.
    • src/main/webapp/WEB-INF/classes/messages_en.properties: Default English texts for CAS UI. Can be configured if preferred.
    • pom.xml: Main build file for Maven.

    3. Edit src/main/webapp/WEB-INF/deployerConfigContext.xml and find the following element:

    <bean class="org.jasig.cas.adaptors.generic.AcceptUsersAuthenticationHandler">
       <property name="users">
          <map>
             <entry>
                <key>
                   <value>testlabusername</value>
                </key>
                <value>caspassword</value>
             </entry>
          </map>
       </property>
    </bean>

    Edit the testlabusername to match the user name you have in your Testlab. This is only used for testing and when configured properly, this will always allow the user “testlabusername” to log in to Testlab with a password “caspassword”. We will uncomment this out later on when the proper AD configuration is set up.

    4. Assemble the cas.war by running the following in PROJECTHOME directory.

    # mvn clean package

    The command should report BUILD SUCCESS and generate a target/cas.war package.

    5. Copy target/cas.war package to Tomcat’s webapps directory for deployment.

    cas@testlab:~$ cp target/cas.war ~/apache-tomcat-7.0.62/webapps/

    6. Start Tomcat

    cas@testlab:~$ cd ~/apache-tomcat-7.0.62/bin
    cas@testlab:~$ chmod u+x *.sh
    cas@testlab:~$ ./startup.sh

    7. Access the CAS application from your Tomcat and verify, that it responds correctly by navigating to https://mycompanycas:18443/cas

     

    Tomcat and CAS is now set up with a simple configuration that will grant access to a single user account (testlabusername configured above). We will now configure the Testlab to use this CAS instance and when verified that it works, we will configure the actual AD authentication.

  • Testlab configuration

    To configure Testlab to authenticate using the CAS, do the following:

    1. Testlab validates CAS provided tickets from CAS web application. To do this, it must be able to make a trusted SSL call to CAS which requires that the SSL certificate of the CAS server (Tomcat) must be present in Testlab’s Glassfish keystore.

    Export the SSL certificate from Tomcat by running

    cas@testlab:~$ cd ~/apache-tomcat-7.0.62/
    cas@testlab:~$ keytool -export -alias tomcat -file tomcat.crt -keystore conf/.keystore -rfc
    Enter keystore password: changeit
    Certificate stored in file

    2. Copy the exported tomcat.crt file to the server hosting Testlab and run

    # cd .../glassfish/domains/domain1/config
    # keytool -import -trustcacerts -alias tomcat -file tomcat.crt -keystore cacerts.jks 
    Enter keystore password: changeit
    ...
    Trust this certificate? [no]:  yes
    Certificate was added to keystore

    3. Create a cas.properties configuration file to your Testlab’s Glassfish domain1/lib/classes directory with the following:

    enabled.for=company
    company.cas.url=https://mycompanycas:18443/cas

    Make sure to set the company.cas.url setting to the full URL of the CAS application setup earlier.

    Note: Testlab will make a request to this URL to validate the ticket. Please make sure the CAS is accessible from Testlab server and the hostname resolves correctly from the server.

    Note: If you are using a certificate with an incorrect hostname (for example in some proxy configuration) the SSL request will fail. To skip the hostname validation of the SSL certificate, you can add

    company.cas.skipHostNameCheck=true

    to the cas.properties file. Note that this setting only disables the hostname validation. The certificate must still be trusted (exported & imported) normally.

    4. Restart Testlab’s Glassfish

    5. Access your Testlab and verify, that the browser gets redirected to CAS’s login page

    6. Enter the testlabusername and caspassword you set up earlier. The CAS should authenticate the request and redirect you back to Testlab for proceeding.

     

    If everything works correctly, you now have the CAS based Single Sign-On set up in your Testlab. Good!

  • Configuring Active Directory

    The configuration we are using uses LDAPS protocol to communicate with the AD so the Active Directory must have LDAPS (SSL) enabled. Applying and creating server certificates to your Active Directory is out of the scope of this document, but we will give brief instructions on how to set up self-signed certificates for testing purposes only.

    To enable LDAPS in Active Directory:

    1. Install SelfSSL.exe from IIS Resource Kit Tools if the command is not available.

    2. In command prompt, run

    # cd C:\Program Files (x86)\IIS Resources\SelfSSL
    # selfssl.exe /N:cn=ad.mycompany.lan /K:1024 /V:3650

    The command might print out an error relating to opening metabase, but it can be ignored. The new certificate should now be visible your mmc.

    3. Select Run > “mmc” and

    • Choose File > Add/Remove Snap-in … and install “Certificates” snap-in by choosing “Computer account” and “Local computer” when asked which certificates should be managed
    • Copy “Personal/Certificates/ad.mycompany.lan” -certificate to “Trusted Root Certification Authorities/Certificates” folder

    4. Verify that your AD now gives an SSL response by running the command below on your CAS server:

    # curl -v -i -k https://ad.mycompany.lan:636

    .. and check that your AD server responds with SSL from port 636.

    5. In your “mmc” again, choose the certificate you generated with selfssl.exe and select “Export…” with “no private keys” and “pkcs7” format. This exports the self-signed SSL certificate set up in your AD server to a file.

  • Configuring CAS to bind to AD

    The next step is to configure the CAS application to use your Active Directory as an authentication source. This requires some changes to CAS configuration files in PROJECTHOME, rebuilding the cas.war and re-deployment of the cas.war application to Tomcat.

    1. Edit src/main/webapp/WEB-INF/deployerConfigContext.xml and remove the following element by commenting it out:

    <!--
    <bean>
       <property name="users">
          <map>
             <entry>
                <key>
                   <value>testlabusername</value>
                </key>
                <value>caspassword</value>
             </entry>
          </map>
       </property>
    </bean>
    -->

    This removes the fixed authentication we used for testing.

    2. In src/main/webapp/WEB-INF/deployerConfigContext.xml find the commented out blocks below, remove the comment tags so that they take effect and configure them as described below:

    <!--
           LDAPS based connection context source for Testlab authentication
           ==> Replace ldaps://ad.mycompany.lan with an valid URL pointing to your AD
    -->
    <bean id="adContextSource">
       <property name="pooled" value="false"/>
       <property name="url" value="ldaps://ad.mycompany.lan" />
    </bean>
    
    …
    
    <!–
    AD settings for Meliora Testlab
    ==> Replace filter with one matching your user directory (%u is the user name of the logging user)
    –>
    <bean class=”org.jasig.cas.adaptors.ldap.FastBindLdapAuthenticationHandler” >
    <property name=”filter” value=”%u@mycompany.lan” />
    <property name=”contextSource” ref=”adContextSource” />
    <property name=”ignorePartialResultException” value=”yes” />
    </bean>

    The URL property in adContextSource should point to your Active Directory server. The filter parameter in the authentication parameter should match your directory structure – usually, a simple %u@domain should work as long as the domain is replaced with your AD domain name.

    4. Assemble the cas.war again by running the following in PROJECTHOME directory.

    # mvn clean package

    The command should report BUILD SUCCESS and generate a target/cas.war package.

    5. Stop Tomcat

    cas@testlab:~$ ps -f | grep tomcat
    cas@testlab:~$ kill <tomcat PID>

    5. Redeploy target/cas.war package to Tomcat’s webapps directory for deployment and replace the earlier cas.war deployed.

    cas@testlab:~$ cd ~/apache-tomcat-7.0.62/webapps/
    cas@testlab:~$ rm -rf cas
    cas@testlab:~$ rm -f cas.war
    cas@testlab:~$ cp ..../target/cas.war ~/apache-tomcat-7.0.62/webapps/

    As no hot-deploy features are enabled in Tomcat, make sure to really re-deploy the cas.war by manually deleting the cas.war and the extracted cas/ directory from the webapps dir (as done above). Then copy the new cas.war to webapps directory. Tomcat will extract and deploy the new version on startup.

    6. Install the LDAPS-based SSL certificate exported from your AD server in step 5 of Configuring Active Directory chapter. Copy the exported certificate file to your Tomcat server and run

    # openssl pkcs7 -in adcert.p7b -inform DER -print_certs -outform PEM -out adcert.pem

    This converts the AD certificate to PEM format compatible with Java keytool.

    Important! Clean up the PEM file by opening up the PEM file to editor and

    • remove everything before the BEGIN CERTIFICATE line and
    • remove everything after the END CERTIFICATE line.

    Then run the following command to import and trust the certificate to the cacert-keystore of your JRE (run as root):

    # keytool -importcert -trustcacerts -keystore /opt/jdk1.7.0_55/jre/lib/security/cacerts -file adcert.pem

    Modify the path to your local JRE, answer “changeit” as keystore password and answer yes when asked if to trust the certificate.

    7. Restart tomcat

    cas@testlab:~$ cd ~/apache-tomcat-7.0.62/bin
    cas@testlab:~$ ./startup.sh

    You have now everything set up for the whole authentication pipeline to work. Please continue on and try it out. Make sure you have matching user accounts in your Active Directory and in your Testlab. If not, add an account to your AD for testing.

    Accessing Testlab should now redirect you to CAS, CAS should verify the password of the account from Active Directory by LDAPS bind and if succeeded, the log on to your Testlab should continue normally.

  • Granting permissions to new accounts

    When a user authenticates via CAS for the first time, it is often the case that the user does not have a user account in Testlab yet. When this happens the user is presented with a UI to register a new account to Testlab. After the registration, the user won’t have any roles or permissions to any Testlab project and will be rejected access until your administrator manually grants the needed roles for the new user.

    If you prefer, that all new user accounts will get roles to some projects after registration, your testlab.properties file can be configured with

    ### projects & roles for new user account registrations
    newuser.projects=TLABDEMO
    newuser.roles=VIEWER

    Separate multiple values with commas and remember to restart Testlab after the testlab.properties file is edited. The above example will grant all new registered accounts a VIEWER role to the Demo project (with TLABDEMO prefix).

    Note: When the user registers the account all administrators of your Testlab will get an automatic e-mail notification.

  • Troubleshooting

    The security-related configuration is always a bit complex. This chapter describes some of the common problems you might encounter during configuration and gives hints on troubleshooting the setup.

    Log files

    CAS writes a verbose audit trail log to Tomcat’s logs/catalina.out log file. This is the first place to check for any problems in the authentication. Testlab writes various lines of log on CAS related authentication to its testlab.log file. These lines are easiest to find by searching for “CAS” in the log file.

    Error situations and hints

    • When trying to authenticate in CAS, the request just stalls and seems to take a very long time.
      • Your CAS server is probably not able to communicate to the AD server. Check the catalina.out for
        [org.jasig.cas.adaptors.ldap.FastBindLdapAuthenticationHandler] - <Failed to authenticate user username with error ad.mycompany.lan:636; nested exception is javax.naming.CommunicationException: ad.mycompany.lan:636 [Root exception is java.net.ConnectException: Connection timed out]>

        Check your firewalls and make sure the LDAPS is enabled in your Active Directory server. You should verify the LDAPS-connection from your CAS server to your AD with curl or telnet or any tool of your choice for network-related debugging.

    • When trying to authenticate in CAS, CAS catalina.out gives an error
      Failed to authenticate user username with error simple bind failed: ad.mycompany.lan:636; nested exception is javax.naming.CommunicationException: simple bind failed: ad.mycompany.lan:636 [Root exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target]
      •  This means, that the CAS server does not trust the LDAPS certificate in your Active Directory. Please make sure you have exported it and successfully imported it to the keystore of your CAS server as instructed.
    • I get these errors in CAS’s catalina.out:
      [org.jasig.cas.adaptors.ldap.FastBindLdapAuthenticationHandler] - <Failed to authenticate user username with error [LDAP: error code 49 - 80090308: LdapErr: DSID-0C0903A9, comment: AcceptSecurityContext error, data 52e, v1db1]; nested exception is javax.naming.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C0903A9, comment: AcceptSecurityContext error, data 52e, v1db1]>
      • These are normal. There is no matching account in your Active Directory or the password is incorrect.
    • My shutdown.sh script of Tomcat does not work.
      • The minimal server.xml set up does not provide a control port for Tomcat so the script will fail. You can alter the server.xml to have a port to fix the situation or, just send a kill signal to Tomcat when you need to stop it.
    • It seems that replacing cas.war does not have an effect on Tomcat.
      • Minimal Tomcat setup does not hot deploy changes from war files. You should stop tomcat, delete the webapps/cas* by hand and drop the new cas.war to Tomcat’s webapps directory.