Posts Tagged rubygems

Lock down a Rails 3 app with a single password using lock

This tutorial shows you more about the power and simplicity of Rails 3 Engines. When I release a new feature for one of my  production Rails apps (or an entirely new app) that needs to be beta tested by a select group of people, it is usually necessary to password protect part or all of the application.  A quick and dirty way to do this is to use basic http authentication with Nginx. Previously, I would choose this method because it is fairly easy to set up and it allowed me to create a single username and password for an entire group of testers, without having to modify the user authentication system that I use inside my Rails apps. If you are using nginx, then you can add something like this to the nginx.conf file:
It is also necessary to create the htpasswd file and add the user name and password hash.  The password hash can be generated using Ruby’s String crypt method.  When users visit the protected URL, the basic http auth browser popup is displayed and if they enter the correct login information, they gain access to the protected URL.  While this setup is fairly simple, I prefer staying within Rails to achieve this and having more control over the login page, etc.  HTTP Basic Authentication is a bit too basic for me. I decided to create a simple Rails 3 Engine that would allow me to easily lock down controller/actions and customize the login and error pages.  I call this one lock. Note that this will not protect your public assets, only the Rails actions… so you may want to lock down your server using http basic if you need public assets protected as well.

Here is how you use it in your own application:

1. Install the gem

#Gemfile
gem “lock”
cowboycoded$  bundle install

2. Generate the password file

cowboycoded$  rails g lock:create_password_file yourpasswordhere

3. Add the lock configuration to application_controller.rb

4. Unlock the app

visit this URL and enter the password you created with the generator

http://www.yoursitehere.com/lock/login

5. Override the views:

Login Page: /app/views/lock/login.html.erb #NOTE: POST to /lock/unlock and use a field named “password”
Refused Access Page: /app/views/lock/refused.html.erb
Unlock Confirmation Page: /app/views/lock/unlock.html.erb

By default, these views will render inside your default layout. To create a custom layout for these files, just add /app/views/layouts/lock.html.erb The layout must contain a yield.

TECH DETAILS ABOUT THE GEM

(if you are interested in how the gem was created)

The design around this was simple. Use a class method within the application_controller that accepts controllers & actions as parameters. The class method creates a before_filter and that takes these controllers & actions and compares them against the requested URL. If the URL matches the controller/action and the user has not unlocked the app, then access to the page is denied. Using Rails 3 engines makes it easy to add views and a LockController to handle the login, failed login and unlock confirmation pages. Here are the gory details about how this gem was created:

A Note about TESTING

I am using RSpec and Cucumber to test this engine.  Engines are a different beast than other gems, because they are so closely tied to Rails.  As a result of this, I prefer to create a new Rails 3 app inside my gem called “test_app” for any testing.  I have seen a few things out there about creating a dummy app, that I am guessing is a stripped down version of a real rails app, but I am not sure what the advantage is over a real Rails app for testing.  The footprint of a blank Rails app is not that large, so I doubt it is a concern about gem file size (which should not matter, since the test files are not packaged with the gem).  I still need to read up and give it a fair comparison, but for now I dont see a problem with using a real Rails app to test engines.

First, I bootstrap the “test_app” with rspec and cucumber.  Then I include the local path to the gem in the Gemfile:

#Gemfile

gem “lock”, :path=>”/my_plugins/lock”

Providing the path to the local gem, will tell Bundler to load the files in that directory as opposed to installed the packaged gem. This is necessary, in order to avoid building your gem after every code change. If I remember correctly, you will need to generate a gemspec in the root of the gem before you bundle install with the “path” option.

Start with a gem skelaton and make it an engine

The skelaton can be as simple as a “lib” directory and a file inside the lib directory named “lock.rb”. To make it an engine only one file is needed. I always call it “engine.rb” and place it within a subdirectory of lib that matches the name of my engine. So here is my directory structure so far:

/lock/lib/lock.rb
/lock/lib/lock/engine.rb

When the gem is loaded, it will first execute lock.rb, so the engine.rb file must be required in lock.rb:

The engine.rb file needs to subclass Rails::Engine, require rails and lock itself, in order to make it an engine that Rails can load:

Now the gem can function as an engine. So what does that really mean? Well for one, you use the same directory structure as you would in a normal Rails app. And you can add initializers to engine.rb to interact with rails when it is loading at boot.

Add the Rails-like directory structure

Take a look at my Rails-like directory structure:

The helper & model directories are not necessary for this gem, but I went ahead and added them in case I need them later.

Add the views & controllers

As I mentioned earlier I have 3 views that I use for the login form, unlock confirmation, and refusal page… there is not much to these views. Rails Engines also allow you to add routes, so I placed mine in /lock/config/routes.rb. Most of the code (and its not really much) is in the controllers. I have a lock_controller that handles the login. As you can see, it just checks to see if the form password is equal to the generated password. I placed the “password_match?” method in /lib/lock.rb, to reduce the logic in the controller.

I wrote a few blogs in March about how Rails prevents you from reopening engine classes. Basically, if you have the file in the parent Rails app, then the one in the engine is ignored. For this reason, I was not able to create a file named “application_contoller.rb” and simply add my methods to it. In order to make this work, I have to use a different file name (lock_application_controller.rb) and include/extend the methods into action_controller using an initializer. Here is what the module looks like:

When you create a class method and put it in action_controller, then application_controller can call this method and make it look like a nice DSL (as you can see in step #3 of the gem installation tutorial). So this class method just adds a before_filter and an instance method is created that matches what the before_filter is calling. lock_filter checks to see if it is a locked action and if the user has already unlocked the app. It redirects them to the refusal URL if they have not unlocked and the action is on the lock list. Note that you may prefer to use ActiveSupport::Concern when coding a module that includes instance methods and extends class methods. I am not using it here, but many find the syntax a bit sweeter, so if you dont know about it then google it.

Use an initializer to include the instance methods and extend the class methods in action_controller

There is a pretty cool feature in Rails 3, which allows you to lazy load code in initializers. Check out Simone Carletti’s tutorial on Lazy Load Hooks for details on how this works. In short, when action_controller is loaded, our code can be placed in that class. So I want to include/extend my methods in action_controller. Here is what the engine.rb file looks like after I add this code:

I find that the engine.rb is the best place to put code that dynamically modifies classes at boot. It gives you a central location where you can place all of these calls, and IMO makes engines easier to read. You know exactly what modifications are being made to Rails, just by looking at the engine file.

Creating the password generator

The last piece of the puzzle is to create a Rails generator to spit out our hashed password file. When you make your gem an engine, Rails automatically picks up your generator if you put it in the default path that is expected from an engine. Here is what the directory structure looks like:

So Rails is expecting this path for the generator class (expressing variables in uppercase):

/GEM_NAME/lib/generators/GEM_NAME/GENERATOR_NAME/GENERATOR_NAME_generator.rb

USAGE will allow rails to ouput some documentation for it, and the templates directory (which I don’t use in lock) can house any template files needed by the generator. The generator class is pretty basic:

Subclassing “Rails::Generators::Base” gives you the functionality you need to make this a generator. Any methods contained within this class will be executed. Notice that the argument class method is necessary to pull in the command line arg for the password. source_root will tell the generator where your templates are stored. This code generates a salt and a password hash from the password & salt combination and writes it to a file using the create_file method. You can read more about Rails generators HERE.

So there you have it. Pretty basic, but IMO useful. I hope you find this gem useful and also hope you learned something about Rails Engines. If you have any problems with this gem, leave me a comment or open a github issue. As always, suggestions are welcome, as well as criticism!

Tags: , ,

Application-wide variables for your Rails 3 app using Yettings

Application-wide settings for Rails apps can be very useful in many different scenarios.  For example, let’s say you want a place to store API keys for various 3rd party services used in your app.  Instead of hard-coding them in the model, I think it is much cleaner to have a settings file where you store all of this information.  And to make things even easier, you should be able to define different values for dev, test, and production.  There are many ways to achieve this.  You can set some Ruby constants and namespace them or create a model that stores these settings in the database.  I prefer a simpler solution that does not require much setup.  Initially I was using settingslogic, which I found very useful, but I decided to take this a bit further and build a plugin that I could maintain and one that fits my needs.  Yettings is what I came up with.  While very much inspired by settingslogic, the key difference is not having to define a class along with your YAML file.  The class you will use to access your key/value pairs is created dynamically at boot time, based on the name of the yml file in your config directory.

Here is how you use Yettings in your own app:

Install the gem

Add Yettings to your Gemfile and “bundle install”

#Gemfile
gem “yettings”
#command line
> bundle install

Create a YAML file: app/config/yetting.yml

This file will define all of your key/value pairs. Include all relevant key/value pairs in the default section and anything related to a specific environment in the dev, test, production sections. Note that custom environments will also work without any additional setup. staging for example. Any valid YAML will work, and you can also use erb within the YAML.

Access the values anywhere in your Rails app

Creating custom named Yettings

If you need separate Yettings for different pieces of your app (or if you are using this in a rails plugin), then you can add the yml file to a subdirectory named “yettings”. For instance:

app/config/yettings/main.yml
app/config/yettings/secondary.yml

Yettings will append the name you specified in camel case to the class that you access the values with:

I am using this with several of my rails apps and so far it seems to be working well. If you have any suggestions or issues, please leave me a comment or open up a github issue in the repo.

Tags: , ,

Working with private RubyGems in Rails 3

I have several gems that contain proprietary code that I do not want public to have access to.    Rubygems.org is great for gem hosting, but they do not allow security restricted gems, since it defeats the purpose of having an open community for ruby gems.  There are several options if you want to host your own gems and restrict access to them.  Here are some of the options that I considered

1. Install gemcutter and use that for a gem server.

2. Install the geminabox sinatra app.  This is a lightweight gem server with a web interface.

3. Use github.  They no longer build gems, but you can still install from github using Bundler (or a plain rake task).

I started playing around with the first 2 options, but I ultimately decided to just use the github solution.  Why waste resources setting up a private server when my code is already stored on github with security.  I am assuming you know how to set up a project on github, password protect it and push your gem source to github.

Git’r tagged

Probably one of the coolest parts of working with gems is being able to install specific versions of a gem in your project.. which is much easier than using vendor plugins.  In order to keep track of your versions you need to work with git tags.  You could also do this with branches, but it would get a bit hairy if you created a new branch for every patch version.  A good example of the proper way to set this up is the Ruby on Rails source on github – > http://github.com/rails/rails.  Click the drop-down where it says “Switch Branches”.  You can see they have a branch for every minor & major version 1.2, 2.0, 2.1, 2.2, 2.3, and 3.0 (master).  But notice that you do not see branches for minor versions like 2.3.8.  They use git tags to keep track of each version instead.  Click “Switch Tags” on the rails source github page.  Here you can see they created a separate tag for each version.  You will want to do the same with your private gems that you host on github.

Jeweler to the rescue

Luckily, jeweler has already done most of the work for us.  Install jeweler first:

gem install jeweler

Jeweler provides some nice shortcuts for creating, building and installing your gems. Take a look at the documentation for more info. I am only going to touch on the versioning that is included with this gem. After you create a project with Jeweler, you get a rakefile that gives you building and versioning tasks. Lets say you make a bunch of changes in your gem project, commit and push them to github and you are ready to bump this gem to a new version. You can use these Jeweler rake tasks to accomplish that:

rake version:bump:patch
#you can also use version:bump:minor and version:bump:major.. 1.2.3 -> 1=major, 2=minor, 3=patch
rake github:release
rake git:release

Jeweler also has a rake task called “release”. This will accomplish the 3 tasks above, but it also tries to push the gem to gemcutter. I could not find a way to turn that off in the documentation (although it may be possible.. I have not looked at the source in depth). I opted to write some custom tasks that combine these 3 tasks into a single task. So I added this to my rakefile:

namespace :version do
  desc "create a new version, create tag and push to github"
  task :github_and_tag do
    Rake::Task['github:release'].invoke
    Rake::Task['git:release'].invoke
  end

  task :patch_release do
    Rake::Task['version:bump:patch'].invoke
    Rake::Task['version:github_and_tag'].invoke
  end

  task :minor_release do
    Rake::Task['version:bump:minor'].invoke
    Rake::Task['version:github_and_tag'].invoke
  end

  task :major_release do
    Rake::Task['version:bump:major'].invoke
    Rake::Task['version:github_and_tag'].invoke
  end
end

The first tasks takes care of the git tag and github commit/push. The other 3 tasks use the first task and add the version bump for major, minor or patch. So now if I want to do a new patch version, I just have to execute one rake task.

rake version:patch_release

That is half of the equation. The other half is installing the gem from github in your Rails 3 project with Bundler.

Bundler takes care of the rest

Bundler ships with Rails 3 and its purpose is gem dependency management. I really like this tool so far, and the development seems to be moving along very fast. I learned a little trick when I was trying to see if something was fixed in Rails Edge. You can specify github as the source of the gem and it will pull the source code from github, build it and install it for you. You can even specify the tag which makes life even easier. So all I have to do is add one line to the Gemfile in my Rails 3 project and install the bundle. Check this out:

Gemfile

gem ‘mygem’, :git => ‘git@github.com:myuserid/mygem.git’, :tag=>”v1.0.2″
bundle install

Now that is easy!

Tags: , , , , ,