HTTPS tricks

Using HTTPS with the catalyst built in server

The built in server is extreemly useful during development, but it does not support HTTPS. These are some tricks that let you develop using https more easily.

Using pound to handle the https connections

pound is a very lightweight load balancer which can be used to decrypt https traffic and then forward it to a http server for processing. The following bash script will check for prerequisites and then start pound.

More details on pound can be found at http://www.apsis.ch/pound/

It should be run like this:

bash> path/to/script/run_pound_for_dev.bash 3000 3001

The first argument is the http port to forward to, the second the https port to listen on. We usually can't use '80' and '443' (the defaults) as we are not running as root.

The script contents:

#!/bin/bash

# Change to the directory that this script is in
cd `dirname $0`

# capture the port numbers to use
HTTP_PORT=$1
HTTPS_PORT=$2

echo "HTTP_PORT: $HTTP_PORT, HTTPS_PORT: $HTTPS_PORT";

# echo out the config to the config file - put in the correct port numbers
echo "
Daemon   0
LogLevel 2

ListenHTTPS
    Address 0.0.0.0
    Port    ${HTTPS_PORT}
    Cert    \"server_dev.pem\"

    AddHeader \"X-Secure-Connection: true\"

    Service
        BackEnd
            Address 127.0.0.1
            Port    $HTTP_PORT
        End
    End
End

" > pound_dev.cfg

# create the certificate if needed
if test ! -e server_dev.pem; then
    echo " ---- creating the required certificate: server_dev.pem ---- ";

    openssl                              \
        req                              \
        -new                             \
        -x509                            \
        -days 365                        \
        -nodes                           \
        -out server_dev.pem              \
        -keyout server_dev.pem

    echo;
    echo "---- certificate created ----- ";
    echo;
fi;

# start pound
/usr/sbin/pound -v -f pound_dev.cfg -p pound_dev.pid

Starting pound when you start the server

To start pound whenever you start the test server put the following in your myapp_server.pl script:

# we want to start a pound process to handle the
if ( my $child_pid = fork() ) {
    warn "Pound has been started on pid $child_pid.\n";
} else {
    my $http_port  = $port;
    my $https_port = $port + 1;
    exec "misc/pound/run_pound_for_dev.bash $http_port $https_port";
}

This should come just after the pod2usage(1) if $help line.

Working out if the request was secure

As all traffic now reaches the catalyst server over http we need some other way of determining if the traffic was originally https. In the pound config you'll note the AddHeader line which will add the following header to all requests that pound forwards for us:

X-Secure-Connection: true

We can now check for this header in our app and use it to toggle the secure flag on the request.

This should go in your MyApp.pm file:

=head2 prepare_headers

     $c->prepare_headers;

We want to pretend that the connection was secure if the header
C<X-Secure-Connection> is set to a true value. This allows the tedious HTTPS
encryption/decryption/negotiating to be dealt with by the load balancers.

=cut

sub prepare_headers {
    my $c = shift;

    # run the other bits first
    $c->maybe::next::method();

    # check for the X-Secure-Connection header
    $c->req->secure(1)
        if $c->req->header('X-Secure-Connection');

    return 1;
}

Creating secure links

This will vary depending on your app, but the following code might be a useful starter:

Again, in your MyApp.pm file:

my $USE_TESTING_HTTPS_PORT = undef;    # Should we use the testing port?

# make changes to config for the development environment
my $engine = $ENV{CATALYST_ENGINE} || '';
if ( $engine =~ m{ ^ HTTP (\:\:Restarter)? }x ) {

    # we should be running pound for the tests to work
    $USE_TESTING_HTTPS_PORT = 1;
}

=head2 redirect_to_secure

    $c->redirect_to_secure();

Redirect the current request to the secure url. On live this is just
replacing the 'http' with 'https'. On the catalyst test server it is also
changing the port to C<$http_port + 1> which is where pound is expected to
be running.

=cut

sub redirect_to_secure {
    my $c = shift;

    # get a copy of the url
    my $uri = $c->req->uri->clone;

    # change the protocol
    $uri->scheme('https');

    # change the port if needed
    if ($USE_TESTING_HTTPS_PORT) {
        $uri->port( $uri->port + 1 );
    }

    # debug output
    $c->log->debug(
        sprintf(
            "redirecting from %s to %s",
            $c->req->uri->as_string, $uri->as_string
        )
    ) if $c->debug;

    # redirect to this new url
    $c->res->redirect($uri);

    return;
}
My tags:
 
Popular tags:
 
Powered by Catalyst
Powered by MojoMojo Hosted by Shadowcat - Managed by Nordaaker