<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>lib/castronaut/presenters/service_validate.rb</filename>
    </added>
    <added>
      <filename>spec/castronaut/presenters/service_validate_spec.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -4,8 +4,7 @@ Autotest.add_hook :initialize do |autotest|
  # autotest.sleep = 3  
   
  # Ignore files with suffix  
- %w{.svn .log .hg .git .erb .rhtml .png .txt .sh .project .rjs .rake .jpg .css .xml}.each { |exception| autotest.add_exception(exception) }  
- 
- # autotest.add_exception(/^\.\/vendor/)
+
+ %w{.svn .log .hg .git .erb .rhtml .png .txt .sh .project .rjs .rake .jpg .css .xml vendor db}.each { |exception| autotest.add_exception(exception) }  
 
 end</diff>
      <filename>.autotest</filename>
    </modified>
    <modified>
      <diff>@@ -21,6 +21,9 @@ get '/validate' do
 end
 
 get '/serviceValidate' do
+  # @presenter = Castronaut::Presenters::ServiceValidate.new(self)
+  # @presenter.represent!
+  # @presenter.your_mission.call
   body 'serviceValidate-Get'
 end
 </diff>
      <filename>app/controllers/application.rb</filename>
    </modified>
    <modified>
      <diff>@@ -9,6 +9,7 @@ require File.expand_path(File.join(File.dirname(__FILE__), 'castronaut', 'authen
 require File.expand_path(File.join(File.dirname(__FILE__), 'castronaut', 'ticket_result'))
 require File.expand_path(File.join(File.dirname(__FILE__), 'castronaut', 'presenters', 'login'))
 require File.expand_path(File.join(File.dirname(__FILE__), 'castronaut', 'presenters', 'process_login'))
+require File.expand_path(File.join(File.dirname(__FILE__), 'castronaut', 'presenters', 'service_validate'))
 require File.expand_path(File.join(File.dirname(__FILE__), 'castronaut', 'adapters'))
 require File.expand_path(File.join(File.dirname(__FILE__), 'castronaut', 'adapters', 'restful_authentication', 'adapter'))
 require File.expand_path(File.join(File.dirname(__FILE__), 'castronaut', 'adapters', 'restful_authentication', 'user'))</diff>
      <filename>lib/castronaut.rb</filename>
    </modified>
    <modified>
      <diff>@@ -8,6 +8,8 @@ module Castronaut
       include Castronaut::Models::Consumeable
       include Castronaut::Models::Dispenser
       
+      MissingMessage = &quot;Ticket or service parameter was missing in the request.&quot;
+      
       belongs_to :ticket_granting_ticket
       
       before_validation :dispense_ticket, :if =&gt; :new_record?
@@ -19,6 +21,33 @@ module Castronaut
                 :client_hostname =&gt; client_host,
                 :ticket_granting_ticket =&gt; ticket_granting_ticket
       end
+
+      def self.validate_ticket(service, ticket, allow_proxy_tickets = false)
+
+        return Castronaut::TicketResult.new(nil, MissingMessage, &quot;INVALID_REQUEST&quot;) unless service &amp;&amp; ticket
+        
+        service_ticket = find_by_ticket(ticket)
+
+        return Castronaut::TicketResult.new(nil, &quot;Ticket #{ticket} not recognized.&quot;, &quot;INVALID_TICKET&quot;) unless service_ticket
+        
+        return Castronaut::TicketResult.new(service_ticket, &quot;Ticket '#{ticket}' has already been used up.&quot;, &quot;INVALID_TICKET&quot;) if service_ticket.consumed?
+        
+        service_ticket.consume!
+        
+        # if service_ticket.kind_of?(CASServer::Models::ProxyTicket) &amp;&amp; !allow_proxy_tickets
+        #   return Castronaut::TicketResult.new(service_ticket, &quot;Ticket '#{ticket}' is a proxy ticket, but only service tickets are allowed here.&quot;, &quot;INVALID_TICKET&quot;) 
+        # end
+        
+        return Castronaut::TicketResult.new(service_ticket, &quot;Ticket '#{ticket}' has expired.&quot;, &quot;INVALID_TICKET&quot;) if service_ticket.expired?
+
+        mismatched_service_message = &quot;The ticket '#{ticket}' belonging to user '#{service_ticket.username}' is valid, but the requested service '#{service}' does not match the service '#{service_ticket.service}' associated with this ticket.&quot;
+
+        return Castronaut::TicketResult.new(service_ticket, mismatched_service_message, &quot;INVALID_SERVICE&quot;) unless service_ticket.matches_service?(service)
+      end
+      
+      def matches_service?(other_service)
+        service == other_service
+      end
       
       def service_uri
         return nil if service.blank?
@@ -46,6 +75,10 @@ module Castronaut
         &quot;ST&quot;
       end
       
+      def expired?
+        # Time.now - service_ticket.created_on &gt; CASServer::Conf.service_ticket_expiry
+      end
+      
     end
 
   end</diff>
      <filename>lib/castronaut/models/service_ticket.rb</filename>
    </modified>
    <modified>
      <diff>@@ -13,13 +13,13 @@ module Castronaut
       def self.validate_cookie(ticket_cookie)
         Castronaut.logger.debug(&quot;#{self} - Validating ticket for #{ticket_cookie}&quot;)
 
-        return Castronaut::TicketResult.new(nil, &quot;No ticket granting ticket given&quot;) if ticket_cookie.nil?
+        return Castronaut::TicketResult.new(nil, &quot;No ticket granting ticket given&quot;, 'warn') if ticket_cookie.nil?
 
         ticket_granting_ticket = find_by_ticket(ticket_cookie)
 
         if ticket_granting_ticket
           Castronaut.logger.debug(&quot;#{self} -[#{ticket_cookie}] for [#{ticket_granting_ticket.username}] successfully validated.&quot;)
-          return Castronaut::TicketResult.new(ticket_granting_ticket, &quot;Your session has expired. Please log in again.&quot;) if ticket_granting_ticket.expired?
+          return Castronaut::TicketResult.new(ticket_granting_ticket, &quot;Your session has expired. Please log in again.&quot;, 'warn') if ticket_granting_ticket.expired?
         else
           Castronaut.logger.debug(&quot;#{self} - [#{ticket_cookie}] was not found in the database.&quot;)
         end</diff>
      <filename>lib/castronaut/models/ticket_granting_ticket.rb</filename>
    </modified>
    <modified>
      <diff>@@ -48,7 +48,7 @@ module Castronaut
         ticket_granting_ticket_result = Castronaut::Models::TicketGrantingTicket.validate_cookie(ticket_generating_ticket_cookie)
 
         if ticket_granting_ticket_result.valid?
-          messages &lt;&lt; &quot;You are currently logged in as #{ticket_granting_ticket_result.username}.  If this is not you, please log in below.&quot;
+        messages &lt;&lt; &quot;You are currently logged in as #{ticket_granting_ticket_result.username}.  If this is not you, please log in below.&quot;
         end
 
         if redirection_loop?</diff>
      <filename>lib/castronaut/presenters/login.rb</filename>
    </modified>
    <modified>
      <diff>@@ -45,7 +45,7 @@ module Castronaut
       # POSSIBLE SHARED ABOVE
 
       def username
-        params['username'].strip
+        params['username'].to_s.strip
       end
 
       def password
@@ -58,7 +58,7 @@ module Castronaut
         login_ticket_validation_result = Castronaut::Models::LoginTicket.validate_ticket(@login_ticket)
 
         if login_ticket_validation_result &amp;&amp; login_ticket_validation_result.invalid?
-          messages &lt;&lt; login_ticket_validation_result.error_message
+          messages &lt;&lt; login_ticket_validation_result.message
           @login_ticket = Castronaut::Models::LoginTicket.generate_from(client_host).ticket
           @your_mission = lambda { controller.erb :login, :locals =&gt; { :presenter =&gt; self } } # TODO: STATUS 401
           return self</diff>
      <filename>lib/castronaut/presenters/process_login.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,13 +1,15 @@
 module Castronaut
 
   class TicketResult
-    
-    attr_reader :ticket, :error_message
+    InvalidMessageCategories = %w{warn error fatal invalid} 
+
+    attr_reader :ticket, :message, :message_category
         
-    def initialize(ticket, error_message=nil)
+    def initialize(ticket, message=nil, message_category=nil)
       @ticket = ticket
-      @error_message = error_message
-      Castronaut.logger.info(&quot;#{self.class} - #{@error_message} for #{@ticket}&quot;) if @error_message &amp;&amp; @ticket
+      @message = message
+      @message_category = message_category
+      Castronaut.logger.info(&quot;#{self.class} - #{@message_category} #{@message} for #{@ticket}&quot;) if @message &amp;&amp; @ticket
     end
     
     def username
@@ -15,11 +17,11 @@ module Castronaut
     end
 
     def valid?
-      error_message.nil?
+      !invalid?
     end
     
     def invalid?
-      !valid?
+      InvalidMessageCategories.any?{ |cat| message_category.to_s.downcase.include?(cat) }
     end
     
   end</diff>
      <filename>lib/castronaut/ticket_result.rb</filename>
    </modified>
    <modified>
      <diff>@@ -76,4 +76,146 @@ describe Castronaut::Models::ServiceTicket do
     
   end
 
+  describe &quot;matching service?&quot; do
+    
+    it &quot;matches if the given service is equal to the ticket's service&quot; do
+      service_ticket = Castronaut::Models::ServiceTicket.new(:service =&gt; 'http://foo')
+      service_ticket.matches_service?('foo').should be_false
+      service_ticket.matches_service?('http://foo').should be_true
+      service_ticket.matches_service?('http://foo/').should be_false
+    end
+    
+  end
+  
+  describe &quot;validating ticket&quot; do
+  
+    describe &quot;when the service and ticket are missing returns a ticket result&quot; do
+      
+      it &quot;with the missing ticket message&quot; do
+        Castronaut::Models::ServiceTicket.validate_ticket(nil, nil).message.should == Castronaut::Models::ServiceTicket::MissingMessage
+      end
+      
+      it &quot;with the INVALID_REQUEST message category&quot; do
+        Castronaut::Models::ServiceTicket.validate_ticket(nil, nil).message_category.should == 'INVALID_REQUEST'
+      end
+      
+      it &quot;is marked as invalid&quot; do
+        Castronaut::Models::ServiceTicket.validate_ticket(nil, nil).should be_invalid
+      end
+      
+    end
+    
+    describe &quot;when the service and ticket are given&quot; do
+      
+      it &quot;attempts to find the ServiceTicket by the given ticket&quot; do
+        Castronaut::Models::ServiceTicket.expects(:find_by_ticket).with('ticket').returns(stub_everything)
+        Castronaut::Models::ServiceTicket.validate_ticket('service', 'ticket')
+      end
+      
+      describe &quot;when it fails to find a service ticket returns a ticket result&quot; do
+        
+        it &quot;with the ticket not recognized message&quot; do
+          Castronaut::Models::ServiceTicket.stubs(:find_by_ticket).returns(nil)
+          Castronaut::Models::ServiceTicket.validate_ticket('service', 'ticket').message.should == &quot;Ticket ticket not recognized.&quot;
+        end
+
+        it &quot;with the INVALID_TICKET message category&quot; do
+          Castronaut::Models::ServiceTicket.stubs(:find_by_ticket).returns(nil)
+          Castronaut::Models::ServiceTicket.validate_ticket('service', 'ticket').message_category.should == 'INVALID_TICKET'
+        end
+
+        it &quot;is marked as invalid&quot; do
+          Castronaut::Models::ServiceTicket.stubs(:find_by_ticket).returns(nil)
+          Castronaut::Models::ServiceTicket.validate_ticket('service', 'ticket').should be_invalid
+        end
+        
+      end
+            
+      describe &quot;when it finds a service ticket&quot; do
+        
+        describe &quot;when it is already consumed it returns a ticket result&quot; do
+          
+          it &quot;with the ticket used up message&quot; do
+            Castronaut::Models::ServiceTicket.stubs(:find_by_ticket).returns(stub_everything(:consumed? =&gt; true))
+            Castronaut::Models::ServiceTicket.validate_ticket('service', 'ticket').message.should == &quot;Ticket 'ticket' has already been used up.&quot;
+          end
+
+          it &quot;with the INVALID_TICKET message category&quot; do
+            Castronaut::Models::ServiceTicket.stubs(:find_by_ticket).returns(stub_everything(:consumed? =&gt; true))
+            Castronaut::Models::ServiceTicket.validate_ticket('service', 'ticket').message_category.should == 'INVALID_TICKET'
+          end
+
+          it &quot;is marked as invalid&quot; do
+            Castronaut::Models::ServiceTicket.stubs(:find_by_ticket).returns(stub_everything(:consumed? =&gt; true))
+            Castronaut::Models::ServiceTicket.validate_ticket('service', 'ticket').should be_invalid
+          end
+          
+        end
+        
+        describe &quot;when it has not been consumed&quot; do
+          
+          it &quot;consumes the service ticket&quot; do
+            service_ticket = stub_everything(:consumed? =&gt; false)
+            service_ticket.expects(:consume!)
+            
+            Castronaut::Models::ServiceTicket.stubs(:find_by_ticket).returns(service_ticket)
+            Castronaut::Models::ServiceTicket.validate_ticket('service', 'ticket')
+          end
+          
+          describe &quot;when it encounters a proxy ticket it returns a ticket result&quot; do
+            
+            it &quot;with the ticket is a proxy ticket message&quot;
+            
+            it &quot;with the INVALID_TICKET message category&quot;
+            
+            it &quot;is marked as invalid&quot;
+            
+          end
+          
+          describe &quot;when it is already expired it returns a ticket result&quot; do
+
+            it &quot;with the ticket expired message&quot; do
+              Castronaut::Models::ServiceTicket.stubs(:find_by_ticket).returns(stub_everything(:expired? =&gt; true, :consumed? =&gt; false))
+              Castronaut::Models::ServiceTicket.validate_ticket('service', 'ticket').message.should == &quot;Ticket 'ticket' has expired.&quot;
+            end
+
+            it &quot;with the INVALID_TICKET message category&quot; do
+              Castronaut::Models::ServiceTicket.stubs(:find_by_ticket).returns(stub_everything(:expired? =&gt; true, :consumed? =&gt; false))
+              Castronaut::Models::ServiceTicket.validate_ticket('service', 'ticket').message_category.should == 'INVALID_TICKET'
+            end
+
+            it &quot;is marked as invalid&quot; do
+              Castronaut::Models::ServiceTicket.stubs(:find_by_ticket).returns(stub_everything(:expired? =&gt; true, :consumed? =&gt; false))
+              Castronaut::Models::ServiceTicket.validate_ticket('service', 'ticket').should be_invalid
+            end
+
+          end   
+          
+          describe &quot;when it encounters a mismatched service it returns a ticket result&quot; do
+
+            it &quot;with the service mismatch message&quot; do
+              Castronaut::Models::ServiceTicket.stubs(:find_by_ticket).returns(stub_everything(:expired? =&gt; false, :consumed? =&gt; false, :service =&gt; 'blah'))
+              Castronaut::Models::ServiceTicket.validate_ticket('service', 'ticket').message.should include(&quot;does not match the service&quot;)
+            end
+
+            it &quot;with the INVALID_SERVICE message category&quot; do
+              Castronaut::Models::ServiceTicket.stubs(:find_by_ticket).returns(stub_everything(:expired? =&gt; false, :consumed? =&gt; false, :service =&gt; 'blah'))
+              Castronaut::Models::ServiceTicket.validate_ticket('service', 'ticket').message_category.should == 'INVALID_SERVICE'
+            end
+
+            it &quot;is marked as invalid&quot; do
+              Castronaut::Models::ServiceTicket.stubs(:find_by_ticket).returns(stub_everything(:expired? =&gt; false, :consumed? =&gt; false, :service =&gt; 'blah'))
+              Castronaut::Models::ServiceTicket.validate_ticket('service', 'ticket').should be_invalid
+            end
+
+          end
+                 
+        end
+        
+      end
+      
+    end
+    
+  end
+  
 end</diff>
      <filename>spec/castronaut/models/service_ticket_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -10,10 +10,14 @@ describe Castronaut::Models::TicketGrantingTicket do
 
     describe &quot;when given no ticket&quot; do
 
-      it &quot;has an error message explaining you must give a ticket&quot; do
-        Castronaut::Models::TicketGrantingTicket.validate_cookie(nil).error_message.should == 'No ticket granting ticket given'
+      it &quot;has a message explaining you must give a ticket&quot; do
+        Castronaut::Models::TicketGrantingTicket.validate_cookie(nil).message.should == 'No ticket granting ticket given'
       end
-
+      
+      it &quot;is invalid&quot; do
+        Castronaut::Models::TicketGrantingTicket.validate_cookie(nil).should be_invalid
+      end
+      
     end
 
     describe &quot;when given a ticket&quot; do
@@ -34,7 +38,7 @@ describe Castronaut::Models::TicketGrantingTicket do
 
         it &quot;returns an error message if the ticket granting ticket is expired&quot; do
           @ticket_granting_ticket.stubs(:expired?).returns(true)
-          Castronaut::Models::TicketGrantingTicket.validate_cookie('abc').error_message.should == &quot;Your session has expired. Please log in again.&quot;
+          Castronaut::Models::TicketGrantingTicket.validate_cookie('abc').message.should == &quot;Your session has expired. Please log in again.&quot;
         end
 
       end
@@ -45,7 +49,7 @@ describe Castronaut::Models::TicketGrantingTicket do
 
       it &quot;returns a TicketResult with no error message&quot; do
         Castronaut::Models::TicketGrantingTicket.stubs(:find_by_ticket).returns(nil)
-        Castronaut::Models::TicketGrantingTicket.validate_cookie('abc').error_message.should be_nil
+        Castronaut::Models::TicketGrantingTicket.validate_cookie('abc').message.should be_nil
       end
 
     end</diff>
      <filename>spec/castronaut/models/ticket_granting_ticket_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -145,8 +145,11 @@ describe Castronaut::Presenters::Login do
   
   describe &quot;login ticket generation&quot; do
     
-    it &quot;generates a login ticket at the end&quot; 
-    
+     it &quot;generates a new login ticket when you call :login_ticket&quot; do
+       Castronaut::Models::LoginTicket.expects(:generate_from).returns(stub_everything(:ticket =&gt; 'ticket'))
+       Castronaut::Presenters::Login.new(@controller).login_ticket
+     end
+
   end
 
 end</diff>
      <filename>spec/castronaut/presenters/login_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -189,7 +189,6 @@ describe Castronaut::Presenters::ProcessLogin do
               @controller.expects(:redirect).with(:service_uri_stub, 303)
               process_login = Castronaut::Presenters::ProcessLogin.new(@controller)
               process_login.represent!
-              puts process_login.instance_variables
               process_login.instance_variable_get(&quot;@your_mission&quot;).call
             end
 </diff>
      <filename>spec/castronaut/presenters/process_login_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,12 +6,37 @@ describe Castronaut::TicketResult do
     Castronaut::TicketResult.new('ticket').ticket.should == 'ticket'
   end
   
-  it &quot;exposes the given message at :error_message&quot; do
-    Castronaut::TicketResult.new('ticket', 'my error').error_message.should == 'my error'
+  it &quot;exposes the given message at :message&quot; do
+    Castronaut::TicketResult.new('ticket', 'my error').message.should == 'my error'
   end
   
-  it &quot;is valid if there is no error message&quot; do
-    Castronaut::TicketResult.new('ticket', nil).should be_valid
+  it &quot;exposes the given message category at :message_category&quot; do
+    Castronaut::TicketResult.new('ticket', 'my error', 'message cat').message_category.should == 'message cat'
   end
+  
+  describe &quot;valid?&quot; do
 
+    it &quot;negates invalid? for it's result&quot; do
+      ticket_result = Castronaut::TicketResult.new('ticket', 'msg', 'cat')
+      ticket_result.stubs(:invalid?).returns(false)
+      ticket_result.should be_valid
+      
+      ticket_result.stubs(:invalid?).returns(true)
+      ticket_result.should_not be_valid
+    end
+  
+  end
+  
+  describe &quot;invalid?&quot; do
+    
+    Castronaut::TicketResult::InvalidMessageCategories.each do |invalid_category|
+    
+      it &quot;is invalid if the message category contains #{invalid_category}&quot; do
+        Castronaut::TicketResult.new('ticket', 'my error', &quot;BlaBlaBla-#{invalid_category}-AlbAlbAlb&quot;).should be_invalid
+      end
+      
+    end
+    
+  end
+  
 end</diff>
      <filename>spec/castronaut/ticket_result_spec.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>4471ae15ceade1b913670ee93c5a6c1e61c89edb</id>
    </parent>
  </parents>
  <author>
    <name>Chad Humphries</name>
    <email>chad@spicycode.com</email>
  </author>
  <url>http://github.com/relevance/castronaut/commit/f41176f43351034cd51254b1430afc5b1fa3f7d1</url>
  <id>f41176f43351034cd51254b1430afc5b1fa3f7d1</id>
  <committed-date>2008-09-09T08:34:34-07:00</committed-date>
  <authored-date>2008-09-09T08:34:34-07:00</authored-date>
  <message>Service ticket validation complete</message>
  <tree>244cd70c9441d5ce9a8f949645ded7d3941f70c1</tree>
  <committer>
    <name>Chad Humphries</name>
    <email>chad@spicycode.com</email>
  </committer>
</commit>
