Apache 2.4 and the missing SSL certificate chain issue, my notes.

Add Comment | May 15, 2012

I'm running Mahara in a Windows Server 2008 environment using Apache web server and just for fun I wanted to enable SSL :-).


I setup SSL and tested the setup using a self-signed certificate, all good, SSL was working.

I requested a server certificate from our corporate CA, which is an intermediate CA for GlobalSign, this was done using an online MS certificate server service.

When the certificate was ready, I revisit the site, and the certificate is installed automagically into the current user certificate store.


Okay, so now I have a SSL certificate stored in the Windows certificate store, but I want to use it with Apache, so I sort of need to blend the MS way of doing things with the Apache way of doing things.


Here is what I did once I had the proper certificate.


First of I needed to export the certificate from the current users certificate store so it can be used by Apache, to do this.

  • Fire up an MMC console, and add a certificate snap-in, selecting My users account
  • Once opened, browse to the new certificate
  • Right click on it and export
  • Select, Yes, export the private key
  • Select, Include all certificates in the certification path if possible and Export all extended properties
  • Enter a password <importprivatekeypassword> and confirm
  • An then enter a descriptive filename, I used "newcert-19-05-2012-with-privte-key.pfx"


Next I need to convert the certificate to something Apache understands, and at the same time export the private key. Apache needs the private key in a separate file when running on Windows.

I copied "newcert-19-05-2012-with-privte-key.pfx" to the same folder openssl.exe is located, c:\web\apache\bin, just to make it easier.

I start an elevated command prompt

CD to the folder where openssl.exe is located

Run openssl and I get the OpenSSL> prompt.

Now I'm going to run the following commands

  • To export the private key file from the pfx file
    • pkcs12 -in newcert-19-04-2012-with-privte-key.pfx -nocerts -out key.pem
  • To export the certificate file from the pfx file
    • pkcs12 -in newcert-19-04-2012-with-privte-key.pfx -clcerts -nokeys -out cert.pem
  • To remove the passphrase from the private key
    • rsa -in key.pem -out server.key


This is what it looked like at the OpenSSL> prompt

OpenSSL> pkcs12 -in newcert-19-04-2012-with-privte-key.pfx -nocerts -out key.pem

Enter Import Password:

MAC verified OK

Enter PEM pass phrase:

Verifying - Enter PEM pass phrase:

OpenSSL> pkcs12 -in newcert-19-04-2012-with-privte-key.pfx -clcerts -nokeys -out cert.pem

Enter Import Password:

MAC verified OK

OpenSSL> rsa -in key.pem -out server.key

Enter pass phrase for key.pem:

writing RSA key



Now I have a server certificate "cert.pem", and a key file, "server.key"

I copied these to where I'm storing my certificate files, c:\web\apache\cert


Next updat httpd-ssl.conf...

SSLCertificateFile "c:/web/apache/cert/cert.pem"

SSLCertificateKeyFile "c:/web/apache/cert/server.key "

Restart Apache


At this point the certificate worked, sort of...

It was fine in Mozilla Firefox, but Internet Explorer couldn't see the certificate chain.


To fix this I had to download the CA chain from the same server the certificate was requested, an then extract each of the 4 certificates in the certificate chain. All the guides I read said I need the certificates as Base-64, and to use the Unix CAT command to copy them to the one file. I tried doing this with a standard text editor, but that didn't work, I ended up using the DOS (Windows?) TYPE command.


So download the CA chain file

Double click on the CA chain file, and then drill down to the CA and intermediate certificates

Right click on each of the certificates starting from the top level certificate and export them as Base-64 encoded X.509 (.CER) files

I exported them as cert1.cer, cert2.cer, cert3.cer, cert4.cer

Now concatenate the certificates into one file using the "type" command

C:>Type cert1.cer cert2.cer cert3.cer cert4.cer >server-ca.crt

Then I copied "server-ca.crt" to my certificate folder, c:\web\apache\cert


Update httpd-ssl.conf

SSLCertificateChainFile "C:/web/apache/cert/server-ca.crt"

Restart Apache


Test, all good...


Hope this helps someone, or me if I try to do this again :-)...

Moodle 2.2.2 Backup Issue

2 Comments | May 04, 2012

Here’s what happened…

  • Moodle 2.2.2
  • PHP 5.3.10
  • IIS 7.5
  • MS SQL 2008

We have a very large course with 31 topics, each Topic has at least 6 Book Resources and 4 or 5 Quizzes but may have as many as 22 Books and 18 Quizzes.
Overnight backups seem to work without reporting errors.
We have automated backup configured to include; users,  role assignments, activities, blocks, filters, comments, user completion information, logs, and histories.
But we are unable to run manual backups of this course.
We are unable restore overnight backups of this course if “Include enrolled users” is ticked on the “3. Setting” restore tab/page, it fails with the red “X.” Locked icon as described above.
But we can restore the overnight backups without “Include enrolled users” ticked.
When we try to manually backup the course it fails with red X next to items from about halfway through Topic 23 to the end, trying to proceed from this point gives the error “You must enter a valid filename for this backup” but the filename is the default generated, and changing file name doesn’t help.
Smaller courses don’t have any of these issues.
Debugging is turned on, but not trapping any errors.

After several hours debugging and searching I found the culprit, and the clue was “You must enter a valid filename for this backup” error message.
The manual back pages dynamically build/adding input form fields, so that you can select which topics/sections you want to include in the backup, and also so you can select to include user data for each section.
With this course there are 30 or more input form fields added to the page for each topic, plus form topic and section fields plus all the other visible and hidden form fields on the page.
And that’s what was causing the problem, PHP is configured by default to only accept 1000 values (max_input_vars=1000), and the backup page had well over 1000 form fields.
The “You must enter a valid filename for this backup” error message was being generated because now value was posted back for the form field that should have contained the filename, simple really…
Setting max_input_vars to  5000 (max_input_vars = 5000) in PHP.INI fixes this issue.

Hope this helps someone out there…

Cats Paws - walking across the page - jQuery

One Comment | Mar 13, 2012

This is just a little script to have cat paws walking across the page using jQuery.
I searched for something similar, but couldn’t find anything so this is what I ended up with…

<!DOCTYPE html>
  <script type="text/javascript" src="
  <script type="text/javascript" src="catpaws.js"></script>
Put anything you like here, catpaws.js will append a couple of DIVs to the body tag when the page loads...


* Cat Paws
* Requires, jQuery JavaScript Library v1.7.1
* Copyright 2012, Trevor Johnson, :-)
* Date: Mon March 12 2012

// when the page loads, startPaws

function startPaws() {
    // append 2 hidden DIVs
    var $newdiv1 = $('<div id="pawprint1" style="height: 85px; display: none;"><img src="paw.gif" alt="cat paw" /></div>');
    var $newdiv2 = $('<div id="pawprint2" style="height: 85px; display: none;"><img src="paw.gif" alt="cat paw" /></div>');
    $('body').append($newdiv1, $newdiv2);
    // move the DIVs

function movePaws(count) {
    // start positions
    leftpos = 100;
    toppos = 75;
    n = 0;
    var pawprint1 = document.getElementById("pawprint1");
    var pawprint2 = document.getElementById("pawprint2");
    pawprint1.style.position = "absolute";
    pawprint1.style.left = 25 + "px";
    pawprint1.style.top = 85 + "px";
    pawprint2.style.position = "absolute";

    function moveit() {
        n += 1;
        if (n < 10) {
            if (isEven(n)) {
                pawprint1.style.display = "inherit";
                pawprint1.style.left = ((parseInt(pawprint1.style.left) || 0) + leftpos) + "px";
                pawprint1.style.top = ((parseInt(pawprint1.style.top) || 0) + toppos) + "px";
            else {
                pawprint2.style.display = "inherit";
                pawprint2.style.left = ((parseInt(pawprint2.style.left) || 0) + leftpos) + "px";
                pawprint2.style.top = ((parseInt(pawprint2.style.top) || 0) + toppos) + "px";
        if (n >= 10 & n < 20) {
            if (isEven(n)) {
                pawprint1.style.left = ((parseInt(pawprint1.style.left) || 0) + leftpos) + "px";
                pawprint1.style.top = ((parseInt(pawprint1.style.top) || 0) - toppos) + "px";
            else {
                pawprint2.style.left = ((parseInt(pawprint2.style.left) || 0) + leftpos) + "px";
                pawprint2.style.top = ((parseInt(pawprint2.style.top) || 0) - toppos) + "px";
        if (n >= 20) {
            if (isEven(n)) {
                pawprint1.style.display = "inherit";
                pawprint1.style.left = ((parseInt(pawprint1.style.left) || 0) + leftpos) + "px";
                pawprint1.style.top = ((parseInt(pawprint1.style.top) || 0) + toppos) + "px";
            else {
                pawprint2.style.display = "inherit";
                pawprint2.style.left = ((parseInt(pawprint2.style.left) || 0) + leftpos) + "px";
                pawprint2.style.top = ((parseInt(pawprint2.style.top) || 0) + toppos) + "px";

        if (count-- > 0) {
            setTimeout(moveit, 750);
        else {
            pawprint1.style.display = "none";
            pawprint2.style.display = "none";

    function isEven(value) {
        if (value % 2 == 0)
            return true;
            return false;

C# IsNumeric

9 Comments | Mar 29, 2011

 My replacement for the the VB Function IsNumeric... 

 public static Boolean IsNumeric(string stringToTest)

    int result;
    if (int.TryParse(stringToTest, out result))
        return true;
        return false;
Or even better... (thanks Anon)
public static Boolean IsNumeric(string stringToTest)
    int result;
    return int.TryParse(stringToTest, out result);

Google Search, Get a better Page Rank

Add Comment | Aug 24, 2010

Google uses something called a page rank to determine your position on the search page.
To get a better Google Page Rank, there are a couple of key objects Google looks at.
The first and most important is page content.
If you don’t have the content being searched for, it can’t rank your site.
It’s very basic requirement really, but some people just don’t get this part. :)
And the second is how many people link to your page content, combined with how their page rank is, i.e. the page rank of the page that is linking to your page.
Another words, if someone links to your page, from a page that has a low page rank, it won’t help you much.
But if someone links to your page, from a page that has a high page rank (Google sees them as an expert), that will help increase your page rank.

MVC & Windows Authentication

One Comment | Jun 17, 2010

Okay so basically all we are doing here is changing the ValidateUser function so that it makes an LDAP connection using the username and password passed from the LogOn view form.

If it succeeds, we have a vaild user and password combination.

Changed ValidateUser function.

// new for authentication 
using System.DirectoryServices;
using System.DirectoryServices.Protocols;
using System.Net;
public bool ValidateUser(string userName, string password)
            bool validation;
                LdapConnection ldc = new LdapConnection(new LdapDirectoryIdentifier((string)nullfalsefalse));
                NetworkCredential nc = new NetworkCredential(userName, password, "domainname.com");
                ldc.Credential = nc;
                ldc.AuthType = AuthType.Negotiate;
                ldc.Bind(nc); // user has authenticated at this point, as the credentials were used to login to the dc. 
                string myvar = ldc.SessionOptions.DomainName;
                validation = true;
            catch (LdapException)
                validation = false;
            return validation;