Tag Archive: LDAPS


In the first part of this series I covered installing several PHP tools for continuous integration testing (PHPUnit, Mess Detecter, Copy Paste Detecter, Code Sniffer, Code Coverage, Documenter 2, Lines of Code, and Simple Test) and installing Jenkins.  You can find the first part here  In this part I will cover installing the needed plugins to use the installed PHP tools and to authenticate to active directory, and to use HTTPS (SSL) instead of the standard HTTP connection.

If the Jenkins server is currently running (if you just finished up part 1, it probably is) stop the server by running the following command

$/etc/init.d/jenkins stop

Setup the LDAP / AD Certificate

If you care planning to connect to an LDAP server or Active Directory and use LDAPS when doing so, you will need to let Jenkins know about the certificate the server has. To do so following the following steps:

Download the InstallCert tool from here

Install the unzip application

$apt-get install unzip

Unzip the tool

$unzip InstallCert.zip

Move the tool the the Java bin location

$mv InstallCert* $JAVA_HOME/jre/bin

Get the servers certificate. If you have multiple servers to get certs from, repeat this step for each.

$java InstallCert someServer.example.com:636

If you are prompted for anything, just press enter to continue on.

The certificate(s) will be placed in a file called jssecerts. Now we need to import this file into the cacerts file that java uses.

$keytool --importkeystore -srckeystore jssecacerts -destkeystore $JAVA_HOME/jre/lib/security/cacerts -noprompt

The password for the keystore is “changeit”.

To inform Jenkins of the cacerts file, edit the file /etc/defaults/jenkins and add the line to the file before the end (preferable under the commented out JAVA_ARGS line)

JAVA_ARGS="-Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts"

Setting Up SSL (HTTPS)

Edit the file /etc/defaults/jenkins and add the following lines

HTTPS_PORT=8443

HTTPS_KEYSTORE=/etc/ssl/certs/java/YourCertFile.crt
HTTPS_KEYSTORE_KEY=/etc/ssl/certs/java/YourCertKeyFile.key

Also set HTTP_PORT line to -1 to disable it

HTTP_PORT = -1

At the bottom of the file, set the JENKINS_ARGS line to the following

JENKINS_ARGS="--webroot=/var/cache/jenkins/war --httpPort=$HTTP_PORT --ajp13Port=$AJP_PORT --httpsPort=$HTTPS_PORT --httpsCertificate=$HTTPS_KEYSTORE --httpsPrivateKey=$HTTPS_KEYSTORE_KEY"

Installing the Plugins

  1. Open a web browser and go to https://yourServer. example.com:8443
  2. Click on Manage Jenkins
  3. Click on Manage Plugins
  4. Select the “Available” tab
  5. Select the following plugins
    • Active Directory Plugin
    • checkstyle
    • clover php plugin
    • dry
    • html publisher plugin
    • jdepend plugin
    • plot plugin
    • pmd plugin
    • violations
    • xUnit plugin
  6. Click “Install without Restart”

Setup Authentication to Active Directory

  1. Go to Manage Jenkins -> Configure Global Security
  2. Check “Enable Security”
  3. Select “Active Directory” under the Security Realm section
  4. Click “Advanced”
  5. Set the following fields:Domain Name: example.com
    Bind DN: CN=someUser,OU=Users,DC=example,DC=com
    Bind Password: TheBindUsersPassword
  6. Click “Test”
  7. If all is good, click “Apply”, else trouble shoot the issue
  8. Click “Save”
  9. Try to authenticate as a known user by clicking “log in” in the upper right corder and authenticating

NOTE: This setup did not work when I entered a domain controller. If I left the field blank, Jenkins was able to find the appropriate server and authenticate without issue.

Setting up LDAP Authentication

If you don’t want to use the active directory plugin, you can also authenticate using LDAP functionality Jenkins already has.

  1. Go to Manage Jenkins -> Configure Global Security
  2. Check “Enable Security”
  3. Under the Security Realm section, select “LDAP”
  4. Set the following fields:Server: ldaps://someServer.example.com:636
    User Search Filter: sAMAccountName={0}
    Manager DN:CN=someUser,OU=Users,DN=example,DN=com
    Manager Password:The manager users password
  5. Click “Apply”
  6. Click “Save”
  7. Test authenticating as a known user by clicking the “log in” link in the upper right corner and trying to log in

NOTE: If you intend to authenticate to an LDAP server like eDir (Novell) do not set the User Search Field to sAMAccountName={0} as it will not work

A Little Extra Security

To help prevent Cross-Site Scripting do the following:

  1. Go to Manage Jenkins -> Configure Global Security
  2. Check “Prevent Cross Site Request Forgery Exploits”
  3. Select “Default Crumb Issuer”
  4. Click “Apply”
  5. Click “Save”

Configuring Access

Now that you have users authenticating to Jenkins, you should limit what they can do. By default, Jenkins allows all users to do all things.

  1. Go to Manage Jenkins -> Configure Global SecurityUnder the “Authorization” section select “Project-based Matrix Authorization Strategy”
  2. Enter your username in the “User/group to add” field and click the “Add” button
  3. You should probably give yourself full permissions, you can do this quickly by clicking the image next to the red X on the right side of the row for your user
  4. If you want to add a group, just enter the group name in the “User/group to add” filed and click add. You used to have to prefix groups with ROLE_, but this is no longer required
  5. Set the permissions for the group or users you add to the list

NOTE: Under this authorization scheme, the permissions given to the users or groups here should be their base permissions site wide. In other words, give them the minimum amount here. Then in the projects they are a working on, you can specify additional rights under the “job configuration screen” for the project.

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