casablanca 0.0.2

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