<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,3 +1,5 @@
+* Added logger
+
 === 0.0.2 / 2009-01-07
 
 * 1 major enhancement</diff>
      <filename>History.txt</filename>
    </modified>
    <modified>
      <diff>@@ -12,8 +12,10 @@ Casablanca is a single sign-on client for the CAS 2.0 protocol.
 
 == TODO:
 
-* Add logging
 * Add extra attributes returned from the server
+* /login
+  - add gateway
+  - make service optional
 * Implement gateway and proxy
 * Check for single signout
 * Check for endless redirects</diff>
      <filename>README.rdoc</filename>
    </modified>
    <modified>
      <diff>@@ -9,8 +9,8 @@ Hoe.new('casablanca', Casablanca::VERSION) do |p|
   p.remote_rdoc_dir = '' # Release to root  
 end
 
-# require 'metric_fu'
-# 
-# MetricFu::Configuration.run do |config|
-#   config.coverage = { :test_files =&gt; ['test/**/test_*.rb'] }
-# end
\ No newline at end of file
+require 'metric_fu'
+
+MetricFu::Configuration.run do |config|
+  config.coverage = { :test_files =&gt; ['test/**/test_*.rb'] }
+end
\ No newline at end of file</diff>
      <filename>Rakefile</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,8 @@ irb = RUBY_PLATFORM =~ /mswin32/ ? 'irb.bat' : 'irb'
 options = { :sandbox =&gt; false, :irb =&gt; irb }
 
 libs =  &quot; -r irb/completion&quot;
-libs &lt;&lt; &quot; -r #{File.dirname(__FILE__)}/../lib/casablanca.rb&quot;
-libs &lt;&lt; &quot; -r #{File.dirname(__FILE__)}/../lib/casablanca/cli.rb&quot;
+libs &lt;&lt; &quot; -r #{File.expand_path(File.dirname(__FILE__))}/../lib/casablanca.rb&quot;
+libs &lt;&lt; &quot; -r #{File.expand_path(File.dirname(__FILE__))}/../lib/casablanca/client.rb&quot;
+libs &lt;&lt; &quot; -r #{File.expand_path(File.dirname(__FILE__))}/../lib/casablanca/cli.rb&quot;
 
 exec &quot;#{options[:irb]} #{libs} --simple-prompt&quot;
\ No newline at end of file</diff>
      <filename>bin/casablanca</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,5 @@
 module Casablanca
-  VERSION = '0.0.2'
+  VERSION = '0.0.3'
 end
 require 'casablanca/client'
 require 'casablanca/response_parsers'
\ No newline at end of file</diff>
      <filename>lib/casablanca.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,8 +6,19 @@ CASABLANCA CLIENT CONSOLE (#{Casablanca::VERSION})
 Use C for a configured client (#{config.inspect})
 Example:
 
-t = C.get_service_ticket('admin', 'admin')
-C.authenticate_ticket(t)
+  t = C.login('admin', 'admin')
+  C.authenticate_ticket(t)
+  
+  # use gateway to login to another service with
+  # the current session
+  C.service_url = &quot;http://example.com/application&quot;
+  t = C.gateway
+  C.authenticate_ticket(t)
+  
+  t = C.renew_service_ticket
+  C.authenticate_ticket(t)
+
+  C.logout
 
 The configuration can be changed:
 C.cas_server_url = &quot;http://example.com/cas_server&quot;
@@ -15,6 +26,7 @@ C.service_url = &quot;http://example.com/application&quot;
 
 )
 
-C = @client = Casablanca::CommandLineClient.new(config)
+C = Casablanca::CommandLineClient.new(config)
+C.logger.level = Logger::DEBUG
 
 puts INFO
\ No newline at end of file</diff>
      <filename>lib/casablanca/cli.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,11 +2,12 @@ require 'uri'
 require 'cgi'
 require 'net/https'
 require 'rexml/document'
+require 'logger'
 
 module Casablanca
 
   class Client
-    attr_accessor :cas_server_url, :service_url
+    attr_accessor :cas_server_url, :service_url, :logger
 
     def initialize(config)
       raise &quot;:cas_server_url is required&quot; unless config[:cas_server_url]
@@ -18,14 +19,21 @@ module Casablanca
     # Validates a Ticket to the validation url of the CAS Server
     # and checks if the ticket is authenticated
     def authenticate_ticket(ticket)
-      response = request_validation(ticket)
-      ticket.authenticate(response)
+      request_validation(ticket)
+      ticket.authenticate
+    end
+
+    def gateway
+      uri = URI.parse(login_url)
+      uri.merge_query(:gateway =&gt; 'true')
+      response = get(uri)
+      get_service_ticket(response)      
     end
 
     ##
     # The login url of the Cas server. This page has the login form.
     def login_url
-      url = &quot;#{@cas_server_url}/login?service=#{@service_url}&quot; 
+      &quot;#{@cas_server_url}/login?service=#{@service_url}&quot; 
     end
 
     ##
@@ -40,6 +48,14 @@ module Casablanca
       &quot;#{@cas_server_url}/proxyValidate&quot;
     end
 
+    def logger
+      unless @logger
+        @logger = ::Logger.new($stderr)
+        @logger.level = Logger::WARN
+      end
+      @logger
+    end
+
     private
 
     def request_validation(ticket)
@@ -47,49 +63,77 @@ module Casablanca
       uri = URI.parse(validate_url)
       uri.merge_query(ticket.to_request_params)
       response = get(uri)
-      puts &quot;#{@cas_server_url} #{response.inspect}:\n#{response.body}&quot;
       unless response.kind_of?(Net::HTTPSuccess)
         raise ResponseError, &quot;#{response.code}, #{response.body}&quot;
       end
-      response.body
+      ticket.body = response.body
     end
     
     def get(uri)
       https(uri) do |h|
-        h.get(&quot;#{uri.path}?#{uri.query}&quot;)
-      end   
+        h.get(&quot;#{uri.path}?#{uri.query}&quot;, headers)
+      end
     end 
 
     def https(uri)
       https = Net::HTTP.new(uri.host, uri.port)
       https.use_ssl = (uri.scheme == 'https')
       begin
-        https.start do |h|
+        response = https.start do |h|
           yield(h)
         end
       rescue Errno::ECONNREFUSED =&gt; error
         raise CasServerException
       end
+      logger.debug(response_log(response))
+      response     
+    end
+    
+    def headers
+      {'cookie' =&gt; @ticket_granting_ticket || ''}
+    end
+
+    def response_log(response)
+      msg = &quot;################\n&quot;
+      msg &lt;&lt; &quot;  #{@cas_server_url} #{response.inspect}:\n&quot;
+      msg &lt;&lt; &quot;  body: #{response.body}\n&quot;
+      msg &lt;&lt; &quot;  headers:\n&quot;
+      response.each_key do |k|
+        msg &lt;&lt; &quot;    - #{k}: #{response[k]}\n&quot;
+      end
+      msg
     end
 
   end
 
   class CommandLineClient &lt; Client
-
+    attr_reader :ticket_granting_ticket
     ##
     # Logs in to the CAS server and returns the response
     def login(username, password)
-      post(URI.parse(login_url), {:username =&gt; username, :password =&gt; password, :service =&gt; service_url})
+      @ticket_granting_ticket = nil
+      response = post(URI.parse(login_url), {:username =&gt; username, :password =&gt; password, :service =&gt; service_url})
+      set_ticket_granting_ticket(response)
+      get_service_ticket(response)      
     end
-
-    ##
-    # Logs in to the CAS server and returns the service ticket from the response
-    def get_service_ticket(username, password)
-      location = login(username, password)['location']
-      query = {}
-      URI.parse(location).query.collect{|q| k,v = q.split('='); query[k] = v }
-      Ticket.new(query['ticket'], @service_url)
+    
+    def renew_service_ticket
+      get_service_ticket(get(URI.parse(login_url)))
     end
+
+    def renew
+      uri = URI.parse(login_url)
+      uri.merge_query(:renew =&gt; 'true')
+      response = get(uri)
+      get_service_ticket(response)      
+    end 
+    
+    def logout(follow_url=nil)
+      @ticket_granting_ticket = nil
+      uri = URI.parse(logout_url)
+      uri.merge_query(:url =&gt; follow_url) if follow_url
+      get(uri)
+    end    
     
     private
     
@@ -99,23 +143,34 @@ module Casablanca
       https(uri) do |h|
         h.request(req)
       end
-    end  
+    end
+    
+    def get_service_ticket(response)
+      if (location = response['location'])
+        query = {}
+        URI.parse(location).query.collect{|q| k,v = q.split('='); query[k] = v }
+        Ticket.new(query['ticket'], @service_url)
+      end
+    end
+
+    def set_ticket_granting_ticket(response)
+      @ticket_granting_ticket = (response['set-cookie'] || '').split(/;/)[0] # tgt=TGC-1232569033r763536CC6753E6F357
+    end    
   end
 
   class Ticket
     attr_accessor :user, :failure_code, :failure_message
     attr_reader :service_url, :ticket
-    
-    def initialize(ticket, service_url, renew = false)      
+    attr_writer :body
+    def initialize(ticket, service_url)      
       @service_url = service_url
       @ticket  = ticket
-      @renew   = renew
     end
 
     ##
     # Create a Ticket from a Hash. Useful for unserializing
     def self.from_hash(hash)
-      ticket = Ticket.new(hash[:ticket], hash[:service_url], hash[:renew])
+      ticket = Ticket.new(hash[:ticket], hash[:service_url])
       ticket.user = hash[:user]
       ticket
     end
@@ -125,7 +180,6 @@ module Casablanca
     def to_hash
       props = {}
       props[:user] = @user if authenticated?
-      props[:renew] = @renew if @renew
       props[:service_url] = @service_url
       props[:ticket] = @ticket
       props
@@ -134,9 +188,9 @@ module Casablanca
     ##
     # Convert the ticket to a Hash for a request
     def to_request_params
-      params = {:service =&gt;  @service_url,
-        :ticket =&gt; @ticket }
-      params[:renew] = 1 if @renew
+      params = {}
+      params[:service] = @service_url
+      params[:ticket] = @ticket if @ticket
       params
     end
     
@@ -144,8 +198,8 @@ module Casablanca
       !!@user
     end
 
-    def authenticate(body)
-      response = CasResponseParser.parse(self, body)
+    def authenticate
+      response = CasResponseParser.parse(self, @body)
       authenticated?
     end
   end</diff>
      <filename>lib/casablanca/client.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,16 +1,7 @@
 module Casablanca
   class RailsFilter
-    @@client = nil
 
     class &lt;&lt; self
-      
-      def client=client
-        @@client = client
-      end
-      
-      def client
-        @@client
-      end
 
       ##
       # Configure the client
@@ -22,21 +13,31 @@ module Casablanca
       def config
         config = {}
         yield config
-        @@client = Client.new(config)
+        @cas_server_url = config[:cas_server_url]
+        @service_url = config[:service_url]
+        # set logger to rails logger
+        @logger = ::ActionController::Base.logger        
       end
       
       def filter(controller)
-        return true if previous_ticket(controller) &amp;&amp; !controller.params[:renew]     
-        ticket = Ticket.new(controller.params[:ticket], @@client.service_url, controller.params[:renew])
-        if @@client.authenticate_ticket(ticket)
-          puts &quot;Ticket authenticated&quot;
+        client = Client.new(:cas_server_url =&gt; @cas_server_url, :service_url =&gt; @service_url)
+        client.logger = @logger
+        
+        #if gatewaying? 
+        #  client.ticket_granting_ticket = controller.params[:ticket_granting_ticket]
+        #  ticket = client.gateway
+        #  client.authenticate_ticket(ticket)
+        # return true if client.gateway
+        return true if previous_ticket(controller) &amp;&amp; !controller.params[:renew]
+        ticket = Ticket.new(controller.params[:ticket], client.service_url)
+        if client.authenticate_ticket(ticket)
+          @logger.debug &quot;Ticket authenticated&quot;
           controller.session[:cas_user] = ticket.user
-          controller.session[:cas_ticket] = ticket.to_hash
+          controller.session[:cas_ticket_granting_ticket] = client.ticket_granting_ticket
           return true
-        else
-          puts &quot;Ticket authentication failed: #{ticket.failure_message}&quot;          
-          controller.session[:cas_user] = nil
-          controller.session[:cas_ticket] = nil
+        else          
+          @logger.warn &quot;#{logger.inspect} Ticket authentication failed: #{ticket.failure_message}&quot;          
+          logout(controller)
           controller.send(:redirect_to, login_url)
           return false
         end
@@ -49,10 +50,16 @@ module Casablanca
       end
 
       ##
-      # Logs out of the Cas server.
+      # The logout url of the Cas server.
+      def logout_url
+        @@client.logout_url
+      end
+      
+      ##
+      # Logs out of the Cas server.      
       def logout(controller)
-        controller.send(:reset_session)
-        controller.send(:redirect_to, @@client.logout_url)
+        controller.session[:cas_user] = nil
+        controller.session[:cas_ticket_granting_ticket] = nil
       end
       
       private</diff>
      <filename>lib/casablanca/filters/rails.rb</filename>
    </modified>
    <modified>
      <diff>@@ -18,7 +18,7 @@ class TestClient &lt; Test::Unit::TestCase
   def test_authenticate_ticket
     service_ticket = get_service_ticket
     @client = Client.new(:cas_server_url =&gt; &quot;http://localhost:4567&quot;, :service_url =&gt; &quot;http://localhost:3000&quot;)    
-    mock_authenticate_ticket(VALID_REQUEST)    
+    mock_authenticate_ticket(VALID_REQUEST)
     @client.authenticate_ticket(service_ticket)
     assert_equal 'admin', service_ticket.user
   end
@@ -26,7 +26,7 @@ class TestClient &lt; Test::Unit::TestCase
   def test_validate_expired_ticket
     mock_authenticate_ticket(INVALID_TICKET)
     ticket = 'ST-1231341579r871C5757B79767C21E'
-    service_ticket = Ticket.new(ticket, 'http://localhost:3000', true)
+    service_ticket = Ticket.new(ticket, 'http://localhost:3000')
     @client.authenticate_ticket(service_ticket)
     assert_equal 'INVALID_TICKET', service_ticket.failure_code
     #assert_equal &quot;Ticket 'ST-1231341579r871C5757B79767C21E' has already been used up.&quot;, ticket.failure_message
@@ -35,7 +35,7 @@ class TestClient &lt; Test::Unit::TestCase
   def test_validate_invalid_ticket
     mock_authenticate_ticket(INVALID_TICKET)
     ticket = 'ST-1231242314r72465638160B31E8D1'
-    service_ticket =  Ticket.new(ticket, 'http://localhost:3000', true)
+    service_ticket =  Ticket.new(ticket, 'http://localhost:3000')
     @client.authenticate_ticket(service_ticket)
     assert_equal 'INVALID_TICKET', service_ticket.failure_code
     assert_equal &quot;Ticket ST-1231242314r72465638160B31E8D1 not recognized.&quot;, service_ticket.failure_message
@@ -69,16 +69,40 @@ class TestCommandLineClient &lt; Test::Unit::TestCase
 
   def test_login
     mock_get_service_ticket
-    res = @client.login('admin', 'admin')
-    assert_equal '', res.body
-    assert_equal '303', res.code
-    assert_equal 0, res['location'] =~ /^http:\/\/localhost:3000\?ticket=ST-/
-    assert_equal 61, res['location'].size
+    service_ticket = @client.login('admin', 'admin')
+    #assert_equal '', res.body
+    #assert_equal '303', res.code
+    #assert_equal 0, res['location'] =~ /^http:\/\/localhost:3000\?ticket=ST-/
+    assert_equal 32, service_ticket.ticket.size
+    assert_equal 37, @client.ticket_granting_ticket.size
   end
 
+  def test_logout
+    mock_get_service_ticket
+    service_ticket = @client.login('admin', 'admin')
+    assert_equal 37, @client.ticket_granting_ticket.size    
+    # if MOCK_REQUESTS
+      # @client.expects(:get).returns(MockResponse.new(body, '200', :location =&gt; 'http://localhost:3000?ticket=ST-1231341579r871C5757B79767C21E'))
+    # end
+    service_ticket = @client.logout
+    assert_equal nil, @client.ticket_granting_ticket
+  end
+
+  def test_logout_with_follow_url
+    mock_get_service_ticket
+    service_ticket = @client.login('admin', 'admin')
+    assert_equal 37, @client.ticket_granting_ticket.size    
+    # if MOCK_REQUESTS
+      # @client.expects(:get).returns(MockResponse.new(body, '200', :location =&gt; 'http://localhost:3000?ticket=ST-1231341579r871C5757B79767C21E'))
+    # end
+    service_ticket = @client.logout('follow_url')
+    assert_equal nil, @client.ticket_granting_ticket
+    # TODO check for follow_url
+  end
+  
   def test_get_service_ticket
     mock_get_service_ticket
-    ticket = @client.get_service_ticket('admin', 'admin')
+    ticket = @client.login('admin', 'admin')
     assert_equal 0, ticket.ticket =~ /^ST-/
     assert_equal 32, ticket.ticket.size    
   end</diff>
      <filename>test/test_client.rb</filename>
    </modified>
    <modified>
      <diff>@@ -18,16 +18,16 @@ class Test::Unit::TestCase
   
   def mock_get_service_ticket
     if MOCK_REQUESTS
-      @client.expects(:post).returns(MockResponse.new('', '303', :location =&gt; 'http://localhost:3000?ticket=ST-1231341579r871C5757B79767C21E'))
+      @client.expects(:post).returns(MockResponse.new('', '303', :location =&gt; 'http://localhost:3000?ticket=ST-1231341579r871C5757B79767C21E', :'set-cookie' =&gt; 'tgt=TGC-1232569033r763536CC6753E6F357'))
     end
   end
 
   def get_service_ticket
     cli = CommandLineClient.new(:cas_server_url =&gt; &quot;http://localhost:4567&quot;, :service_url =&gt; &quot;http://localhost:3000&quot;)
     if MOCK_REQUESTS
-      cli.expects(:post).returns(MockResponse.new('', '303', :location =&gt; 'http://localhost:3000?ticket=ST-1231341579r871C5757B79767C21E'))
+      cli.expects(:post).returns(MockResponse.new('', '303', {:location =&gt; 'http://localhost:3000?ticket=ST-1231341579r871C5757B79767C21E', :'set-cookie' =&gt; 'tgt=TGC-1232569033r763536CC6753E6F357'}))
     end
-    cli.get_service_ticket('admin', 'admin')
+    cli.login('admin', 'admin')
   end 
 end
 </diff>
      <filename>test/test_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,5 @@
 require File.join(File.dirname(__FILE__), 'test_helper.rb')
-require 'action_pack'
+#require 'action_pack'
 class TestRailsFilter &lt; Test::Unit::TestCase
   def setup
     @client = Client.new(:cas_server_url =&gt; &quot;http://localhost:4567&quot;, :service_url =&gt; &quot;http://localhost:3000&quot;)
@@ -10,8 +10,18 @@ class TestRailsFilter &lt; Test::Unit::TestCase
   
   def test_login_url
     assert_equal 'http://localhost:4567/login?service=http://localhost:3000', RailsFilter.login_url
+  end
+  
+  def test_logout_url
+    assert_equal 'http://localhost:4567/logout', RailsFilter.logout_url
   end  
   
+  def test_logout
+    @controller.session = { :cas_ticket =&gt; 'ticket', :cas_user =&gt; 'admin' }
+    RailsFilter.logout(@controller)
+    assert_equal({:cas_user=&gt;nil, :cas_ticket=&gt;nil}, @controller.session)
+  end
+  
   def test_config
     Casablanca::RailsFilter.config do |config|
        config[:cas_server_url]  = &quot;http://example.com/cas_server&quot;
@@ -20,17 +30,6 @@ class TestRailsFilter &lt; Test::Unit::TestCase
     assert_equal &quot;http://example.com/cas_server&quot;, RailsFilter.client.cas_server_url
     assert_equal &quot;http://example.com/application&quot;, RailsFilter.client.service_url    
   end
-  # def test_filter_requires_config
-  #   RailsFilter.config = nil
-  #   assert_raises(RuntimeError) do
-  #     RailsFilter.filter(Controller.new)
-  #   end
-  # end
-
-  def test_logout
-    RailsFilter.logout(@controller)
-    assert_equal({}, @controller.session)
-  end
 
   def test_filter_invalid_attempt
     mock_authenticate_ticket(INVALID_TICKET)
@@ -70,6 +69,16 @@ class TestRailsFilter &lt; Test::Unit::TestCase
 
 end
 
+module ActionController
+  module Base
+    def self.logger
+      @logger = ::Logger.new($stderr)
+      @logger.level = ::Logger::ERROR
+      @logger
+    end
+  end
+end
+
 class Controller # &lt; ActionController::Base
   attr_accessor :params, :session
   def initialize</diff>
      <filename>test/test_rails_filter.rb</filename>
    </modified>
    <modified>
      <diff>@@ -23,7 +23,6 @@ class TestTicket &lt; Test::Unit::TestCase
   def test_from_hash
     props = {:ticket =&gt; 'ticket',
                   :service_url =&gt; &quot;http://localhost:3000&quot;,
-                  :renew    =&gt; 1,
                   :user     =&gt; 'admin' }
     ticket = Ticket.from_hash(props)
     assert_equal props, ticket.to_hash
@@ -36,34 +35,31 @@ class TestTicket &lt; Test::Unit::TestCase
     assert_equal(expected, ticket.to_request_params)
   end
 
-  def test_to_request_params_with_renew
-    ticket = Ticket.new('ticket', 'http://localhost:3000', true)
-    expected = {:ticket =&gt; 'ticket',
-                  :service  =&gt; &quot;http://localhost:3000&quot;,
-                  :renew    =&gt; 1 }
-    assert_equal(expected, ticket.to_request_params)
-  end
-  
   def test_authenticate_valid_ticket
-    @ticket.authenticate(VALID_REQUEST)
+    @ticket.body = VALID_REQUEST
+    @ticket.authenticate
     assert_equal 'admin', @ticket.user
   end
 
   def test_authenticate_invalid_request_resets_ticket_to_unauthenticated
-    @ticket.authenticate(VALID_REQUEST)
+    @ticket.body = VALID_REQUEST
+    @ticket.authenticate
     assert_equal true, @ticket.authenticated?
-    @ticket.authenticate(INVALID_REQUEST)
+    @ticket.body = INVALID_REQUEST
+    @ticket.authenticate
     assert_equal false, @ticket.authenticated?
   end
     
   def test_authenticate_invalid_request
-    @ticket.authenticate(INVALID_REQUEST)
+    @ticket.body = INVALID_REQUEST
+    @ticket.authenticate
     assert_equal 'INVALID_REQUEST', @ticket.failure_code    
     assert_equal 'Ticket or service parameter was missing in the request.', @ticket.failure_message
   end
   
   def test_authenticate_invalid_ticket
-    @ticket.authenticate(INVALID_TICKET)
+    @ticket.body = INVALID_TICKET
+    @ticket.authenticate
     assert_equal 'INVALID_TICKET', @ticket.failure_code    
     assert_equal 'Ticket ST-1231242314r72465638160B31E8D1 not recognized.', @ticket.failure_message
   end</diff>
      <filename>test/test_ticket.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>33eae876d1f3fe15d100221574f5b163a7ecf9d4</id>
    </parent>
  </parents>
  <author>
    <name>Petrik</name>
    <email>petrik@deheus.net</email>
  </author>
  <url>http://github.com/p8/casablanca/commit/c440a7eb0e423b0cd44ba4b7f80ba41d30aacd9c</url>
  <id>c440a7eb0e423b0cd44ba4b7f80ba41d30aacd9c</id>
  <committed-date>2009-01-22T11:52:29-08:00</committed-date>
  <authored-date>2009-01-22T11:52:29-08:00</authored-date>
  <message>Added logger. Changing rails client. Started implementing gatewaying</message>
  <tree>1a8be9aca65383ae35009fea00cc055d050a6f15</tree>
  <committer>
    <name>Petrik</name>
    <email>petrik@deheus.net</email>
  </committer>
</commit>
