4

I'm restricting access to the settings page of my Sinatra app with the following code, from the Sinatra docs.

helpers do 
  def protected!
    unless authorized?
      response['WWW-Authenticate'] = %(Basic realm="Access restricted")
      throw(:halt, [401, "Login incorrect\n"])
    end
  end

  def authorized?
    @auth ||=  Rack::Auth::Basic::Request.new(request.env)
    @auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == ['admin', 'admin']
  end
end

before "/admin" do
  protected!
end

Is Rack::Auth identical to .htaccess basic auth?

Is there anything else I could or should do to secure it?

djb
  • 5,591
  • 5
  • 41
  • 47

1 Answers1

4

Yes it's the same. You could use Digest auth or if you want to stick with Basic you could make sure it uses SSL.

Basic and Digest example:

https://github.com/sinatra/sinatra-book-contrib/blob/master/middleware/rack_auth_basic_and_digest.md

HTTPS with Basic example app:

./config.ru

require 'rubygems'
require 'sinatra'
require 'haml'

require './app'

run App

./app.rb

class App < Sinatra::Application

  configure do
    set :haml, :format => :html5
    set :root, File.dirname(__FILE__)
    # more config stuff, db, mailers, file storage etc...
  end

end

# HELPERS
require 'helpers/helpers'

# CONTROLLER
require 'controller/admin'

./helpers/helpers.rb

module Sinatra
  module RegexpRouteFilter
    def before_with_regexp(pattern, &blk)
      before do
        instance_eval(&blk) if request.path =~ pattern
      end
    end
  end

  register RegexpRouteFilter
end

class App < Sinatra::Application
  helpers do
    def protected!
      unless authorized?
        response['WWW-Authenticate'] = %(Basic realm="Testing HTTP Auth")
        throw(:halt, [401, "Not authorized\n"])
      end
    end

    def authorized?
      @auth ||=  Rack::Auth::Basic::Request.new(request.env)
      @auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == ['user', 'pass']
    end
  end

  before_with_regexp(/^\/admin/) do
    if settings.environment == :production
      unless (@env['HTTP_X_FORWARDED_PROTO'] || @env['rack.url_scheme']) == 'https'
        redirect "https://#{request.env['HTTP_HOST']}#{request.env["REQUEST_PATH"]}"
      end
    end
    protected!
  end
end

./controller/admin.rb

class App < Sinatra::Application

  get '/admin' do
    haml :"admin/index"
  end

end

./views/admin/index.haml

%h1 Admin
%p Welcome!

Then run the app with the shotgun gem shotgun config.ru -p 4567

kreek
  • 8,774
  • 8
  • 44
  • 69
  • very interesting. thanks. grateful for the introduction to 'before_with_regexp' too. why are you wrapping the whole thing in the 'App' class and adding Sinatra::Partials? – djb Aug 26 '11 at 15:43
  • 1
    Woops, copied the code from one of my apps, I'll edit to remove `helpers Sinatra::Partials` and show the `before_with_regexp` module. Wrapping the code in the app class allows the app to be broken up across different files, similar to this http://stackoverflow.com/questions/5015471/using-sinatra-for-larger-projects-via-multiple-files – kreek Aug 26 '11 at 16:14