Stripping a UK O2 Samsung Galaxy SIII Mini down to the bare essentials

The company I work for have recently issued all On Call engineers in my team a Samsung Galaxy SIII Mini to give us access to company e-mail and resources out of hours. Rather than shipping a customized image, we have received a stock O2 imaged mobile, and so this is my limited guide to bringing this to as close to “Stock” Android as I can manage (or want).

Most of what we need is provided to us using a commercial solution called Touchdown, so I won’t be covering that here, as whatever you get shipped to you will not include that. I’ve elected not to use the device for my personal systems, barring my Google calendar, which means I’ll stand a fighting chance of not booking overtime and other work things for personal appointments.

So, on power-on, I completed the post-install steps, including setting up my Google account. I decided not to keep the device in sync with my Google account, as I already have a few other Android devices, and I don’t want to get my work infrastructure mixed up with my home kit.

Next, I went into Settings, and from there into the Google Account. I clicked on my e-mail address and unselected the following options:

  • Sync App Data
  • Sync Contacts
  • Sync Gmail
  • Sync Internet
  • Sync People details

After that, I went into Application Manager (again, in Settings), and swapped to the “All” tab. Firstly, I needed to clear out the downloaded contacts, which I did by selecting Contacts Storage, and then pressing the “Clear Data” button.

Next, I disabled all the applications that I either don’t need, or don’t want on my work phone. I did this by selecting each in turn, and then selecting the option to disable them. Here’s the list:

  • Amazon MP3
  • eBay
  • Flipboard
  • Gallery
  • Game Hub
  • Gmail
  • Google Play Books
  • Google Play Magazines
  • Google Play Music
  • Google+
  • Music
  • O2 Space
  • S Planner
  • S Planner Widget
  • S Suggest
  • S Voice
  • Samsung Account
  • Samsung Apps
  • Samsung Backup Provider
  • Samsung Browser SyncAdapter
  • Samsung Calendar SyncAdapter
  • Samsung Cloud Data Relay
  • Samsung Contact SyncAdapter
  • Samsung Push Service
  • Samsung Syncadapters
  • Tags
  • Talk
  • Talkback
  • Video Hub
  • Yahoo! Finance
  • Yahoo! News
  • YouTube

Wow, isn’t that a list!

My next step was to hide some of the applications I don’t need. To do this, I went into the applications page, pressed the menu button, and selected “Hide applications”. This puts selection boxes next to all the applications on the page, and once you’ve done selecting options, press “Done” in the top right corner to hide them. Here’s my list:

  • Contacts
  • Downloads
  • E-Mail
  • FM Radio
  • Google Settings
  • Help
  • Memo
  • Music Player
  • My Files
  • Video Player
  • Voice Recorder
  • Voice Search

Lastly, installed a couple of applications from the Play Store:

Once I’d got Agenda Widget Plus, and Google Keyboard configured, I hid those applications in the applications pane too.

After all of that, I set up Touchdown… which you’ll need to follow up though your own instructions!

One final thing before I wrap this all up… even though I’m on-call, this doesn’t include being engaged via e-mail. As such, my e-mail doesn’t need to disturb me, and so I’ve disabled the touchdown application’s notifications for e-mail. To do this, go into Touchdown, make sure you’re at the “main” screen (not the default e-mail screen, but the one which also includes all your tasks and calendar options), and then press the menu button, press “Settings”, and select the “Advanced” tab. Scroll right to the bottom of the list, and press the “Email Alerts” button. Select “Customize settings” and then select appropriate options. If you leave nothing ticked, all you’ll get is a flag in the notifications tray showing an e-mail has appeared. Personally, I’ve turned on “Enable lights” and picked a colour, so I can quickly see whether I’ve had a mail just by checking the screen.

Broadcom BCM43228 and recent Linux support

I have an Acer V5-171 laptop, with a BCM43228 802.11a/b/g/n wireless network adaptor. In Ubuntu 12.04 and 12.10, I had absolutely no issues with my wireless connectivity. I upgraded to Ubuntu 13.04, and the wifi device dropped out.

I fixed the wifi by performing the following command (found via this forum post):

sudo apt-get install --reinstall bcmwl-kernel-source

I’d had a few issues with my Ubuntu install – mostly due to tinkering, so I thought I’d give a few other distributions a shot. Unfortunately, the state of the support of this driver was even worse on the others I installed.

Sabayon 13.04 (note, this is from memory!): You need to edit /etc/modprobe.d/blacklist.conf and uncomment the blacklisting of the b43 module. You need to comment the blacklisting of the 5 or so modules above it (mostly to enable the “wl” module). While this brought the NIC up, it didn’t survive an upgrade of packages, and by this point I’d spent about 2 days on it, so I was getting ratty, and wanted to try something else.

Fedora 18: Also didn’t work – I checked this distro because of my issues with Sabayon, but I figured that as it wasn’t working, perhaps there was something fundamental going on – probably either installing a package, or blacklisting a module would have solved this – I won’t know now!

OpenSUSE 12.3: I finally settled on installing OpenSUSE after I’d realised my issues were just with the module and not the distribution. I’d considered running OpenSUSE for some time and thought I’d give it a shot. I found a post (which I’ve subsequently lost) which showed that the package wasn’t installed by default to support this adaptor, so I found this page which listed both the relevant kernel module (in my case the x86_64 12.3 package) and the matching software package. As I was doing the install semi-offline (I can’t tether my phone to the laptop right now, and had no wired access) I transferred the relevant RPMs over, and installed them using rpm (the RedHat/Fedora/OpenSUSE/etc package manager). Wireless came up, but I’m missing certain APs – probably a configuration item that I’ve not yet fixed. It’s not disastrous, but is annoying :)

Building a WPA2 Protected Wireless Access Extender for Jogglers using Ubuntu 12.04

Shesh! What a lot of keywords in the title!

For those who don’t know what some of those key words were, I’ll break down the title

  • Ubuntu is a Linux distribution, and 12.04 is the version number of the latest Long Term Stable version.
  • Joggler is the name of a device sold by O2 a couple of years ago. It is a re-branded OpenPeak tablet.
  • A Wireless Access Extender is a device like a WiFi enabled router, but it uses the same DHCP pool and should use the same SSID name and WPA2 passphrase.
  • WPA2 is the latest incarnation of the WiFi security protocol. It is currently (at this time, as far as I know) uncracked, unlike WPA1 or WEP.

So, now that we know what I’m talking about, let’s look at what components we will be using today.

  • An O2 Joggler. EBay lists them from between £30 and £100. They originally sold for around £100, but got popular when O2 dropped the price to £50. They are no longer available for sale from O2, hence EBay.
  • A wired network connection. I’m using a pair of Ethernet over Power (or “HomePlug”) devices to let me position this device in a useful place in my house. I’ve had a lot of success with the 200M devices sold by 7DayShop.com, but if I were buying new today, I’d probably stretch up to the 500M devices, as they will be Half Duplex (like a narrow street permitting traffic only one way at a time), and will loose some data due to interference and “collisions” – where two devices on the Ethernet over Power “network” are talking at the same time. Ultimately, you won’t get the equivalent to 100M Full Duplex with the 200M devices, but should do with the 500M devices.
  • A USB stick. This needs to be 4Gb or greater, but not all devices are suitable. I bought some 4Gb sticks from 7DayShop.com and found they only actually held around 3.5Gb… making them unsuitable. I bought three 8Gb sticks from 7DayShop.com, but only used one for this task!
  • A Ubuntu 12.04 install. Actually, I used the Xubuntu 12.04 image, because I didn’t need everything that Ubuntu 12.04 gave me. This is a special non-official build of Xubuntu, customised for Joggler hardware and it’s touchscreen, and is what I’ll be moving all my Jogglers in the house to, eventually, however, the principals in making all of this stuff work will apply just as much to Ubuntu as it would Xubuntu – special build or not!
  • Once installed, you’ll use a combination of VNC and SSH to manage your device, these will be through the X11VNC project and OpenSSH-Server. You should have an SSH client (for Linux/Mac, ssh should be fine, for Windows, use PuTTY) and a VNC client (for Ubuntu, I use Remmina, for Windows, I use TightVNC).

So, you’ve got all your goodies, and you’re ready to go. Let’s do this!

  1. Transfer the Xubuntu image to the USB stick. This is a simple task, and is clearly documented on the site where I got the Xubuntu image from, and involves you copying the image directly to the USB stick, not to one of it’s partitions. It sounds complicated, it really isn’t.
  2. Stick the Xubuntu stick into the side of the Joggler. Get used to that shape, as it’s going to be in the side of that from now on. This is because the Linux distribution needs more than the 1Gb that the Joggler holds internally.
  3. Plug in the HomePlug device – make it as close to the wall as you can make it! I’ve had experience of it being three 4way plug strips away from the wall and it worked fine, but I’ve also had the same HomePlug only one 4way away, and it’s completely failed to work, and had to juggle all my sockets to get it plugged directly into the wall. I think it may be down to the number of “noisy” plugs in the same 4way, but I can’t be sure. Just experiment!
  4. Plug your Ethernet cable between the HomePlug and the Joggler.
  5. Power on the Joggler. It will start up with an O2 logo (or possibly an “OpenPeak” logo – depends on when the device was manufactured)  – sometimes either of these may corrupt or show with a big white block as it’s booting. Don’t worry too much about this, we’ll stay away from the boot screen as much as possible! :)
  6. Once you get to a blue screen with icons on it – this is Xubuntu (well, actually XFCE4, but the semantics are moot really). Click on the blue spot in the top left corner of the screen – it may be a little fiddly – and select Ubuntu Software Centre.
  7. Open the “Florence” keyboard – found by pressing the small grid icon near the clock in the top right corner of the screen. If you struggle with this keyboard (I did), you may find it easier to use the “OnBoard” keyboard, found through the applications menu (again, via the blue button in the top corner).
  8. Select the Search box in the Software Centre and search for OpenSSH-Server. Click on the only entry which comes back (you need to search for the exact term) and then click install. While that’s installing, click on the two arrows icon in the top right corner, and select Connection Information. Make a note of the IP address you have received. Once it’s finished installing you can move away to something a little more comfortable to work on your Joggler!
  9. SSH to your Joggler’s IP address – the username for the device is “joggler” and the password is also “joggler”. All of the following you’ll need to be root for. I always use the following line to become root:
    sudo su -
  10. The wireless driver that is installed by default on the Jogglers don’t support “Master” mode – the mode you need to be a wifi access point or extender, so you’ll need to change the wireless driver. Thanks to this post, we know that you edit the file /etc/modprobe.d/joggler.conf and move the comment symbol (#) from before the line blacklist rt2870sta to the line blacklist rt2800usb. It should look like this after you’re done:
    # blacklist rt2800usb
    blacklist rt2870sta
  11. We need to bridge the wlan0 and eth0 interfaces.
    1. Install bridge-utils using apt-get install.
    2. Now we’ll start to configure the bridge. Edit /etc/network/interfaces to create your bridge interfaces.
      auto lo
      iface lo inet loopback
      
      auto eth0
      iface eth0 inet manual
      
      auto wlan0
      iface wlan0 inet manual
          pre-up service hostapd start
          post-up brctl addif br0 wlan0
      
      auto br0
      iface br0 inet dhcp
          bridge_ports eth0 wlan0
          pre-up iptables-restore -c < /etc/iptables.rules
          post-down iptables-save -c > /etc/iptables.rules

      If you want to use a static IP address instead of a DHCP one, then change the last block (auto br0; iface br0 inet dhcp) to the following (this assumes your network is a 192.168.0/24 with .1 as your router to the outside world):

      auto br0
      iface br0 inet static
          bridge_ports eth0 wlan0
          address 192.168.0.2
          broadcast 192.168.0.255
          netmask 255.255.255.0
          gateway 192.168.0.1
    3. Setup /etc/sysctl.conf to permit forwarding of packets. Find, and remove the comment symbol (#) from the line which looks like this:
      # net.ipv4.ip_forward = 1
    4. Create your initial /etc/iptables.rules (this is based on details from this page) and then “restore” them using iptables.
      *filter
      :INPUT ACCEPT [0:0]
      :FORWARD ACCEPT [0:0]
      :OUTPUT ACCEPT [1:81]
      -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
      -A FORWARD -m state --state INVALID -j DROP
      -A FORWARD -i wlan0 -o eth0 -j ACCEPT
      -A FORWARD -i eth0 -o wlan0 -j ACCEPT
      COMMIT
    5. Check the iptables have restored properly by running iptables -L -v which should return the following data:
      # iptables -L -v
      Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
       pkts bytes target     prot opt in     out     source               destination         
      
      Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
       pkts bytes target     prot opt in     out     source               destination
          0     0 ACCEPT     all  --  any    any     anywhere             anywhere             state RELATED,ESTABLISHED
          0     0 DROP       all  --  any    any     anywhere             anywhere             state INVALID
          0     0 ACCEPT     all  --  wlan0  eth0    anywhere             anywhere
          0     0 ACCEPT     all  --  eth0   wlan0   anywhere             anywhere            
      
      Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
       pkts bytes target     prot opt in     out     source               destination
  12. Now you’ve got a bridged interface, and your wifi adaptor is ready to go, let’s get the DHCP relay in and working right.
    1. apt-get install dhcp3-relay
    2. It’ll ask you where to forward the DHCP requests to – that is your current gateway – if you have your network as 192.168.0.0/24 with the gateway as .1, then it should be 192.168.0.1.
    3. Next, it’ll ask which interfaces to listen on – this is br0.
    4. The last screen asks for some options to configure – this is “-m forward” (without the quote marks).
  13. Last thing to do, we need to configure something to listen on the wifi interface to provide the Access Point facility to your device. This is “hostapd”.
    1. apt-get install hostapd
    2. zcat /usr/share/doc/hostapd/examples/hostapd.conf.gz > /etc/hostapd/hostapd.conf
    3. Edit /etc/hostapd/hostapd.conf replacing the following config items:
      FROM: # driver = hostapd
      TO:   driver = nl80211
      FROM: #country_code = US
      TO:   country_code = GB
      FROM: hw_mode = a
      TO:   hw_mode = g
      FROM: channel = 60
      TO:   channel = 12
      FROM: #ieee80211n = 1
      TO:   ieee80211n = 1
      FROM: #wpa = 1
      TO:   wpa = 2
      FROM: #wpa_passphrase=secret passphrase
      TO:   wpa_passphrase=MySecretPassword
      FROM: #wpa_pairwise = TKIP CCMP
      TO:   wpa_pairwise = TKIP CCMP
    4. Edit /etc/default/hostapd amending the DAEMON_CONF line to show /etc/hostapd/hostapd.conf

Reboot, and your access point should come to life! Huzzah!! Initially it’ll have the SSID of “test” (it’s in /etc/hostapd/hostapd.conf as the config line “ssid = test”) but you should probably change it to the same SSID as your main router. If you do that, ensure your WPA passphrase is the same as your main router too, otherwise your network will get very confused!

So, now you’ve got an Access extender, running Ubuntu… what else could you do with it? Well, I run one of two things on all of mine – sqeezeplay or vlc monitoring a webcam. All very useful stuff, and stuff I was doing with it before it was an access extender!

Proxying and using alternate host names with Apache

After spotting this comment on StatusNet saying about using another port on the same IP address for a web service, I thought I’d jot down what I do instead, to ensure I use the standard HTTP and HTTPS ports for my web applications.

In /etc/apache2/sites-available, I create a file called subdomain.your.host.name

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    ServerName subdomain.your.host.name

    ErrorLog ${APACHE_LOG_DIR}/subdomain.your.host.name.error.log

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

    CustomLog ${APACHE_LOG_DIR}/subdomain.your.host.name.access.log combined

    ProxyPass / http://127.0.0.1:12345/
    ProxyPassReverse / http://127.0.0.1:12345/
</VirtualHost>

Configure your non-apache app to bind to a port on 127.0.0.1, here I’ve set it to 12345

This proxies an HTTP only application… but if you want to proxy an HTTPS application, you either need to have a wildcard SSL certificate, use multiple IP addresses, or, as the original post suggested, use an alternate port.

If you’re proxying an application for HTTPS, try this:

<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerAdmin webmaster@localhost
    ServerName subdomain.your.host.name

    ErrorLog ${APACHE_LOG_DIR}/ssl_subdomain.your.host.name.error.log
    LogLevel warn
    CustomLog ${APACHE_LOG_DIR}/ssl_subdomain.your.host.name.access.log combined

    SSLEngine on
    SSLCertificateChainFile /etc/openssl/root.crt
    SSLCertificateFile /etc/openssl/server.crt
    SSLCertificateKeyFile /etc/openssl/server.key

    BrowserMatch "MSIE [2-6]" \
        nokeepalive ssl-unclean-shutdown \
        downgrade-1.0 force-response-1.0
    # MSIE 7 and newer should be able to use keepalive
    BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown

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

Of course, if you’re looking to create several virtual hosts for apache, rather than proxy them, you can instead do this:

<VirtualHost *:80>
    ServerName subdomain.your.host.name
    ServerAdmin webmaster@localhost

    DocumentRoot /var/www_subdomain.your.host.name/
    <Directory />
        Options FollowSymLinks
        AllowOverride None
    </Directory>

    <Directory /var/www_subdomain.your.host.name/>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Order allow,deny
        allow from all
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/subdomain.your.host.name.error.log

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

    CustomLog ${APACHE_LOG_DIR}/subdomain.your.host.name.access.log combined

</VirtualHost>

Once you’ve got your config files up, you’ll need to enable them with the following command:

a2ensite subdomain.your.host.name

That assumes you named the file /etc/apache2/sites-available/subdomain.your.host.name

You may need to enable the proxy module with the command:

a2enmod proxy

Logitech Media Server vs Ubuntu 12.04

A while back I upgraded my home server to Ubuntu 12.04 (while it was still in beta) and immediately the first thing I noticed was that the Logitech Media Server (previously known as Squeezebox Server) had stopped working.

Checking through the logs, I saw a lot of messages about perl dependencies being missing or not working [1]. As I was a bit busy at the time (the decision to upgrade had been due to something else entirely), I put it to one side (much to my wife’s annoyance!) to pick up later.

As I’ve been wallowing at home the past couple of days with a stomach bug, and not really been fit to do much other than moan, lie there and feel sorry about myself, I thought about what I could do to get my squeezebox server back up and running.

A few Google searches later, and I turn up this page: http://forums.slimdevices.com/archive/index.php/t-89057.html which suggests that this message below is due to Ampache… which now that I look at the log entry, it kinda makes sense. Queue digging into the depths of the server.

Under Ubuntu, all the serious configuration for the server is stored in /var/lib/squeezeboxserver, which includes the plugins.

So, firstly, I deleted the downloaded Zip file from /var/lib/squeezeboxserver/cache/DownloadedPlugins/Ampache.zip

rm /var/lib/squeezeboxserver/cache/DownloadedPlugins/Ampache.zip

Next, I removed the unpacked plugin from /var/lib/squeezeboxserver/cache/InstalledPlugins/Ampache

rm -Rf /var/lib/squeezeboxserver/cache/InstalledPlugins/Ampache

I made a mistake here on my box, and restarted the server. Woohoo it came back up, but the first thing it did was to re-download the plugin again! D’oh. So, now I need to find what’s telling it to re-install the plugin. Queue a quick grep. Ahhh, there’s a file called extensions.prefs, which says:

prefs/plugin/extensions.prefs:  Ampache: 1

And another file called state.prefs which says:

prefs/plugin/state.prefs:Ampache: needs-install

Note, these are both the output from grep – so the filename includes the path from the point /var/lib/squeezeboxserver. A quick nano away (or whatever editor you prefer) and I’d removed the line from the extensions.prefs which showed Ampache: 1, but the state.prefs was marginally more tricky. In here it lists them in three states, enabled, disabled and needs-install. So, I changed it to show disabled and then restarted the service. Tada. I’ve got a working Logitech Media Server again! Huzzah!

[1] Log file looks like this:

Slim::bootstrap::tryModuleLoad (285) Warning: Module [Plugins::GrabPlaylist::Plugin] failed to load:
Can't locate Math/VecStat.pm in @INC (@INC contains: /usr/sbin/Plugins/Gallery /var/lib/squeezeboxserver/cache/InstalledPlugins/Plugins/Gallery /var/lib/squeezeboxserver/cache/Installed
Plugins/Plugins/CustomScan/lib /var/lib/squeezeboxserver/cache/InstalledPlugins/Plugins/Ampache/lib CODE(0xb911c40) /var/lib/squeezeboxserver/cache/InstalledPlugins /usr/share/squeezebo
xserver/CPAN/arch/5.14/i386-linux-thread-multi-64int /usr/share/squeezeboxserver/CPAN/arch/5.14/i386-linux-thread-multi-64int/auto /usr/share/squeezeboxserver/CPAN/arch/5.14.2/i686-linu
x-gnu-thread-multi-64int /usr/share/squeezeboxserver/CPAN/arch/5.14.2/i686-linux-gnu-thread-multi-64int/auto /usr/share/squeezeboxserver/CPAN/arch/5.14/i686-linux-gnu-thread-multi-64int
 /usr/share/squeezeboxserver/CPAN/arch/5.14/i686-linux-gnu-thread-multi-64int/auto /usr/share/squeezeboxserver/CPAN/arch/i686-linux-gnu-thread-multi-64int /usr/share/squeezeboxserver/li
b /usr/share/squeezeboxserver/CPAN /usr/share/squeezeboxserver /usr/sbin /etc/perl /usr/local/lib/perl/5.14.2 /usr/local/share/perl/5.14.2 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/
5.14 /usr/share/perl/5.14 /usr/local/lib/site_perl . CODE(0xb911e20)) at Slim/Player/Player.pm line 18.
BEGIN failed--compilation aborted at Slim/Player/Player.pm line 18.
Compilation failed in require at /var/lib/squeezeboxserver/cache/InstalledPlugins/Plugins/GrabPlaylist/Plugin.pm line 22.
BEGIN failed--compilation aborted at /var/lib/squeezeboxserver/cache/InstalledPlugins/Plugins/GrabPlaylist/Plugin.pm line 22.
Compilation failed in require at (eval 924) line 2.
BEGIN failed--compilation aborted at (eval 924) line 2.

Nice, right?

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.

Use GMail’s SMTP gateway using the command line from !Ubuntu without lots of config #tips

I’m writing a few little scripts at the moment, and one of them needed to be able to send an e-mail. I’d not got around to sorting out what my SMTP gateway was from my ISP – but I do tend to use GMail’s SMTP gateway for non-essential stuff.

I thought I could easily setup sendmail, but no, that’s SCARY stuff, and then I thought of Postfix, but that needs an awful lot of configuration for an TLS based SMTP connection, so I did a bit of digging.

Thanks to this post over at the Ubuntu Forums, I worked out how to get a local port 10025 to run, but PHP kept complaining, so I next looked for a “sendmail replacement”, in comes nullmailer.

So, thankfully this is all rather easy.

  • sudo apt-get install openssl xinetd nullmailer
  • sudo tee /usr/bin/gmail-smtp <<EOF >/dev/null#!/bin/sh# Thanks to http://ubuntuforums.org/showthread.php?t=918335 for this install guide/usr/bin/openssl s_client -connect smtp.gmail.com:465 -quiet 2>/dev/nullEOFsudo chmod +x /usr/bin/gmail-smtp
  • sudo tee /etc/xinetd.d/gmail-smtp <<EOF >/dev/null# default: on# description: Gmail SMTP wrapper for clients without SSL support# Thanks to http://ubuntuforums.org/showthread.php?t=918335 for this install guideservice gmail-smtp{    disable         = no    bind            = localhost    port            = 10025    socket_type     = stream    protocol        = tcp    wait            = no    user            = root    server          = /usr/bin/gmail-smtp    type            = unlisted}EOFsudo /etc/init.d/xinetd reload
  • sudo tee /etc/nullmailer/remotes <<EOF >/dev/null127.0.0.1 smtp --port=10025 --user=your@user.tld --pass=Y0urC0mp3xGM@ilP@ssw0rdEOFsudo /etc/init.d/nullmailer reload

Setting all this lot up was pretty easy with these guides. There’s no reason why it wouldn’t work on any other version of Linux (provided you can install all these packages).

Good luck with your project!