casablanca 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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