Monday, February 27, 2012

Deploying a Mediawiki server in an Active Directory environment

I recently implemented a knowledge base web application at work using Mediawiki.  There are a number of group collaboration packages out there, but I was really looking for something that would be extremely simple.  I wanted to create a knowledge base web site to replace a  bunch of folders full of Word documents shared on our servers.  Since all of this information is meant to be shared with anybody in the company my aim was to provide something that would make it easier for people to find information or at least make it easier for them to remember where to look.  I prefer to follow Unix philosophy whenever possible even though I am currently working in a predominantly Windows environment.  Part of that philosophy is keeping things as simple as possible and making each component in a system do one thing well.  With that in mind I didn't want to implement a complicated groupware system that had a bunch of features that would either confuse people or just not get used.  For this project I didn't need a document management system, enterprise social networking, project management, granular permission sets, etc.  I just wasn't looking for a one web application to rule them all sort of a setup.    My other criteria when choosing a software package was that the organization behind it have a good history, that they provide regular updates, that there is a good likelihood that the software will have a future, that there is good documentation for it and that data could be migrated to another platform in the future if necessary.  Basically it needed to be easy to install and maintain either by me or anyone else that needs to maintain it in the future and our data should not be locked into a proprietary format.  Mediawiki fit all of those requirements and it does the one thing that it was designed for well.

I expect that the majority of our users will be content consumers rather than contributors, so I was not terribly concerned with authenticating everyone.  If all somebody needs to do is read something I didn't want to force them to log into the site.  I did however want some amount of accountability for the edits that are made to the pages in the knowledge base so it needed to have a user authentication system to log users in before editing content.  If you are implementing any sort of application that uses authentication, you'll can make both using your application and administering it much easier by using a centralized authentication mechanism.  So my one requirement in this regard was that the system must allow them to use their existing Active Directory user account to log in.  Using Ryan Lane's "LdapAuthentication" extension made things easier for me and our users.

The installation instructions for this extension are well documented so I won't go into great detail here. Basically you need to install the required software packages on your system and install the certificate(s) of the domain controller(s) and configure open-ldap telling it where you have stored those certificates.  Next you'll need to create a user with read access to Active Directory to act as a proxy for your application.  A regular user with no special privileges will work just fine.  My proxy user is just a member of the "Domain Users" group and that's it.  Download the latest tarball of the extension and extract the contents into its own directory underneath your extensions directory and you're ready to configure it.

I found some of the documentation of the configuration to be somewhat incomplete but appropriately the documentation was hosted on a Mediawiki site, so I created a user account and made some edits to add what I found to be lacking.  Here is the configuration that is in my "LocalSettings.php" file.

# End of automatically generated settings.
# Add more configuration options below.

#LdapAuthentication Configuration

require_once("$IP/extensions/LdapAuthentication/LdapAuthentication.php");
$wgAuth = new LdapAuthenticationPlugin();
$wgLDAPDomainNames = array("domain");
$wgLDAPServerNames = array("domain" => "domainController.domain.local");
$wgLDAPSearchStrings = array("domain" =>"domain\\USER-NAME");
$wgLDAPSearchAttributes = array("domain" => "sAMAccountName");
$wgLDAPBaseDNs = array("domain" => "dc=domain,dc=local");
$wgLDAPEncryptionType = array("domain" => "ssl");
$wgMinimalPasswordLength = 1;
$wgLDAPDisableAutoCreate = array("domain"=>false);
$wgLDAPProxyAgent =  array("domain" => "cn=proxyUser,ou=organizationalUnit,dc=domain,dc=local");
$wgLDAPProxyAgentPassword = array("domain"=>"V+r<I(DNm8%vA");


Some explanation of these lines are in order to fully understand what you'll need to fill in for your particular environment.   I'll now go over the configuration.

require_once("$IP/extensions/LdapAuthentication/LdapAuthentication.php");
$wgAuth = new LdapAuthenticationPlugin();

These two lines tell your Mediawiki installation to load the extension and create a new instance of the LdapAuthenticationPlugin class to use as its authentication mechanism.  Please take care to ensure that "$IP/extensions/..." is the actual path into which you unpacked your extension.

Anywhere that you see "domain" in my example, just substitute the NETBIOS domain name for your AD domain.  The $wgLDAPServerNames array is a space separated list of your domain controllers that you'd like your server to talk to.  $wgLDAPDomainNames, $wgLDAPSearchStrings and $wgLDAPSearchAttributes are self-documenting.  

Your $wgLDAPBaseDNs variable is where you would like the extension to start searching for users.  In the example above it would start at the domain root, but you can start at any arbitrary container as long as all of your users accounts will be found below there in the AD structure, e.g. cn=users,dc=domain,dc=local or ou=users,ou=northamerica,dc=domain,dc=local.  

Using "ssl" for $wgLDAPEncryptionType will keep your domain credentials secure from eavesdropping while they are sent over the wire.  

Setting $wgMinimalPasswordLength to "1" just means that you can't have a blank password.  

The variable $wgLDAPDisableAutoCreate should be set to false if you would like to have Mediawiki automatically create new Mediawiki user accounts for any users that it finds in Active Directory.  If you comment out or delete this line, the default will be false however explicitly setting it makes for good documentation of what your intention is.

Your $wgLDAPProxyAgent will be the full LDAP distinguished name of your proxy user account and $wgLDAPProxyAgentPassword should be a randomly generated complex password such as the example above.

Running a Mediawiki server makes for an easy way for people to share information in a format that they are comfortable using.  Running it with the LDAP Authentication extension installed introduces a modicum of accountability for those that choose to edit or post content with the ease of using account credentials that they already have.

Saturday, February 25, 2012

Configuring Apache to use SSL to secure web traffic

Configuring Apache to secure web traffic is pretty straight forward but as with many things one simple error can cause it to fail to work as it is intended.  I would like to share how I've configured Apache to use SSL to secure web traffic and I'll include a couple of pitfalls that you may run across.  In the end it is a simple process, but it is an essential one to keep your data and your users safe from the possibility of usernames and passwords or other sensitive information from being captured somewhere between the server and the client.  I use SSL to secure all of my web servers whether they are running on Windows or Linux and whether they are accessible from the public internet or only from the local network.  No matter how secure you may think your LAN is or how trustworthy your users are, encrypting network traffic will guarantee that client-server communications are secured against eavesdropping.  Of course any traffic containing sensitive information traversing a public network should be secured without question.

Before configuring Apache, you must first acquire an SSL certificate from a certificate authority that your users will trust.  Depending on where your web site or application will be accessible and what resources you have at your disposal, you can either obtain a certificate from a trusted third party CA or from a CA in your own enterprise public key infrastructure.  I happen to work with a predominantly Windows infrastructure, so I used my Windows Server 2008 R2 CA to generate the certificate.  If you decide, like I did, to use a certificate that is not from a third party CA, Firefox users will be presented with the warning message "This connection is untrusted".  Each user will have to import either the server certificate or the CA certificate in Firefox to avoid the warning. Internet Explorer, Chrome and Safari browsers will trust the Windows CA because they use the integrated Windows certificate store which will contain a copy of your Windows CA certificate and trust it.  If you're expecting that a lot of your site visitors will be using non-windows devices or predominantly Firefox, then save yourself a support headache and buy a certificate from a third party CA.

Once you have your server certificate you can finish the SSL configuration. The particular server that I'm using as an example is running CentOS 6.2.  You will need to check file locations for your distribution if it is different.  The default configuration for Apache running on CentOS is to use '/etc/httpd/conf/httpd.conf' as well as all '.conf' files located in '/etc/httpd/conf.d' because 'httpd.conf' contains the following directive.

Include conf.d/*.conf

The only indication that I'm running this server over SSL from httpd.conf is the directive:

ServerName server.domain.local:443 
  
I left 'Listen 80' in 'httpd.conf' so that my clients could connect to the web site without specifying either "https" or appending ":443" to my site address.  Everything else is configured in '/etc/httpd/conf.d/ssl.conf'. Be sure that only one of your .conf files contains the directive 'Listen 443', which I have in ssl.conf.  If you include it in both your 'httpd.conf' and 'ssl.conf' Apache will fail to start with an "address already in use" error message.

You can leave the majority of  'ssl.conf' with the default configuration that ships with Apache but make sure that it includes 'SSLEngine On'.  The primary lines that you will need to edit in 'ssl.conf' tell Apache which certificates to present to your users' web browsers as well as which private key is associated with the server certificate.  It is the public key / private key pair that are the basis of SSL cryptography.  The public key is provided to the client in the certificate and the private key is held by the server.  Those keys combined with agreed upon encryption algorithms and random number generation provide the session keys that are used by both parties to encrypt a particular conversation.  Here are the directives from 'ssl.conf':

SSLCertificateFile /etc/pki/tls/certs/server.domain.local.crt
SSLCertificateKeyfile /etc/pki/tls/private/server.domain.local.key
SSLCACertificateFile /etc/pki/tls/certs/ca.domain.local.crt
SSLCertificateChainFile /etc/pki/tls/certs/server-chain.crt 

The names of these directives make them self-documenting.  The last line is not strictly needed and I'm not using it, but I thought I'd include it for completeness.  My server certificate was generated by the root CA in my PKI, so in my case there is no server chain to speak of.  It's also not needed if your server certificate contains a concatenated list of all of the certificates of any intermediate certificate authorities in the certification chain.

To test your configuration run 'service httpd restart' and browse to your site in the web browsers that your users are likely to be using.  If everything is working properly you should see http redirect to https automatically.  If something isn't working right, check your configuration files for misspellings or other syntax errors and check '/var/log/httpd/error_log' for any other indications of what might be going wrong.  One thing that lies outside of the Apache configuration that will stop traffic cold is firewall rules.  Check your iptables rules to make sure that you are allowing inbound connections on ports 80 and 443.  If you have any doubts about where a problem may lie you can turn your firewall off temporarily just to rule out that possibility.  Securing your web traffic with SSL is fairly easy, but it is essential for keeping your data and your users safe.

Thursday, February 23, 2012

Using a certificate issued by an Active Directory Certificate Authority to secure Apache on Linux

Getting Linux servers to inter-operate with Microsoft's Active Directory can sometimes be challenging.  Finding documentation for getting those two operating systems to talk to each other can be equally challenging.  Sometimes the information that I've found has been out of date or the sources contained little typos which caused commands to fail on one system or another. 

Last weekend I was working on setting up a Linux virtual machine to serve up a Mediawiki site that will act as a knowledge base where I work.  I chose to install a Linux based Mediawiki server  because it does what I want and nothing more and it does it well.  In my case I decided to set up a CentOS 6.2 server to run Apache for me.  Secondly, by not installing another Windows server I've just saved the company I work for about $700 in licensing fees.  So why CentOS you ask?  Well I started out playing with Red Hat Linux when you could still choose "Red Neck" as your installation language and years later got my first IT job working for a local ISP that was running a mix of Red Hat and SunOS servers.  So I like to use CentOS because I know my way around it better than the other Linux distributions out there and it is maintained on an enterprise lifecycle like its upstream counterpart.  My Windows Active Directory environment is running on Windows Server 2008 R2 at the 2008 R2 forest and domain functional levels and my Certificate Authority is running on 2008 R2 as well.

Next you might ask, why do you need to use SSL for a server on your own LAN?  If you are asking people to enter a username and password on a website, then you should secure the communication between the browser and the server no matter how secure you think the network is.  It's just the right thing to do.

After putting together little bits and pieces of information from a variety of websites and a little bit of trial and error, I came up with the procedure detailed below.  While working on this, like my other projects, I kept notes on what worked and what didn't and I thought that I'd share this so that perhaps somebody else will have an easier time setting up something similar.  Let me also say that this is not the only way to accomplish this task.  There are other ways of generating your certificate request and there are other ways of generating the certificate, but these seemed the most straight forward provided that you have root access to your Linux server and Domain Administrator privileges on your Windows CA.


On the Linux server

First you need to use OpenSSL to create the keys that are used to secure traffic to your site. You will want to do this where you are going to store your private keys. On a Red Hat based system it will be '/etc/pki/tls/private'  Once you are working in that directory type:
 
openssl genrsa -out site.domain.local.key 2048
 
This will create a 2048 bit private key and put it in the file site.domain.local.key. This private key is not encrypted so be sure to keep it in a secure location. Keeping it in '/etc/pki/tls/private' should keep it secure. Next you will need to create a certificate request file to submit to the AD CA so that it can generate your certificate.  Generate the certificate request using:

openssl req -new -key site.domain.local.key -out site.domain.local.req
 
This command will prompt you for information that is used by the CA when it creates the certificate.  If you've ever requested an SSL certificate before this information will be familiar to you. The most important one is the common name (CN), which is the fully qualified domain name of your site. When that command has finished you need to copy your certificate request file to a location where you can access it from the Windows Certificate Authority.

On the Windows server 


The Windows CA will not take the request as it was generated by your Linux server. It will be expecting a special certificate attribute that tells it what certificate template to use when creating the certificate. In this case we want to use the "WebServer" template which the Windows CA will use to determine the "Key Usage" attributes that it writes to the certificate. Using that template it will write "Digital Signature" and "Key Encipherment (a0)", which is the intended use of this certificate.  If you haven't already, you will need to add "Web Server" to the list of certificate templates that your CA uses to issue certificates using the Certification Authority mmc. With the certificate request file available you will need to open an elevated command prompt to make the certificate request. At the command prompt type:

certreq -attrib "CertificateTemplate:WebServer" site.domain.local.req
 
When prompted, save the certificate as 'site.domain.local.crt'. You can now copy that certificate back to your Linux server and place it in '/etc/pki/tls/certs' or the appropriate location for your Linux distribution.


Now that you have your certificate, you can go back you your Linux server and configure Apache to use SSL and to authenticate your users using Active Directory but that is a subject for another post.