Tuesday, December 27, 2011

Rails authentication using Devise and devise_ldap_authenticatable

About a week ago I posted about my attempts to integrate Rails applications with Active Directory.  I have successfully rolled my own authentication using net/ldap, but I want to use a gem so that there will be more than just me using it and fixing it up.

Last week I was successful getting Devise and Omniauth-ldap to work together to integrate with Active Directory, but I decided that the solution was not enterprise-ready because there is currently no way to override the login page and make it look like the rest of my application.

Now I think I have the solution, and it was a little bit easier too.  Devise + devise_ldap_authenticatable.  Here is the walkthrough for what worked for me.

Adding your Gems
For this project I am going to add the following lines to my gemfile:
gem "nifty-generators", :git => 'https://github.com/ryanb/nifty-generators.git'
gem 'devise'
gem 'devise_ldap_authenticatable', :git => 'git://github.com/cschiewek/devise_ldap_authenticatable.git'
gem 'annotate', :git => 'git://github.com/ctran/annotate_models.git'

The annotate gem and the nifty-generators gem aren't necessary, but I like to use them. Nifty-generators will make the flash notices that you'll need later on in the project so you might consider using it if you're just following along. Now run bundle to get everything set up.

Setting up nifty-generators
There are a couple steps that I'm going to go through to set up nifty-generators which are optional if you decide that you don't mind having your rails project look ugly.

rails generate nifty:config
rails generate nifty:layout
rails generate nifty:scaffold Change title:string description:string
cp public/stylesheets/application.css app/assets/stylesheets/nifty.css
rm public/index.html
cat app/views/layouts/application.html.erb | sed \
's/javascript_include_tag :defaults/javascript_include_tag "application"/' \
> /tmp/what.txt
 cp /tmp/what.txt app/views/layouts/application.html.erb
rake db:migrate
Also, make sure you edit config/routes.rb and add a path to root:
root :to => 'changes#index'
At this point you should have a working application that will allow you to create, edit, and delete changes.  It should look nice and neat.  Make sure that you have the ability to delete objects, and if you do not check the line in app/views/layouts/application.html.erb to make sure that javascript_include_tag is including "application" not :defaults.  A tell-tale sign that javascript is the source of your delete problem is that when you try to delete a change you're not even given the "are you sure" prompt.


Configuring devise for user management
 Now we need to create a model for our users, and we'll call that model User.  We will use devise because then we'll have all of the helpers created for things like checking if the current user is authenticated.  This part is amazingly simple.
rails generate devise:install
rails generate devise User 
rake db:migrate 
Bam!  That's it.  Now you have a user model with all kinds of neat options.  If you didn't want to perform Active Directory authentication you would be almost done now with just some work to customize the views.

Setting up devise_ldap_authenticatable
First we need to generate the devise_ldap_authenticatable installation.
rails generate devise_ldap_authenticatable:install
There are options that you can set, but I don't need them.  The gem assumes that your user model is called User which mine is.

Now we need to set the LDAP parameters used to connect to Active Directory.  This is kept config/ldap.yml.

development:
  host: domaincontroller.domain.com 
  port: 389 
  attribute: sAMAccountName 
  base: dc=domain,dc=com
  admin_user: cn=admin,dc=test,dc=com
  admin_password: admin_password
  ssl: false
  # <<: *AUTHORIZATIONS

The most important thing here is that you set the attribute to sAMAccountName and that you have the full DN and password of your binding user.  There are options here to force certain group membership or make sure that certain attributes are set, but I haven't played with that yet.  Right now, anybody that is a member of the domain is able to log into my app.

The last thing we need to do is make some edits to config/initializers/devise.rb which has some new options that were added by the devise_ldap_authenticatable installer.  This is why my configuration looks like:

  # ==> LDAP Configuration 
  config.ldap_logger = true
  config.ldap_create_user = true 
  # config.ldap_update_password = true
  config.ldap_config = "#{Rails.root}/config/ldap.yml"
  config.ldap_check_group_membership = false
  config.ldap_check_attributes = false
  config.ldap_use_admin_to_bind = true 
  # config.ldap_ad_group_check = false

Look a little further in the document to find these lines and change them to match mine:

config.authentication_keys = [ :username ]
config.case_insensitive_keys = [ :email, :username ]

Changes to the user model
We want to keep track of some Active Directory attributes, so we need to make a few changes to our user model.  Let's add a firstname, lastname, username, and displayname field.

rails generate migration add_fields_to_users firstname:string lastname:string username:string displayname:string
rake db:migrate

This is when I like to use annotate so that I can keep track of what I've done to my models.  Anyway, lets take a look at the app/models/user.rb file.  We need to update our attributes accessible, and add some methods to pull in Active Directory attributes and save them with our user.

attr_accessible :username, :email, :password, :password_confirmation, :remember_me, :firstname, :lastname, :displayname

  before_save :get_ldap_lastname, :get_ldap_firstname, :get_ldap_displayname, :get_ldap_email

  def get_ldap_lastname
      Rails::logger.info("### Getting the users last name")
      tempname = Devise::LdapAdapter.get_ldap_param(self.username,"sn")
      puts "\tLDAP returned lastname of " + tempname
      self.lastname = tempname
  end 

  def get_ldap_firstname
      Rails::logger.info("### Getting the users first name")
      tempname = Devise::LdapAdapter.get_ldap_param(self.username,"givenname")
      puts "\tLDAP returned firstname of " + tempname
      self.firstname = tempname
  end 

  def get_ldap_displayname
      Rails::logger.info("### Getting the users display name")
      tempname = Devise::LdapAdapter.get_ldap_param(self.username,"displayname")
      self.displayname = tempname
  end 

  def get_ldap_email
      Rails::logger.info("### Getting the users email address")
      tempmail = Devise::LdapAdapter.get_ldap_param(self.username,"mail")
      self.email = tempmail
  end


Changes to the views
The final change is to make sure that our view is going to reflect whether or not a user is logged in and provide some basic information about the logged in user.  I added this right under the title in app/views/changes/index.html.erb

<% if user_signed_in? %>
    Welcome <%= current_user.firstname %>, you last logged on <%= current_user.last_sign_in_at %> from <%= current_user.last_sign_in_ip %>


<% else %>
    <%= link_to "login", new_user_session_path %>
<% end %>

We also need to make a critical change to the login form.  Right now it is still asking for an email address and it wont let you get away with typing a username into the email field.  So we need to have devise show us our view so that we can edit it.
rails generate devise:views
Now edit app/views/devise/sessions/new.html.erb.  Change the email label to say username and change the email_field to text_field.

Also, if you want to have the user redirect to your root path, then you need to add something like this to config/routes.rb
match '/changes' => 'changes#index', :as => 'user_root'

Tuesday, December 20, 2011

Rails authentication using devise and omniauth-ldap

Recently I've been doing some development in Ruby on Rails and I wanted to be able to have users log into the application using Active Directory credentials and I wanted some user information to persist in a database so that I could make objects belong_to a User.  In this case the application is for IT Change Management so I have two models, User and Change.  User has_many changes and Change belongs_to user.  I started to code something up myself, but then I thought I would take some time to figure out how to do it using some of the gems out there that make life simple.  So I wanted to combine devise with omniauth-ldap.  It took me a while to get it all working, and so I want to document my process for everyone (especially me) to come back and reference.  So here is my walkthrough of creating a very simple application using devise and omniauth-ldap for user management.

Adding your gems
For this project I am going to add the following lines to my gemfile:

gem "nifty-generators", :git => 'https://github.com/ryanb/nifty-generators.git'
gem 'devise', :git => 'https://github.com/plataformatec/devise.git'
gem 'omniauth-ldap', :git => 'https://github.com/intridea/omniauth-ldap.git'
gem 'annotate', :git => 'git://github.com/ctran/annotate_models.git'
The annotate gem and the nifty-generators gem aren't necessary, but I like to use them.  Nifty-generators will make the flash notices that you'll need later on in the project so you might consider using it if you're just following along.  Now run bundle to get everything set up.

Setting up nifty-generators
There are a couple steps that I'm going to go through to set up nifty-generators which are optional if you decide that you don't mind having your rails project look ugly.
rails generate nifty:config
rails generate nifty:layout
rails generate nifty:scaffold Change title:string description:string
cp public/stylesheets/application.css app/assets/stylesheets/nifty.css
rm public/index.html
cat app/views/layouts/application.html.erb | sed \
's/javascript_include_tag :defaults/javascript_include_tag "application"/' \
> /tmp/what.txt
 cp /tmp/what.txt app/views/layouts/application.html.erb
Also, make sure you edit config/routes.rb and add a path to root:
root :to => 'changes#index'
At this point you should have a working application that will allow you to create, edit, and delete changes.  It should look nice and neat.  Make sure that you have the ability to delete objects, and if you do not check the line in app/views/layouts/application.html.erb to make sure that javascript_include_tag is including "application" not :defaults.  A tell-tale sign that javascript is the source of your delete problem is that when you try to delete a change you're not even given the "are you sure" prompt.

You have probably also seen some devise warnings popping up when you run some of these commands.  Don't worry, we're going to take care of that in the next section.

Configuring devise for user management
 Now we need to create a model for our users, and we'll call that model User.  We will use devise because then we'll have all of the helpers created for things like checking if the current user is authenticated.  This part is amazingly simple.
rails generate devise:install
rails generate devise User 
rake db:migrate 
Bam!  That's it.  Now you have a user model with all kinds of neat options.  If you didn't want to perform Active Directory authentication you would be almost done now with just some work to customize the views.  Now we're going to start on the stuff that took me the longest.

Integrating omniauth-ldap into devise
There are two things that really caused me a lot of headache and once I learned them this whole process went a lot faster.  The first thing you should know is that omniauth-ldap does not use the credentials that the user enters to bind to LDAP.  So unless your Active Directory is configured to allow anonymous LDAP then you're going to need to provide credentials for binding.  I wasn't doing that and I couldn't figure out why I kept getting LDAP errors.  The second thing that is useful to know is that the configuration for omniauth-ldap is done in the devise initialization file: config/initializers/devise.rb.  If you go to the github site for omniauth-ldap, Ping (the author) has some instructions and a sample application (look in the wiki for the sample application).  In that sample application, the omniauth-ldap configuration is in a file called config/initializers/omniauth.rb.  In our application, we're going to ignore that and instead put that into config/initializers/devise.rb.  Look for the string config.omniauth and include this in the configuration right after the comments:

config.omniauth :ldap, :host => 'YOUR_LDAP_SERVER,
      :base => 'THE_BASE_WHERE_YOU_SEARCH_FOR_USERS',
      :uid => 'sAMAccountName',
      :port => 389,
      :method => :plain,
      :bind_dn => THE_FULL_DN_OF_THE_USER_YOU_WILL_BIND_WITH',
      :password => 'THE_PASSWORD_OF_THE_BIND_USER'
You'll probably need to get most of this information from an Active Directory administrator.  I don't advise using your own DN and password because then every time you change your password the application will break.  I would suggest running rails server right now just to make sure that you didn't enter anything that will cause the application to fail.  


Setting up your views
In my view, I want to do something really simple.  If a user is logged in, I want to welcome them and provide a logout link.  If a user is not logged in, I want to present a login link.  So I'm going to go into app/views/changes/index.html.erb and add this right under the title:

<% if user_signed_in? %>
    Welcome <%= current_user.email %> (<%= link_to "logout", destroy_user_session_path,  :method => :delete %>)
<% else %>
    Nobody logged in.  <%= link_to "log in here", user_omniauth_authorize_path(:ldap) %>
<% end %>
Those routes to destroy_user_session_path and user_omniauth_authorize_path are all generated by devise and didn't take any additional work on my part.

We also need to make a change to our user model that was generated by devise.  If you look in app/model/users.rb you'll see a line with some devise configuration that makes this user model :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, and :validatable.  To this list we need to add :omniauthable.  If you're seeing an error about user_omniauth_authorize_path not being defined it is because you didn't add :omniauthable to the user model.

At this point your application should run and you should be able to click those links.  You'll be taken to an ugly looking log in screen.  Log in isn't going to work yet because we haven't wired up the callback.  Here are a couple tests you can run to make sure that everything is right so far.  1. Try to log in with valid credentials.  You'll be directed to a sign in page and see an error message that you couldn't log in because of an LDAP error.  2. Try to log in with invalid credentials.  This time you'll be redirected to the same page, but you'll have an error message about invalid credentials.

More changes to the User model
In my case I want to retain some information about the user that is returned from LDAP so that I can have associations between changes and users.  So we need to generate a migration to add a few database fields to our User table.  Run this command:
rails generate migration AddColumnsToUsers firstname:string lastname:string displayname:string username:string
That should generate a migration for you that looks like this:



If you want to make sure that your username is also unique, you should add add_index :users, :username, :unique => true to the migration.  I also want to make sure that the username is not blank.  Now run rake db:migrate to add those fields to your table.  Then we need to edit the file app/models/user.rb to make those fields useful.  First, we need to add our new columns to the attributes_accessible line in the model.  
attr_accessible :firstname, :lastname, :displayname, :username, :email, :password, :password_confirmation, :remember_me
In my application, we are not going to set the users password, we're going to depend on Active Directory to do the authentication.  But I don't like the idea of removing the validation from devise and I don't want to have user accounts with no password in the database.  So I'm going to create a method that I can use to set a random password for each user.  I'm using the self.method notation to make this a class method rather than an instance method.

  def self.generate_random_password
      Digest::SHA1.hexdigest(Time.now.to_s)
  end 
Wiring up the callback
The next thing we need to do is tell devise what controller to use for the omniauth callback.  We're going to do this in our routes file, so edit config/routes.rb and find the line that reads devise_for :users and change it to read:
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
That tells devise that when we get an answer back from ldap, we should look in app/controllers/users/omniauth_callbacks.  If we were using omniauth without devise, the user would log in by visiting /auth/ldap.  What we've done here is make use of the integration between devise and omniauth.  So users will visit /users/auth/ldap.  We also need to specify what controller is going to handle the callback.  Without devise we do the same thing by adding a line like this to config/routes:

match "/auth/:provider/callback" => "users/omniauth_callbacks#create"


 When you successfully authenticate to LDAP you'll get back a big bundle of information about the user.  We're going to use that information to either log in an existing user or create a new user and log that user in.  The code for this is going to be located in the omniauth_callbacks file which does not exist right now.  We need to create the file and add a method called ldap to handle the way LDAP results are returned.  This ldap method is going to check if there is an existing user and log that person in, otherwise create a new user.  Here is the code for that file:

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController


    def ldap
        # We only find ourselves here if the authentication to LDAP was successful.
        ldap_return = request.env["omniauth.auth"]["extra"]["raw_info"]
        firstname = ldap_return.givenname[0].to_s
        lastname = ldap_return.sn[0].to_s
        displayname = ldap_return.displayname[0].to_s
        username = ldap_return.sAMAccountName[0].to_s
        email = ldap_return.proxyaddresses[0][5..-1].to_s

        if @user = User.find_by_username(username)
            sign_in_and_redirect @user
        else
            @user = User.create(:firstname => firstname,
                                :lastname => lastname,
                                :displayname => displayname,
                                :username => username,
                                :email => email,
                                :password => User.generate_random_password)
            sign_in_and_redirect @user
        end
    end
end

This information could use a bit of explaining.  The results from LDAP are put into an environment variable called omniauth.auth, which is in a format called omniauth.auth format.  If we were using something like Facebook or Twitter for our authenticator omniauth could probably figure out things like the username and this code wouldn't be as ugly.  But the data we need is in an a hash called raw_info, which itself is a hash within a hash within a hash.  Each of the return values that we need are in an array, so my firstname is in an array which is why I have to put the [0] after ldap_return.givenname.  Don't worry too much about the email line, in your organization you probably will be able to use ldap_return.email.  In my case, the email address that I want an application to use is different than what is stored in that value, so I am grabbing an address from a different part of the response and stripping off the SMTP: that appears at the begining.

What's next?
We have a working application that can authenticate users via Active Directory.  There are a few loose ends that I would like to clean up, but this is as far as I was able to get.  For example, if a user's authentication fails he is redirected to a sign up page that I don't want them to see.  However, I wasn't able to figure out how to change the application routing to make them redirect to the sign in page instead.  Also, the login page is not customizable at all.  That really doesn't work for an enterprise environment which is where you're most likely to see Active Directory integration.  It looks unprofessional when your user gets redirected to a login page that looks nothing like the rest of your site.

So while this will work for back end stuff or personal stuff that you aren't going to expose to the end users it isn't going to meet your needs right now for enterprise applications.  If you want Active Directory integration that looks professional you're stuck with rolling your own for now.

I hope someone proves me wrong in the comments.  I really wanted this to work.



Thursday, November 10, 2011

Stats for risk modeling: The Uniform Distribution

This blog entry originally appeared on the Society of Information Risk Analysts web page on November 3, 2011: http://societyinforisk.org/content/stats-risk-modeling-uniform-distribution


Next up in my series on distributions, I'd like to talk about the Uniform distribution.  Uniform is quickly becoming my favorite distribution because it is really easy to understand and it helps us to avoid a common mistake in risk modeling; namely that we tend to underestimate the likelihood of the extremes.  If you remember back to my previous post on the Normal distribution you will recall that once you get three standard deviations away from the mean you are getting into frequencies that are pretty low.  In fact, in a perfect normal distribution it would take 10,000 loss events to find 15 losses that were greater than 3 times the standard deviation.

Uniform distribution makes a great "safety" distribution.  Maybe you're pretty confident that some random variable can be represented by a normal distribution, and if that is the case then use it.  That's what it's there for.  But what if your random variable is bimodal, meaning that has ups and downs and no single most likely value?  What if you think that values at the far end of the distribution likely occur more often than what the Normal distribution allows?  Uniform distribution never lets me underestimate my tails (unless my random variable is a strange U shaped phenomenon) and it never makes me ignore one mode in favor of another.




SOME BACKGROUND: Distributions can be discreet or continuous.  Discrete distributions have clear values with nothing in between.  In the two pictures above, the distribution on top is continuous, and the bottom is discrete.  A fair six-sided die is a good example of a discrete uniform distribution.  It has 6 and only 6 possible outcomes.  If I used a continuous uniform distribution to represent that variable I might get values like 4.5.  One of the "rules" of modeling risk in Monte Carlo simulations is that each value in each iteration has to be possible.  No gibberish in the model.  So having a variable that tells you (with great frequency) that you rolled 3.291 is bad.  Built into Excel you have the RANDBETWEEN function which will give you a discrete uniform distribution of random numbers.  If you're using the FAIR Lite tool, you can get a nearly uniform distribution by setting the confidence of an estimate to very low and putting the most likely value right between the minimum and the maximum.  It's not exactly uniform, but probably close enough.

WHEN TO USE IT: Use the uniform distribution when you have a good idea about the upper and lower bound of your variable, but you are uncertain about the shape.

WHAT MAKES IT COOL: It's easy to understand.  You can explain this distribution to even the most statistically challenged of executives.  And thanks to the Central Limit Theorem when you combine several uniform distributions you'll get a normal distribution which will satisfy the people that want nice graphs and tighter estimates of the most likely value.

WHEN TO AVOID IT: You should absolutely avoid this distribution if you have any evidence that the variable you're representing is U-shaped, in other words the values at the extreme are more likely than values in the middle.  Other than that, this is a great distribution if you want to be open to possibilities and are willing to admit that you don't know a whole lot.

EXTRA CREDIT: U-shaped distributions are most often seen where there is cyclic data.  For example, if you were molding the the snowfall in a given month and your X axis starts with January and ends with December then you would likely see more snowfall on the two ends and less in the middle.  Can you think of any variables in information security that might follow a U-shaped distribution?

Monday, November 7, 2011

Stats for risk modeling: The Normal Distribution

This blog entry was originally posted on the Society of Information Risk Analysts web page on November 1, 2011: http://societyinforisk.org/content/stats-risk-modeling-normal-distribution

A few months ago I did a presentation at the Twin Cities Information Risk Round Table (TCIRRT) about basic statistical distributions that you might use in your risk models.  The presentation proved to be rather popular and so I thought maybe I should write a series of blog posts to review the material that I covered in that presentation.

I was a little torn over whether to start with a normal distribution or a uniform distribution and ultimately just decided to pick one.  So I’m going to talk about the normal distribution in this post.

SOME BACKGROUND: Distributions are all about the area under a curve.  That’s why calculus is so important to statistics.  We use distributions to represent random variables that we encounter in our risk models.  These are the unknowns, like how much is a loss event going to cost us.  I have included here a picture of a normal distribution with a mean of 50 and a standard deviation of 15.  In the picture the total area under the curve (which is all the blue stuff) adds up to 1.  That is going to be the case for every distribution that you look at.  The whole curve represents every possible outcome for a random variable, and the cumulative probability of every possible outcome is 1.

I have highlighted the area between 35 and 50 on this curve, and you might notice at the top that this accounts for 34.1% of the area under the curve.  If this distribution was an accurate representation of a random variable, I could say that 34.1% of the time I should see a value that falls between 35 and 50.

WHEN TO USE IT:  It seems to me that there are 3 tests you can use to decide if the normal distribution is the right distribution to represent your random variable.
  1. You have an average value that you can calculate or reasonably estimate.  If you were using FAIR for your risk modeling, this would be your “most likely” value.
  2. The “shape” of the random variable is nearly symmetric.  It can be skewed a bit in one direction or another, but it should not be extreme.
  3. There is a low probability of getting a value at the far left or far right of your distribution.  In other words, it’s bell shaped.
WHAT MAKES IT COOL: The normal distribution is cool because of the 68-95-99 rule.  A normal distribution has two parameters, the mean and the standard deviation.  You could think of standard deviation as how fat or skinny the distribution appears.  I mentioned earlier that this picture has a mean of 50 and a standard deviation of 15.  If you were to go from 50 to 35, you have moved 1 standard deviation away from the mean.  If you take the values from 35 to 65, you have 1 standard deviation in either direction.  And that should cover 68% of the area under the curve.  So in a normal distribution, 68% of the values are within one standard deviation in either direction from the mean.  If you move two standard deviations in either direction you have 95% of the area, and three will get you 99% of the area.  So if you can calculate or reasonably estimate the mean and standard deviation of a random variable, you will know that 99% of your values should be greater than the mean minus (standard deviation * 3) and smaller than the mean plus (standard deviation * 3).

WHEN TO AVOID IT: It should be obvious that if your random variable doesn’t pass the three tests I wrote up there then you should avoid using the normal distribution.  The main reason outside of failing the 3 tests that you should avoid it is that the normal distribution is continuous and boundless.  Continuous means that ANY value between two points is possible.  So my random variable could be assigned a value of 35.000654780.  I might just round that to two decimal places and call it a dollar value, but you should be aware that these values are possible.  Also, it will return values that extend beyond that 99% mark.  For example, let’s say that your mean is 30 and your standard deviation is 10.  You should know that 3 times out of 1000 your random number generator will give you a value that is less than zero.  If that is not possible in real life then you need to consider another distribution.

Tuesday, November 1, 2011

Aggregating Risk Scenarios: put away the calculator.

This post appeared on the Society of Information Risk Analysts blog on October 20, 2011.

The other day I was thinking about how one might go about expressing the aggregate information risk of an organization.  Lately I find myself favoring a balanced scorecard approach to expressing risk, but even after breaking risk scenarios into several groups, you still need to aggregate them in some way.  So how would one go about expressing the combined distribution of loss from several loss risk scenarios?

Let's make up a story to illustrate.  Lets say that you are going to go to your favorite amusement park in Minnesota.  Your mom is going to her favorite amusement park in California and your dear sweet grandmother is going to her favorite amusement park in Florida.  Each of you is going to bring $100 with you.  You all have an equal risk of being robbed, but your mother and grandmother are so paranoid that they wont go unless you promise to reimburse them for any robbery they suffer.  If any of you are robbed you know that the robber will get at least $1 and no more than $100.  So you could express each risk scenario as a uniform distribution with a minimum of $1 and a maximum of $100.  But what is your total risk exposure?

Your total risk exposure is $300 because you have three risks with a maximum loss of $100.  But we usually do not want to express what is possible, we want to express what is probable.  You might want to express risk out to the 95th percentile or the 99th percentile.  The total exposure number is actually quite rare.  How rare?  There is a 1% chance that one of you will be robbed for $100.  Since these events are independent, the probability of two of you being robbed for $100 is 1% of 1% or .01%.  The probability of all three of you being robbed for $100 is .0001% or once every million trips to the amusement park.  And even that is assuming that all three of you will certainly be robbed!

The same effect happens on the minimum side of the aggregate risk distribution for the same reason.  I ran a monte carlo simulation with these three scenarios with 5000 samples.  Even after 5000 samples I couldn't get a minimum value less than 11.  In fact, only 10% of the simulations had less than $85 for the aggregate loss.  What you're seeing here is the Central Limit Theorem at work.  When we combine three uniform distributions, we get a result that starts to look more like a normal distribution.  The graphic here shows the outcome of adding these three loss distributions together.  The effect becomes even more pronounced when the distributions aren't uniform.  If we had used a Pert distribution to describe each of the losses with a most likely loss of $30 then the effect is even greater.  I never saw a loss less than $22 or more than $228.  If you wanted to have enough cash to cover your losses for 95% of the trips to the amusement park, I would only need to have $164.

So if you're going to be aggregating the loss from several risk simulations then the tool of choice is not a calculator, but another simulation.  The aggregate risk becomes a simulation where each of the inputs is the output of a risk scenario.  That way you can more accurately express what is probable rather than what is possible.

Tuesday, October 4, 2011

Creating a cheap progressive pin lock set

The other day I gave a presentation to a group of information security students about why they should care about lock picking and how lock picking works.  I wanted to have some hands on material that they could try to pick, but I didn't want to spend a bunch of money buying a progressive pin lock kit.  After all, I don't talk about this very often and I don't need much experience picking a two or three pin lock.  But, if you've got some tools in your garage (or in my case a friend that has tools) you can make your own progressive pin kit on the cheap.

Step one: go out and buy a set of the cheapest locks you can get your hands on.  You're going to grind them up and destroy them so don't buy expensive locks.  Also, this is for practicing simple stuff so you don't want things to get too complicated.  You can buy a set of locks that are keyed alike, but it isn't important since you're going to be picking the locks, not using the key.  There is a non-zero probability that you will really screw up the first one you try so you might consider planning for that in advance.

Step two: Take an angle grinder to the bumps on the bottom of a lock near the keyway.  These are the pins that basically hold the whole lock together.  Here is an action shot of my friend Jeremy grinding down the pins. Try to be careful that you don't damage the keyway itself. 

When you've ground those pins off, you'll probably have to do some work to get the bottom plate off of the lock.  After all, it is designed to not be broken into.  We had to take a chisel and beat at the bottom layer of steel to get it to come off.

When you're done, the actual pin assembly should slide out, and you're looking at the inside of the lock where the shackle release is.  You could unlock the lock with a screwdriver right now.

Here are some optional steps for cleaning things up a bit.  You might want to take a file to the sharp edges that are left of the pins you ground off.  Those are sharp and they could hurt you.  You might also want to drill the holes a bit bigger on the bottom plate that you took off in case you want to put it back on.  Hammer that sucker flat again too since it probably got a bit beat up when you were removing it.

OK, now for the pins.  There are two approaches you could take here: the easy inflexible way or the hard flexible way.  We chose the easy way.  Put your key into the lock mechanism, and turn it 180 degrees.  In our case, the key pins fell out through holes in the bottom of the lock assembly.  So if you want to have a two pin lock, cover up two of the holes and dump the key pins from the other two holes.  Then turn the lock back to the upright position.  This will cause the driver pins to fall into the spot that the key pins were in.  Now turn the lock 180 degrees again and the driver pins will fall out.  After that, put the key in the upright position, and use a tool to sneak the springs out of the lock mechanism.  It's easy, but you can't easily rekey or change the configuration of the lock.

The harder way is to drill out the top of the lock mechanism.  You should see four small holes at the top of the lock if you have a four pin lock.  Drill those holes bigger and you'll be able to take out the spring, driver pin, and key pin.  Then you can rekey to your hearts content and then use some black electricians tape to hold the pins in when you're done.  What if you don't know any black electricians?  Use some other kind of tape.  Now put the whole lock back together if you want or just pick away at the small lock assembly that was inside the padlock. 

Fun fact: hard to believe, but the cheapest lock I could find had three spool pins and only one regular driver pin in it.



Thursday, September 22, 2011

Quote of the day

I don't normally do Quote of the Day posts because I think that pretty much amounts to taking someone Else's information and regurgitating it on your own blog.  That's part of the reason why my blog is so rarely updated.  I like to populate my blog with either original ideas or information that was hard to come by on the Internet before I found it.

That said, I was reading a paper from the Society of Actuaries on Modern Operational Risk and there was a statement that really jumped out at me.  "... the top few losses from a relevant 200 company-year data set is much more valuable than even a million hard data points from one institution collected over a five year period."  That really jumped out at me because in my own treatment of risk management I have been known to favor the idea that my organization needed to collect data points and use that to create distributions.  But as the document points out, if the events that we are trying to model are independent, then ten years of data from 20 companies is roughly equivalent to 200 years of data from a single company. 

I don't know if I am ready to accept that one year of data from 200 companies is of equal value, but the paper I'm reading hasn't made that assertion either.  Here is the paper if you feel like reading it.  I am really enjoying it so far.
www.soa.org/files/pdf/research-new-approach.pdf