Customer support, what a joke.

Sainsbury's online grocery site was broken last night; it kept giving me 404 errors when I tried to pay for my order. There was one slot left that would get here before I had to pick the kids up, I'd booked it and wanted to keep it,  so I emailed their customer support. I was hoping maybe they'd tell me when it would be fixed, reserve the slot for me or something. 

I kept checking my email and trying their site and eventually later in the evening it worked, so I forgot about the whole thing until this morning when I got this: 

From: "Sainsbury's Online " <sainsburys@mailuk.custhelp.com>
Subject: Shopping online [Reference: 120110-00XXXX]
Date: 11 January 2012 09:54:42 GMT
Reply-To: "Sainsbury's Online " <sainsburys@mailuk.custhelp.com>

Dear Mr McCall

Thank you for your email about our website. I'm sorry you've been having problems on our website due to an error 404 message. I understand this must be frustrating.

I've spoke to our Customer Support Team and they have told me that Microsoft have been experiencing issues accessing the Sainsbury's servers that our website is based upon. They suggest that you search Google for "Error 404 Fix" and a Microsoft Tool will be available for download. Once downloaded this tool will fix the error and you'll be able to use our website again.

If you need any further help please contact us on 0800 328 1700. One of my colleagues will be happy to assist you.

We appreciate you taking the time to contact us and hope this issue is resolved for you soon.

Kind regards

<Name Removed>
Customer Manager
Sainsbury's Online
onlineservice@sainsburys.co.uk


I don't know what I can add to that. 

Validation 1.0.0 released.

I just pushed my little JSR-303 validation lib out as a 1.0.0 release. The JSR-303 is not 1.0 so it seemed like a good idea. 

The biggest changes are probably the ones needed to support those. If you were using the library you won't notice any difference, the changes are all internal and the actual annotations haven't changed. 

I've also removed the springframework package. JSR-303 is now supported in spring 3 and their support is better.

Finally I've added some static methods to AbstractAnnotationTest, assertValid and assertViolation; I've found them useful testing annotated classes and figure someone else may too. 

Check it out and let me know what you think. 

http://github.com/andrewmccall/validation

oEmbed

I came across oEmbed the other day, completely by accident.

I've been working on a couple of projects in my free time and in a few of them I really wanted to be able to embed better information about a URL, if it existed. I'd been working up my own rough JSON schema that was in many ways similar to oEmbed.

Then I came across a tweet that mentioned embed.ly and oEmbed and embed.ly are the perfect solution. Instead of rolling my own service I'm integrating theirs.

At it's most basic it's a standard way of getting more than just a link you can embed in your site and provides a standard interface for doing it across the web. 

If you're looking to embed things in your website, take a look. There are plugins available for wordpress and others as well as a jQuery plugin you can use pretty much anywhere. 

Even more secure passwords.

A few days ago I posted suggesting that you salt your passwords, I'm back armed with even more knowledge and better advice. Turns out the relative strengths of one hashing algorithm vs another can in fact make a difference, in a way I didn't even consider - their speed. 

Most crypto hash functions are designed for speed, you want to be able to compute the hashes of lots of data pretty quickly if your pushing it down the wire. That speed works in an attackers favour if they're brute forcing a list of passwords and newer hashing functions can make it worse, one of the requirements for SHA-3 is that it's faster than the SHA-2 family. 

So what's the new right answer? 

Choose a function that takes enough time that an attacker has to work for each and every password - ideally long enough that it would take forever to crack just one - while making sure that legitimate users aren't waiting forever while you check their passwords. 

There are two ways of doing this, run a fast hash function many times or deliberately pick a slow hash function.

Running many iterations of a fast hashing algorithm is pretty self explanatory, run it twice and it takes twice as long, run it a thousand times and it takes a thousand times as long to attack each password.

Bcrypt is an example of the second, based on the blowfish algorithm it uses the fact that the key setup step is a relatively expensive operation and difficult to optimise. By making use of this bcrypt allows you to set a work factor and creates a hashing algorithm that is expensive and also difficult to optimise. 

Which is better? I have no idea, both are widely used and it really depends on your environment. I'd love to hear what others think though.

Chrome OS.

I don't think Chrome OS is going to be a success.

It's perfect for Google, shows that all you really need is a browser and does it in a compelling way. But it's not going to be a success and I'll cast my lot in with those that predict that it'll get rolled into Android.
The reason I don't see it working is that Google won't use it. Google is a company of engineers, developers and hackers - what do they want with a computer they can't use to do that?
The Chrome OS team is designing and building a product for someone else. Taking things away is a great thing, look at Apple, but if you take so much away that it becomes a product for someone else and you're no longer eating your own dog food. That doesn't usually work out well.

I may be wrong, maybe the team is great and maybe they can overcome the obstacles, but I'll put my money on the best that will come of Chrome OS is that it's evolved into another product or as many are predicting, rolled into Android.

Salt your passwords.

Gawker media is the latest in a long list of compromised systems that have exposed user passwords. Unlike when it happened to the ASF a few months ago, I'm unaffected.

Forbes and others are banging on about weak encryption being the problem, it's not. Passwords aren't encrypted generally, they're passed through a one way hash function. You can't undo the hash, so you can't decrypt the passwords. When you hash the same value though it will always produce the same hash - so you can ask a user for their password, hash the value they enter and check that against the hash you've stored.

The relative strengths of one hash function vs another actually makes very little difference when it comes to passwords. As long as it's collision free for the set of possible passwords, which almost all will be, they're really strong enough no matter how old they are. 

Gawker made a basic mistake that even the most advanced algorithm wouldn't help, they're not salting their passwords. 


Cracking hashed passwords involves computing the hashes until you create the same hashed value. You run the algorithm across a list of know common passwords, dictionary words and common variations. The same value will always produce the same hash, so everyone who uses the same password will also always have the same hash. You just need to compute all the common/obvious ones and look at all the users to find the ones with that match your list. Lots of those users will probably be using their password for email and other services too... oops.

Salting adds something unique to a user, say their email address or ID, forcing an attacker to compute every possible password for each user individually.  Even if two users have chosen the same password they will have a different hash. The better the salt you can choose, the more work an attacker has to do to get passwords.

It's not a panacea though, you've still exposed their details and given enough time a determined attacker can and will be able to recover every last password. What it gives you is time to disclose the breach and your users time to change their passwords on other services which may be the same.

UPDATE: I've added a new post with some more thoughts, clarifications and corrections here

Maven and self signed client certs.

I've been using a self-signed client certificate on my development server. Today working on my OAuth lib I started getting problems connecting to twitter, failed SSH handshakes. With a message something like: 

Connection has been shutdown: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

It's because in my maven command I'm using a custom truststore which doesn't have any of the default root certificates in it, just mine. Running this command imported the default roots into the truststore I've been using with maven: 

 keytool -importkeystore -srckeystore $JAVA_HOME/lib/security/cacerts -destkeystore ./trust.jks 

I got a long list of  Entry for alias keychainrootca-xx successfully imported and now everything works as it should. 

Hope it helps. 

Git checkout a tag.

When I recently rebuilt my development server using Puppet I decided not to backup my nexus repository since there were all of three files I'd built in there. Today I wanted to start recreating them and couldn't find out how to checkout a git tag. 

A couple of google searches weren't terrible successful and it's something that's not really explained well so here it is. 

To checkout a tag you just have to 
git checkout <TAG_NAME> 

Yes it's that simple. 

You'll probably get the same warning message telling you you're in a detached HEAD state. If you intended to do some work here it's probably a really good idea to take the advice the message gives you and create a branch. You could do that when you checkout by adding -b

git checkout <TAG_NAME> -b <BRANCH_NAME>

I didn't want to do anything except a
mvn clean deploy
to get my library deployed back to nexus, then get back to where I was. So I didn't. 

Multiple users, same key in puppet.

I've been a bit quiet on the server front and to be honest a bit stuck. I'm new to Puppet and it took me a while to figure out how to get users working the way I wanted them to. Sleeping on it and reading some more and eventually I got there. I also have a day job to hold down and a family to entertain on the weekend, so as much as I really wanted to get this done life got in the way. My goal now is to get my repositories back online and to create a new one and start committing this Puppet config I've been building somewhere. I decided I'd go with Git for my main projects, the ones that had graduated out of the sandbox but that the sandbox would keep running subversion. I've also planned to run them both via SSH to lower the ports I open and to stick with the same key infrastructure I was building to access everything else. The only problem I had was that I couldn't figure out how to use the same key in multiple places with the otherwise good ssh::auth module from the Puppet patterns wiki. And I wasn't the only one, even the module author thought it was a good idea but difficult to implement. After working on it a few evenings I eventually learned enough about puppet to have a crack at it myself- it may no be the most elegant solution, but it seems to work. I allowed root to login via ssh and turned password authentication on while I did this - I didn't want to lock myself out of my server if I made a mistake. You may want to do the same, or you may not. It's up to you. If you do undo the edits you made to your sshd_config a few days ago In the most simple terms I added a parameter $key throughout ssh::auth which when present indicated you're using a different key, not the one normally used in title.
modules/user/manifests/auth.pp
# =========                                                 
# ssh::auth                                                 
# =========                                                 
#                                                           
# The latest official release and documentation for ssh::auth can always
# be found at http://reductivelabs.com/trac/puppet/wiki/Recipes/ModuleSSHAuth .
#                                                                              
# Version:          0.3.2                                                      
# Release date:     2009-12-29                                                 

class ssh::auth {

$keymaster_storage = "/var/lib/keys" 

Exec { path => "/usr/bin:/usr/sbin:/bin:/sbin" }
Notify { withpath => false }                    


##########################################################################


# ssh::auth::key 

# Declare keys.  The approach here is just to define a bunch of
# virtual resources, representing key files on the keymaster, client,
# and server.  The virtual keys are then realized by                 
# ssh::auth::{keymaster,client,server}, respectively.  The reason for
# doing things that way is that it makes ssh::auth::key into a "one  
# stop shop" where users can declare their keys with all of their    
# parameters, whether those parameters apply to the keymaster, server,
# or client.  The real work of creating, installing, and removing keys
# is done in the private definitions called by the virtual resources: 
# ssh_auth_key_{master,server,client}.                                

define key ($ensure = "present", $filename = "", $force = false, $group = "puppet", $home = "", $keytype = "rsa", $length = 2048, $maxdays = "", $mindate = "", $options = "", $user = "", $key = "") {                                                                                                                                                    

  ssh_auth_key_namecheck { "${title}-title": parm => "title", value => $title }

  # apply defaults
  $_filename = $filename ? { "" => "id_${keytype}", default => $filename }
  $_length = $keytype ? { "rsa" => $length, "dsa" => 1024 }               
  $_user = $user ? {                                                      
    ""      => regsubst($title, '^([^@]*)@?.*$', '\1'),                   
    default => $user,                                                     
  }                                                                       
  $_home = $home ? { "" => "/home/$_user",  default => $home }            

  ssh_auth_key_namecheck { "${title}-filename": parm => "filename", value => $_filename }

  @ssh_auth_key_master { $title:
    ensure  => $ensure,         
    force   => $force,          
    keytype => $keytype,        
    length  => $_length,        
    maxdays => $maxdays,        
    mindate => $mindate,        
  }                             
  @ssh_auth_key_client { $title:
    ensure   => $ensure,        
    filename => $_filename,     
    group    => $group,         
    home     => $_home,         
    user     => $_user,         
  }                             
  @ssh_auth_key_server { $title:
    ensure  => $ensure,         
    group   => $group,          
    home    => $_home,          
    options => $options,        
    user    => $_user,  
    key                => $key,        
  }                             
}                               


##########################################################################


# ssh::auth::keymaster
#                     
# Keymaster host:     
# Create key storage; create, regenerate, and remove key pairs

class keymaster {

  # Set up key storage

  file { $ssh::auth::keymaster_storage:
    ensure => directory,               
    owner  => puppet,                  
    group  => puppet,                  
    mode   => 644,                     
  }                                    
                                       
  # Realize all virtual master keys    
  Ssh_auth_key_master             

} # class keymaster


##########################################################################


# ssh::auth::client
#                  
# Install generated key pairs onto clients

define client ($ensure = "", $filename = "", $group = "", $home = "", $user = "") {

  # Realize the virtual client keys.
  # Override the defaults set in ssh::auth::key, as needed.
  if $ensure   { Ssh_auth_key_client  { ensure   => $ensure   } }
  if $filename { Ssh_auth_key_client  { filename => $filename } }
  if $group    { Ssh_auth_key_client  { group    => $group    } }

  if $user { Ssh_auth_key_client  { user => $user, home => "/home/$user" } }
  if $home { Ssh_auth_key_client  { home => $home } }                       
  if $key { Ssh_auth_key_client  { key => $key } }

  realize Ssh_auth_key_client[$title]

} # define client


##########################################################################


# ssh::auth::server
#                  
# Install public keys onto clients

define server ($ensure = "", $group = "", $home = "", $options = "", $user = "", $key="") {

  # Realize the virtual server keys.
  # Override the defaults set in ssh::auth::key, as needed.
  if $ensure  { Ssh_auth_key_server  { ensure  => $ensure  } }
  if $group   { Ssh_auth_key_server  { group   => $group   } }
  if $options { Ssh_auth_key_server  { options => $options } }

  if $user { Ssh_auth_key_server  { user => $user, home => "/home/$user" } }
  if $home { Ssh_auth_key_server  { home => $home } }  
  if $key  { Ssh_auth_key_server  { key => $key } }
                       

  realize Ssh_auth_key_server[$title]

} # define server

} # class ssh::auth


##########################################################################


# ssh_auth_key_master
#                    
# Create/regenerate/remove a key pair on the keymaster.
# This definition is private, i.e. it is not intended to be called directly by users.
# ssh::auth::key calls it to create virtual keys, which are realized in ssh::auth::keymaster.

define ssh_auth_key_master ($ensure, $force, $keytype, $length, $maxdays, $mindate) {

  Exec { path => "/usr/bin:/usr/sbin:/bin:/sbin" }
  File {                                          
    owner => puppet,                              
    group => puppet,                              
    mode  => 600,                                 
  }                                               

  $keydir = "${ssh::auth::keymaster_storage}/${title}"
  $keyfile = "${keydir}/key"                          

  file { 
    "$keydir":
      ensure => directory,
      mode   => 644;      
    "$keyfile":           
      ensure => $ensure;  
    "${keyfile}.pub":     
      ensure => $ensure,  
      mode   => 644;      
  }                       

  if $ensure == "present" {

    # Remove the existing key pair, if
    # * $force is true, or            
    # * $maxdays or $mindate criteria aren't met, or
    # * $keytype or $length have changed            

    $keycontent = file("${keyfile}.pub", "/dev/null")
    if $keycontent {                                 

      if $force {
        $reason = "force=true"
      }                       
      if !$reason and $mindate and generate("/usr/bin/find", $keyfile, "!", "-newermt", "${mindate}") {
        $reason = "created before ${mindate}"                                                          
      }                                                                                                
      if !$reason and $maxdays and generate("/usr/bin/find", $keyfile, "-mtime", "+${maxdays}") {      
        $reason = "older than ${maxdays} days"                                                         
      }                                                                                                
      if !$reason and $keycontent =~ /^ssh-... [^ ]+ (...) (\d+)$/ {                                   
        if       $keytype != $1 { $reason = "keytype changed: $1 -> $keytype" }                        
        else { if $length != $2 { $reason = "length changed: $2 -> $length" } }                        
      }                                                                                                
      if $reason {                                                                                     
        exec { "Revoke previous key ${title}: ${reason}":                                              
          command => "rm $keyfile ${keyfile}.pub",                                                     
          before  => Exec["Create key $title: $keytype, $length bits"],                                
        }                                                                                              
      }                                                                                                
    }                                                                                                  

    # Create the key pair.
    # We "repurpose" the comment field in public keys on the keymaster to
    # store data about the key, i.e. $keytype and $length.  This avoids  
    # having to rerun ssh-keygen -l on every key at every run to determine
    # the key length.                                                     
    exec { "Create key $title: $keytype, $length bits":                   
      command => "ssh-keygen -t ${keytype} -b ${length} -f ${keyfile} -C \"${keytype} ${length}\" -N \"\"",
      user    => "puppet",                                                                                 
      group   => "puppet",                                                                                 
      creates => $keyfile,                                                                                 
      require => File[$keydir],                                                                            
      before  => File[$keyfile, "${keyfile}.pub"],                                                         
    }                                                                                                      

  } # if $ensure  == "present"

} # define ssh_auth_key_master


##########################################################################


# ssh_auth_key_client
#                    
# Install a key pair into a user's account.
# This definition is private, i.e. it is not intended to be called directly by users.

define ssh_auth_key_client ($ensure, $filename, $group, $home, $user) {

  File {
    owner   => $user,
    group   => $group,
    mode    => 600,   
    require => [ User[$user], File[$home]],
  }                                                    

  $key_src_file = "${ssh::auth::keymaster_storage}/${title}/key" # on the keymaster
  $key_tgt_file = "${home}/.ssh/${filename}" # on the client                       

  $key_src_content_pub = file("${key_src_file}.pub", "/dev/null")
  if $ensure == "absent" or $key_src_content_pub =~ /^(ssh-...) ([^ ]+)/ {
    $keytype = $1                                                         
    $modulus = $2                                                         
    file {                                                                
      $key_tgt_file:                                                      
        ensure  => $ensure,                                               
        content => file($key_src_file, "/dev/null");                      
      "${key_tgt_file}.pub":                                              
        ensure  => $ensure,                                               
        content => "$keytype $modulus $title\n",                          
        mode    => 644;                                                   
    }                                                                     
  } else {                                                                
    notify { "Private key file $key_src_file for key $title not found on keymaster; skipping ensure => present": }
  }                                                                                                               

} # define ssh_auth_key_client


##########################################################################


# ssh_auth_key_server
#                    
# Install a public key into a server user's authorized_keys(5) file.
# This definition is private, i.e. it is not intended to be called directly by users.

define ssh_auth_key_server ($ensure, $group, $home, $options, $user, $key) {

  # on the keymaster:
  $key_src_dir = "${ssh::auth::keymaster_storage}/${key}"
  $key_src_file = "${key_src_dir}/key.pub"                 
  # on the server:                                         
  $key_tgt_file = "${home}/.ssh/authorized_keys"           
                                                           
  File {                                                   
    owner   => $user,                                      
    group   => $group,                                     
    require => User[$user],                                
    mode    => 600,                                        
  }                                                        
  Ssh_authorized_key {                                     
    user   => $user,                                       
    target => $key_tgt_file,                               
  }                                                        

  if $ensure == "absent" {
    ssh_authorized_key { $title: ensure => "absent" }
  }                                                  
  else {
    $key_src_content = file($key_src_file, "/dev/null")
    if ! $key_src_content {
      notify { "Public key file $key_src_file for key $_key not found on keymaster; skipping ensure => present": }
    } else { if $ensure == "present" and $key_src_content !~ /^(ssh-...) ([^ ]*)/ {
      err("Can't parse public key file $key_src_file")
      notify { "Can't parse public key file $key_src_file for key $_key on the keymaster: skipping ensure => $ensure": }
    } else {
      $keytype = $1
      $modulus = $2
      ssh_authorized_key { $title:
        ensure  => "present",
        type    => $keytype,
        key     => $modulus,
        options => $options ? { "" => undef, default => $options },
      }
    }} # if ... else ... else
  } # if ... else

} # define ssh_auth_key_server


##########################################################################


# ssh_auth_key_namecheck
#
# Check a name (e.g. key title or filename) for the allowed form

define ssh_auth_key_namecheck ($parm, $value) {
  if $value !~ /^[A-Za-z0-9]/ {
    fail("ssh::auth::key: $parm '$value' not allowed: must begin with a letter or digit")
  }
  if $value !~ /^[A-Za-z0-9_.:@-]+$/ {
    fail("ssh::auth::key: $parm '$value' not allowed: may only contain the characters A-Za-z0-9_.:@-")
  }
} # define namecheck
I won't go through all the changes line by line, the important things to note are that I added the variable $key and limited the ssh_auth_key_master automatic realisation to only calls that have not provided a key. Basically if you give it a key you're trying to use an exisiting key, otherwise you're looking to create a new key for a user.

Usage

Using the new calls is easy. Assuming you've cerated your user addding the following lines will allow the previously created andrewmccall key to login as root:
manifests/nodes.pp
node build {
    include sudo, user, sshd, ssh::auth, user::keystore, repos
    user::create{"andrewmccall": groups => "sudo"}
    user::client_key{"andrewmccall":}
    user::server_key{"andrewmccall":}

    ssh::auth::key{"andrewmccall-root": key=>"andrewmccall"}
    ssh::auth::server{"andrewmccall-root": key=>"andrewmccall", user=>"root", home=>"/root"}
}
In lines 7 & 8 you can see I use the andrewmccall key to allow logins as root. Apologies for the brevity of the post, I guess you can probably tell I'm sick of looking at this code. If you do have any questions or there is any interest in it I'll elaborate in the comments or a future post.