Dependency Hell – and it’s not my package manager to blame

I’m writing a web service for conferences. I’ve been writing it, on and off for 3 years, and I think it would be fair to say the coding reflects my learning over those three years. The script is written in PHP. It has a MySQL backend. It has undergone a lot of changes.

In the beginning, was a concept. The concept was to have a digital timetable. One where you could register your interest in a talk, and the busiest talks got the biggest rooms. It should use any tech the user had to use the system including SMS. It would not expect you to have a user name and password combo (heaven forbid!), but would use OpenID.

The concept was implemented and demo’d at an event 2 years ago, and a friend [1] asked where the API was. “API?” I replied, feeling somewhat foolish, “It doesn’t have an API“.

[1] Lorna Jane Bowman (neƩ Mitchell aka @lornajane)

I realised the foolishness of my coding when discussing this issue [2]. “It’s dead simple, just create another view which returns just JSON” said someone. “View? I don’t know what you mean“… “Model, View, Controller? MVC – it’s a pretty common pattern”. “Oh no” I replied, “my project has inline PHP. It just seemed simpler that way.” “Well, how about you add a toString() function to your classes, and use that to render the output?” “Classes. Another thing my project doesn’t have. Sorry. Can’t do that either.

[2] With Lorna again, and adding Katherine Reeve (aka @BinaryKitten)

Did you ever get that slightly sinking feeling that maybe you’re making a fool of yourself?

“Well, there are lots of benefits to Classes in PHP, not least of which that you can use PHP CodeSniffer to enforce your coding standards” I start to laugh a little at this point “and you can use PHP Documenter to create all your developer documentation” which shut me right back up again “you can use PDO to create your objects from your database results” wow… mind blown – I’ve jumped on this little trick of a pony… “and of course, you can’t really do unit testing without classes”. Uh oh. “What’s unit testing?” “It’s a set of automated tests you can run against your code every time you commit to your version control software” whew! I’m using that at least! “to make sure that the code you’re committing hasn’t broken anything”.

Fast forward to this week, and I asked on Facebook whether anyone could teach me how to do Unit Testing. See, I’ve managed to cobble together my own MVC – I have classes called “Object_” which are the Models, the controller is my routing script – otherwise known as index.php, and then the Views are templates in Smarty, or just a json_encode((array) $object) [3] for my API. I have my own set of tests – not unit tests, it’s a script called “Test.sh” which runs PHP against the file (to make sure that the pages don’t have brackets missing or similar), then runs PHP Code Sniffer against it, and finally, if all the files are OK, it then runs PHPDoc against the whole mass of it.

[3] As the Apple iPhone/iPad adverts say – some sequences shortened

So, one of the books suggested to me, again by the lovely Lorna Jane, was The Grumpy Programmer’s Guide To Building Testable PHP Applications which mentioned that it’s much easier to do unit testing if you set up dependency injection. Note, I’m still not yet doing Unit testing here.

Woah. What the hell is Dependency Injection? Well, fortunately, there were code examples in that book. Oh boy, were there code examples. So let’s look through this idea. Instead of writing

$stuff = new MyStuff();

class MyStuff()
{
    function construct()
    {
        $this->db = mysql_connect('localhost', 'username', 'password');
        mysql_use_database('production', $this->db);
    }
}

You could instead write this:

$db = mysql_connect('localhost', 'username', 'password');
mysql_use_database('production', $this->db);
$stuff = new MyStuff($db);

class MyStuff()
{
    function construct($db = null)
    {
        $this->db = $db;
    }
}

So, this now means that in your testing framework, you could pass it a non-production database, or a testing database, or, well, anything that relies on something outside your script.

I did a bit of digging around to find some other examples of dependency injection code that might be a bit easier to use, which is to say, something so I don’t need to amend all my constructor functions.

I found this slideshare from a talk at PHP Barcelona about dependency injection which says you can do dependency injection like this:

$thing = new MyClass($dependency);

OR

$thing = new MyClass();
 $thing->setDependency($dependency);

OR

$thing = new MyClass();
 $thing->dependency = $dependency;

but somewhat weirdly, it also says that you can create a container class which holds your dependencies, and refer to that later – and that this isn’t a singleton. Sadly, I didn’t understand all that code fully (and have gone on to file a bug for the PHP documentation for the functions I didn’t understand to help people who follow behind with it!), but (and I’ve copied this verbatim from the slideshare) essentially, it looks like this:

class Container { protected $values = array(); function __set($id,$value) {  $this->values[$id] = $value;  }  function __get($id) {  if (!isset($this->values[$id])) {  throw new InvalidArgumentException(sprintf('Value "%s" is not defined.', $id));  }  if (is_callable($this->values[$id])) {  return $this->values[$id]($this);  } else { return $this->values[$id];  }  }  function asShared ($callable) {  return function($c) use ($callable) {  static $object; if (is_null($object)) {  $object=$callable($c);  }  return $object; }; } } $container = new Container(); $container->session_name='SESSION_ID'; $container->storage_class='SessionStorage'; $container->user = $container->asShared( function($c) {  return new User($c->storage);  } ); $container->storage = $container->asShared(  function($c) {  return new $c->storage_class($c->session_name); } );

Now, I have to be honest, this confuses the hell out of me. How on earth do I use this in my code? I’ve been doing this in my code thus far:

class Object_User{
  protected $intUserID    = null; // Obtained by the getCurrentUser() function
  protected $strUsername  = null;
  protected $hashPassword = null; // More of these, depending on the SQL

  function getCurrentUser() { // Called as $user = Base_User::getCurrentUser();
 $objCache  = Base_Cache::getHandler(); // A singleton to "cache" any data we've pulled to save getting it repeatedly
    if (
          isset($objCache->arrCache['Object_User']['current'])
          && $objCache->arrCache['Object_User']['current'] != false
        ) {
      return $objCache->arrCache['Object_User']['current'];
    }
   Ā $arrRequest  = Base_Request::getRequest(); // Returns array of parsed request data
    $objDatabase = Base_Database::getConnection(); // Returns a PDO object

    $sql = "SELECT * FROM users WHERE strUsername = ? and hashPassword = ?";
    $query = $db->prepare($sql);
    $query->execute(array($request['username'], $request['password'])); $result = $query->fetchObject('Object_User');
    if ($result != false) {
      $objCache->arrCache['Object_User']['id'][$result->getVal('intUserID')] = $result;
      $objCache->arrCache['Object_User']['current'] = $result;
    }
    return $result;
  }

  function getVal($key) { // Return protected variables
    if (!isset($this->$key)) {
      return false;
    }
    return $this->$key;
  }
}

I know that singleton methods are considered “Bad” because they’re (apparently) difficult to unit test, but I would have thought that it would have been pretty straightforward to create a singleton class which holds all the dependencies (see following)

class Base_Dependencies
{
  protected static $handler = null; protected $arrDependencies = array();  Ā protected function GetHandler() {
    if (self::$handler == null) { self::$handler = new self(); }
    return self::$handler;
  }

  function set($key, $dependency) {
    $handler = self::GetHandler();
    $handler->arrDependencies[$key] = $dependency;
  }

  function get($key) {
    $handler = self::GetHandler();
    if (isset($handler->arrDependencies[$key])) {
      return $handler->arrDependencies[$key];
    } else {
      return false;
    }
  }

  function unset($key) { // Only used for Unit Testing, I would imagine
    $handler = self::GetHandler();
    if (isset($handler->arrDependencies[$key])) {
      unset($handler->arrDependencies[$key]);
    }
  }
}

Doing it this way means I can, from, for example, my database class, which is currently a singleton, say instead:

function GetConnection() {
  $db = Base_Dependencies::get("Database");
  if ($db != false) {
    return $db;
  }
  $config = Base_Config::getAllConfig();
  $db = new PDO($config['DSN'], $config['DB_User'], $config['DB_Pass']);
  Base_Dependencies::set("Database", $db);
  return $db;
}

Is this wrong? Is this just not best practice? Given the above, how can I fix my dependencies in such a way that the poor schmuck who wants to commit a patch can figure out what they’re sending? Or do I just need to fix how my head works with this stuff? If it’s the latter, can someone provide some samples of what I’m doing wrong?

Thanks for reading this mammoth post!

Trials and Tribulations of StatusNet with Meteor

I have recently moved this domain to a VPS, and the main reason was so I could speed up my StatusNet site, but a nice side effect to that was that I could add the auto-content-update plugins to my StatusNet site.

I plumped for Meteor, as it was more-or-less the defacto choice (or so it seems at the moment), and went away to follow the instructions at http://meteorserver.org. Having added my meteor server, and knowing that there’s only me that is likely to be using the auto-update plugin, I set up Apache to proxy the meteor connections.

Here’s what I’ve got:

I used the default /etc/meteord.conf, but added at the top of the file the following two lines:

SubscriberIP 127.0.0.1
ControllerIP 127.0.0.1

I started meteor and checked that meteor was running:

# netstat -an | grep 467
tcpĀ Ā Ā Ā Ā Ā Ā  0Ā Ā Ā Ā Ā  0 127.0.0.1:4670Ā Ā Ā Ā Ā Ā Ā Ā Ā  0.0.0.0:*Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā  LISTEN
tcpĀ Ā Ā Ā Ā Ā Ā  0Ā Ā Ā Ā Ā  0 127.0.0.1:4671Ā Ā Ā Ā Ā Ā Ā Ā Ā  0.0.0.0:*Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā  LISTEN

Next, I added a new file to /etc/apache2/sites-available called metor-proxy

<VirtualHost *:80>
Ā Ā Ā Ā Ā Ā Ā  ServerAdmin webmaster@localhost
Ā Ā Ā Ā Ā Ā Ā  ServerName meteor.jon.sprig.gs

Ā Ā Ā Ā Ā Ā Ā  ErrorLog ${APACHE_LOG_DIR}/meteor-error.log

Ā Ā Ā Ā Ā Ā Ā  # Possible values include: debug, info, notice, warn, error, crit,
Ā Ā Ā Ā Ā Ā Ā  # alert, emerg.
Ā Ā Ā Ā Ā Ā Ā  LogLevel warn

Ā Ā Ā Ā Ā Ā Ā  CustomLog ${APACHE_LOG_DIR}/meteor-access.log combined

Ā Ā Ā Ā Ā Ā Ā  ProxyPass / http://127.0.0.1:4670/
Ā Ā Ā Ā Ā Ā Ā  ProxyPassReverse / http://127.0.0.1:4670/
</VirtualHost>

Then, I used the a2ensite script:

# a2ensite meteord-proxy
Enabling site meteord-proxy.
Run '/etc/init.d/apache2 reload' to activate new configuration!

I ensured my DNS had an entry for this hostname, it does.

Lastly, I added some lines to my StatusNet config.php file:

addPlugin('Meteor', array(
Ā Ā Ā  'webserver' => 'meteor.jon.sprig.gs',
Ā Ā Ā  'webport' => 80,
Ā Ā Ā  'channelbase' => 'statusnet',
Ā Ā Ā  'controlserver' => '127.0.0.1',
Ā Ā Ā  'controlport' => '4671'
));
addPlugin('Realtime');

All looks good so far, right?

I fire up my StatusNet site, and check in firebug – the meteor.js file is being loaded OK, but straight away, it’s loading /poll.html, and not /stream.html, so I’m guessing there’s an issue here…

Head over to the console tab, and what do we see here?

Permission denied to access property 'Meteor'
parent.Meteor.register(this);

AAARRRGGGGHHH!

I’ve fallen foul of the XSS that we were trying to prevent.

But, hang on a second. Perhaps this is because we’ve configured StatusNet to use HTTPS always. ARGH.

Let’s put the proxy lines into the SSL config for apache (inside the VirtualHost *:443 section):

Ā Ā Ā Ā Ā Ā Ā  ProxyPass /poll.html http://127.0.0.1:4670/poll.html
Ā Ā Ā Ā Ā Ā Ā  ProxyPassReverse /poll.html http://127.0.0.1:4670/poll.html
Ā Ā Ā Ā Ā Ā Ā  ProxyPass /stream.html http://127.0.0.1:4670/stream.html
Ā Ā Ā Ā Ā Ā Ā  ProxyPassReverse /stream.html http://127.0.0.1:4670/stream.html
Ā Ā Ā Ā Ā Ā Ā  ProxyPass /meteor.js http://127.0.0.1:4670/meteor.js
Ā Ā Ā Ā Ā Ā Ā  ProxyPassReverse /meteor.js http://127.0.0.1:4670/meteor.js
Ā Ā Ā Ā Ā Ā Ā  ProxyPass /push/ http://127.0.0.1:4670/push/
Ā Ā Ā Ā Ā Ā Ā  ProxyPassReverse /push/ http://127.0.0.1:4670/push/

Edit the meteor.js file (from /usr/local/meteor/public_html/meteor.js) and changing all http:// to https:// and port==80 to port=443, then amending the StatusNet’s config.php to show:

addPlugin('Meteor', array(
Ā Ā Ā  'webserver' => 'jon.sprig.gs',
Ā Ā Ā  'webport' => 443,
Ā Ā Ā  'channelbase' => 'statusnet',
Ā Ā Ā  'controlserver' => '127.0.0.1',
Ā Ā Ā  'controlport' => '4671',
Ā Ā Ā  'protocol' => 'https'
));

OK, that’s looking a lot healthier. Oh, no it isn’t – now, my poll.html requests are going to http://jon.sprig.gs:443/poll.html ARGH.

I’m very confused now.

I’ve commented out the Meteor and realtime plugins while I try to figure it all out :(

Installing MOTP-AS under Ubuntu 11.10

Please note, I am having issues with localhost authentication. See below

MOTP-AS is a simple installable two-factor authentication system using the mOTP algorythm for generating one-time passwords. MOTP-AS integrates with FreeRadius to provide the same authentication to log in to managed servers in a consistent manner.

I’ve recently installed this on my Ubuntu 11.10 laptop and on my Ubuntu 12.04 Beta server, and the installation instructions worked on both, so I thought I’d share them with you.

Installing appropriate packages

sudo apt-get install libpam-radius-auth freeradius mysql-server phpmyadmin

Alternatively, use tasksel to install the LAMP server task, then

sudo apt-get install libpam-radius-auth freeradius

Download the latest version of motp-as from http://motp-as.network-cube.de/index.php/download/current-version

Unpack it.

tar xfz ~/Downloads/motp-as*

Setting up the database

Go into the Setup/MySQL directory of the MOTP-AS directory. Edit motp_schema.sql at the line “CREATE USER”. Change the password from motp to something more secure.

mysql -u root -p < motp_schema.sql

Now update Setup/config.php with the new password you just created.

Setting up the web site

Copy the HTML directory to /var/www/motp (or somewhere else in your web root). You may need to do this either as root, or as a user with permissions to write to /var/www

cp -Rf ~/MOTP-AS_*/HTML /var/www/motp

Note this must be done after you’ve made your changes to Setup/config.php

Setting up FreeRadius

Stop the FreeRadius service

sudo /etc/init.d/freeradius stop

Users

Backup the users file

sudo mv /etc/freeradius/users /etc/freeradius/users.dist

Edit the users file you’re about to copy in

nano ~/MOTP-AS_*/Setup/Freeradius/users

Find the part where it says “/var/www/htdocs/radius-auth.php” and change that to “/var/www/motp/radius-auth.php

Copy in the new users file

sudo cp ~/MOTP-AS_*/Setup/Freeradius/users /etc/freeradius/users

Dynamic Clients

Backup the dynamic-clients file

sudo mv /etc/freeradius/sites-available/dynamic-clients /etc/freeradius/sites-available/dynamic-clients.dist

Edit the new dynamic-clients file

nano ~/MOTP-AS_*/Setup/Freeradius/dynamic-clients

Find the three lines saying “/var/www/htdocs” and replace that string with “/var/www/motp” (I use Ctrl+W, Ctrl+R in nano to do a replace-all.)

Copy in the new dynamic-clients file

sudo cp ~/MOTP-AS_*/Setup/Freeradius/dynamic-clients /etc/freeradius/sites-available/dynamic-clients

Then make that function available

sudo ln -s /etc/freeradius/sites-available/dynamic-clients /etc/freeradius/sites-enabled/dynamic-clients

Accounting

Amend the default script to enable accounting

sudo cp /etc/freeradius/sites-available/default /etc/freeradius/sites-available/default.dist

Then edit it to use the MOTP accounting functions

sudo nano /etc/freeradius/sites-available/default

Search for the line “accounting {” then comment that whole block out with the hash/pound sign “#“. Fortunately in the distribution supplied default file, this only means commenting out a few lines, which are “detail“, “unix“, “radutmp“, “exec“, “attr_filter.accounting_response“, and then the closing “}” for that block.

If you’re using nano, press the insert key (or Ctrl+R if you can’t find that easily) and enter /home/MyUserName/MOTP-AS_v0.7.2/Setup/Freeradius/accounting (amend the path as appropriate). Replace the section “/var/www/htdocs” with “/var/www/motp“.

Save and exit

Finishing off FreeRadius

sudo /etc/init.d/freeradius start

Install your client

Personally, I have an Android device, and I chose to install the Mobile-OTP app from the Android Marketplace. I also, through work, have a Nokia 6303i Classic, on which I installed the MOTP application from the MOTP site.

I’ve heard good things about iOTP for iPhone, although I personally don’t have one.

Configuring MOTP

Go to http://localhost/motp (or https://yourdomain.com/motp)

Login with the username admin and password of motp.

Securing the admin account

Click on the red text in “First time configuration

Click on “Change password of User ‘admin’

Enter a new password. Do not set the time or uses section of this page. Click “Set“. Ignore the warning.

Click on “Home

Setting up your first user

Click on “Quick Add” (under “Wizards”)

Enter a username. It should be the username for your Ubuntu 11.10 device.

On the client, create a profile for the device. Most of them create a profile by asking for a seed, rather than a secret, so those will likely be more than 16 characters long – maybe even 20 (Mobile-OTP for Android) or 25 (MOTP Java app).

Once you’ve got your secret (on Mobile-OTP, by pushing-and-holding on the profile name and selecting “Show Secret“, on MOTP Java app, once you’ve put 0000 as the PIN for the first time to initialize it, you get a string “Init-Secret:“), put that into the “Secret” field, and then ask the user to set their pin here – I suggest 1234 initially, as the user can change it to something they want after.

Click OK, then click “Logout” and test authentication. If it all goes OK, they should be presented with “Welcome to the Mobile OTP Authentication Server“.

Under “Settings” they can change their own PIN.

Testing radius authentication works OK

Run the radius testing program, like this, as a user:

radtest username passcode localhost 0 testing123

(This assumes the default localhost password hasn’t changed)

If you get anything like “rad_recv: Access-Reject packet from host“, then you’ve failed to configure something properly, or you’ve entered the PIN or code wrong.

Restart FreeRadius in debugging mode by doing the following:

/etc/init.d/freeradius stop
/usr/sbin/freeradius -X

This will produce a large quantity of logs on-screen, so I’d suggest running the test itself from a separate window. Run the radtest command (listed above) again. Look for your error messages. In my case, I forgot to update the line in users, so I saw this error message: Could not open input file: /var/www/htdocs/radius-auth.php

To find where this fault was, I did (as root, in /etc/freeradius)

find -R 'htdocs' /etc/freeradius

And got back:ƂĀ users: Exec-Program-Wait = “/usr/bin/php /var/www/htdocs/radius-auth.php %{User-Name} %{User-Password} %{Client-Shortname}”

That told me the fault was in the users file.

Fix the issue, check it again, and when you get this message “rad_recv: Access-Accept packet from host” press Ctrl+C to cancel the test mode of FreeRadius, and then run:

sudo /etc/init.d/freeradius start

Configuring pam_radius_auth.conf

Edit /etc/pam_radius_auth.conf

sudo nano /etc/pam_radius_auth.conf

Find the line which says “127.0.0.1” and replace the shared secret with something you want your server to use. You will also need to amend /etc/freeradius/clients.conf and replace the “secret” in the localhost client there (by default, it’s “testing123” in freeradius).

If you want to use your OTP for all authentication credentials, edit /etc/pam.d/common-auth, or if you just want to use it with specific access protocols, edit the relevant file in /etc/pam.d for the authentication systems you want to use OTP for.

You need to add the following line – either on the line before “@include common-auth” (for non common-auth files) or after the primary comment block for common-auth.

auth sufficient pam_radius_auth.so

Open a separate terminal session to your box (especially! if you’re remote) and ensure you can still login with your regular credentials.

Then try a connection with your radius credentials. It should just work! If not, stop the freeradius server and re-run it using /usr/sbin/freeradius -X and see whether you’re getting a different error message.

** UPDATE **

I have noticed that I’m getting locked out when using my non-radius credentials. This is probably due to the placement of the line in the /etc/pam.d/common-auth – it should probably come after the pam_unix.so line, but I’ve not tested that yet. I’m also going to try to suggest that there be an optional time-out period on locked accounts to the developers of MOTP-AS.

The second issue I’m struggling with is that I’m getting errors when using the LightDM. I’m getting the following error message in /var/log/auth.log:

pam_succeed_if(lightdm:auth): requirement "user ingroup nopasswdlogin" not met by user "spriggsj"

I don’t know if this is because I’m using ecryptfs as well, or because there’s something wonky going on with the common-auth structure I’m using.

Using Amazon an EC2 instance as an off-site CronJob

I run the CCHits.net website, and part of the day-to-day tasks that running the site entailed was the daily show creation which involved creating some text-to-speech audio for insertion into the podcasts. As I run the website on shared hosting, to which I didn’t have full access to the OS, I couldn’t just install Festival on the platform, and for whatever reason (I never did figure out what went wrong), I couldn’t build Festival to run on the shared host either.

Until “The Big Rewrite” (the capitals are totally worth it), I’d been doing the text-to-speech on my home server, but frankly, I’m on DSL, which meant I needed to set up Dynamic DNS, I had to be sure the server was always up (and it wasn’t!), etc, etc, etc. While I was looking into why I couldn’t get Festival to build, someone said “Well, why not just use EC2 to do it”.

After nearly a year of faffing about trying to make the …….. stupid thing work (as is testified by the draft in this very blog called “How I built my Audio Stack for CCHits”), I finally decided to spin up an EC2 instance for just this one task.

Now, I’m not the greenest guy on the block – hell, I drive 45 minutes into work each day, but I figured, why keep an EC2 instance running all the time, when I only need it for less than 20 minutes each day, so I did some reading, and found a post on making EC2 do the hard work for you, using the scalable computing APIs, but frankly, all I actually needed was the code to make it spin up, run the task and shut down again, especially as with using his methods, I’d have needed to either create an AMI image, or download the festival voice files each time… at around 100Mb. Not good. I ended up using the stuff I did know (bash scripting, cron tasks) and ditching the stuff I didn’t (AMI files, scalable computing API). I may revisit this later to do it the way he said instead. We’ll see :)

So, here’s the crack.

Create your EC2 image. It doesn’t need to do anything fancy yet – just boot up and keep running. You’ll do some tweaks later. Make a note of the instance number – it’ll probably start i- and then 8 or so hexedecimal digits, like this: i-12345678.

On your shared web host, download the EC2 API tools. According to this page, the API tools are available from here. The first link of those two is unlikely to change for a while, the second, maybe more so. You’ll need to make sure you have Java installed on that web host.

Once you’ve got the tools, you’ll need to create an X.509 certificate and key pair. See this page to find instructions. It was pretty straightforward.

So, you now have in, let’s say for sake of argument, your home directory:

  • /home/user/ec2-api-tools-x.x.x.x # The directory containing all the EC2 API tools
  • /home/user/ec2-keys/pk-{32[A-Za-z1-0]}.pem
  • /home/user/ec2-keys/cert-{32[A-Za-z1-0]}.pem

Also, you have java in /usr/bin/java.

Create the following script also in /home/user/ec2-api-tools-x.x.x.x – I called it ec2-wrapper.

#!/bin/bash
export EC2_HOME=/home/user/ec2-api-tools-x.x.x.x
export JAVA_HOME=/usr
export EC2_KEY=/home/user/ec2-keys/pk-{32[A-Za-z1-0]}.pem
export EC2_CERT=/home/user/ec2-keys/cert-{32[A-Za-z1-0]}.pem
${EC2_HOME}/bin/$* -K ${EC2_KEY} -C ${EC2_CERT

Obviously, you should change your paths to match what you have. What this script does is to add the X.509 certs to every EC2 request, plus adds the appropriate java and EC2_HOME paths to the script before running it.

I set up a CRON job (using crontab -e) to schedule the regular startup of the instance. Here’s the entry from my crontab:

#M   H  DoM Mth DoW  Command (Regular Crontab columns)
30   1ƂĀ Ć‚Ā  *ƂĀ Ć‚Ā  *ƂĀ Ć‚Ā  *ƂĀ Ć‚Ā  /home/user/ec2-api-tools-x.x.x.x/ec2-wrapper ec2-start-instances i-12345678
30ƂĀ Ć‚Ā  2ƂĀ Ć‚Ā  *ƂĀ Ć‚Ā  *ƂĀ Ć‚Ā  *ƂĀ Ć‚Ā  /home/user/ec2-api-tools-x.x.x.x/ec2-wrapper ec2-stop-instances i-12345678

So, this runs the start task at 30 minutes past 1am, local server time, and the stop task at 30 minutes past 2am. The second one there is just to be on the safe side, as we’ll try to shut down the box once it’s finished processing anyway. This way, the maximum time you’ll be billed for is 1 hour of time each day.

I then logged into my EC2 machine, and created, then tweaked the script from the earlier blog post (the scalable computing one).

#!/bin/bash -x
exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1
#
# This code is licensed under an Apache License - for the original 
# code and license, please see the footer of this script.
#
# !!!IMPORTANT!!!
# Edit this file and change this next line to your own email address:
#

EMAIL=user@example.com

# Get some information about the running instance
instance_id=$(wget -qO- instance-data/latest/meta-data/instance-id)
public_hostname=$(wget -qO- instance-data/latest/meta-data/public-hostname)

# Wait 5 minutes in case we want to get in to stop this from doing stuff
Sleep 300

if [ -f /home/ubuntu/donotrun ]
then
  exit 0
fi

# Send status email
/usr/sbin/sendmail -oi -t -f $EMAIL <<EOM
From: $EMAIL
To: $EMAIL
Subject: Running EC2 Scripts

== Making sure everything is up to date ==

`cd /home/ubuntu/website-rewrite && su -c "git pull" ubuntu 2>&1`

== Running the scheduled task ==

`php /home/ubuntu/website-rewrite/scheduled_task.php`

== Notes ==

This email was generated on the EC2 instance: $instance_id

If the instance is still running, you can monitor the output of this
job using a command like:

ƂĀ  ssh ubuntu@$public_hostname tail -1000f /var/log/user-data.log

EOM

# Give the email some time to be queued and delivered
sleep 300 # 5 minutes

if [ -f /home/ubuntu/shutdownwhendone ]
then
  shutdown -h now
fi

exit 0

########################################################################
# For more information about the original version of this code see:
#ƂĀ Ć‚Ā  http://alestic.com/2011/11/ec2-schedule-instance
# The original code and its license are available on github:
#ƂĀ Ć‚Ā  https://github.com/alestic/demo-ec2-schedule-instance
########################################################################

So, with that, I get a script which runs on schedule, on an EC2 platform, I get a confirmation e-mail it’s running. It shuts itself down, and hopefully, keeps on trucking :)

SOPA

So, today was the “great blackout”.

I have to be honest, although I participated in the blackout [1], I’ve not really been much impacted by the blackout today. I tried to access wikipedia a couple of times, and drew a blank, well… ish. I tried to follow up a link to a profile on identi.ca, and got a black page. I tried to get a link to a podcast I listen to, and got a redirect to another site.

So, how do I feel it went? As a guy who lives in the UK, I think it was really interesting. I saw more comments about the loss of Wikipedia than I did about SOPA, I saw that the BBC did a news story on Wikipedia being down, and I had a really hard time explaining why it was an issue to my wife (to be fair she said “you always go into a long rambling explanation, why don’t you just summarize it in a sentence for me” – I said “It’ll might take down the blog site you spend a lot of time reading”, and she said “Oh, OK”).

I saw a lot of people posted a link to The Oatmeal’s SOPA blackout comic. I’d link to it, but it’s not exactly work safe, and you might be browsing this site, and don’t want to see a koala making sweet love to a donkey, or Oprah and Jesus on a jetski in space! Er, so anyway.

I don’t know. I hope it had much more of an impact in the US, but I think really, most people would have been going “WTF? Wikipedia is down… now how are we going to find out what the 23rd episode of the Transformers TV series was about” than about anything to actually do with SOPA, and I think people who did take an interest are going to be more like my wife (“how is this actually *really* going to impact me looking at lolcats” – not actual quote) than me (“OMG, The stinking AMERICAN GOVERNMENT are going to take down my podcast, my blog and all my code” – nearly actual quote).

[1] CCHits.net had a redirect on the main page to http://sopastrike.com/, and the daily exposure show was just Doris (actually the Festival voice “cmu_us_clb_arctic_clunits”) saying some stuff I programmed into her. The nearly-actual quote above was actually something like “This law, if enacted could take down not just cchits.net, but my personal blog, open source code I have written, my e-mail server, my authentication systems, and this is just my content. I use a shared web server, and every other customer on the same server could also be affected if any single user posts material they do not own the copyright to. Simply put, the law the American government wants to enact would destroy everything that is good about the internet.” There was more than that, but like my wife said, I waffle a lot. Sorry. See, I’m doing it again. BAH!

Transfer my files using SFTP and SCP only?

A colleague today asked for some guidance around setting up an SFTP and SCP only account on a RedHat based Linux machine.

I sent him a collection of links, including one to the CopSSH project, and he implemented the code on that link, but then struggled when it didn’t work.

Aside from the fact the shell wasn’t copied into /etc/shells (which wasn’t disastrous, but did mean we couldn’t reuse it again later), it was still returning an error on each load.

Doing some digging into it, and running some debugging, I noticed that pscp (the PuTTY SCP) tool uses the SFTP subsystem rather than the SCP command to upload files, so we need to also check that the SFTP server hasn’t been called, instead of the SCP command, and also the SCP command needs to be corrected.

Here follows a script, complete with comments. Personally, I’d save this in /bin/sftponly, created and owned by root, and set to permissions 755 (rwxr-xr-x). Then, set the shell to this for each user which needs to do SFTP or SCP only.

#!/bin/bash
# Based on code from http://www.itefix.no/i2/node/12366
# Amended by Jon Spriggs (jon@sprig.gs)
# Last update at 2011-09-16

# Push the whole received command into a variable
tests=`echo $*`

# Set up a state handler as false
isvalid=0

# Test for the SFTP handler.
# The 0:36 values are the start character and length of the handler string.
if [ "${tests:0:36}" == "-c /usr/libexec/openssh/sftp-server" ]; then
  # Set the state handler to true
  isvalid=1
  # Configure the handling service
  use=/usr/libexec/openssh/sftp-server
fi

# Test for the SCP handler.
if [ "${tests:0:6}" == "-c scp" ]; then
  # Set the state handler to true
  isvalid=1
  # Configure the handling service
  use=/usr/bin/scp
fi

# If the state handler is set to false (0), exit with an error message.
if [ "$isvalid" == "0" ]; then
  echo "SCP only!"
  exit 1
fi

# Run the handler
exec $use $*

Quick Fix for Apache CVE-2011-3192 – Ubuntu/Debian

Please note – Apache have released a fix to this issue, and as such the below guidance has now been superseded by their fix.

I have been aware of the Apache web server issue for the last few days, where an overly wide range is requested from the server, leading to a crash in the server. As a patch hasn’t yet been released by Apache, people are coding their own solutions, and one such solution was found at edwiget.name.

That fix was for CentOS based Linux distributions, so this re-write covers how to do the same fix under Debian based distributions.
Read More

Getting my head around coding Object Orientated PHP

I’ve been writing two open source projects over the last couple of years. My code has never really been particularly great, but I’ve been trying to learn how to improve my code and over the last few months, I’ve been really trying to polish up my coding skills.

A few months back, I attended a series of fantastic sessions at PHPNW about using Unit Testing, PHP CodeSniffer and phpDocumentor, and how these can be incorporated into Object Orientated code (or in fact, requiring Object Orientated code to implement them).

So, I went back into my main projects and started to look at how I could fix the code to start adopting these tools.

So, the first thing I needed to do was to start thinking about the structure. CCHits.net (which is the “big project” I’ve been working on recently) has several chunks of data, and these are:

User
Track
Artist
Show
ShowTrack
Vote
Chart

Each of these have been broken down into three “things” – The Object itself, a “Broker” which finds all the relevant objects, and a class to create new items, so let’s start with a user class. We’ll define a few properties in the initial class creation.

class UserObject
{
    protected $intUserID = 0;
    protected $strOpenID = "";
    protected $strCookieID = "";
    protected $sha1Pass = "";
    protected $isAuthorized = 0;
    protected $isUploader = 0;
    protected $isAdmin = 0;
    protected $datLastSeen = "";
}

By setting these as protected, it stops me from directly setting or accessing these variables from outside of the class – instead I want to do it from a function, so let’s add those in (I’ll just do one – assume these will be copied on to the rest of the values).

class UserObject
{
    protected $strOpenID = "";

    function set_strOpenID($strOpenID = "") {
        if ($strOpenID != $this->strOpenID) {
            $this->strOpenID = $strOpenID;
        }
    }

    function get_strOpenID() {
        return $this->strOpenID;
    }
}

In the set_ functions, we already do a little bit of error checking here (is the value already set to this?) but we could add other things like, on the integer items, is it actually an integer, with the boolean values ($is[SOMETHING]), make sure it’s set to 1 or 0 (or true/false).

Now, let’s add some documentation to this:

/**
 * CCHits.net is a website designed to promote Creative Commons Music,
 * the artists who produce it and anyone or anywhere that plays it.
 * These files are used to generate the site.
 *
 * PHP version 5
 *
 * @category Default
 * @package  CCHitsClass
 * @author   Jon Spriggs 
 * @license  http://www.gnu.org/licenses/agpl.html AGPLv3
 * @link     http://cchits.net Actual web service
 * @link     http://code.cchits.net Developers Web Site
 * @link     http://gitorious.net/cchits-net Version Control Service
 */
/**
 * This class deals with user objects
 *
 * @category Default
 * @package  Objects
 * @author   Jon Spriggs 
 * @license  http://www.gnu.org/licenses/agpl.html AGPLv3
 * @link     http://cchits.net Actual web service
 * @link     http://code.cchits.net Developers Web Site
 * @link     http://gitorious.net/cchits-net Version Control Service
 */
class UserObject
{
    /**
     * This is the Setter function for the strOpenID value
     *
     * @param string $strOpenID The value to set
     *
     * @return void There is no response from this function
     */
    function set_strOpenID($strOpenID = "") {
        // Do stuff
    }
}

So, let’s make it do stuff with the database. Firstly, we need to set up a connection to the database. I’ll be using PDO (PHP Database Object, I think) to set up the connection (I’ll show why in a minute).

So, here’s another class – Database, this time it’s using a singleton factory (which is to say, while it may exist many times in the code, it’ll only ever have one connection open at once) – note it’s got hard-coded authentication details here – this isn’t how it actually is in my code, but this way it’s a bit more understandable!

class Database
{
    protected static $handler = null;
    protected $db = null;

    /**
     * This function creates or returns an instance of this class.
     *
     * @return object $handler The Handler object
     */
    private static function getHandler()
    {
        if (self::$handler == null) {
            self::$handler = new self();
        }
        return self::$handler;
    }

    /**
     * This creates or returns the database object - depending on RO/RW requirements.
     *
     * @return object A PDO instance for the query.
     */
    public function getConnection()
    {
        $self = self::getHandler();
        try {
            $self->rw_db = new PDO('mysql:host=localhost;dbname=cchits', 'cchits', 'cchits', array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
            return $self->rw_db;
        } catch (Exception $e) {
            echo "Error connecting: " . $e->getMessage();
            die();
        }
    }
}

So, now let’s create yet another class, called GenericObject. This will be re-used in all of the “Object” classes to perform our main database calls. Try to move as much code up to your highest level objects – so you could have a “validateBoolean($value)” function that is used any time you set or get a boolean value here… we even mentioned something like this above!

class GenericObject
{
    protected $arrDBItems = array();
    protected $strDBTable = "";
    protected $strDBKeyCol = "";
    protected $arrChanges = array();

    /**
     * Commit any changes to the database
     *
     * @return boolean Status of the write action
     */
    function write()
    {
        if (count($this->arrChanges) > 0) {
            $sql = '';
            $strDBKeyCol = $this->strDBKeyCol;
            $values[$strDBKeyCol] = $this->$strDBKeyCol;
            $values = array();
            foreach ($this->arrChanges as $change) {
                if ($sql != '') {
                    $sql .= ", ";
                }
                if (isset($this->arrDBItems[$change])) {
                    $sql .= "$change = :$change";
                    $values[$change] = $this->$change;
                }
            }
            $full_sql = "UPDATE {$this->strDBTable} SET $sql WHERE {$this->strDBKeyCol} = :{$this->strDBKeyCol}";
            try {
                $db = Database::getConnection();
                $query = $db->prepare($full_sql);
                $query->execute($values);
                return true;
            } catch(Exception $e) {
                return false;
            }
        }
    }

    /**
     * Create the object
     *
     * @return boolean status of the create operation
     */
    protected function create()
    {
        $keys = '';
        $key_place = '';
        foreach ($this->arrDBItems as $field_name=>$dummy) {
            if ($keys != '') {
                $keys .= ', ';
                $key_place .= ', ';
            }
            $keys .= $field_name;
            $key_place .= ":$field_name";
            $values[$field_name] = $this->$field_name;
        }
        $full_sql = "INSERT INTO {$this->strDBTable} ($keys) VALUES ($key_place)";
        try {
            $db = Database::getConnection();
            $query = $db->prepare($full_sql);
            $query->execute($values);
            if ($this->strDBKeyCol != '') {
                $key = $this->strDBKeyCol;
                $this->$key = $query->lastInsertId();
            }
            return true;
        } catch(Exception $e) {
            return false;
        }
    }

    /**
     * Return an array of the collected or created data.
     *
     * @return array A mixed array of these items
     */
    function getSelf()
    {
        if ($this->strDBKeyCol != '') {
            $key = $this->strDBKeyCol;
            $return[$key] = $this->$key;
        }
        foreach ($this->arrDBItems as $key=>$dummy) {
            $return[$key] = $this->$key;
        }
        return $return;
    }
}

Any protected functions or variables are only accessible to the class itself or classes which have been extended from it (referred to as a child class). We need to make some changes to our UserObject to make use of these new functions:

class UserObject extends GenericObject
{
    // Inherited Properties
    protected $arrDBItems = array(
        'strOpenID'=>true,
        'strCookieID'=>true,
        'sha1Pass'=>true,
        'isAuthorized'=>true,
        'isUploader'=>true,
        'isAdmin'=>true,
        'datLastSeen'=>true
    );
    protected $strDBTable = "users";
    protected $strDBKeyCol = "intUserID";
    // Local Properties
    protected $intUserID = 0;
    protected $strOpenID = "";
    protected $strCookieID = "";
    protected $sha1Pass = "";
    protected $isAuthorized = 0;
    protected $isUploader = 0;
    protected $isAdmin = 0;
    protected $datLastSeen = "";

    function set_strOpenID($strOpenID = "") {
        if ($this->strOpenID != $strOpenID) {
            $this->strOpenID = $strOpenID;
            $this->arrChanges[] = 'strOpenID';
        }
    }
}

Notice I’ve stripped the “phpDoc” style comments from this re-iteration to save some space! In the real code, they still exist.

Now we have an object we can work with, let’s extend it further. It’s probably not best practice, but I find it much more convenient to create new objects by extending the UserObject into a new class called NewUserObject. Notice once we’ve set our database items, we run the create(); function, which was previously defined in the GenericObject class.

class NewUserObject extends UserObject
{
    public function __construct($data = "")
    {
        if (strpos($data, "http://") !== false or strpos($data, "https://") !== false) {
            $this->set_strOpenID($data);
        } elseif ($data != "") {
            $this->set_sha1Pass($data);
        } else {
            if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
                $cookie_string = $_SERVER['HTTP_X_FORWARDED_FOR'];
            } else {
                $cookie_string = $_SERVER['REMOTE_ADDR'];
            }
            $cookie_string .= $_SERVER['HTTP_USER_AGENT'];
            $cookie_string .= $_SERVER['HTTP_ACCEPT_LANGUAGE'];
            $cookie_string .= $_SERVER['HTTP_ACCEPT_ENCODING'];
            $cookie_string .= $_SERVER['HTTP_ACCEPT_CHARSET'];
            $this->set_strCookieID(sha1sum($cookie_string));
        }
        $this->datLastSeen = date("Y-m-d H:i:s");
        $_SESSION['cookie'] = sha1($cookie_string);
        return $this->create();
    }
}

Using the code $user = new NewUserObject($login_string); we can create a new user, but how about retrieving it.

This is where the reason I’m loving PDO comes into play. See, before PDO, when you did a database request, you might have had something like this:

$db = mysql_connect("localhost", "root", "");
if ($db == false) {
    die ("Failed to connect to the Database Server");
}
if (! mysql_select_db("database")) {
    die ("Failed to select the database");
}
$intUserID = mysql_real_escape_string($_GET['intUserID']);
$sql = "SELECT * FROM users WHERE intUserID = '$intUserID' LIMIT 1";
$qry = mysql_query($sql);
if (mysql_errno() > 0) {
    echo "Failed to make Database Call: " . mysql_error();
} else {
    if (mysql_num_rows($qry) == 0) {
        echo "Failed to retrieve record 1";
    } else {
        $row = mysql_fetch_array($qry);
    }
}

Now, let’s assume you’re looking for a few users? You need to do more of those mysql_real_escape_strings and mysql_num_rows() and mysql_fetch_array()s to get your data out – it’s far from clean and clear code.

How about this instead?

try {
    $db = Database::getConnection();
    $sql = "SELECT * FROM users WHERE intUserID = ? LIMIT 1";
    $query = $db->prepare($sql);
    $query->execute(array($_GET['intUserID']));
    $row = $query->fetch();
} catch(Exception $e) {
    echo $e;
    $row = false;
}

The most complicated bit here is that you’re having to prepare your SQL query and then tell it what to get. The reason we do that is that PDO will automatically ensure that anything being passed to it using the ? is sanitized before passing it into the query. If you look back at the GenericObject class we created earlier, it uses something like this there too, except there (if you work out what it’s doing) it prepares something like INSERT INTO users (intUserID) VALUES (:intUserID); and then executes it with the values like this: array(‘:intUserID’=>1) and with this you can have some very complex statements. Other code you might spot while mooching through CCHits (if you decide to) looks like this:

$sql = "UPDATE IGNORE votes SET intTrackID = ? WHERE intTrackID = ?; DELETE FROM votes WHERE intTrackID = ?";
$query = $db->prepare($sql);
$query->execute(array($intNewTrackID, $intOldTrackID, $intOldTrackID));

By wrapping it all up in a try/catch block, you can get your error dumped in one place, including a stack trace (showing where the issue turned up). You don’t need to check for mysql_num_rows – if the row doesn’t exist, it’ll just return a false. Sweet.

Where it gets REALLY nice, is that if you swap $row = $query->fetch() with $object = $query->fetchObject(‘UserObject’); and it’ll create the object for you!

So, now, with the function getUser (visible at https://gitorious.org/cchits-net/website-rewrite/blobs/master/CLASSES/class_UserBroker.php) it’ll try to return a UserObject based on whether they’re using OpenID, Username/Password or just browsing with a cookie… and if it can’t, it’ll create you a new user (based on the above criteria) and then return you that UserObject.

The last thing to add, is that I wrapped up all the nice phpDocumentor, PHP CodeSniffer functions, plus wrote a script to check for missing or incorrectly labelled functions across a suite of classes. These sit in https://gitorious.org/cchits-net/website-rewrite/trees/master/TESTS if you want to take a look around :)

EDIT 2011-08-25: Correcting some errors in the code, and to adjust formatting slightly.
EDIT 2012-05-05: Changed category, removed the duplicated title in the top line, removed some whitespace.

VNC in Ubuntu 11.04 with Unity

I recently bought myself a new laptop. Sometimes though, I want to check something on it on a rare occasion when I’ve not taken it with me. In comes VNC. Under Ubuntu 11.04, turning on VNC support is pretty straight forward.

To turn on VNC, go to the power icon in the top right corner (I think they call it the “Session Menu”, but it looks like a power button to me) and select “System Settings”. Under the “Internet and Network” heading, is an option called “Remote Desktop”. Click on that. Tick the top two boxes “Allow other users to view your desktop” and “Allow other users to control your desktop”. Tick the box “Require the user to enter this password” (and enter a password) and “Configure network automatically to accept connections”. Untick “You must confirm each access to this machine” and select “Only display an icon when there is someone connected”. Close it.

Now, try connecting to your device, and see what happens. I had some issues with Compiz elements not rendering correctly, and found a few hints to fix it. The first says to turn on the “disable_xdamage” option. It says to use gconf-editor, but I’m SSHing in, so I need to use gconftool-2 as follows:

gconftool-2 --set "/desktop/gnome/remote_access/disable_xdamage" --type boolean "true"

Personally, I only want to ever connect over OpenVPN to this, so I added the following:

gconftool-2 --set "/desktop/gnome/remote_access/network_interface" --type string "tun0"

You may wish to only ever access it over SSH, in which case replace “tun0” with “lo”

Now, I next made a big mistake. I followed some duff guidance, and ended up killing my vino server (I’m still not sure if I was supposed to do this or not), but to get it back, I followed this instruction to restart it. I had to tweak it a little:

sudo x11vnc -rfbport 5901 -auth guess

Once you’ve started this, tunnel an extra port (5901) to your machine, start VNC to the tunnelled port, and then go back through the options above. Exit your VNC session to the new tunnelled port, and then hit Control+C on the SSH session to close that x11vnc service.