Replace Windows XP with a minimal Ubuntu based thin client

At one of my clients there is a preference to keep using equipment as long as it is good enough for the task at hand. This means a lot of older computers running Windows XP, some of them barely chugging along. Due to a lot of legacy software in the business, this is arguably not a problem.Yet.

A slow transition to a Citrix XenApp solution is taking place since a few years ago. Old computers that die of age are replaced with thin clients, mainly HP ones.

Windows XP is due for replacement for real by next year. So I decided to prepare a minimal Linux with Citrix Receiver for the old or otherwise lesser computers. My first client to run this custom installation on was a HP T5740 thin client, with only 2 GB local storage. Ubuntu doesn’t like this very well, since it is less than the minimum required.

I looked at and gave Jackie Chen’s guide based on Tiny Core Linux a shot, but I find the Citrix Receiver openmotif interface offending. And my users are accustomed to the XenApp web interface. What I wanted was a setup with a stripped-down LXDE, Mozilla Firefox and integrated Citrix Receiver. I also wanted to use Ubuntu to stay on the same distribution across servers and desktop.

Starting with the Ubuntu MinimalCD, I chose to select what packages to install. These packages being: libmotif4, lxde-core, lxrandr, xserver-xorg, gdm, firefox and remmina.

GDM because I wanted to use AutomaticLoginEnable in /etc/gdm/custom.conf. libmotif4 because Citrix Receiver depends on it. lxde-core for a minimal desktop with a start menu, and lxrandr to adjust screen resolution. And, of course, Firefox to access the Citrix XenApp web page. I added Remmina for Windows server management.

When all was said and done I came across some awesome work by Tony Brijeski. Remastersys let me easily save the whole setup to a LiveCD. I had an issue with not enough local storage space to perform the “backup” to a Live iso. I solved this by plugging in a 32GB USB stick with an ext4 filesystem on it for remastering storage.

Then I installed the remastered ISO image to a USB stick. Now I have a USB stick that boots straight into Firefox with the client’s Citrix XenApp login as the home page. Citrix Receiver is well integrated with Firefox on Ubuntu, so it all works like a charm.

Finding every email address in your IMAP folder

I recently had the pleasure of extracting every email address in a Dovecot IMAP folder on my Ubuntu server. Bash is killing me with how to escape files from this find:

find . -type d -name cur

I tried everything I found by googling, but I couldn’t get it. I didn’t have only whitespaces, but ampersands and other funny characters some people name their email folders with. I guess I’m not the bash power user I should be.

So, Ruby it is:

 

How to implement a BrowserID Primary

While working on my browserid-provider gem I had to figure out a few basic things to get this working, so I thought I’d share the essence here.

UPDATE: The primary source now is found at MDN.

The requirements for a BrowserID Primary Identity Provider are as follows.

  • A Primary authorize and certify users of it’s own domain by email address
  • The provider must respond to the following requests:
    1. GET /.well-known/browserid
    2. GET /provision
    3. GET /whoami
    4. GET /sign_in
    5. POST /certify

But wait, the only strict requirement is the first of those, since the rest can be configured to any other path of your preference.

GET /.well-known/browserid

You can observe the well-known/browserid at eyedee.me is is a JSON file with three keys:

  • public-key: An RSA public key
  • authentication: where to GET /sign_in
  • provisioning: where to GET /provision

I found some understanding of the RSA key here and the JWS here. The wiki page about the Primary Protocol gives more details about the requirements. Here’s how you can make one:

GET /provision

Next, your browser will send a request to your provisioning path for the HTML content that goes into the iframe mentioned on the Primary wiki page. I modified the static page from eyedee.me to my own dynamic page.

GET /whoami

This is a simple “application/json” document showing the username part of an email address:

{"user":null} or {"user":"mormor"}

GET /sign_in

This is where you present your authentication form, it will be loaded in the BrowserID window. You have to use the BrowserID authentication_api.js here, but watch out for getting this from the same site as the client gets the include.js and the /provision gets the provisioning_api.js. See more at the developer tips.

POST /certify

Last, The provisioning generates a key pair for the current user session on the client side, and sends a POST to the certify path. Have a look at the navigator.id.genKeyPair function in the provision document. The JSON data posted should look like this:

What we would like to do is:

  1. Verify that the browser session is active (a user is logged in)
  2. Sign the client certificate with our Primary certificate

BrowserID expects a JSON document like this one in response:

{"cert":"c429d3345a8d17eb3bf4a06a349d392e00d329744a5179380344e .... "}

Which I generate like this:

If you’re a Rubyist, go use my gem. Otherwise, go make a Primary.

By the way: I couldn’t have done this without the json-jwt.

Manually testing Rails REST API with cURL

I was reading REST-esting with cURL and found this very useful for manually testing my Rails JSON APIs. I am using Cucumber for my Behavious-Driven Development but I find that I often need to see how it feels to actually use the API with other tools than the Ruby ones.

I noticed that when running tests, the params Capybara generated in the controller was a Hash, while the cURL-generated params was a String. This was problematic when I was designing a JSON API, as I didn’t want to allow more than one way of posting JSON. Besides, I wanted to make as much use of the Rails magic as possible, so I added to the PostsController a condition for accepting the POST request:
[ruby] # POST /quantities
def create
begin
if params[“post”].is_a? Hash
@post = Post.create(params[:post])
respond_with(@post)
else
respond_with({:error => “Malformed JSON object.”}, :status => 406)
end
rescue
respond_with({:error => “Post Not Created.”}, :status => 400)
end
end[/ruby]

My User model looks like this:
[ruby]class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :token_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable

# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :username

# Create the authentication token for the user
before_save :ensure_authentication_token
end[/ruby]
This gives us the ability to accept requests with an authentication token. On the client side, just add a User’s token to the URL: [javascript]?auth_token=token_hash[/javascript] This is a Devise property. The User is :token_authenticatable and therefore have a an authentication_token in the database.

So here’s my Rails magic compatible cURL PUT:
[bash]$ curl -v -H “Accept: application/json” \n
-H “Content-Type: application/json” -X PUT \n
-d ‘{“post”:{“category_id”:1,”confirmed”:false}}’\n
http://localhost:3000/posts/1?auth_token=UeF1pJi5yxHjjgfrjpVf[/bash]
The reason this is compatible is simply the Content-Type HTTP header being specified.

This is how I perform a GET:
[bash]$ curl -v -H “Accept: application/json” \n
-H “Content-Type: application/json” -X GET \n
http://localhost:3000/posts/1?auth_token=UeF1pJi5yxHjjgfrjpVf[/bash]

Now, when I want to test different types of request, I can just replace the MIME types:

  • HTML is text/html
  • XML is application/xml or text/xml
  • JSON is application/json

This form of testing is much faster than running Cucumber for each time I want to see subtle changes. Besides, when I write tests for an API, and I want to prepare a POST test like this:

  Scenario: POST a post should be successful
    Given I send and accept JSON
    When I send a POST request to "/posts" with the following:
      """
        {"post":
          { "category_id":3,
            "date":"2012-02-14 05:00:00",
            "body":"Here's some text for ya!"
          }
        }
      """
    Then the response status should be "201"
    And the newest post should have the following:
      | category_id | body                     | date                |
      | 3           | Here's some text for ya! | 2012-02-14 05:00:00 |

    Given I send and accept XML
    When I send a POST request to "/posts" with the following:
      """
        
          2012-02-14T15:00:00
          1
          Here's some text for me!
        
      """
    Then the response status should be "201"
    And the newest paynote should have the following:
      | category_id | body                     | date                |
      | 1           | Here's some text for me! | 2012-02-14 15:00:00 |

To get the XML structure, I just use my cURL to GET /posts/1.xml or /posts/1.json, then I don’t have to write up the structure for the input myself. 🙂