ClustrMap

Last week we got a TeamCity Enterprise license at work. After using this great product for about a year we found ourselves running out of available build configurations. (There are 20 in the fully-functional free Professional edition which should be enough to evaluate the product. I recommend giving it a try.) There are a couple of advanced features in the TeamCity Enterprise edition we were looking forward to, for example authentication against a LDAP directory, an Active Directory in our case (AD = LDAP + DNS + a bunch of other stuff).

TeamCity uses LDAP to determine if a user should be able to access the TeamCity web interface. It does that through the LDAP bind operation, asking LDAP to validate the username and password combination entered at the login page.

After hitting the login button TeamCity will connect to the LDAP server, basically taking the text entered in the dialog above passing it to the LDAP bind operation. If the server accepts the username/password combination this means that access is granted. Some things to take into consideration when using LDAP authentication are:

TeamCity does not authenticate against an organizational unit in Active Directory (X.500 address). It just determines if the user (authenticated by username and password) exists anywhere in the directory. You can vote on this ticket to get that fixed.

Because TeamCity does not try to get additional information on the user’s groups memberships it is currently (as of TeamCity 4.0) not possible to automatically assign TeamCity roles to an LDAP user.

If you use the default LDAP configuration settings as shown in the TeamCity documentation, the LDAP connection will be unsecured, making the username and password vulnerable to eavesdropping by anyone who knows how to use packet sniffer.

Given the things above, what are your options to secure the LDAP connection? You could change the authentication scheme to not use "simple” LDAP authentication, but choose from a variety of SASL options. I didn’t go down that road, because when I started to configure LDAP for TeamCity I basically knew nothing about neither LDAP nor SASL.

Using LDAPS (LDAP over SSL), which is also supported by Windows servers running some AD mode, appeared to be a viable option to enforce secure communication between TeamCity and the LDAP server.

Installing The LDAP Server

Setting Up LDAPS with Active Directory (Domain Controller mode)

There’s not much set up needed with this configuration. When you install Active Directory in Domain Controller mode you should also get an instance of Certificate Services that will create a self-signed certificate for your domain controller. This certificate will be used for LDAPS connections to the directory server, which is typically the domain controller.

As an aside, I’m not expert in setting up AD, please refer to your network administrator.

As noted above, this setup is supported on any Windows Server and does not require the full-blown “Domain Controller” version of Active Directory. ADAM/LDS supports user authentication either against the ADAM/LDS instance (users created in the directory) or a against local Windows accounts (through a user proxy, see below)

Installing ADAM or AD LDS

Installing ADAM/LDS differs depending on which Windows Server version you have. I did it with Windows Server 2003:

Navigate to the Control Panel and open up the Software control panel applet, appwiz.cpl

User Management

You now have a LDAP server running that will serve requests for the LDAP and LDAPS protocols. Next, you would have to add users to the directory, which could either be

Local directory users: user and password stored in the directory; used with “simple” bindings, or

Windows users: users password stored by the local Windows account manager or in a full-blown AD domain; used with “proxied” bindings (from the outside, these also appear as “simple” bindings).

Windows users require a user proxy in the directory, linking the proxy to a Windows account SID. The link between the proxy and the Windows account is established though the Windows account’s Security Identifier (SID) which must be supplied when the proxy is created. Setting up user proxies is a bit complicated and well worth another post.

Please note that by default authenticating users through their respective proxies (proxied binding) requires a secure connection, unless you explicitly disable it. Unfortunately the attribute to change is not given in the linked article: it is msDS-Other-Settings. You can either require security for simple or proxied bindings by setting RequireSecureProxyBind (defaults to 1) and RequireSecureSimpleBind (defaults to 0) to either 0 or 1.

The net result of the default ADAM configuration (RequireSecureProxyBind=1) together with the default TeamCity configuration (ldap://some-server, which is unsecured) is that authentication requests for user proxies will always fail.

Now we need to set up the correct "user name" string to present it to the LDAP server. This string is created from the text entered in the "Username" text box on the login screen ($login$) and differs depending on whether you use LDAP with AD or ADAM/LDS:

Changing the protocol to use ldaps:// will not instantly work and users would not be authenticated. Why?

Trusting The Certificate

What does LDAPS mean from a Java perspective? If you work on a domain (AD) or use ADAM/LDS with SSL you are very likely to work with self-signed SSL certificates. Such certificates are inherently untrusted as they are not issued by some trusted party (and this trusted party will charge money). Nevertheless they are perfectly okay for your environment.

When TeamCity establishes the SSL connection to your LDAP server, it is first presented with that untrusted certificate – and bails. Here’s a snippet from the TeamCity log files:

Place the files from the ZIP in your <TeamCity root>\jre\bin directory. Open a command prompt and enter

java InstallCert ldap.test.local:636

Following the procedure described in Andreas' post, the utility will create a file called jssecacerts in the same directory. Overwrite <TeamCity root>\jre\lib\security\cacerts with that file.

After re-starting the TeamCity web server, it is now able to establish secured connections to the LDAP server. The user names and passwords transmitted over these connections will not be visible to outsiders.

Wrapping It Up

In this article I’ve shown you how to enable and secure TeamCity’s LDAP authentication in any Windows environment, be it an Active Directory domain or a couple of stand-alone Windows Servers. For both scenarios user management is centralized, either though the AD console or LDAP console in combination with the Windows user management console.

Figuring out all that has taken a considerable amount of time for me and hopefully saves you a couple of minutes that you can spend outside in the sun.