Generic (Fast)CGI handler to ease integration into current systems

Handles CGI requests using prepared HTML templates and Turing::Challenge object.

Example of use:

  #!/usr/bin/ruby
  require 'rubygems'
  gem 'turing'
  require 'turing'
  tcgi_config = {
      :imagepath => "/imgs",
      :outdir => '/home/wejn/ap/htdocs/imgs',
      :store => '/home/wejn/ap/data/turing.pstore',
      :redirect_to => 'http://localhost:8000/secured/',
  }
  tcgi_config[:on_success] = proc do
      out = {}
      out[:headers] = {
          "cookie" => CGI::Cookie.new({
              'name' => 'turing_passed',
              'value' => 'true',
              'path' => '/',
              'expires' => Time.now + 3600*24,
              }),
          "dude" => "you_rock!",
      }
      out
  end
  Turing::CGIHandler.new(tcgi_config).handle

This CGI script forces user to pass turing challenge. After he passes the test, he‘s given cookie turing_passed with value true and redirected to localhost:8000/secured/.

Please note: Using this script verbatim is like having no turing challenge at all — any non-braindead attacker will get around it in no time.

Methods
Classes and Modules
Class Turing::CGIHandler::Template
Public Class methods
new(options = {})

Configure instance using options hash.

Warning: Keys of this hash must be symbols.

Accepted options:

  • templatedir: directory where templates (challenge.rhtml, error.rhtml, success.rhtml) reside, by default it‘s set to gem‘s shared/templates/ directory.
  • on_success: proc object (or any object responding to call) which returns Hash. Recognized keys of the returned hash are headers and variables. Former are used as HTTP response headers, latter are used as variables for success template (if no redirect given).
  • redirect_to: redirect to this location on success. This can be also done by returning Location header in on_success‘s headers hash.
  • imagepath: path under which generated images are accessible.

Given hash will be also used to initialize Turing::Challenge object.

    # File lib/turing/cgi_handler.rb, line 65
65:         def initialize(options = {}) # {{{
66:                 @options = options
67:                 base = File.join(File.dirname(__FILE__), '..', '..', 'shared')
68:                 
69:                 if @options[:templatedir].nil?
70:                         @options[:templatedir] = File.join(base, 'templates')
71:                 end
72: 
73:                 begin
74:                         td = @options[:templatedir]
75:                         raise "not directory" unless FileTest.directory?(td)
76:                 rescue
77:                         error_response("Templatedir is invalid", $!)
78:                 end
79:                 
80:                 begin
81:                         @tc = Turing::Challenge.new(@options)
82:                 rescue
83:                         error_response("Unable to initialize Turing::Challenge class", $!)
84:                         exit 1
85:                 end
86:         end
Public Instance methods
handle(cgi = nil)

Handle incoming CGI request.

If you don‘t pass one, it will create it using CGI.new

     # File lib/turing/cgi_handler.rb, line 91
 91:         def handle(cgi = nil) # {{{
 92:                 cgi ||= CGI.new
 93: 
 94:                 if "POST" == cgi.request_method
 95:                         if @tc.valid_answer?(cgi["id"], cgi["solution"])
 96:                                 # process on_success
 97:                                 os = @options[:on_success]
 98:                                 if os.nil? || ! os.respond_to?(:call)
 99:                                         extra = verify_extra({}) # assure correct structure
100:                                 else
101:                                         extra = verify_extra(os.call)
102:                                 end
103: 
104:                                 # is there redir from config or from on_success?
105:                                 if @options[:redirect_to] || extra[:headers]["Location"]
106:                                         redirect_to(cgi, extra[:headers]["Location"] || \
107:                                                 @options[:redirect_to], extra)
108:                                 else
109:                                         success_response(cgi, extra)
110:                                 end
111:                         else
112:                                 show_challenge(cgi, true)
113:                         end
114:                 else
115:                         show_challenge(cgi)
116:                 end
117:         end