Rails Recipe: NIS/YP Login for Ruby on Rails (RoR)

Tilo Sloboda, Jan 2006


Most examples of Rails login controllers in books assume you store the user passwords in your database. This may be good for applications where you have 'random' users sign-up via the web. However in an enterprise environment you want to leverage the existing NIS/YP infrastructure or LDAP infrastructure, and not maintain user passwords in your application. Usually in a large enterprise environment all the user data is stored/maintained in LDAP, and the data from the NIS database is fed from the LDAP master.

This Rails recipe shows how to use check user passwords against an existing NIS/YP server.

Ingredients:

You will need the 'ruby-nis' library from Takaaki Tateishi, which is available at http://sourceforge.net/projects/ruby-nis/ and http://raa.ruby-lang.org/project/ruby-nis/ .   You will need to download it, un-tar it, and then do a 'ruby extconf.rb' to create a Makefile. After that you need to run 'make' and 'make install' as root.  After you installed the Ruby NIS library, you can start an irb session and type:  require 'irb'
If the result is 'true', then the library installation succeeded.

You need to make sure that the machine where you intend to run/develop your Rails application on has a working NIS/YP setup.
You can type "ypwhich" to verify that it can bind to a NIS server -- this UNIX command should yield the name of the NIS-server.

Implementation:

Go to your Rails application's directory.
ruby script/generate migration add_user_table

Then fill out the migration code to look like this:
class AddUserTable < ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      t.column "nis_userid", :string           # a user's UNIX user name, e.g. 'tilo'
      t.column "unix_uid", :integer           # a user's UNIX UID, e.g. '1001'
      t.column "unix_gid", :integer           # a user's UNIX GID, e.g. '123'
      t.column "fullname", :string             # a user's full name - taken from NIS - e.g. 'Tilo Sloboda'
      t.column "homedir", :string              # a user's home directory, e.g. '/home/tilo'
      t.column "first_login", :datetime
      t.column "last_login", :datetime
    end
  end

  def self.down
    drop_table :users
  end
end
This user record captures most of what is stored in NIS, but please note that it does not capture or store the user's password. The benefit of this is that the user can maintain/change his/her password in a central location (usually provided by IT), and that you don't have to worry about users who change or forget their passwords.

Please note that the userid above is the user's UNIX user-id. Do not confuse this with user.id, which refers to the primary key 'id" of the user table.

We will have to make sure that a user's record only gets created after s/he successfully logs in.

We can now use the migration above to generate the database table with the following command:
rake migrate
Next, we will need an Active Record model to support our new table:
ruby script/generate model User
Please note that we will not generate any users manually through an admin interface!  The reason is simple: our application is not authoritative to create new users - it's merely a consumer of the user records which are already stored in NIS/YP!    The authoritative source is either LDAP or NIS.