Tag Archive: SSL


Introduction

About four years ago I wrote a series of posts covering installing Jenkins on Ubuntu 12.04 with Tomcat 6 and using Jenkins for PHP Continuous Integration.  A lot of the tools for PHP CI where provided via pear, but things have changed since then.  For starters, phpUnit as of version 4.0 was no longer provided by the channel pear.phpunit.de and should be installed by other means.

So in this new set of posts I plan to cover the following:

  • Installing the needed prerequisites
  • Globally installing Composer
  • Installing the PHP CI tools with Composer
  • Installing Tomcat 8.x
    • Installing Tomcat APR
    • Installing TCNative
  • Installing Jenkins
  • Configuring Apache to act as a SSL handler and proxy for Tomcat 8
    • TLSv1.2 and appropriate ciphers
    • HSTS (HTTP Strict Transport Security)
    • Port 80 redirect with 301 response code to 443
    • OCSP Stapling
    • Proxy Setup in Apache

 

Installing the Needed Prerequisites

In this section we are going to install several packages via apt-get, from Oracle-Java-8 to PHP 7.1

Installing Oracle Java 8

  1.  Add the Oracle Java PPA to apt-get
    add-apt-repository ppa:webupd8team/java
  2. Update apt-get and install Oracle Java 8
    apt-get update; sudo apt install oracle-java8-installer
  3. Agree to the license agreement.
  4. Edit /etc/environment
    vim /etc/environment
  5. add the following line
    JAVA_HOME="/usr/lib/jvm/java-8-oracle"
    
  6. Save the file and relaunch the terminal to use the updated environment

 

Installing PHP 7.1

  1. Add the PPA for PHP 7.1
    add-apt-repository ppa:ondrej/php
  2. Update with “apt-get update”
  3. Install the many PHP 7.1 libraries via apt-get
    • php7.1
    • php7.1-cli
    • php7.1-common
    • php7.1-curl
    • php7.1-dev
    • php7.1-fpm
    • php7.1-iconv
    • php7.1-intl
    • php7.1-json
    • php7.1-ldap
    • php7.1-mbstring
    • php7.1-mcrypt
    • php7.1-mysql
    • php7.1-opcache
    • php7.1-pdo
    • php7.1-pgsql
    • php7.1-xdebug
    • php7.1-xsl
    • php7.1-xml
    • php-pear
    apt-get install php7.1 php7.1-cli php7.1-common php7.1-curl php7.1-dev php7.1-fpm php7.1-iconv php7.1-intl php7.1-json php7.1-ldap php7.1-mbstring php7.1-mcrypt php7.1-mysql php7.1-opcache php7.1-pdo php7.1-pgsql php7.1-xdebug php7.1-xsl php7.1-xml php-pear

 

Install Subversion 1.9

  1. Add the WanDisco Repository
    sh -c 'echo "deb http://opensource.wandisco.com/ubuntu `lsb_release -cs` svn19" >> /etc/apt/sources.list.d/subversion19.list'
    
    wget -q http://opensource.wandisco.com/wandisco-debian.gpg -O- | sudo apt-key add -
    
    apt-get update
  2. Install subversion 1.9
    apt-get install subversion

 

Install Other Needed Libraries

There are a few more needed packages/libraries we need to install before we can move on

apt-get install graphviz python-software-properties build-essential git ant libxml2-utils libcrypt-openssl-dsa-perl maven libapache2-mod-proxy-html libxml2-dev

 

 

Globally Installing Composer

Since PHPUnit is now no longer on pear.phpunit.de, the new method of installing these tools uses Composer.  Which after a little setup, isn’t all the bad to use.

Setting up Composer globally is pretty easy with just a few commands

  1. Download composer
    curl -sS https://getcomposer.org/installer | php
  2. Move composer.phar into place
    mv composer.phar /usr/local/bin/composer
  3. Make sure composer is executable
    chmod +x /usr/local/bin/composer

 

 

Installing the PHP CI Tools With Composer

For this section, we will create a centrally accessible location for our PHP CI tools to reside and then use a simple composer.json file for the installation.  I could go with several composer commands instead, but this is far easier.

  1. Create a central location for the tools to be installed to
    mkdir -p /opt/composer/vendor
  2. Create the composer.json file
    {
        "config": {
             "vendor-dir": "/opt/composer/vendor"
        },
    
        "require-dev": {
             "phpunit/phpunit": "^6.0",
             "doctrine/annotations": "^1.3"
        },
    
        "require": {
             "phpunit/dbunit": "^3.0",
             "symfony/console": "2.8.9",
             "phing/phing": "^2.16",
             "sebastian/phpcpd": "2.0.4",
             "phploc/phploc": "^3.0",
             "phpmd/phpmd": "^2.6",
             "squizlabs/php_codesniffer": "^2.8",
             "phpdocumentor/reflection-docblock": "~2.0",
             "symfony/config": "~2.8",
             "symfony/filesystem": "~2.8",
             "symfony/finder": "~2.8",
            "phpdocumentor/phpdocumentor": "2.9"
        }
    }

    Alternatively, you can download the file here

     

  3.  Install the libraries/bundles (In the directory that you made composer.json or where ever you places it).
    composer install
  4. Add the following to the PATH variable line in /etc/environment to update the path for  all of the users
    :/opt/composer/vendor/bin/
  5. Close and re-open your terminal to have the new environment take effect

 

 

Installing Tomcat 8.x

This part will be pretty easy to do as I’m going to use the apt-get version and not the source version.  Apache will be handling our front end SSL and other things, so we just need Tomcat to serve the application.

  1. Install tomcat8
    apt-get install tomcat8

 

For the next two sections, if you do not want to do an install from source for APR or TC-Native, you can just install the libraries from apt-get, if you are happy with the versions in the repository for your ubuntu version.

apt-get install libapr1 libtcnative-1

 

Installing Tomcat APR

  1. Download the APR source from the Apache Portable Runtime Project
    wget http://mirrors.advancedhosters.com/apache/apr/apr-1.5.2.tar.gz
  2. Move the and extract the tar file to /opt
    mv apr-1.5.2.tar.gz /opt
    cd /opt
    tar xvf apr-1.5.2.tar.gz
  3.  Change to the directory and run the following
    cd apr-1.5.2
    ./configure
    make
    make install

Installing TC Native

  1. Download the source from Apache’s Site or use wget to download it.
    wget http://mirrors.ocf.berkeley.edu/apache/tomcat/tomcat-connectors/native/1.2.12/source/tomcat-native-1.2.12-src.tar.gz
  2. Extract the tar file and move into the new directories native directory
    tar xvf tomcat-native-1.2.12-src.tar.gz
    cd tomcat-native-1.2.12/native
  3. Configure TC-Native
     ./configure --with-apr=/usr/local/apr/bin/apr-1-config --with-java-home=/usr/lib/jvm/java-8-oracle --with-ssl=yes --prefix=/usr/share/tomcat8
  4. Make and install
    make
    make install
  5. Create or edit setenv.sh
    Under /usr/share/tomcat8/bin there should be a file called setenv.sh, if there is not, created it with your favorite editor and set its contents to the following

    LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CATALINA_HOME/lib
    export LD_LIBRARY_PATH
  6. Restart Tomcat 8 and check or watch with “tail -f”, /var/log/tomcat/catalina.out for the line where APR and TC Native is loaded, to make sure all went as expected.
  7. Open a browser and navigate to http://<your ip or server here>:8080 to see if tomcat is up and running
  8. Edit /etc/tomcat/server.xml with your favorite editor and uncomment the apr line in the file, while setting it’s ssl attribute to false so it looks like
    <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="off" />
  9. Change the connector for port 8080 to look like the following:
    note: remove the address= part if you want to test the page without apache first as it restricts access to only that address.

    <Connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol"
                   connectionTimeout="20000"
                   URIEncoding="UTF-8"
                   server="Apache"
                   maxThreads="150"
                   address="127.0.0.1"/>
  10. Save server.xml and restart tomcat

 

 

Installing Jenkins

The installation of Jenkins is pretty easy and doesn’t have a lot of configuration

  1. Make the home directory for jenkins in /opt/jenkins
    mkdir /opt/jenkins
  2. Add the following home directory environment variable definition to tomcat8 in /etc/init.d/tomcat8
    #JENKINS HOME
    JENKINS_HOME=/opt/jenkins
    export JENKINS_HOME
  3. Download the version Jenkins you want (I’m using the LTS version) from the Jenkins-CI site or download it with wget, like so:
    wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war
  4. Make jenkins.war the root site of tomcat8 (you don’t have to do this, you could just copy it over to webapps, but you will need to append /jenkins to the proxy configuration when you get there)
    mv jenkins.war /var/lib/tomcat8/webapps/ROOT.war
  5. Restart Jenkins
    service tomcat8 restart

 

 

Configuring Apache to Act as an SSL Handler and Proxy for Tomcat 8

Since Apache is already installed by installing PHP 7.1, we can move straight on to the configuration and enabling the needed mods.

First, we are going to enable the needed mods: headers, proxy, proxy_connect, proxy_html, proxy_http, rewrite, and ssl.

  1. enable needed mods
    a2enmod headers
    a2enmod rewrite
    a2enmod ssl
    a2enmod proxy
    a2enmod proxy_http
    a2enmod proxy_html
  2. Restart Apache to enable the modsservice apache2 restart

 

TLSv1.2 and appropriate ciphers

For this particular install we are going to use TLS 1.2 only and a handful of high security ciphers.  For your users to use your site, they will need to be running the following clients or higher:

  • Android 5.0
  • Chrome 30
  • Edge
  • Firefox 27
  • IE 11 on Windows 7
  • Java 8
  • Opera 17
  • Safari 9

 

The first thing you will need to be able to perform the steps in this section, is to have an SSL cert, either self signed or not.  Once you have that and have placed it (I tend to prefer to put them under /etc/ssl/private), you will need to tell Apache where it is.  After which , we can set what ciphers are allowed and what versions of SSL will be accepted.

  1. Edit /etc/apache2/sites-available/default-ssl.conf
  2. Add the following lines
    SSLEngine on
    
    SSLCertificateChainFile /etc/ssl/private/<your chain cert>.crt
    SSLCertificateFile /etc/ssl/private/<your cert>.crt
    SSLCertificateKeyFile /etc/ssl/private/<your cert key>.key
    
    SSLProtocol -all +TLSv1.2
    
    SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
  3. Save and then restart apache2

 

If these ciphers are too restrictive for your, please check the following resources for some more cipher and TLS options.

Mozilla- Server Side TLS
OWASP – Securing Tomcat (Although this is for Tomcat, the translation to Apache is pretty easy)

HSTS (HTTP Strict Transport Security)

By enabling HSTS, your browser is instructed to always use HTTPS when communicating with your site, and it is quiet easy to turn on.

  1.  Add the following line to your ssl vhost definition for apache, /etc/apache2/sites-available/default-ssl.conf
    Header always set Strict-Transport-Security "max-age=86300; includeSubdomains;"
    


    In the above line max-age should be around a week or less than a day

 

Port 80 Redirect with 301 Response Code to 443

Now that we have HSTS setup and SSL, we should default our site to use SSL.  To do so, we will edit the default VHost for port 80 to redirect to the same URL, but with https and a response of 301.

  1. Edit /etc/apache2/sites-available/000-default.conf and make it look like the following
    <VirtualHost *:80>
            ServerAdmin webmaster@localhost
            ErrorLog ${APACHE_LOG_DIR}/error.log
            CustomLog ${APACHE_LOG_DIR}/access.log combined
    
           <IfModule mod_rewrite.c>
                   RewriteEngine On
                   RewriteCond %{HTTPS} off
                   RewriteRule (.*) https://%{SERVER_NAME}$1 [R=301,L]
           </IfModule>
    </VirtualHost>

 

OCSP Stapling

OCSP Stapling delivers certificate revocation information during the TLS handshake and can improve performance  of TLS when using HTTPS.  To use this, we simply need to enable it and specify a cache location.

  1.  Specify a cache location by adding the following line to the top of your default-ssl.conf vhost
    SSLStaplingCache shmcb:/tmp/stapling_cache(128000)
  2. Add the following line somewhere in the <VirtualHost _default_:443> block of the same file
    SSLUseStapling on
  3.  Restart Apache2
    service apache2 restart
  4. Check of your cert is using OCSP as you expect
    openssl.exe s_client -connect [yoursite.com]:443 -status

    You should see a line in the OCSP Response Data section like “OCSP Response Status: successful (0x0)

 

Proxy Setup in Apache

Having Apache act as an SSL handler for Tomcat is not too hard to setup and allows us to use the SSL Ciphers we want to use, without having to deal the capabilities of the Java version we have installed.

To set this up we need to add the following lines to our default-ssl.conf in the VirtualHost definition block.

ProxyRequests Off
ProxyPreserveHost On
AllowEncodedSlashes NoDecode

<Proxy *>
    Order deny,allow
    Allow from all
</Proxy>

ProxyPass        / http://localhost:8080/ nocanon
ProxyPassReverse / http://localhost:8080/
ProxyPassReverse / http://your_server_url.com/

# lets jenkins know SSL is being handled elsewhere
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"

Introduction

This post will cover the installation of Tomcat 7 and Central Authentication Service (CAS) 3.52.  Although the process is pretty straight forward, there are a lot of bits of information scattered all around for setting these two things up and I figured bringing those to a single place would be useful for others.

Beyond installing CAS and Tomcat 7, this post will cover:

  • Configuring and Hardening (SSL wise) Tomcat 7

 

The next part will cover:

  • Authenticating against LDAP
  • Using the JPA Ticket Registry with Postgresql

Installing Tomcat 7 and Needed Libraries

To setup Tomcat 7, its needed libraries, and the libraries you will need for CAS, run the following commands:

sudo apt-get update
sudo apt-get install tomcat7 maven2 default-jdk libctnative-1 libssl-dev

The above commands will install

  • maven2  → This will be used for CAS.  We will be using the WAR overlay method.
  • Tomcat 7
  • default-jdk (openjdk-6) → This is needed by CAS
  • libctnative-1 → Installs libraries that will be needed by Apache Portable Runtime
  • libssl-dev  → Installs libraries for SSL

After the installation there will be several new environment variables that you may want to set (though Tomcat figures them out automatically).

  • CATALINA_HOME = /usr/share/tomcat7
  • CATALINA_BASE = /var/lib/tomcat7     (we’ll be doing most of our configuring here)
  • JAVA_HOME = /usr/lib/jvm/java-6-openjdk-amd64

Note: For the rest of this post and in the other parts of this series, I will use the above variable names.

My JAVA_HOME Path is Different! What Do I Do?

It is possible that your JAVA_HOME path may be different.  If you are not running a 64-bit system, the path will probably be /usr/lib/jvm/java-6-openjdk.

If this is not your path you can use the find command to find the cacerts file, which should help you get the path (minus the /jre/lib/security/ part) like so:

find / -name "cacerts"

Or you can check your java alternatives using the update-java-alternatives command, like so:

update-java-alternatives -l

Note: If your java path does not fit /usr/lib/jvm/java-6-openjdk-*  or /usr/lib/jvm/java-7-openjdk-*, you will need to set the environment variable JAVA_HOME because Tomcat will not find it.

Configuring Tomcat 7 for SSL

To setup Tomcat to use SSL you will need to either have a self signed certificate or a signed certificate from a Certificate Authority like DigiCert or Verisign.  If you want to create a self signed cert, check out this tutorial Creating a Self Signed Cert.  If you already have a signed certificate then you can move on to the next part.

When configuring Tomcat to use SSL, you have two options for how you want to do it.  The first way is to import the certificate into the cacerts file and use the keystoreFile and keystorePass attributes in the Connector declaration in the server.xml file for Tomcat.  If you want to use this approach MuleSoft has a good tutorial on how to do it here (This tutorial also includes the second method close to the bottom).

The other way (the one I’m doing) is to use the attributes SSLCertificateFile and SSLCertificateKeyFile to reference the files directly.  Whichever way you choose to go, be sure to define the ciphers attribute like I have done in the code snippet below.  This is needed because by default Tomcat will use whatever ciphers the Java library has to offer and some of these are very weak.

Once you have your SSL certificate and key file ready and stored in some place like /etc/ssl/certs you can move on to configuring Tomcat.  For this part

  1. Edit $CATALINA_BASE/conf/server.xmlUn-comment the following section:
    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
        maxThreads="150" scheme="https" secure="true"
        clientAuth="false" sslProtocol="TLS" />
    

    And make it look like

    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
                   maxThreads="150" scheme="https" secure="true"
                   clientAuth="false" sslProtocol="TLS"
                   SSLCertificateFile="/some/path/cert.crt"
                   SSLCertificateKeyFile="/some/path/cert.key"
                   ciphers="TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA256,
                            TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
                            TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
                            SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
                            SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA" />
    

    Note: If you are sure that you will not have any Windows XP clients, you can remove the 3DES ciphers.

  2. Save the file
  3. Edit /etc/default/tomcat7 and add “-Dhttps.protocols=TLSv1” to the JAVA_OPTS line. Mine looks like this:
    JAVA_OPTS="-Djava.awt.headless=true -Xms512M -Xmx1024M -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=512m -XX:+CMSIncrementalMode -Dhttps.protocols=TLSv1"
    

    Note: You need to make this change because java will allow different ciphers than your restricted CAS instance, which will cause SSL issues.
    Note 2: The other parameters in the above line let the JVM allocate more memory for your CAS instance and have it clean said memory more often to make more efficient use of it.  It would probably be a good idea to use these flags as well, just adjusted to your servers capability.

  4. Save the file
  5. Restart tomcat
    /etc/init.d/tomcat7 restart

    Note: you may also want to watch the catalina log file in another console using

    tail -f $CATALINA_BASE/catalina.out
  6. Open a browser and navigate to https://your_server:8443.  If everything worked, you should see the “It Works” screen

Wait!  I Want to Use Port 80 and 443, not 8080 and 8443

If you want to use the standard HTTP and SSL ports of 80 and 443, make sure of the following first

  • No other application is binding to port 80 or 443
  • You are not using IP v6 (this is a restriction of AuthBind)

 

  1. Edit $CATALINA_BASE/conf/server.xml and change the following section:
    <Connector port="8080" protocol="HTTP/1.1"
                   connectionTimeout="20000"
                   URIEncoding="UTF-8"
                   server="Apache"
                   redirectPort="8443" />
    

    And make it look like

    <Connector port="80" protocol="HTTP/1.1"
                   connectionTimeout="20000"
                   URIEncoding="UTF-8"
                   server="Apache"
                   redirectPort="443" />
    
  2. Edit /etc/default/tomcat7  and make the AUTHBIND line look like:
    AUTHBIND=yes
    
  3. Restart tomcat

 

HTTPS Everywhere

Once you have HTTPS/SSL working from the previous part, let’s configure Tomcat so every site goes through HTTPS.

  1. Edit $CATALINA_BASE/conf/web.xml
  2. Add the following code snippet to the end of the file, just above the </web-app> line at the end of the file
        <security-constraint>
            <web-resource-collection>
                <web-resource-name>Protected Context</web-resource-name>
                    <url-pattern>/*</url-pattern>
            </web-resource-collection>
            <!-- auth-constraint goes here if you require authentication -->
            <user-data-constraint>
                 <transport-guarantee>CONFIDENTIAL</transport-guarantee>
            </user-data-constraint>
        </security-constraint>
    
  3. Save the file and restart Tomcat7
  4. Open a web browser and navigate to http://your_server:8080.  You should be redirected to https://your_server:8443.

 

Setting Up The CAS WAR Overlay

One of the easiest and recommend ways to setup CAS is to use the Maven WAR Overlay method. To do this, do the following: (or you can follow the guide from Jasig)

  1.   Create the workspace directory, in the future referred to as $project_home
    mkdir /opt/work/cas-local
    
  2. Create a file called pom.xml in the created folder, add add the following to it:
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd ">
        <modelVersion>4.0.0</modelVersion>
        <groupId>edu.university.cas</groupId>
        <artifactId>local-cas</artifactId>
        <packaging>war</packaging>
        <version>1.0-SNAPSHOT</version>
    
        <build>
            <plugins>
                <plugin>
                     <artifactId>maven-war-plugin</artifactId>
                                 <configuration>
                                     <warName>cas</warName>
                                 </configuration>
                            </plugin>
            </plugins>
        </build>
    
        <dependencies>
            <dependency>
                <groupId>org.jasig.cas</groupId>
                <artifactId>cas-server-webapp</artifactId>
                <version>${cas.version}</version>
                <type>war</type>
                <scope>runtime</scope>
            </dependency>
        </dependencies>
    
        <properties>
            <cas.version>3.5.2</cas.version>
        </properties>
    
            <repositories>
                 <repository>
                      <id>ja-sig</id>
                      <url>http://oss.sonatype.org/content/repositories/releases/ </url>
                 </repository>
            </repositories>
    </project>
    
  3. Change the groupId tag to have the url for your place of business.
  4. Next we will add the parts that actually make our CAS package building useful.  Our customizations.Create the directory $project_home/src/main/webapp/WEB-INF
  5. Create a file called deployerConfigContext.xml in the new folder, and populate it with this contents.
  6. (Optional) The default service context for CAS will work just fine out of the box, but only restrict traffic to IMAP(S) or HTTP(S)If you would like to be a little more restrictive to say, just your domain, you will want to change the following line in deployerConfigContext.xml
    <property name="serviceId" value="^(https?|imap?)://.*" />

    To something more restrictive, like:

    <property name="serviceId" value="^(https?|imaps?)://([A-za-z0-9_-]+\.)*(your_domain\.com)(:\d{1,5})?/.*" />

    This will restrict service to HTTP(S) or IMAP(S) from your domain only, with a possible port number in the url.
    Note: the “(:\d{1,5})?” part is not needed if you use port 80 and 443 for CAS.

  7. Create a file called cas.properties in the same folder, and populate it with this contents.
  8. Alter the following line:
    server.name=https://localhost:8080

    and change it to

    server.name=https://<your domain>:<port_number>

    e.x. server.name=http://cas.example.com:8443

  9. Alter this line
    host.name=cas01.example.org

    and change it to

    host.name=<your cas servers FQDN>

    e.x. host.name=cas.example.com

  10. Save the cas.properties file.
  11. (Optional) If you want to setup throttling of repeat authentication attemps
    1. Create the file $project_home/src/main/webapp/WEB-INF/cas-servlet.xml and populate it with this contents.
    2. Change the following bean:
        <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping" p:flowRegistry-ref="flowRegistry"
              p:order="2">
          <property name="interceptors">
            <ref local="localeChangeInterceptor"/>
          </property>
        </bean>
      

      to

        <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping" p:flowRegistry-ref="flowRegistry"
              p:order="2">
          <property name="interceptors">
                <list>
                      <ref local="localeChangeInterceptor"/>
                      <ref bean="throttleInterceptor"/>
                </list>
          </property>
        </bean>
      
    3. Create the file $project_home/src/main/webapp/WEB-INF/spring-configuration/throttleInterceptorTrigger.xml and put the following in it:
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:p="http://www.springframework.org/schema/p"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
      
      <bean id="throttleInterceptor" class="org.jasig.cas.web.support.InMemoryThrottledSubmissionByIpAddressAndUsernameHandlerInterceptorAdapter"
         p:failureRangeInSeconds="120"
         p:failureThreshold="100"/>
      
      <bean id="throttleInterceptorJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"
         p:targetObject-ref="throttleInterceptor"
         p:targetMethod="decrementCounts" />
      
      <bean id="periodicThrottleCleanerTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"
         p:jobDetail-ref="throttleInterceptorJobDetail"
         p:startDelay="0"
         p:repeatInterval="1000" />
      </beans>
      
  12. (Optional) If you want to setup a ticket expiration policy for your Ticket Granting Tickets
    1. Create the file $project_home/src/main/webapp/WEB-INF/spring-configuration/ticketExpirationPolicies.xml
    2. Populate it with this contents.
    3. If you want to change the default ticket expiration settings you will want to alter the attributes p:maxTimeToLiveInSeconds and p:timeToKillInSeconds 
  13. Change directory to $project_home
  14. Run the following command to build you cas package (this cleans the workspace and builds the package).
    mvn clean package
  15. Create a soft link for freshly built cas.war file for Tomcat 7
    ln -s target/cas.war /var/lib/tomcat7/webapps/cas.war

    The new package should be automatically deployed by Tomcat

    NOTE: When rebuilding the cas.war file because you’ve made changes to the configuration, you will want to issue the following commands:

    service tomcat7 stop
    service tomcat7 start

    This is because Tomcat will re-deploy the cas.war and throw a bunch of errors in the log and act wonky, until you stop and restart Tomcat.

  16. Open a browser and navigate to “https://<your_cas_server&gt;:8443/cas” (minus the port number if you are using port 80 and 443).  You should see the CAS login screen.

 

At this point CAS should be up and hopefully there aren’t any errors being spat in your /var/log/tomcat7/catalina.out log.  But, CAS isn’t all the useful yet.  It just gives you a nice login box to no where.

In the next part I’ll discuss several things to make CAS more useful:

  1. Setting up PostgreSQL ticket management
  2. Configuring CAS to use LDAP
  3. Configuring CAS to use pooling for LDAP and PostgreSQL

There are several options for setting up CI (continuous integration) for PHP.  Some of your options include Hudson (now owned by Oracle), Jenkins (the fork from Hudson), PHPUnderControl, and CruiseControl to name a few. While they each have their strengths, I wanted something that would be easy to use and have a company backing.  Through my searching I found TeamCity.

Team City is free to use for you first 20 build configurations (that is the only limit), after that you could make a new server to service your additional builds or actually pay for it.

This part of the two part series will cover the setup and configuration of TeamCity in the following sections below:

  1. Post setup
  2. Installing TeamCity
  3. Configuring TeamCity
  4. Configuring Apache to Redirect to Teamcity

Post Setup

This section will cover the various things that need to be setup on our server before we can install and configure TeamCity.

Apt-get Installs

To begin, we need to install several packages using apt-get (you could also use aptitude if you want).  These installs will cover PHP, Apache, subversion, and other libraries/applications.  To install each of these packages below simply type “sudo apt-get install <package-name>

  • ant
  • build-essential
  • libtcnative-1 (this installs the Apache APR module)
  • openssl
  • php-pear
  • php5
  • php5-cli
  • php5-curl
  • php5-dev
  • subversion

Installing Java JDK 6

Java no longer is included with Ubuntu out of the box and only OpenJDK is in the package repository.  This creates a problem as TeamCity doesn’t work with OpenJDK.  However, it will work with Java JDK 6 (update 32) at the time of this posts writing.  Fortunately, installing Java from Oracle is rather painless, but you will need sudo to do these commands.

  1. Download the latest  JDK 6 Update from here (I use the .bin files as they are the easiest to install, so grab one of those, either x86 or x64 depending on your architecture).
  2. Go to where you downloaded the the bin file and make it executable by doing the following
    chmod +x jdk-6u32-linux-x64.bin
  3. Run the binary.  This will extract the files into a directory like jdk1.6.0_32
    ./jdk-6u32-linux-x64.bin
  4. Create a directory to put java in
    mkdir /usr/lib/jvm
  5. Move the java directory to the new on and rename it to something nicer
    mv jdk1.6.0_32 /usr/lib/jvm/java-6
  6. Inform ubutnu of the new java install
    update-alternatives --install "/usr/bin/java" "java" "/usr/lib/jvm/java-6/bin/java" 1
    update-alternatives --install "/usr/bin/javac" "javac" "/usr/lib/jvm/java-6/bin/javac" 1
    update-alternatives --install "/usr/bin/javaws" "javaws" "/usr/lib/jvm/java-6/bin/javaws" 1
  7. For each of the lines above you will need to configure the default  to use by executing the following lines and choosing the path to your new java install from the given list.  Note that if this is your only install of java for this system, you can skip this step.
    update-alternatives --config java
    update-alternatives --config javac
    update-alternatives --config javaws
  8. Now we need to add the JAVA_HOME variable to our environment and update the PATH variable.   Edit /etc/environment and add the following line to the top
    JAVA_HOME="/usr/lib/jvm/java-6"
  9. Add the following lines to the end of /etc/profile
    JAVA_HOME="/usr/lib/jvm/jdk-6"
    PATH=$PATH:$JAVA_HOME/bin
    export JAVA_HOME
    export PATH
  10. Reconnect to your ssh session or restart your terminal to update the profile settings and test that java and javac are on the path by issuing the following commands
    java --version
    javac --version

    You  should get output for each of these commands.

Installing the Pear Tools for PHP CI

For this setup, TeamCity is going to be using a fair number of PHP tools in it ant script.  We will be using the following PHP tools

  • PHP Codesniffer
  • PHP Copy And Past Detector
  • PHP Dead Code Detector
  • PHP Depend
  • PHP Documentor 2
  • PHP Mess Detector
  • PHP Unit

As you can see there are quite a few to install; however, it is relatively painless to do so (again you will need sudo to do this).

  1. Update the pear channel
    pear channel-update pear.php.net
  2. Update Pear
    pear update pear
  3. Discover the needed pear channels
    pear channel-discover pear.phpdoc.org
    pear channel-discover bartlett.laurent-laville.org
    pear channel-discover pear.phpunit.de
    pear channel-discover components.ez.no
    pear channel-discover pear.symfony-project.com
    pear channel-discover pear.pdepend.org
    pear channel-discover pear.phpmd.org
  4. Install the pear modules
    pear install bartlett/PHP_CompatInfo
    pear install --alldeps phpunit/PHPUnit
    pear install --alldeps PHP_Codesniffer
    pear install pdepend/PHP_Depend-beta
    pear install phpmd/PHP_PMD
    pear install phpunit/phpcpd
    pear install phpunit/phpdcd-beta
    pear install phpdoc/phpDocumentor-alpha

Installing TeamCity

This section covers the download and installation of TeamCity and the changes we need to make before first launch.

Installation

  1. Go to the TeamCity website here and select your os and click download.  If you are using command line, you can use wget -c http://download.jetbrains.com/teamcity/TeamCity-7.0.2a.tar.gz
  2. Unpack your download
    tar -xvf TeamCity-7.0.2a.tar.gz
  3. Move your new directory to an appropriate place (I prefer the opt directory)
    mv TeamCity-7.0.2a /opt/TeamCity
  4. Set the permissions for the directory (we are going to run as www-data, not root)
    chown -R www-data /opt/TeamCity
  5. Create the following script called teamcity in /etc/init.d  (vim /etc/init.d/teamcity)
    #!/bin/sh
    # /etc/init.d/teamcity -  startup script for teamcity
    export TEAMCITY_DATA_PATH="/opt/TeamCity/.BuildServer"
    
    case $1 in
    start)
    start-stop-daemon --start  -c www-data --exec /opt/TeamCity/bin/teamcity-server.sh start
    ;;
    
    stop)
    start-stop-daemon --start -c www-data  --exec  /opt/TeamCity/bin/teamcity-server.sh stop
    ;;
    
    esac
    
    exit 0

    The above script is from Johannes Rudolph’s Blog and modified to fit my configuration

  6. Add the script to the startup routine
    update-rc.d teamcity defaults

Before First Launch

There is not much you can configure before the first launch of TeamCity; however, we can configure what port it is going to use.  For this installation I intend to authenticate off of Active Directory and I do not want those accounts going over the wire in plain text so SSL needs to be configured.

  1. Edit the server.xml
    vim /opt/TeamCity/conf/server.xml
  2. In the section for SSL connector add the following connector (you can find this section by searching for SSL)
    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
    maxthreads="150" scheme="https" secure="true"
    SSLCertificateFile="/path/to/cert/file.crt"
    SSLCertificateKeyFile="/path/to/cert/file.key"
    SSLCertificateChainFile="/path/to/cert/chain.crt" />

    If you have a self generated certificate you probably do not have a chain file, so you can leave that attribute out.

Creating the Data Directory

  1. Start the server
    /etc/init.d/teamcity start
  2. Open a web browser and navigate to https://yourServer.domain.com:8443 (if you don’t have a DNS entry for your machine go to https://localhost:8443 or https://yourServersIP:8443)
  3. You should see a screen saying this is the first run for the server and asking if you want to proceed.  Obviously we do, so click Proceed
  4. Next it will show you the EULA which you will need to accept
  5. Now you will see a form asking you to fill out the information for the admin user.  Stop here and shutdown the server
    /etc/init.d/teamcity stop

Configuring TeamCity

This section will cover connecting TeamCity to an external database (in this case PostgreSQL) and having TeamCity authenticate against LDAP

Connecting TeamCity To PostgreSQL

  1. Navigate to the place where JDBC database drivers are stored for TeamCity
    cd /opt/TeamCity/.BuildServer/lib/jdbc/
  2. Download the latest PostgreSQL JDBC driver from hereor use wget like so
    wget -c http://jdbc.postgresql.org/download/postgresql-9.1-901.jdbc4.jar
  3. Make www-data the owner of the file
    chown www-data postgresql-9.1-901.jdbc4.jar
  4. Make the file executable
    chmod +x postgresql-9.1-901.jdbc4.jar
  5. Connect to your PostgreSQL server and use the following SQL to create the TeamCity user account
    CREATE USER TeamCityUser WITH PASSWORD 'something _secret';
  6. Create a database and set it’s owner to the new user using the SQL statement below
    CREATE DATABASE TeamCityDB  OWNER TeamCityUser ENCODING 'UTF-8';
  7. Go to TeamCitiy’s config directory in the data directory
    cd /opt/TeamCity/.BuildServer/config
  8. Copy the template database file for PostgreSQL to make it the database config file to use
    cp database.postgresql.properties.xml database.properties
  9. Edit database.properties file and set the following lines
    connectionUrl=jdbc:postgresql://db.server.address.com:5432/database_name
    connectionProperties.user=your_db_account
    connectionProperties.password=your_db_account_password

    If you where connecting to a server at dbServer.example.edu and using database TeamCity with account appAccount and password P@455W0rd, it would look like this

    connectionUrl=jdbc:postgresql:// dbServer.example.edu:5432/TeamCity
    connectionProperties.user=appAccount
    connectionProperties.password=P@455W0rd

    Notice that there are not quotes.  The reason for this is TeamCity automatically quotes the values for you.  If you add quotes, it will fail authentication.

Authenticating to LDAP

Authenticating against LDAP is pretty easy; however, it gets a bit tricky when you want to use a secure connection (LDAP with SSL).  In the following sections I will show you how to install the SSL certificate from an Active Directory domain controller and how to configure TeamCity to use LDAPS.

Importing the LDAPS Certificate

Before we can authenticate using LDAPS, we have to import the certificate that the domain controller is using so Java will trust it.  Method 1 is pretty easy to do and relatively painless, but does require you to download an additional Java tool.  If you do not want to install any additional Java tools and you have access to the DC.  You can manually export the certificate from each DC and import tem into the Java keystore  using Method 2.

Method 1: Using InstallCert and Keytool

  1. Download the InstallCert tool created by Andreas Sternbenz from here
  2. If you do not have unzip installed, install it using
    apt-get install unzip
  3. unzip the tool
    unzip InstallCert.zip
  4. Move the contents to your java bin directory
    mv InstallCert* $JAVA_HOME/jre/bin
  5. Acquire the cert from your AD servers like so (note port for LDAPS is usually 636)
    java InstallCert dcServer.domain.com:636
    • If you are prompted for anything, just hit enter to continue
    • If you have more than one server you intended to use for LDAPS authentication, repeat this step
  6. This process will create a file called jssecacerts.  We now want to import this file into our existing cacert file like so
    keytool --importkeystore -srckeystore jssecacerts -destkeystore $JAVA_HOME/jre/lib/security/cacerts -noprompt

    You will be prompted for the password to the cacerts keystore and the jssecacerts keystore.  Enter the password changeit
    Once this is done, you should see a status message saying something around 78 entries where imported.

Method 2: Exporting the Cert from AD and Importing it With Keytool

  1. From a Windows workstation open a run prompt (windows key + r)
  2. Enter mmc and press ok
  3. Go to File -> Add/Remove Snapin..
  4. From the “Available snap-ins” list on the left select “Certificates”
  5. Click the “Add >” button to add Certificates to the Selected snap-ins list on the right
  6. Select “Computer Account” from the options.
  7. Select Local computer if you are on the serve that has the certificate, else select “Another Computer” and enter the host name for the domain controller to get the certificate from
  8. Click finish
  9. Click OK
  10. Expand Certificates folder under Console Root and expand the Personal folder
  11. Click the Certificates folder
  12. Right click the certificate you want to export
  13. Go to All Tasks -> Export
  14. Click Next
  15. Select “Yes, export the private key”
  16. Click Next
  17. Select “Personal Information Exchange – PKCS #12(.PFX)” and check “Export all extended properties” if you can.  If you cannot, select PKCS #7 option above this one, and check the check box below it.
  18. Enter a name for the file
  19. Click ok.  You should now have the server cert
  20. Move the cert to your Linux server using WinSCP or some other file transfer tool
  21. Import the cert by typing
    keytool --import -keystore $JAVA_HOME/jre/lib/security/cacerts -file /path/to/your/cert/file
  22. Enter the password of changeit for the cacerts keystore
  23. If prompted to “Trust this certificate?” type yes and press enter

Setting up the LDAPS Connection

To configure TeamCity to LDAPS for authentication is pretty simple by this point, you simple need to do the following

  1. Edit /opt/TeamCity/.BuildServer/config/main-config.xml and replace the following line
    <login-module class="jetbrains.buildServer.serverSide.impl.auth.DefaultLoginModule" />

    with

    <login-module class="jetbrains.buildServer.serverSide.impl.auth.LDAPLoginModule" />
  2. copy the file ldap-config.properties.dist to ldap-config.properties or just create the file and go to the next step.
    cp ldap-config.properties.dist ldap-config.properties
  3. Edit ldap-config.properties and set the following lines.  If you just created the file, then just set it to the contents below
    # The server(s) to auth against 
    java.naming.provider.url=ldaps://example.com:636/DC=example,DC=com 
    
    # The account to use to search for accounts in LDAP and read their data 
    java.naming.security.principal=CN=username,CN=Users,DC=example,DC=com 
    java.naming.security.credentials=secret_password 
    
    # The base dn to use when searching for users (if your accounts are all over, just leave it blank) 
    teamcity.users.base=CN=users 
    
    # Handles setting the user name.  acceptedLogin has Teamcity use the username in LDAP.  You should use 
    # this if you cannot filter your usernames because of how they are constructed 
    teamcity.users.acceptedLogin= 
    
    # Sets the username in team city to the one in LDAP 
    teamcity.users.username=sAMAccountName 
    
    # Disallow slashes and @s in the username given at login 
    teamcity.auth.loginFilter=[^/\\\\@]+ 
    
    # Synchronize the user against ldap (this runs every hour) 
    teamcity.options.users.synchronize=true 
    
    # Filter what users to match in sync 
    teamcity.users.filter=(objectClass=user) 
    
    # Don't sync groups 
    teamcity.options.groups.synchronize=false 
    
    # Don't create or delete users during synchronization. 
    teamcity.options.createUsers=false 
    teamcity.options.deleteUsers=false 
    
    # The time interval between synchronizations (in milliseconds). By default, it is one hour. 
    teamcity.options.syncTimeout = 3600000 
    
    # The name of LDAP attribute to retrieve user's full name 
    teamcity.users.property.displayName=displayName 
    
    # The name of LDAP attribute to retrieve user's email 
    teamcity.users.property.email=mail 
    
    # Tell team city to only sync users in team city against LDAP (if you have a lot of users in LDAP, this should be turned on). 
    # Only look at 100 users at a time 
    teamcity.users.syncOnlyTeamcityUsers=true 
    teamcity.users.filterPackSize=100
  4. Set www-data as the owner of the file
    chown www-data ldap-config.properties
  5. Start the server
    /etc/init.d/teamcity start
  6. Navigate to the TeamCity site in your browser https://your.server.com:8443
  7. The server will say that the configuration has changed and that it needs a code from the log file.  Get the last ten lines from the server log to get the code.
    tail /opt/TeamCity/logs/teamcity-server.log
  8. The code should be in the output.  Copy this code and past it into the field in your browser and click proceed
  9. You will now be prompted to login.  The account you do this initial login with will be an administrative account.

Configuring Apache to Redirect to Teamcity

This section will cover how to setup Apache to take a url like yourserver.domain.com/teamcity and redirect it to yourServer.domain.com:8443/teamcity.  Users do not want to remember port numbers, so this will be a welcome step for them.  Also if you setup your DNS records correctly, you could even make the teamcity site something like teamcity.domain.com.

This section assumes you have setup Apache to use SSL.

  1. Enable the proxy module
    a2enmod proxy
  2. Enable the rewrite module
    a2enmod rewrite
  3. Edit the load file for the proxy module
    vim /etc/apache2/mods-enabled/proxy.load
  4. Add the following lines
    LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so
    LoadModule proxy_http_module /usr/lib/apache2/modules/mod_proxy_http.so
    LoadModule headers_module /usr/lib/apache2/modules/mod_headers.so
  5. Edit the default site to redirect all traffic to SSL
    vim /etc/apache2/sites-available/default
  6. Add the following lines
    RewriteEngine on
    RewriteCond %{SERVER_PORT} ^80$
    RewriteRule ^(.*)$ https://%{SERVER_NAME}$1 [L,R]
    RewriteLogLevel 2
  7. Edit the SSL site file
    vim /etc/apache2/sites-available/default-ssl
  8. Add the following lines
    SSLProxyEngine=on
    ProxyPass /teamcity https://localhost:8443/teamcity
    ProxyPassReverse /teamcity https://localhost:8443/teamcity
  9. Move the web directory of TeamCity to a directory that will work for this
    mv /opt/TeamCity/webapps/ROOT /opt/TeamCity/webapps/teamcity
  10. Restart Apache
    /etc/init.d/apache2 restart
  11. Open a web browser and navigate to https://yourServer.domain.com/teamcity
  12. At this point you should be looking at the login window for TeamCity