p8-casablanca 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +6 -0
- data/Manifest.txt +17 -0
- data/README.textile +79 -0
- data/Rakefile +15 -0
- data/bin/casablanca +10 -0
- data/init.rb +3 -0
- data/lib/casablanca.rb +3 -0
- data/lib/casablanca/cli.rb +19 -0
- data/lib/casablanca/client.rb +162 -0
- data/lib/casablanca/filters/rails.rb +48 -0
- data/lib/casablanca/response_parsers.rb +50 -0
- data/lib/casablanca/version.rb +3 -0
- data/test/test_client.rb +96 -0
- data/test/test_helper.rb +54 -0
- data/test/test_parser.rb +22 -0
- data/test/test_rails_filter.rb +92 -0
- data/test/test_ticket.rb +71 -0
- metadata +85 -0
    
        data/History.txt
    ADDED
    
    
    
        data/Manifest.txt
    ADDED
    
    | @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            History.txt
         | 
| 2 | 
            +
            Manifest.txt
         | 
| 3 | 
            +
            README.textile
         | 
| 4 | 
            +
            Rakefile
         | 
| 5 | 
            +
            init.rb
         | 
| 6 | 
            +
            bin/casablanca
         | 
| 7 | 
            +
            lib/casablanca.rb
         | 
| 8 | 
            +
            lib/casablanca/cli.rb
         | 
| 9 | 
            +
            lib/casablanca/client.rb
         | 
| 10 | 
            +
            lib/casablanca/filters/rails.rb
         | 
| 11 | 
            +
            lib/casablanca/response_parsers.rb
         | 
| 12 | 
            +
            lib/casablanca/version.rb
         | 
| 13 | 
            +
            test/test_client.rb
         | 
| 14 | 
            +
            test/test_helper.rb
         | 
| 15 | 
            +
            test/test_parser.rb
         | 
| 16 | 
            +
            test/test_rails_filter.rb
         | 
| 17 | 
            +
            test/test_ticket.rb
         | 
    
        data/README.textile
    ADDED
    
    | @@ -0,0 +1,79 @@ | |
| 1 | 
            +
            h1. Casablanca
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            h2. Description
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            A single sign-on client based on the CAS 2.0 protocol.
         | 
| 6 | 
            +
            Has a filter for Rails so it can be used as a Rails plugin.
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              sudo gem install p8-casablanca
         | 
| 9 | 
            +
                
         | 
| 10 | 
            +
            h2. TODO
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            * Add flag to turn on/off mock request
         | 
| 13 | 
            +
            * Add extra attributes
         | 
| 14 | 
            +
            * Implement gateway and proxy
         | 
| 15 | 
            +
            * Check for single signout
         | 
| 16 | 
            +
            * Check for endless redirects
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            h2. Usage
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            In IRB:
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              require 'casablanca'
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              C = Casablanca::CommandLineClient.new({ :cas_server_url => "http://localhost:4567",
         | 
| 25 | 
            +
                                                    :service_url => "http://localhost:3000" })
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              ticket = C.get_service_ticket('admin', 'admin')
         | 
| 28 | 
            +
              C.authenticate_ticket(ticket)
         | 
| 29 | 
            +
             | 
| 30 | 
            +
             | 
| 31 | 
            +
            In a Rails project:
         | 
| 32 | 
            +
            - environment.rb:
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              Casablanca::RailsFilter.client = Casablanca::Client.new(:cas_server_url => "http://localhost:4567", :service_url => "http://localhost:3000")
         | 
| 35 | 
            +
              
         | 
| 36 | 
            +
            - Add the following to application.rb:
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              before_filter Casablanca::RailsFilter
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              def current_person
         | 
| 41 | 
            +
                @current_person ||= login_from_cas unless @current_person == false
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
                
         | 
| 44 | 
            +
              def login_from_cas
         | 
| 45 | 
            +
                if session[:cas_user]
         | 
| 46 | 
            +
                  person = Person.find_by_name(session[:cas_user])
         | 
| 47 | 
            +
                  logout_killing_session! unless person
         | 
| 48 | 
            +
                  person
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
            - Add the following to you logout action
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              Casablanca::RailsFilter.logout(self)
         | 
| 55 | 
            +
             | 
| 56 | 
            +
            h2. LICENSE:
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            (The MIT License)
         | 
| 59 | 
            +
             | 
| 60 | 
            +
            Copyright (c) 2009 Petrik de Heus
         | 
| 61 | 
            +
             | 
| 62 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining
         | 
| 63 | 
            +
            a copy of this software and associated documentation files (the
         | 
| 64 | 
            +
            'Software'), to deal in the Software without restriction, including
         | 
| 65 | 
            +
            without limitation the rights to use, copy, modify, merge, publish,
         | 
| 66 | 
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         | 
| 67 | 
            +
            permit persons to whom the Software is furnished to do so, subject to
         | 
| 68 | 
            +
            the following conditions:
         | 
| 69 | 
            +
             | 
| 70 | 
            +
            The above copyright notice and this permission notice shall be
         | 
| 71 | 
            +
            included in all copies or substantial portions of the Software.
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
         | 
| 74 | 
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         | 
| 75 | 
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
         | 
| 76 | 
            +
            IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
         | 
| 77 | 
            +
            CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
         | 
| 78 | 
            +
            TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
         | 
| 79 | 
            +
            SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         | 
    
        data/Rakefile
    ADDED
    
    | @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            # -*- ruby -*-
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'rubygems'
         | 
| 4 | 
            +
            require 'hoe'
         | 
| 5 | 
            +
            require 'lib/casablanca/version'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            Hoe.new('casablanca', Casablanca::VERSION) do |p|
         | 
| 8 | 
            +
              p.developer('FIX', 'FIX@example.com')
         | 
| 9 | 
            +
            end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            require 'metric_fu'
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            MetricFu::Configuration.run do |config|
         | 
| 14 | 
            +
              config.coverage = { :test_files => ['test/**/test_*.rb'] }
         | 
| 15 | 
            +
            end
         | 
    
        data/bin/casablanca
    ADDED
    
    | @@ -0,0 +1,10 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            irb = RUBY_PLATFORM =~ /mswin32/ ? 'irb.bat' : 'irb'
         | 
| 3 | 
            +
            options = { :sandbox => false, :irb => irb }
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            libs =  " -r irb/completion"
         | 
| 6 | 
            +
            libs << " -r #{File.dirname(__FILE__)}/../lib/casablanca/client.rb"
         | 
| 7 | 
            +
            libs << " -r #{File.dirname(__FILE__)}/../lib/casablanca/cli.rb"
         | 
| 8 | 
            +
            libs << " -r #{File.dirname(__FILE__)}/../lib/casablanca/response_parsers.rb"
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            exec "#{options[:irb]} #{libs} --simple-prompt"
         | 
    
        data/init.rb
    ADDED
    
    
    
        data/lib/casablanca.rb
    ADDED
    
    
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            config = { :cas_server_url => "http://localhost:4567", :service_url => "http://localhost:3000" }
         | 
| 2 | 
            +
            INFO = %(
         | 
| 3 | 
            +
            =====================================================
         | 
| 4 | 
            +
            CASABLANCA CLIENT CONSOLE
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Use C for a configured client (#{config.inspect})
         | 
| 7 | 
            +
            Example:
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            t = C.get_service_ticket('admin', 'admin')
         | 
| 10 | 
            +
            C.authenticate_ticket(t)
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            C.cas_server_url = "http://example.com/cas_server"
         | 
| 13 | 
            +
            C.service_url = "http://example.com/application"
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            )
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            C = @client = Casablanca::CommandLineClient.new(config)
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            puts INFO
         | 
| @@ -0,0 +1,162 @@ | |
| 1 | 
            +
            require 'uri'
         | 
| 2 | 
            +
            require 'cgi'
         | 
| 3 | 
            +
            require 'net/https'
         | 
| 4 | 
            +
            require 'rexml/document'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Casablanca
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              class Client
         | 
| 9 | 
            +
                attr_reader :service_url  
         | 
| 10 | 
            +
                def initialize(config)
         | 
| 11 | 
            +
                  raise ":cas_server_url is required" unless config[:cas_server_url]
         | 
| 12 | 
            +
                  @cas_server_url = config[:cas_server_url]
         | 
| 13 | 
            +
                  @service_url = config[:service_url]
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def authenticate_ticket(ticket)
         | 
| 17 | 
            +
                  response = request_validation(ticket)
         | 
| 18 | 
            +
                  ticket.authenticate(response)
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def login_url
         | 
| 22 | 
            +
                  url = "#{@cas_server_url}/login?service=#{@service_url}" 
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def logout_url
         | 
| 26 | 
            +
                  "#{@cas_server_url}/logout"
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def validate_url
         | 
| 30 | 
            +
                  "#{@cas_server_url}/proxyValidate"
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                private
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def request_validation(ticket)
         | 
| 36 | 
            +
                  raise "ticket.service_url cannot be empty" if ticket.service_url.nil? || ticket.service_url.strip == ""      
         | 
| 37 | 
            +
                  uri = URI.parse(validate_url)
         | 
| 38 | 
            +
                  uri.merge_query(ticket.to_request_params)
         | 
| 39 | 
            +
                  response = get(uri)
         | 
| 40 | 
            +
                  puts "#{@cas_server_url} #{response.inspect}:\n#{response.body}"
         | 
| 41 | 
            +
                  unless response.kind_of?(Net::HTTPSuccess)
         | 
| 42 | 
            +
                    raise ResponseError, "#{response.code}, #{response.body}"
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                  response.body
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
                
         | 
| 47 | 
            +
                def get(uri)
         | 
| 48 | 
            +
                  https(uri) do |h|
         | 
| 49 | 
            +
                    h.get("#{uri.path}?#{uri.query}")
         | 
| 50 | 
            +
                  end   
         | 
| 51 | 
            +
                end 
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                def https(uri)
         | 
| 54 | 
            +
                  https = Net::HTTP.new(uri.host, uri.port)
         | 
| 55 | 
            +
                  https.use_ssl = (uri.scheme == 'https')
         | 
| 56 | 
            +
                  begin
         | 
| 57 | 
            +
                    https.start do |h|
         | 
| 58 | 
            +
                      yield(h)
         | 
| 59 | 
            +
                    end
         | 
| 60 | 
            +
                  rescue Errno::ECONNREFUSED => error
         | 
| 61 | 
            +
                    raise CasServerException
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              class CommandLineClient < Client
         | 
| 68 | 
            +
                attr_accessor :cas_server_url, :service_url
         | 
| 69 | 
            +
                def login(username, password)
         | 
| 70 | 
            +
                  post(URI.parse(login_url), {:username => username, :password => password, :service => service_url})
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                def get_service_ticket(username, password)
         | 
| 74 | 
            +
                  location = login(username, password)['location']
         | 
| 75 | 
            +
                  query = {}
         | 
| 76 | 
            +
                  URI.parse(location).query.collect{|q| k,v = q.split('='); query[k] = v }
         | 
| 77 | 
            +
                  Ticket.new(query['ticket'], @service_url)
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
                
         | 
| 80 | 
            +
                private
         | 
| 81 | 
            +
                
         | 
| 82 | 
            +
                def post(uri, form_data)
         | 
| 83 | 
            +
                  req = Net::HTTP::Post.new(uri.path)
         | 
| 84 | 
            +
                  req.set_form_data(form_data, ';')
         | 
| 85 | 
            +
                  https(uri) do |h|
         | 
| 86 | 
            +
                    h.request(req)
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
                end  
         | 
| 89 | 
            +
              end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
              class Ticket
         | 
| 92 | 
            +
                attr_accessor :user, :failure_code, :failure_message
         | 
| 93 | 
            +
                attr_reader :service_url
         | 
| 94 | 
            +
                
         | 
| 95 | 
            +
                def initialize(ticket, service_url, renew = false)      
         | 
| 96 | 
            +
                  @service_url = service_url
         | 
| 97 | 
            +
                  @ticket  = ticket
         | 
| 98 | 
            +
                  @renew   = renew
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                def self.from_hash(hash)
         | 
| 102 | 
            +
                  ticket = Ticket.new(hash[:ticket], hash[:service_url], hash[:renew])
         | 
| 103 | 
            +
                  ticket.user = hash[:user]
         | 
| 104 | 
            +
                  ticket
         | 
| 105 | 
            +
                end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                def to_request_params
         | 
| 108 | 
            +
                  params = {:service =>  @service_url,
         | 
| 109 | 
            +
                    :ticket => @ticket }
         | 
| 110 | 
            +
                  params[:renew] = 1 if @renew
         | 
| 111 | 
            +
                  params
         | 
| 112 | 
            +
                end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                def to_hash
         | 
| 115 | 
            +
                  props = {}
         | 
| 116 | 
            +
                  props[:user] = @user if authenticated?
         | 
| 117 | 
            +
                  props[:renew] = @renew if @renew
         | 
| 118 | 
            +
                  props[:service_url] = @service_url
         | 
| 119 | 
            +
                  props[:ticket] = @ticket
         | 
| 120 | 
            +
                  props
         | 
| 121 | 
            +
                end
         | 
| 122 | 
            +
                
         | 
| 123 | 
            +
                def authenticated?
         | 
| 124 | 
            +
                  !!@user
         | 
| 125 | 
            +
                end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                def authenticate(body)
         | 
| 128 | 
            +
                  response = CasResponseParser.parse(self, body)
         | 
| 129 | 
            +
                  authenticated?
         | 
| 130 | 
            +
                end
         | 
| 131 | 
            +
              end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
              class ResponseError < Exception
         | 
| 134 | 
            +
              end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
              class CasServerException < Exception
         | 
| 137 | 
            +
              end
         | 
| 138 | 
            +
              
         | 
| 139 | 
            +
              class UnknownTicketType <  Exception
         | 
| 140 | 
            +
              end
         | 
| 141 | 
            +
            end
         | 
| 142 | 
            +
             | 
| 143 | 
            +
            class URI::HTTP
         | 
| 144 | 
            +
              def merge_query(hash)
         | 
| 145 | 
            +
                q = query ? query + '&' : ''
         | 
| 146 | 
            +
                self.query = "#{q}#{hash_to_uri_array(hash)}"
         | 
| 147 | 
            +
              end
         | 
| 148 | 
            +
              
         | 
| 149 | 
            +
              def hash_to_uri_array(hash)
         | 
| 150 | 
            +
                hash.collect do |name, value|
         | 
| 151 | 
            +
                  if value.kind_of? Array
         | 
| 152 | 
            +
                    value.map {|v| stringify_param(name, v) }
         | 
| 153 | 
            +
                  else
         | 
| 154 | 
            +
                    stringify_param(name, value)
         | 
| 155 | 
            +
                  end
         | 
| 156 | 
            +
                end.join('&')
         | 
| 157 | 
            +
              end
         | 
| 158 | 
            +
             | 
| 159 | 
            +
              def stringify_param(name, value)
         | 
| 160 | 
            +
                "#{CGI::escape(name.to_s)}=#{CGI::escape(value.to_s)}"
         | 
| 161 | 
            +
              end  
         | 
| 162 | 
            +
            end
         | 
| @@ -0,0 +1,48 @@ | |
| 1 | 
            +
            module Casablanca
         | 
| 2 | 
            +
              class RailsFilter
         | 
| 3 | 
            +
                @@client = nil
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                class << self
         | 
| 6 | 
            +
                  
         | 
| 7 | 
            +
                  def client=client
         | 
| 8 | 
            +
                    @@client = client
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
                  
         | 
| 11 | 
            +
                  def filter(controller)
         | 
| 12 | 
            +
                    return true if previous_ticket(controller) && !controller.params[:renew]     
         | 
| 13 | 
            +
                    ticket = Ticket.new(controller.params[:ticket], @@client.service_url, controller.params[:renew])
         | 
| 14 | 
            +
                    if @@client.authenticate_ticket(ticket)
         | 
| 15 | 
            +
                      puts "Ticket authenticated #{ticket.failure_message}"
         | 
| 16 | 
            +
                      controller.session[:cas_user] = ticket.user
         | 
| 17 | 
            +
                      controller.session[:cas_ticket] = ticket.to_hash
         | 
| 18 | 
            +
                      return true
         | 
| 19 | 
            +
                    else
         | 
| 20 | 
            +
                      puts "Ticket authentication failed: #{ticket.failure_message}"          
         | 
| 21 | 
            +
                      controller.session[:cas_user] = nil
         | 
| 22 | 
            +
                      controller.session[:cas_ticket] = nil
         | 
| 23 | 
            +
                      controller.send(:redirect_to, login_url)
         | 
| 24 | 
            +
                      return false
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def login_url
         | 
| 29 | 
            +
                    @@client.login_url
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  def logout(controller)
         | 
| 33 | 
            +
                    controller.send(:reset_session)
         | 
| 34 | 
            +
                    controller.send(:redirect_to, @@client.logout_url)
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
                  
         | 
| 37 | 
            +
                  private
         | 
| 38 | 
            +
                  
         | 
| 39 | 
            +
                  def previous_ticket(controller)
         | 
| 40 | 
            +
                    hash = controller.session[:cas_ticket]
         | 
| 41 | 
            +
                    return nil unless hash
         | 
| 42 | 
            +
                    Ticket.from_hash(hash)
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                  
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            end
         | 
| @@ -0,0 +1,50 @@ | |
| 1 | 
            +
            module Casablanca
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              class CasResponseParser
         | 
| 4 | 
            +
                def protocol
         | 
| 5 | 
            +
                  self.class.to_s.gsub(/(Casablanca::Cas_|_ResponseParser)/, '').gsub('_', '.').to_f
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def self.parse(ticket, body)
         | 
| 9 | 
            +
                  raise ResponseError, "Response body is empty" if body.nil? || body.strip == ""
         | 
| 10 | 
            +
                  #return Cas_1_0_Parser.new(body) if ?
         | 
| 11 | 
            +
                  response = Cas_2_0_ResponseParser.new(body)
         | 
| 12 | 
            +
                  ticket.user = response.user      
         | 
| 13 | 
            +
                  unless response.authenticated?
         | 
| 14 | 
            +
                    ticket.failure_code = response.failure_code
         | 
| 15 | 
            +
                    ticket.failure_message = response.failure_message
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              class Cas_2_0_ResponseParser < CasResponseParser
         | 
| 21 | 
            +
                def initialize(xml)
         | 
| 22 | 
            +
                  doc = REXML::Document.new(xml)
         | 
| 23 | 
            +
                  @xml = doc.elements['cas:serviceResponse'].elements[1]
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def user
         | 
| 27 | 
            +
                  strip_text(@xml.elements['cas:user'])
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def authenticated?
         | 
| 31 | 
            +
                  @xml.name == 'authenticationSuccess'
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def failure_code
         | 
| 35 | 
            +
                  @xml.elements['//cas:authenticationFailure'].attributes['code']
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                def failure_message
         | 
| 39 | 
            +
                  strip_text(@xml.elements['//cas:authenticationFailure'])
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                private
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                def strip_text(tag)
         | 
| 45 | 
            +
                  tag.text.strip if tag
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            end
         | 
    
        data/test/test_client.rb
    ADDED
    
    | @@ -0,0 +1,96 @@ | |
| 1 | 
            +
            require File.join(File.dirname(__FILE__), 'test_helper.rb')
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class TestClient < Test::Unit::TestCase
         | 
| 4 | 
            +
              def setup
         | 
| 5 | 
            +
                @client = Client.new(:cas_server_url => "http://localhost:4567", :service_url => "http://localhost:3000")
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
              
         | 
| 8 | 
            +
              def test_config
         | 
| 9 | 
            +
                assert_equal @client.service_url, "http://localhost:3000"
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              def test_config_requires_cas_server_url
         | 
| 13 | 
            +
                assert_raises(RuntimeError) do
         | 
| 14 | 
            +
                  @client = Client.new({})
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              def test_authenticate_ticket
         | 
| 19 | 
            +
                cli = CommandLineClient.new(:cas_server_url => "http://localhost:4567", :service_url => "http://localhost:3000")
         | 
| 20 | 
            +
                ticket = cli.login_ticket('admin', 'admin') #'ST-1231341579r871C5757B79767C21E'
         | 
| 21 | 
            +
                service_ticket = Ticket.new(ticket, 'http://localhost:3000', true)
         | 
| 22 | 
            +
                @client.authenticate_ticket(service_ticket)
         | 
| 23 | 
            +
                assert_equal 'admin', service_ticket.user
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
              
         | 
| 26 | 
            +
              def test_validate_expired_ticket
         | 
| 27 | 
            +
                ticket = 'ST-1231341579r871C5757B79767C21E'
         | 
| 28 | 
            +
                service_ticket = Ticket.new(ticket, 'http://localhost:3000', true)
         | 
| 29 | 
            +
                @client.authenticate_ticket(service_ticket)
         | 
| 30 | 
            +
                assert_equal 'INVALID_TICKET', service_ticket.failure_code
         | 
| 31 | 
            +
                #assert_equal "Ticket 'ST-1231341579r871C5757B79767C21E' has already been used up.", ticket.failure_message
         | 
| 32 | 
            +
              end  
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              def test_validate_invalid_ticket
         | 
| 35 | 
            +
                ticket = '1231341579r871C5757B79767C21E'
         | 
| 36 | 
            +
                service_ticket =  Ticket.new(ticket, 'http://localhost:3000', true)
         | 
| 37 | 
            +
                @client.authenticate_ticket(service_ticket)
         | 
| 38 | 
            +
                assert_equal 'INVALID_TICKET', service_ticket.failure_code
         | 
| 39 | 
            +
                assert_equal "Ticket 1231341579r871C5757B79767C21E not recognized.", service_ticket.failure_message
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              def test_authenticate_ticket_with_empty_service_url
         | 
| 43 | 
            +
                service_ticket = Ticket.new('ticket', nil)
         | 
| 44 | 
            +
                assert_raises(RuntimeError) do
         | 
| 45 | 
            +
                  @client.authenticate_ticket(service_ticket)
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              def test_login_url
         | 
| 50 | 
            +
                assert_equal 'http://localhost:4567/login?service=http://localhost:3000', @client.login_url
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
              
         | 
| 53 | 
            +
              def test_logout_url
         | 
| 54 | 
            +
                assert_equal 'http://localhost:4567/logout', @client.logout_url
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
             
         | 
| 57 | 
            +
              def test_validate_url
         | 
| 58 | 
            +
                assert_equal 'http://localhost:4567/proxyValidate', @client.validate_url
         | 
| 59 | 
            +
              end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
            class TestCommandLineClient < Test::Unit::TestCase
         | 
| 64 | 
            +
              def setup
         | 
| 65 | 
            +
                @client = CommandLineClient.new(:cas_server_url => "http://localhost:4567", :service_url => "http://localhost:3000")
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
              def test_login
         | 
| 69 | 
            +
                @client.expects(:post).returns(MockResponse.new('', '303', :location => 'http://localhost:3000?ticket=ST-1231341579r871C5757B79767C21E'))
         | 
| 70 | 
            +
                res = @client.login('admin', 'admin')
         | 
| 71 | 
            +
                assert_equal '', res.body
         | 
| 72 | 
            +
                assert_equal '303', res.code
         | 
| 73 | 
            +
                assert_equal 'http://localhost:3000?ticket=ST-1231341579r871C5757B79767C21E', res['location']
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
              def test_get_service_ticket
         | 
| 77 | 
            +
                @client.expects(:post).returns(MockResponse.new('', '303', :location => 'http://localhost:3000?ticket=ST-1231341579r871C5757B79767C21E'))
         | 
| 78 | 
            +
                ticket = @client.get_login_ticket('admin', 'admin')
         | 
| 79 | 
            +
                assert_equal 'ST-1231341579r871C5757B79767C21E', ticket
         | 
| 80 | 
            +
              end
         | 
| 81 | 
            +
              
         | 
| 82 | 
            +
            end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
            class TestURIHTTP < Test::Unit::TestCase
         | 
| 85 | 
            +
              def test_merge_query
         | 
| 86 | 
            +
                uri = URI.parse('http://localhost:4567/login')
         | 
| 87 | 
            +
                uri.merge_query({:order_by => ['1', '2']})
         | 
| 88 | 
            +
                assert_equal 'order_by=1&order_by=2', uri.query   
         | 
| 89 | 
            +
              end
         | 
| 90 | 
            +
                
         | 
| 91 | 
            +
              def test_merge_query_with_existing_query
         | 
| 92 | 
            +
                uri = URI.parse('http://localhost:4567/login?search=ah')
         | 
| 93 | 
            +
                uri.merge_query({:order_by => ['1', '2']})
         | 
| 94 | 
            +
                assert_equal 'search=ah&order_by=1&order_by=2', uri.query   
         | 
| 95 | 
            +
              end
         | 
| 96 | 
            +
            end
         | 
    
        data/test/test_helper.rb
    ADDED
    
    | @@ -0,0 +1,54 @@ | |
| 1 | 
            +
            require(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'casablanca.rb')))
         | 
| 2 | 
            +
            require(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'casablanca', 'filters', 'rails.rb')))
         | 
| 3 | 
            +
            require 'test/unit'
         | 
| 4 | 
            +
            require 'rubygems'
         | 
| 5 | 
            +
            require 'mocha'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            class Test::Unit::TestCase
         | 
| 8 | 
            +
              include Casablanca
         | 
| 9 | 
            +
            end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            class MockResponse < Net::HTTPResponse
         | 
| 12 | 
            +
              attr_accessor :body, :code
         | 
| 13 | 
            +
              def initialize(body, code=200, header={})
         | 
| 14 | 
            +
                  @body, @code, @header = body, code, header
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              def []= key, value
         | 
| 18 | 
            +
                  @header[key.to_sym] = value
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              def [] key
         | 
| 22 | 
            +
                  @header[key.to_sym]
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
              
         | 
| 25 | 
            +
              def kind_of?(klass)
         | 
| 26 | 
            +
                if klass == Net::HTTPSuccess
         | 
| 27 | 
            +
                  code.to_i == 200
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            VALID_REQUEST = %(
         | 
| 33 | 
            +
            <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
         | 
| 34 | 
            +
              <cas:authenticationSuccess>
         | 
| 35 | 
            +
                <cas:user>admin</cas:user>        
         | 
| 36 | 
            +
              </cas:authenticationSuccess>
         | 
| 37 | 
            +
            </cas:serviceResponse>
         | 
| 38 | 
            +
            )
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            INVALID_REQUEST = %(
         | 
| 41 | 
            +
              <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
         | 
| 42 | 
            +
                <cas:authenticationFailure code="INVALID_REQUEST">
         | 
| 43 | 
            +
                Ticket or service parameter was missing in the request.
         | 
| 44 | 
            +
                </cas:authenticationFailure>
         | 
| 45 | 
            +
              </cas:serviceResponse>
         | 
| 46 | 
            +
            )
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            INVALID_TICKET = %(
         | 
| 49 | 
            +
            <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
         | 
| 50 | 
            +
              <cas:authenticationFailure code="INVALID_TICKET">
         | 
| 51 | 
            +
              Ticket ST-1231242314r72465638160B31E8D1 not recognized.
         | 
| 52 | 
            +
              </cas:authenticationFailure>
         | 
| 53 | 
            +
            </cas:serviceResponse>
         | 
| 54 | 
            +
            )
         | 
    
        data/test/test_parser.rb
    ADDED
    
    | @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            require File.join(File.dirname(__FILE__), 'test_helper.rb')
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class TestCas_2_0_ResponseParser < Test::Unit::TestCase
         | 
| 4 | 
            +
              def test_parse_valid_ticket
         | 
| 5 | 
            +
                response = Cas_2_0_ResponseParser.new(VALID_REQUEST)
         | 
| 6 | 
            +
                assert_equal 'admin', response.user
         | 
| 7 | 
            +
                assert_equal 2.0, response.protocol
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
                
         | 
| 10 | 
            +
              def test_parse_invalid_request
         | 
| 11 | 
            +
                response = Cas_2_0_ResponseParser.new(INVALID_REQUEST)
         | 
| 12 | 
            +
                assert_equal 'INVALID_REQUEST', response.failure_code    
         | 
| 13 | 
            +
                assert_equal 'Ticket or service parameter was missing in the request.', response.failure_message
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
              
         | 
| 16 | 
            +
              def test_parse_invalid_ticket
         | 
| 17 | 
            +
                response = Cas_2_0_ResponseParser.new(INVALID_TICKET)
         | 
| 18 | 
            +
                assert_equal 'INVALID_TICKET', response.failure_code    
         | 
| 19 | 
            +
                assert_equal 'Ticket ST-1231242314r72465638160B31E8D1 not recognized.', response.failure_message
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
                
         | 
| 22 | 
            +
            end
         | 
| @@ -0,0 +1,92 @@ | |
| 1 | 
            +
            require File.join(File.dirname(__FILE__), 'test_helper.rb')
         | 
| 2 | 
            +
            require 'action_pack'
         | 
| 3 | 
            +
            class TestRailsFilter < Test::Unit::TestCase
         | 
| 4 | 
            +
              def setup
         | 
| 5 | 
            +
                @client = Client.new(:cas_server_url => "http://localhost:4567", :service_url => "http://localhost:3000")
         | 
| 6 | 
            +
                RailsFilter.client = @client
         | 
| 7 | 
            +
                @controller = Controller.new    
         | 
| 8 | 
            +
                @controller.params = {}       
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
              
         | 
| 11 | 
            +
              def test_login_url
         | 
| 12 | 
            +
                assert_equal 'http://localhost:4567/login?service=http://localhost:3000', RailsFilter.login_url
         | 
| 13 | 
            +
              end  
         | 
| 14 | 
            +
              
         | 
| 15 | 
            +
              # def test_filter_requires_config
         | 
| 16 | 
            +
              #   RailsFilter.config = nil
         | 
| 17 | 
            +
              #   assert_raises(RuntimeError) do
         | 
| 18 | 
            +
              #     RailsFilter.filter(Controller.new)
         | 
| 19 | 
            +
              #   end
         | 
| 20 | 
            +
              # end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              def test_logout
         | 
| 23 | 
            +
                RailsFilter.logout(@controller)
         | 
| 24 | 
            +
                assert_equal({}, @controller.session)
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              def test_filter_invalid_attempt
         | 
| 28 | 
            +
                @controller.session = {}    
         | 
| 29 | 
            +
                assert_equal false, RailsFilter.filter(@controller)
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              def test_filter_authenticated
         | 
| 33 | 
            +
                params = {:ticket => 'a'}
         | 
| 34 | 
            +
                @client.expects(:authenticate_ticket).returns(true)
         | 
| 35 | 
            +
                @controller.params = params
         | 
| 36 | 
            +
                assert_equal true, RailsFilter.filter(@controller)
         | 
| 37 | 
            +
                assert_session(nil, { :ticket => 'a', :service_url => 'http://localhost:3000' })
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              def test_filter_same_ticket
         | 
| 41 | 
            +
                params = {:ticket => 'a'}
         | 
| 42 | 
            +
                @controller.session = { :cas_ticket => params, :cas_user => 'admin' }
         | 
| 43 | 
            +
                @controller.params = params
         | 
| 44 | 
            +
                assert_equal true, RailsFilter.filter(@controller)
         | 
| 45 | 
            +
                assert_session('admin', params)
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              def test_filter_resets_sessions_for_renew
         | 
| 49 | 
            +
                @controller.session[:cas_ticket] = { :ticket => 'a', :service_url => 'b'   }
         | 
| 50 | 
            +
                @controller.params = {:renew => true }    
         | 
| 51 | 
            +
                assert_equal false, RailsFilter.filter(@controller)
         | 
| 52 | 
            +
                assert_session(nil, nil)
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
              def assert_session(user, ticket)
         | 
| 56 | 
            +
                assert_equal ticket, @controller.session[:cas_ticket]
         | 
| 57 | 
            +
                assert_equal user, @controller.session[:cas_user]
         | 
| 58 | 
            +
              end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
            end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
            class Controller # < ActionController::Base
         | 
| 63 | 
            +
              attr_accessor :params, :session
         | 
| 64 | 
            +
              def initialize
         | 
| 65 | 
            +
                @session = {}
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
              
         | 
| 68 | 
            +
              def request
         | 
| 69 | 
            +
                Request.new
         | 
| 70 | 
            +
              end
         | 
| 71 | 
            +
              
         | 
| 72 | 
            +
              def url_for(url)
         | 
| 73 | 
            +
                url
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
              
         | 
| 76 | 
            +
              def redirect_to(url)
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
              
         | 
| 79 | 
            +
              private
         | 
| 80 | 
            +
              
         | 
| 81 | 
            +
              def reset_session
         | 
| 82 | 
            +
                @session = {}
         | 
| 83 | 
            +
              end
         | 
| 84 | 
            +
            end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
            class Request
         | 
| 87 | 
            +
              def headers
         | 
| 88 | 
            +
                {}
         | 
| 89 | 
            +
              end
         | 
| 90 | 
            +
              def post?
         | 
| 91 | 
            +
              end
         | 
| 92 | 
            +
            end
         | 
    
        data/test/test_ticket.rb
    ADDED
    
    | @@ -0,0 +1,71 @@ | |
| 1 | 
            +
            require File.join(File.dirname(__FILE__), 'test_helper.rb')
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class TestTicket < Test::Unit::TestCase
         | 
| 4 | 
            +
              def setup
         | 
| 5 | 
            +
                @ticket = Ticket.new('ST-1231242314r72465638160B31E8D1', 'http://localhost:3000')
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
              
         | 
| 8 | 
            +
              def test_create_service_ticket
         | 
| 9 | 
            +
                ticket = Ticket.new('ST-1231242314r72465638160B31E8D1', 'http://localhost:3000')
         | 
| 10 | 
            +
                assert_equal 'ST-1231242314r72465638160B31E8D1', ticket.to_hash[:ticket]
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
              
         | 
| 13 | 
            +
              def test_create_proxy_ticket
         | 
| 14 | 
            +
                ticket = Ticket.new('PT-1231242314r72465638160B31E8D1', 'http://localhost:3000')
         | 
| 15 | 
            +
                assert_equal 'PT-1231242314r72465638160B31E8D1', ticket.to_hash[:ticket]
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              def test_to_hash
         | 
| 19 | 
            +
                ticket = Ticket.new('ST-1231242314r72465638160B31E8D1', 'http://localhost:3000')
         | 
| 20 | 
            +
                assert_equal 'ST-1231242314r72465638160B31E8D1', ticket.to_hash[:ticket]
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              def test_from_hash
         | 
| 24 | 
            +
                props = {:ticket => 'ticket',
         | 
| 25 | 
            +
                              :service_url => "http://localhost:3000",
         | 
| 26 | 
            +
                              :renew    => 1,
         | 
| 27 | 
            +
                              :user     => 'admin' }
         | 
| 28 | 
            +
                ticket = Ticket.from_hash(props)
         | 
| 29 | 
            +
                assert_equal props, ticket.to_hash
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              def test_to_request_params
         | 
| 33 | 
            +
                ticket = Ticket.new('ticket', 'http://localhost:3000')
         | 
| 34 | 
            +
                expected = {:ticket => 'ticket',
         | 
| 35 | 
            +
                              :service  => "http://localhost:3000" }
         | 
| 36 | 
            +
                assert_equal(expected, ticket.to_request_params)
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              def test_to_request_params_with_renew
         | 
| 40 | 
            +
                ticket = Ticket.new('ticket', 'http://localhost:3000', true)
         | 
| 41 | 
            +
                expected = {:ticket => 'ticket',
         | 
| 42 | 
            +
                              :service  => "http://localhost:3000",
         | 
| 43 | 
            +
                              :renew    => 1 }
         | 
| 44 | 
            +
                assert_equal(expected, ticket.to_request_params)
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
              
         | 
| 47 | 
            +
              def test_authenticate_valid_ticket
         | 
| 48 | 
            +
                @ticket.authenticate(VALID_REQUEST)
         | 
| 49 | 
            +
                assert_equal 'admin', @ticket.user
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              def test_authenticate_invalid_request_resets_ticket_to_unauthenticated
         | 
| 53 | 
            +
                @ticket.authenticate(VALID_REQUEST)
         | 
| 54 | 
            +
                assert_equal true, @ticket.authenticated?
         | 
| 55 | 
            +
                @ticket.authenticate(INVALID_REQUEST)
         | 
| 56 | 
            +
                assert_equal false, @ticket.authenticated?
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
                
         | 
| 59 | 
            +
              def test_authenticate_invalid_request
         | 
| 60 | 
            +
                @ticket.authenticate(INVALID_REQUEST)
         | 
| 61 | 
            +
                assert_equal 'INVALID_REQUEST', @ticket.failure_code    
         | 
| 62 | 
            +
                assert_equal 'Ticket or service parameter was missing in the request.', @ticket.failure_message
         | 
| 63 | 
            +
              end
         | 
| 64 | 
            +
              
         | 
| 65 | 
            +
              def test_authenticate_invalid_ticket
         | 
| 66 | 
            +
                @ticket.authenticate(INVALID_TICKET)
         | 
| 67 | 
            +
                assert_equal 'INVALID_TICKET', @ticket.failure_code    
         | 
| 68 | 
            +
                assert_equal 'Ticket ST-1231242314r72465638160B31E8D1 not recognized.', @ticket.failure_message
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,85 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification 
         | 
| 2 | 
            +
            name: p8-casablanca
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            +
              version: 0.0.1
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors: 
         | 
| 7 | 
            +
            - Petrik de Heus
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            date: 2009-01-17 00:00:00 -08:00
         | 
| 13 | 
            +
            default_executable: casablanca
         | 
| 14 | 
            +
            dependencies: 
         | 
| 15 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 16 | 
            +
              name: hoe
         | 
| 17 | 
            +
              version_requirement: 
         | 
| 18 | 
            +
              version_requirements: !ruby/object:Gem::Requirement 
         | 
| 19 | 
            +
                requirements: 
         | 
| 20 | 
            +
                - - ">="
         | 
| 21 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 22 | 
            +
                    version: 1.8.2
         | 
| 23 | 
            +
                version: 
         | 
| 24 | 
            +
            description: 
         | 
| 25 | 
            +
            email: 
         | 
| 26 | 
            +
            - FIX@example.com
         | 
| 27 | 
            +
            executables: 
         | 
| 28 | 
            +
            - casablanca
         | 
| 29 | 
            +
            extensions: []
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            extra_rdoc_files: 
         | 
| 32 | 
            +
            - History.txt
         | 
| 33 | 
            +
            - Manifest.txt
         | 
| 34 | 
            +
            - README.textile
         | 
| 35 | 
            +
            files: 
         | 
| 36 | 
            +
            - History.txt
         | 
| 37 | 
            +
            - Manifest.txt
         | 
| 38 | 
            +
            - Rakefile
         | 
| 39 | 
            +
            - init.rb
         | 
| 40 | 
            +
            - bin/casablanca
         | 
| 41 | 
            +
            - lib/casablanca.rb
         | 
| 42 | 
            +
            - lib/casablanca/cli.rb
         | 
| 43 | 
            +
            - lib/casablanca/client.rb
         | 
| 44 | 
            +
            - lib/casablanca/filters/rails.rb
         | 
| 45 | 
            +
            - lib/casablanca/response_parsers.rb
         | 
| 46 | 
            +
            - lib/casablanca/version.rb
         | 
| 47 | 
            +
            - test/test_client.rb
         | 
| 48 | 
            +
            - test/test_helper.rb
         | 
| 49 | 
            +
            - test/test_parser.rb
         | 
| 50 | 
            +
            - test/test_rails_filter.rb
         | 
| 51 | 
            +
            - test/test_ticket.rb
         | 
| 52 | 
            +
            - README.textile
         | 
| 53 | 
            +
            has_rdoc: true
         | 
| 54 | 
            +
            homepage: 
         | 
| 55 | 
            +
            post_install_message: 
         | 
| 56 | 
            +
            rdoc_options: 
         | 
| 57 | 
            +
            - --main
         | 
| 58 | 
            +
            - README.txt
         | 
| 59 | 
            +
            require_paths: 
         | 
| 60 | 
            +
            - lib
         | 
| 61 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         | 
| 62 | 
            +
              requirements: 
         | 
| 63 | 
            +
              - - ">="
         | 
| 64 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 65 | 
            +
                  version: "0"
         | 
| 66 | 
            +
              version: 
         | 
| 67 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         | 
| 68 | 
            +
              requirements: 
         | 
| 69 | 
            +
              - - ">="
         | 
| 70 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 71 | 
            +
                  version: "0"
         | 
| 72 | 
            +
              version: 
         | 
| 73 | 
            +
            requirements: []
         | 
| 74 | 
            +
             | 
| 75 | 
            +
            rubyforge_project: casablanca
         | 
| 76 | 
            +
            rubygems_version: 1.2.0
         | 
| 77 | 
            +
            signing_key: 
         | 
| 78 | 
            +
            specification_version: 2
         | 
| 79 | 
            +
            summary: A single sign-on client based on the CAS 2.0 protocol.
         | 
| 80 | 
            +
            test_files: 
         | 
| 81 | 
            +
            - test/test_client.rb
         | 
| 82 | 
            +
            - test/test_helper.rb
         | 
| 83 | 
            +
            - test/test_parser.rb
         | 
| 84 | 
            +
            - test/test_rails_filter.rb
         | 
| 85 | 
            +
            - test/test_ticket.rb
         |