require File.dirname(__FILE__) + '/../test_helper'
require 'openid_controller'
require 'crypto_methods'

# Re-raise errors caught by the controller.
class OpenidController; def rescue_action(e) raise e end; end

class OpenidControllerTest < Test::Unit::TestCase
  def setup
    @controller = OpenidController.new
    @request    = ActionController::TestRequest.new
    @response   = ActionController::TestResponse.new
  end

  def parse_response
    @response.instance_eval {
      @kv = body.parsekv
      def method_missing symbol, *args
        @kv[symbol.to_s] or raise NoMethodError(symbol.to_s)
      end
    }
  end

  def test_invalid_mode
    post :server, :controller=>'openid', 'openid.mode'=>'invald'
    assert_response 400
    assert_tag :tag=>'p', :content => 'openid.mode is missing or invalid'
  end

  def test_associate_cleartext
    post :server, :controller=>'openid', 'openid.mode'=>'associate'
    assert_response :success

    parse_response

    assert_match /^([A-Za-z0-9+\/]+=*)$/, @response.mac_key
    assert_match /^\{HMAC-SHA1\}\d+\/\d+$/, @response.assoc_handle
    assert_equal 7200, @response.expires_in.to_i
    assert_equal 'HMAC-SHA1', @response.assoc_type

    assoc = Assoc.find :first, :conditions=>['handle=?',@response.assoc_handle]
    assert_equal @response.mac_key.unbase64, assoc.secret
  end

  def test_associate_dh_sha1
    dh = DiffieHellman.new

    post :server, :controller=>'openid', 'openid.mode'=>'associate',
      'openid.session_type'=>'DH-SHA1',
      'openid.dh_consumer_public'=>dh.createKeyExchange.btwoc.base64
    assert_response :success

    parse_response

    assert_match /^([A-Za-z0-9+\/]+=*)$/, @response.enc_mac_key
    assert_match /^([A-Za-z0-9+\/]+=*)$/, @response.dh_server_public
    assert_match /^\{HMAC-SHA1\}\d+\/\d+$/, @response.assoc_handle
    assert_equal 7200, @response.expires_in.to_i
    assert_equal 'HMAC-SHA1', @response.assoc_type

    dh_shared = 
      dh.decryptKeyExchange(@response.dh_server_public.unbase64.unbtwoc)
    assoc = Assoc.find :first, :conditions=>['handle=?',@response.assoc_handle]
    assert_equal assoc.secret, 
      @response.enc_mac_key.unbase64 ^ dh_shared.btwoc.sha1
  end

  def test_associate_missing_dh_consumer_public
    post :server, :controller=>'openid', 'openid.mode'=>'associate',
      'openid.session_type'=>'DH-SHA1'
    assert_response 400
    assert_tag :tag=>'p', 
      :content => 'openid.dh_consumer_public is missing or invalid'
  end

  def test_associate_invalid_session_type
    post :server, :controller=>'openid', 'openid.mode'=>'associate',
      'openid.session_type'=>'invalid'
    assert_response 400
    assert_tag :tag=>'p', 
      :content => 'openid.session_type is missing or invalid'
  end
end
