]> git.openstreetmap.org Git - rails.git/commitdiff
Add ROTS gem to vendor tree as it's not in the public GEM repos
authorTom Hughes <tom@compton.nu>
Thu, 13 May 2010 11:07:31 +0000 (12:07 +0100)
committerTom Hughes <tom@compton.nu>
Thu, 13 May 2010 11:07:31 +0000 (12:07 +0100)
vendor/gems/rots-0.2.1/AUTHORS [new file with mode: 0644]
vendor/gems/rots-0.2.1/README [new file with mode: 0644]
vendor/gems/rots-0.2.1/Rakefile [new file with mode: 0644]
vendor/gems/rots-0.2.1/bin/rots [new file with mode: 0755]
vendor/gems/rots-0.2.1/lib/rots.rb [new file with mode: 0644]
vendor/gems/rots-0.2.1/lib/rots/identity_page_app.rb [new file with mode: 0644]
vendor/gems/rots-0.2.1/lib/rots/server_app.rb [new file with mode: 0644]
vendor/gems/rots-0.2.1/lib/rots/test_helper.rb [new file with mode: 0644]
vendor/gems/rots-0.2.1/rots.gemspec [new file with mode: 0644]
vendor/gems/rots-0.2.1/spec/server_app_spec.rb [new file with mode: 0644]
vendor/gems/rots-0.2.1/spec/spec_helper.rb [new file with mode: 0644]

diff --git a/vendor/gems/rots-0.2.1/AUTHORS b/vendor/gems/rots-0.2.1/AUTHORS
new file mode 100644 (file)
index 0000000..ad2dd89
--- /dev/null
@@ -0,0 +1,2 @@
+* Roman Gonzalez <romanandreg@gmail.com>
+* Anibal Rojas <anibal@rojas.net.ve>
\ No newline at end of file
diff --git a/vendor/gems/rots-0.2.1/README b/vendor/gems/rots-0.2.1/README
new file mode 100644 (file)
index 0000000..5369cc6
--- /dev/null
@@ -0,0 +1,64 @@
+= Ruby OpenID Test Server (ROTS), a dummy OpenID server that makes consumer tests dead easy.
+
+ROTS is a minimal implementation of an OpenID server, developed on top of the Rack middleware, this
+server provides an easy to use interface to make testing OpenID consumers really easy.
+
+== No more mocks
+
+Have you always wanted to test the authentication of an OpenID consumer implementation, but find your self 
+in a point where is to hard to mock? A lot of people have been there. 
+
+With ROTS, you only need to specify an identity url provided by the dummy server, passing with it a flag
+saying that you want the authentication to be successful. It handles SREG extensions as well.
+
+== How does it works
+
+When you install the ROTS gem, a binary called rots is provided for starting the server (for more
+info about what options you have when executing this file, check the -h option). 
+
+By default, rots will have a test user called "John Doe", with an OpenID identity "john.doe". 
+If you want to use your own test user name, you can specify a config file to rots. The
+default configuration file looks like this:
+
+# Default configuration file
+identity: john.doe
+sreg:
+  nickname: jdoe
+  fullname: John Doe
+  email: jhon@doe.com
+  dob: 1985-09-21
+  gender: M
+
+You can specify a new config file using the option --config.
+
+== Getting Started
+
+The best way to get started, is running the rots server, and then starting to execute your OpenID consumer tests/specs. You just have to specify the identity url of your test user, if you want the OpenID response be successful just add the openid.success=true flag to the user identity url. If you don't specify the flag it 
+will return a cancel response instead.
+
+Example:
+
+it "should authenticate with OpenID" do
+  post("/consumer_openid_login", 'identity_url' => 'http://localhost:1132/john.doe?openid.success=true')
+end
+
+== Copyright
+
+Copyright (C) 2009 Roman Gonzalez <romanandreg@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/gems/rots-0.2.1/Rakefile b/vendor/gems/rots-0.2.1/Rakefile
new file mode 100644 (file)
index 0000000..7dd59be
--- /dev/null
@@ -0,0 +1,125 @@
+# Rakefile for Rack.  -*-ruby-*-
+require 'rake/rdoctask'
+require 'rake/testtask'
+require 'spec/rake/spectask'
+
+
+desc "Run all the tests"
+task :default => [:spec]
+
+desc "Do predistribution stuff"
+task :predist => [:changelog, :rdoc]
+
+
+desc "Make an archive as .tar.gz"
+task :dist => [:fulltest, :predist] do
+  sh "git archive --format=tar --prefix=#{release}/ HEAD^{tree} >#{release}.tar"
+  sh "pax -waf #{release}.tar -s ':^:#{release}/:' RDOX SPEC ChangeLog doc"
+  sh "gzip -f -9 #{release}.tar"
+end
+
+# Helper to retrieve the "revision number" of the git tree.
+def git_tree_version
+  #if File.directory?(".git")
+  #  @tree_version ||= `git describe`.strip.sub('-', '.')
+  #  @tree_version << ".0"  unless @tree_version.count('.') == 2
+  #else
+    $: << "lib"
+    require 'rots'
+    @tree_version = Rots.release
+  #end
+  @tree_version
+end
+
+def gem_version
+  git_tree_version.gsub(/-.*/, '')
+end
+
+def release
+  "ruby-openid-tester-#{git_tree_version}"
+end
+
+def manifest
+  `git ls-files`.split("\n")
+end
+
+desc "Generate a ChangeLog"
+task :changelog do
+  File.open("ChangeLog", "w") do |out|
+    `git log -z`.split("\0").map do |chunk|
+      author = chunk[/Author: (.*)/, 1].strip
+      date   = chunk[/Date: (.*)/, 1].strip
+      desc, detail = $'.strip.split("\n", 2)
+      detail ||= ""
+      detail.rstrip!
+      out.puts "#{date}  #{author}"
+      out.puts "  * #{desc.strip}"
+      out.puts detail  unless detail.empty?
+      out.puts
+    end
+  end
+end
+
+
+begin
+  require 'rubygems'
+
+  require 'rake'
+  require 'rake/clean'
+  require 'rake/packagetask'
+  require 'rake/gempackagetask'
+  require 'fileutils'
+rescue LoadError
+  # Too bad.
+else
+  spec = Gem::Specification.new do |s|
+    s.name            = "rots"
+    s.version         = gem_version
+    s.platform        = Gem::Platform::RUBY
+    s.summary         = "an OpenID server for making tests of OpenID clients implementations"
+
+    s.description = <<-EOF
+Ruby OpenID Test Server (ROST) provides a basic OpenID server made in top of the Rack gem.
+With this small server, you can make dummy OpenID request for testing purposes,
+the success of the response will depend on a parameter given on the url of the authentication request.
+    EOF
+
+    s.files           = manifest
+    s.bindir          = 'bin'
+    s.executables     << 'rots'
+    s.require_path    = 'lib'
+    s.has_rdoc        = true
+    s.extra_rdoc_files = ['README']
+    s.test_files      = Dir['spec/*_spec.rb']
+
+    s.author          = 'Roman Gonzalez'
+    s.email           = 'romanandreg@gmail.com'
+    s.homepage        = 'http://github.com/roman'
+    s.rubyforge_project = 'rots'
+
+    s.add_development_dependency 'rspec'
+    s.add_development_dependency 'rack'
+    s.add_development_dependency 'ruby-openid', '~> 2.0.0'
+  end
+
+  Rake::GemPackageTask.new(spec) do |p|
+    p.gem_spec = spec
+    p.need_tar = false
+    p.need_zip = false
+  end
+end
+
+Spec::Rake::SpecTask.new do |t|
+end
+
+desc "Generate RDoc documentation"
+Rake::RDocTask.new(:rdoc) do |rdoc|
+  rdoc.options << '--line-numbers' << '--inline-source' <<
+    '--main' << 'README' <<
+    '--title' << 'ROTS Documentation' <<
+    '--charset' << 'utf-8'
+  rdoc.rdoc_dir = "doc"
+  rdoc.rdoc_files.include 'README'
+  rdoc.rdoc_files.include('lib/ruby_openid_test_server.rb')
+  rdoc.rdoc_files.include('lib/ruby_openid_test_server/*.rb')
+end
diff --git a/vendor/gems/rots-0.2.1/bin/rots b/vendor/gems/rots-0.2.1/bin/rots
new file mode 100755 (executable)
index 0000000..37dc1fe
--- /dev/null
@@ -0,0 +1,94 @@
+#!/usr/bin/env ruby
+# -*- ruby -*-
+
+$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
+require "rubygems"
+require "optparse"
+require "rack"
+require "rots"
+
+server_options = {
+  :debugger => false,
+  :port => 1123,
+  :verbose => true,
+  :storage => File.join('.', 'tmp', 'rots'),
+  :config => <<-DEFAULT_CONFIG
+# Default configuration file
+identity: john.doe
+sreg:
+  nickname: jdoe
+  fullname: John Doe
+  email: jhon@doe.com
+  dob: 1985-09-21
+  gender: M
+
+  DEFAULT_CONFIG
+}
+
+opts = OptionParser.new do |opts|
+  opts.banner = "Usage: rots [options]"
+  
+  opts.separator ""
+  opts.separator "Options:"
+  
+  opts.on("-p", "--port PORT",
+            "use PORT (default: 1123)") do |port|
+    server_options[:port] = port
+  end
+  
+  opts.on("-s", "--storage PATH",
+            "use PATH as the OpenID Server storage path (default: ./tmp/rots)") do |storage_path|
+    server_options[:storage] = storage_path
+  end
+  
+  opts.on("-c", "--config FILE.yaml",
+            "server configuration YAML file") do |config_path|
+    abort "\x1B[31mConfiguration file #{config_path} not found\x1B[0m" unless File.exists?(config_path)
+    server_options[:config] = File.new(config_path)
+  end
+  
+  opts.on("-s", "--silent",
+            "If specified, the server will be in silent mode") do 
+    server_options[:verbose] = false
+  end
+  
+  opts.on("-d", "--debugger") do
+    server_options[:debugger] = true
+  end
+  
+  opts.separator ""
+  opts.separator "Common options:"
+  
+  opts.on_tail("-h", "--help", "Show this help message") do
+    puts opts
+    exit
+  end
+  
+end
+
+opts.parse!(ARGV)
+
+config = YAML.load(server_options[:config])
+
+require "ruby-debug" if server_options[:debugger]
+
+server = Rack::Builder.new do 
+  use Rack::Lint
+  if server_options[:verbose]
+    use Rack::CommonLogger, STDOUT
+    use Rack::ShowExceptions
+  end
+  map ("/%s" % config['identity']) do
+    run Rots::IdentityPageApp.new(config, server_options)
+  end
+  map "/server" do
+    run Rots::ServerApp.new(config, server_options)
+  end
+end
+
+puts "\x1B[32mRunning OpenID Test server on port 1123\x1B[0m" if server_options[:verbose]
+begin 
+  Rack::Handler::Mongrel.run server, :Port => server_options[:port]
+rescue LoadError
+  Rack::Handler::WEBrick.run server, :Port => server_options[:port]
+end
diff --git a/vendor/gems/rots-0.2.1/lib/rots.rb b/vendor/gems/rots-0.2.1/lib/rots.rb
new file mode 100644 (file)
index 0000000..644416c
--- /dev/null
@@ -0,0 +1,11 @@
+module Rots
+  
+  def self.release
+    "0.2.1"
+  end
+  
+end
+
+require "rots/server_app"
+require "rots/identity_page_app"
+require "rots/test_helper"
diff --git a/vendor/gems/rots-0.2.1/lib/rots/identity_page_app.rb b/vendor/gems/rots-0.2.1/lib/rots/identity_page_app.rb
new file mode 100644 (file)
index 0000000..09d70db
--- /dev/null
@@ -0,0 +1,36 @@
+require 'rack/request'
+require 'rack/response'
+require 'rack/utils'
+require 'openid'
+
+class Rots::IdentityPageApp 
+  
+  def initialize(config, server_options)
+    @server_options = server_options
+    @config = config
+  end
+  
+  def call(env)
+    @request = Rack::Request.new(env)
+    Rack::Response.new do |response|
+      response.write <<-HERE
+<html>
+  <head>
+  <link rel="openid2.provider" href="#{op_endpoint}" />
+  <link rel="openid.server" href="#{op_endpoint}" />
+  </head>
+  <body>
+    <h1>This is #{@config['identity']} identity page</h1>
+  </body>
+</html>
+      HERE
+    end.finish
+  end
+  
+  def op_endpoint
+    "http://%s:%d/server/%s" % [@request.host, 
+                           @request.port, 
+                           (@request.params['openid.success'] ? '?openid.success=true' : '')]
+  end
+  
+end
\ No newline at end of file
diff --git a/vendor/gems/rots-0.2.1/lib/rots/server_app.rb b/vendor/gems/rots-0.2.1/lib/rots/server_app.rb
new file mode 100644 (file)
index 0000000..e08595c
--- /dev/null
@@ -0,0 +1,147 @@
+require 'openid'
+require 'openid/extension'
+require 'openid/extensions/sreg'
+require 'openid/store/filesystem'
+require 'openid/util'
+require 'rack/request'
+require 'rack/utils'
+require 'fileutils'
+
+
+module Rots
+  
+  class ServerApp
+    
+    attr_accessor :request,:openid_request,
+                  :response, :openid_response,
+                  :server
+    
+    def initialize(config, server_options)
+      @server_options = server_options
+      @sreg_fields = config['sreg']
+    end
+    
+    def call(env)
+      on_openid_request(env) do
+        if !is_checkid_request?
+          @openid_response = @server.handle_request(@openid_request)
+          reply_consumer
+        elsif is_checkid_immediate?
+          process_immediate_checkid_request
+        else
+          process_checkid_request
+        end
+      end
+    end
+    
+    protected
+    
+    def on_openid_request(env)
+      create_wrappers(env)
+      if @openid_request.nil?
+        [200, {'Content-Type' => 'text/html'}, 
+          ["<html><body><h1>ROTS => This is an OpenID endpoint</h1></body></html>"] ]
+      else
+        yield
+      end
+    end
+    
+    def create_wrappers(env)
+      @request = Rack::Request.new(env)
+      @server  = OpenID::Server::Server.new(storage, op_endpoint)
+      @openid_request = @server.decode_request(@request.params)
+      @openid_sreg_request = OpenID::SReg::Request.from_openid_request(@openid_request) unless @openid_request.nil?
+    end
+    
+    def is_checkid_request?
+      @openid_request.is_a?(OpenID::Server::CheckIDRequest)
+    end
+    
+    def is_checkid_immediate?
+      @openid_request && @openid_request.immediate
+    end
+    
+    def process_immediate_checkid_request
+      # TODO: We should enable the user to configure
+      # if she wants immediate request support or not
+      url = OpenID::Util.append_args(@openid_request.return_to, 
+        @request.params.merge('openid.mode' => 'setup_needed'))
+      redirect(url)
+    end
+    
+    def process_checkid_request
+      if checkid_request_is_valid?
+        return_successful_openid_response
+      else
+        return_cancel_openid_response
+      end
+    end
+    
+    def checkid_request_is_valid?
+      @request.params['openid.success'] == 'true'
+    end
+    
+    def return_successful_openid_response
+      @openid_response = @openid_request.answer(true)
+      process_sreg_extension
+      # TODO: Add support for SREG extension
+      @server.signatory.sign(@openid_response) if @openid_response.needs_signing
+      reply_consumer
+    end
+    
+    def process_sreg_extension
+      return if @openid_sreg_request.nil?
+      response = OpenID::SReg::Response.extract_response(@openid_sreg_request, @sreg_fields)
+      @openid_response.add_extension(response)
+    end
+    
+    def return_cancel_openid_response
+      redirect(@openid_request.cancel_url)
+    end
+    
+    def reply_consumer
+      web_response = @server.encode_response(@openid_response)
+      case web_response.code
+      when OpenID::Server::HTTP_OK
+        success(web_response.body)
+      when OpenID::Server::HTTP_REDIRECT
+        redirect(web_response.headers['location'])
+      else
+        bad_request
+      end   
+    end
+
+    def redirect(uri)
+      [ 303, {'Content-Length'=>'0', 'Content-Type'=>'text/plain',
+        'Location' => uri},
+        [] ]
+    end
+
+    def bad_request()
+      [ 400, {'Content-Type'=>'text/plain', 'Content-Length'=>'0'},
+        [] ]
+    end
+    
+    def storage
+      # create the folder if it doesn't exist
+      FileUtils.mkdir_p(@server_options[:storage]) unless File.exist?(@server_options[:storage])
+      OpenID::Store::Filesystem.new(@server_options[:storage])
+    end
+    
+    def success(text="")
+      Rack::Response.new(text).finish
+    end
+    
+    def op_endpoint
+      if @request.url =~ /(.*\?openid.success=true)/
+        $1
+      elsif @request.url =~ /([^?]*)/
+        $1
+      else
+        nil
+      end
+    end
+
+  end
+
+end
\ No newline at end of file
diff --git a/vendor/gems/rots-0.2.1/lib/rots/test_helper.rb b/vendor/gems/rots-0.2.1/lib/rots/test_helper.rb
new file mode 100644 (file)
index 0000000..a7a91de
--- /dev/null
@@ -0,0 +1,16 @@
+require "openid/consumer"
+require "openid/consumer/checkid_request.rb"
+require "net/http"
+
+module Rots::TestHelper
+  
+  def openid_request(openid_request_uri)
+    openid_response = Net::HTTP.get_response(URI.parse(openid_request_uri))
+    openid_response_uri = URI(openid_response['Location'])
+    openid_response_qs = Rack::Utils.parse_query(openid_response_uri.query)
+    
+    { :url => openid_response_uri.to_s,
+      :query_params => openid_response_qs }
+  end
+  
+end
\ No newline at end of file
diff --git a/vendor/gems/rots-0.2.1/rots.gemspec b/vendor/gems/rots-0.2.1/rots.gemspec
new file mode 100644 (file)
index 0000000..0de2410
--- /dev/null
@@ -0,0 +1,31 @@
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+  s.name            = "rots"
+  s.version         = '0.2.1'
+  s.platform        = Gem::Platform::RUBY
+  s.summary         = "an OpenID server for making tests of OpenID clients implementations"
+
+  s.description = <<-EOF
+Ruby OpenID Test Server (ROST) provides a basic OpenID server made in top of the Rack gem.
+With this small server, you can make dummy OpenID request for testing purposes,
+the success of the response will depend on a parameter given on the url of the authentication request.
+  EOF
+
+  s.files           = ["AUTHORS", "README", "Rakefile", "bin/rots", "lib/rots.rb", "lib/rots/identity_page_app.rb", "lib/rots/server_app.rb", "lib/rots/test_helper.rb","rots.gemspec", "spec/server_app_spec.rb", "spec/spec_helper.rb"] 
+  s.bindir          = 'bin'
+  s.executables     << 'rots'
+  s.require_path    = 'lib'
+  s.has_rdoc        = true
+  s.extra_rdoc_files = ['README']
+  s.test_files      = ['spec/server_app_spec.rb', 'spec/spec_helper.rb']
+
+  s.author          = 'Roman Gonzalez'
+  s.email           = 'romanandreg@gmail.com'
+  s.homepage        = 'http://github.com/roman'
+  s.rubyforge_project = 'rots'
+
+  s.add_development_dependency 'rspec'
+  s.add_development_dependency 'rack'
+  s.add_development_dependency 'ruby-openid'
+end
diff --git a/vendor/gems/rots-0.2.1/spec/server_app_spec.rb b/vendor/gems/rots-0.2.1/spec/server_app_spec.rb
new file mode 100644 (file)
index 0000000..f76d689
--- /dev/null
@@ -0,0 +1,99 @@
+require File.join(File.dirname(__FILE__), 'spec_helper')
+
+# This is just a comment test
+
+describe Rots::ServerApp do
+
+  describe "when the request is not an OpenID request" do
+
+    it "should return a helpful message saying that is an OpenID endpoint" do
+      request  = Rack::MockRequest.new(Rots::ServerApp.new({'sreg' => {}}, 
+        {:storage => File.join(*%w(. tmp rots)) }))
+      response = request.get("/")
+      response.should be_ok
+      response.body.should == "<html><body><h1>ROTS => This is an OpenID endpoint</h1></body></html>"
+    end
+
+  end
+
+  describe "when the request is an OpenID request" do
+    
+    before(:each) do
+      @request = Rack::MockRequest.new(Rots::ServerApp.new({
+        'identity' => 'john.doe',
+        'sreg' => {
+          'email' => "john@doe.com",
+          'nickname' => 'johndoe',
+          'fullname' => "John Doe",
+          'dob' => "1985-09-21",
+          'gender' => "M"
+        }},
+        {:storage => File.join(*%w(. tmp rots))}
+      ))
+    end
+    
+
+    describe "and it is a check_id request" do
+
+      describe "and is immediate" do
+
+        it "should return an openid.mode equal to setup_needed" do
+          response = checkid_immediate(@request)
+          params = openid_params(response)
+          params['openid.mode'].should == 'setup_needed'
+        end
+
+      end
+
+      describe "and is not immediate" do
+
+        describe "with a success flag" do
+
+          it "should return an openid.mode equal to id_res" do
+            response = checkid_setup(@request, 'openid.success' => 'true')
+            params = openid_params(response)
+            params['openid.mode'].should == 'id_res'
+          end
+
+        end
+
+        describe "without a success flag" do
+
+          it "should return an openid.mode equal to cancel" do
+            response = checkid_setup(@request)
+            params = openid_params(response)
+            params['openid.mode'].should == 'cancel'
+          end
+
+        end
+        
+        describe "using SREG extension with a success flag" do
+          
+          it "should return an openid.mode equal to id_res" do
+            response = checkid_setup(@request, 'openid.success' => 'true')
+            params = openid_params(response)
+            params['openid.mode'].should == 'id_res'
+          end
+          
+          it "should return all the sreg fields" do
+            response = checkid_setup(@request, {
+              'openid.success' => true,
+              'openid.ns.sreg' => OpenID::SReg::NS_URI,
+              'openid.sreg.required' => 'email,nickname,fullname',
+              'openid.sreg.optional' => 'dob,gender'
+            })
+            params = openid_params(response)
+            params['openid.sreg.email'].should == "john@doe.com"
+            params['openid.sreg.nickname'].should == 'johndoe'
+            params['openid.sreg.fullname'].should == "John Doe"
+            params['openid.sreg.dob'].should == "1985-09-21"
+            params['openid.sreg.gender'].should == "M"
+          end
+          
+        end
+      
+      end
+    end
+  end
+
+end
\ No newline at end of file
diff --git a/vendor/gems/rots-0.2.1/spec/spec_helper.rb b/vendor/gems/rots-0.2.1/spec/spec_helper.rb
new file mode 100644 (file)
index 0000000..3dae012
--- /dev/null
@@ -0,0 +1,73 @@
+$:.unshift(File.dirname(__FILE__), '..', 'lib')
+require "rubygems"
+require "spec"
+require "rack"
+require "rots"
+
+module Rots::RequestHelper
+  
+  def checkid_setup(request, params={}, with_associate=true)
+    assoc_handle = make_association(request) if with_associate
+    send_checkid(request, :setup, params, assoc_handle)
+  end
+  
+  def checkid_immediate(request, params={}, with_associate=true)
+    assoc_handle = make_association(request) if with_associate
+    send_checkid(request, :immediate, params, assoc_handle)
+  end
+  
+  def openid_params(response)
+    uri = URI(response.headers['Location'])
+    Rack::Utils.parse_query(uri.query)
+  end
+  
+  protected
+  
+  def send_checkid(request, mode, params={}, assoc_handle = nil)
+    params = self.send(:"checkid_#{mode}_params", params)
+    params.merge('openid.assoc_handle' => assoc_handle) if assoc_handle
+    qs = "/?" + Rack::Utils.build_query(params)
+    request.get(qs)
+  end
+
+  def make_association(request)
+    associate_qs = Rack::Utils.build_query(associate_params)
+    response = request.post('/', :input => associate_qs)
+    parse_assoc_handle_from(response)
+  end
+  
+  def parse_assoc_handle_from(response)
+    response.body.split("\n")[0].match(/^assoc_handle:(.*)$/).captures[0]
+  end
+  
+  def checkid_setup_params(params = {})
+    {
+      "openid.ns" => "http://specs.openid.net/auth/2.0",
+      "openid.mode" => "checkid_setup",
+      "openid.claimed_id" => 'john.doe',
+      "openid.identity" => 'john.doe',
+      "openid.return_to" => "http://www.google.com"
+      # need to specify the openid_handle by hand
+    }.merge!(params)
+  end
+  
+  def checkid_immediate_params(params = {})
+    checkid_setup_params({'openid.mode' => 'checkid_immediate'}.merge!(params))
+  end
+  
+  def associate_params
+    {
+      "openid.ns" => "http://specs.openid.net/auth/2.0",
+      "openid.mode" => "associate",
+      "openid.session_type" => "DH-SHA1",
+      "openid.assoc_type" => "HMAC-SHA1",
+      "openid.dh_consumer_public" =>
+      "U672/RsDUNxAFFAXA+ShVh5LMD2CRdsoqdqhDCPUzfCNy2f44uTWuid/MZuGfJmiVA7QmxqM3GSb8EVq3SGK8eGEwwyzUtatqHidx72rfwAav5AUrZTnwSPQJyiCFrKNGmNhXdRJzcfzSkgaC3hVz2kpADzEevIExG6agns1sYY="
+    }
+  end
+  
+end
+
+Spec::Runner.configure do |config|
+  config.include Rots::RequestHelper
+end
\ No newline at end of file