casino_core 0.0.5 → 0.0.6
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/Gemfile +1 -0
- data/Gemfile.lock +10 -5
- data/VERSION +1 -1
- data/casino_core.gemspec +9 -2
- data/config/cas.yml +4 -2
- data/db/migrate/20121223135227_proxy_granting_tickets_belongs_to_service_ticket.rb +14 -0
- data/db/schema.rb +7 -7
- data/lib/casino_core/helper/logger.rb +3 -4
- data/lib/casino_core/helper/proxy_granting_tickets.rb +45 -0
- data/lib/casino_core/helper/service_tickets.rb +34 -0
- data/lib/casino_core/helper.rb +1 -0
- data/lib/casino_core/model/proxy_granting_ticket.rb +2 -2
- data/lib/casino_core/model/service_ticket.rb +1 -0
- data/lib/casino_core/model/ticket_granting_ticket.rb +0 -1
- data/lib/casino_core/processor/legacy_validator.rb +2 -33
- data/lib/casino_core/processor/service_ticket_validator.rb +69 -0
- data/lib/casino_core/processor.rb +1 -0
- data/lib/casino_core/railtie.rb +5 -1
- data/lib/casino_core/settings.rb +5 -1
- data/spec/model/login_ticket_spec.rb +7 -0
- data/spec/processor/legacy_validator_spec.rb +5 -5
- data/spec/processor/service_ticket_validator_spec.rb +123 -0
- data/spec/spec_helper.rb +7 -1
- metadata +18 -3
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -15,6 +15,7 @@ GEM
|
|
15
15
|
addressable (2.3.2)
|
16
16
|
arel (3.0.2)
|
17
17
|
builder (3.0.4)
|
18
|
+
crack (0.3.1)
|
18
19
|
database_cleaner (0.9.1)
|
19
20
|
diff-lcs (1.1.3)
|
20
21
|
git (1.2.5)
|
@@ -25,8 +26,8 @@ GEM
|
|
25
26
|
rake
|
26
27
|
rdoc
|
27
28
|
json (1.7.5)
|
28
|
-
multi_json (1.
|
29
|
-
rake (10.0.
|
29
|
+
multi_json (1.5.0)
|
30
|
+
rake (10.0.3)
|
30
31
|
rdoc (3.12)
|
31
32
|
json (~> 1.4)
|
32
33
|
redcarpet (2.2.2)
|
@@ -34,10 +35,10 @@ GEM
|
|
34
35
|
rspec-core (~> 2.12.0)
|
35
36
|
rspec-expectations (~> 2.12.0)
|
36
37
|
rspec-mocks (~> 2.12.0)
|
37
|
-
rspec-core (2.12.
|
38
|
-
rspec-expectations (2.12.
|
38
|
+
rspec-core (2.12.2)
|
39
|
+
rspec-expectations (2.12.1)
|
39
40
|
diff-lcs (~> 1.1.3)
|
40
|
-
rspec-mocks (2.12.
|
41
|
+
rspec-mocks (2.12.1)
|
41
42
|
simplecov (0.7.1)
|
42
43
|
multi_json (~> 1.0)
|
43
44
|
simplecov-html (~> 0.7.1)
|
@@ -45,6 +46,9 @@ GEM
|
|
45
46
|
sqlite3 (1.3.6)
|
46
47
|
tzinfo (0.3.35)
|
47
48
|
useragent (0.4.15)
|
49
|
+
webmock (1.9.0)
|
50
|
+
addressable (>= 2.2.7)
|
51
|
+
crack (>= 0.1.7)
|
48
52
|
yard (0.8.3)
|
49
53
|
|
50
54
|
PLATFORMS
|
@@ -61,4 +65,5 @@ DEPENDENCIES
|
|
61
65
|
simplecov (~> 0.7.1)
|
62
66
|
sqlite3
|
63
67
|
useragent (~> 0.4.13)
|
68
|
+
webmock
|
64
69
|
yard (~> 0.8.3)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.6
|
data/casino_core.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "casino_core"
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.6"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Nils Caspar"]
|
12
|
-
s.date = "2012-12-
|
12
|
+
s.date = "2012-12-24"
|
13
13
|
s.description = "A CAS server core library."
|
14
14
|
s.email = "ncaspar@me.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -41,6 +41,7 @@ Gem::Specification.new do |s|
|
|
41
41
|
"db/migrate/20121125091934_add_issued_from_credentials_to_service_tickets.rb",
|
42
42
|
"db/migrate/20121125185415_create_proxy_granting_tickets.rb",
|
43
43
|
"db/migrate/20121125190013_tickets_should_be_unique.rb",
|
44
|
+
"db/migrate/20121223135227_proxy_granting_tickets_belongs_to_service_ticket.rb",
|
44
45
|
"db/schema.rb",
|
45
46
|
"lib/casino_core.rb",
|
46
47
|
"lib/casino_core/authenticator.rb",
|
@@ -49,6 +50,7 @@ Gem::Specification.new do |s|
|
|
49
50
|
"lib/casino_core/helper/browser.rb",
|
50
51
|
"lib/casino_core/helper/logger.rb",
|
51
52
|
"lib/casino_core/helper/login_tickets.rb",
|
53
|
+
"lib/casino_core/helper/proxy_granting_tickets.rb",
|
52
54
|
"lib/casino_core/helper/service_tickets.rb",
|
53
55
|
"lib/casino_core/helper/ticket_granting_tickets.rb",
|
54
56
|
"lib/casino_core/helper/tickets.rb",
|
@@ -63,6 +65,7 @@ Gem::Specification.new do |s|
|
|
63
65
|
"lib/casino_core/processor/login_credential_acceptor.rb",
|
64
66
|
"lib/casino_core/processor/login_credential_requestor.rb",
|
65
67
|
"lib/casino_core/processor/logout.rb",
|
68
|
+
"lib/casino_core/processor/service_ticket_validator.rb",
|
66
69
|
"lib/casino_core/processor/session_destroyer.rb",
|
67
70
|
"lib/casino_core/processor/session_overview.rb",
|
68
71
|
"lib/casino_core/railtie.rb",
|
@@ -77,6 +80,7 @@ Gem::Specification.new do |s|
|
|
77
80
|
"spec/processor/login_credential_acceptor_spec.rb",
|
78
81
|
"spec/processor/login_credential_requestor_spec.rb",
|
79
82
|
"spec/processor/logout_spec.rb",
|
83
|
+
"spec/processor/service_ticket_validator_spec.rb",
|
80
84
|
"spec/processor/session_destroyer_spec.rb",
|
81
85
|
"spec/processor/session_overview_spec.rb",
|
82
86
|
"spec/spec_helper.rb"
|
@@ -102,6 +106,7 @@ Gem::Specification.new do |s|
|
|
102
106
|
s.add_development_dependency(%q<simplecov>, ["~> 0.7.1"])
|
103
107
|
s.add_development_dependency(%q<sqlite3>, [">= 0"])
|
104
108
|
s.add_development_dependency(%q<database_cleaner>, [">= 0"])
|
109
|
+
s.add_development_dependency(%q<webmock>, [">= 0"])
|
105
110
|
else
|
106
111
|
s.add_dependency(%q<activerecord>, ["~> 3.2.9"])
|
107
112
|
s.add_dependency(%q<addressable>, ["~> 2.3.2"])
|
@@ -114,6 +119,7 @@ Gem::Specification.new do |s|
|
|
114
119
|
s.add_dependency(%q<simplecov>, ["~> 0.7.1"])
|
115
120
|
s.add_dependency(%q<sqlite3>, [">= 0"])
|
116
121
|
s.add_dependency(%q<database_cleaner>, [">= 0"])
|
122
|
+
s.add_dependency(%q<webmock>, [">= 0"])
|
117
123
|
end
|
118
124
|
else
|
119
125
|
s.add_dependency(%q<activerecord>, ["~> 3.2.9"])
|
@@ -127,6 +133,7 @@ Gem::Specification.new do |s|
|
|
127
133
|
s.add_dependency(%q<simplecov>, ["~> 0.7.1"])
|
128
134
|
s.add_dependency(%q<sqlite3>, [">= 0"])
|
129
135
|
s.add_dependency(%q<database_cleaner>, [">= 0"])
|
136
|
+
s.add_dependency(%q<webmock>, [">= 0"])
|
130
137
|
end
|
131
138
|
end
|
132
139
|
|
data/config/cas.yml
CHANGED
@@ -13,7 +13,8 @@ development:
|
|
13
13
|
options:
|
14
14
|
users:
|
15
15
|
testuser:
|
16
|
-
password: foobar123
|
16
|
+
password: "foobar123"
|
17
|
+
name: "Test User"
|
17
18
|
|
18
19
|
test:
|
19
20
|
<<: *defaults
|
@@ -23,4 +24,5 @@ test:
|
|
23
24
|
options:
|
24
25
|
users:
|
25
26
|
testuser:
|
26
|
-
password: foobar123
|
27
|
+
password: "foobar123"
|
28
|
+
name: "Test User"
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'casino_core/model'
|
2
|
+
|
3
|
+
class ProxyGrantingTicketsBelongsToServiceTicket < ActiveRecord::Migration
|
4
|
+
def change
|
5
|
+
CASinoCore::Model::ProxyGrantingTicket.delete_all
|
6
|
+
|
7
|
+
remove_index :proxy_granting_tickets, :ticket_granting_ticket_id
|
8
|
+
remove_column :proxy_granting_tickets, :ticket_granting_ticket_id
|
9
|
+
|
10
|
+
add_column :proxy_granting_tickets, :service_ticket_id, :integer
|
11
|
+
change_column :proxy_granting_tickets, :service_ticket_id, :integer, null: false
|
12
|
+
add_index :proxy_granting_tickets, :service_ticket_id
|
13
|
+
end
|
14
|
+
end
|
data/db/schema.rb
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
#
|
12
12
|
# It's strongly recommended to check this file into your version control system.
|
13
13
|
|
14
|
-
ActiveRecord::Schema.define(:version =>
|
14
|
+
ActiveRecord::Schema.define(:version => 20121223135227) do
|
15
15
|
|
16
16
|
create_table "login_tickets", :force => true do |t|
|
17
17
|
t.string "ticket", :null => false
|
@@ -22,16 +22,16 @@ ActiveRecord::Schema.define(:version => 20121125190013) do
|
|
22
22
|
add_index "login_tickets", ["ticket"], :name => "index_login_tickets_on_ticket", :unique => true
|
23
23
|
|
24
24
|
create_table "proxy_granting_tickets", :force => true do |t|
|
25
|
-
t.string "ticket",
|
26
|
-
t.string "iou",
|
27
|
-
t.
|
28
|
-
t.datetime "
|
29
|
-
t.
|
25
|
+
t.string "ticket", :null => false
|
26
|
+
t.string "iou", :null => false
|
27
|
+
t.datetime "created_at", :null => false
|
28
|
+
t.datetime "updated_at", :null => false
|
29
|
+
t.integer "service_ticket_id", :null => false
|
30
30
|
end
|
31
31
|
|
32
32
|
add_index "proxy_granting_tickets", ["iou"], :name => "index_proxy_granting_tickets_on_iou", :unique => true
|
33
|
+
add_index "proxy_granting_tickets", ["service_ticket_id"], :name => "index_proxy_granting_tickets_on_service_ticket_id"
|
33
34
|
add_index "proxy_granting_tickets", ["ticket"], :name => "index_proxy_granting_tickets_on_ticket", :unique => true
|
34
|
-
add_index "proxy_granting_tickets", ["ticket_granting_ticket_id"], :name => "index_proxy_granting_tickets_on_ticket_granting_ticket_id"
|
35
35
|
|
36
36
|
create_table "service_tickets", :force => true do |t|
|
37
37
|
t.string "ticket", :null => false
|
@@ -1,11 +1,10 @@
|
|
1
|
+
require 'casino_core/settings'
|
2
|
+
|
1
3
|
module CASinoCore
|
2
4
|
module Helper
|
3
5
|
module Logger
|
4
6
|
def logger
|
5
|
-
|
6
|
-
logger = ::Logger.new(STDOUT)
|
7
|
-
logger.level = ::Logger::Severity::UNKNOWN
|
8
|
-
logger
|
7
|
+
CASinoCore::Settings.logger
|
9
8
|
end
|
10
9
|
end
|
11
10
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'addressable/uri'
|
2
|
+
require 'net/https'
|
3
|
+
|
4
|
+
require 'casino_core/helper/logger'
|
5
|
+
require 'casino_core/helper/tickets'
|
6
|
+
|
7
|
+
module CASinoCore
|
8
|
+
module Helper
|
9
|
+
module ProxyGrantingTickets
|
10
|
+
include CASinoCore::Helper::Logger
|
11
|
+
include CASinoCore::Helper::Tickets
|
12
|
+
|
13
|
+
def acquire_proxy_granting_ticket(pgt_url, service_ticket)
|
14
|
+
begin
|
15
|
+
uri = Addressable::URI.parse(pgt_url)
|
16
|
+
https = Net::HTTP.new(uri.host, uri.port || 443)
|
17
|
+
https.use_ssl = true
|
18
|
+
|
19
|
+
https.start do |conn|
|
20
|
+
pgt = service_ticket.proxy_granting_tickets.new({
|
21
|
+
ticket: random_ticket_string('PGT'),
|
22
|
+
iou: random_ticket_string('PGTIOU')
|
23
|
+
})
|
24
|
+
|
25
|
+
uri.query_values = (uri.query_values || {}).merge(pgtId: pgt.ticket, pgtIou: pgt.iou)
|
26
|
+
|
27
|
+
response = conn.request_get(uri.request_uri)
|
28
|
+
# TODO: follow redirects... 2.5.4 says that redirects MAY be followed
|
29
|
+
if "#{response.code}" == "200"
|
30
|
+
# 3.4 (proxy-granting ticket IOU)
|
31
|
+
pgt.save!
|
32
|
+
logger.debug "Proxy-granting ticket generated for pgt_url '#{pgt_url}': #{pgt.inspect}"
|
33
|
+
return pgt
|
34
|
+
else
|
35
|
+
logger.warn "Proxy-granting ticket callback server responded with a bad result code '#{response.code}'. PGT will not be stored."
|
36
|
+
end
|
37
|
+
end
|
38
|
+
rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError
|
39
|
+
logger.warn "Exception while communication with proxy-granting ticket callback server: #{e.message}"
|
40
|
+
end
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -26,6 +26,40 @@ module CASinoCore
|
|
26
26
|
|
27
27
|
clean_service
|
28
28
|
end
|
29
|
+
|
30
|
+
def validate_service_ticket_for_service(ticket, service, renew = false)
|
31
|
+
result = if service.nil? or ticket.nil?
|
32
|
+
logger.warn 'Invalid validate request: no valid ticket or no valid service given'
|
33
|
+
'INVALID_REQUEST'
|
34
|
+
else
|
35
|
+
if ticket.consumed?
|
36
|
+
logger.warn "Service ticket '#{ticket.ticket}' already consumed"
|
37
|
+
'INVALID_TICKET'
|
38
|
+
elsif Time.now - ticket.created_at > CASinoCore::Settings.service_ticket[:lifetime_unconsumed]
|
39
|
+
logger.warn "Service ticket '#{ticket.ticket}' has expired"
|
40
|
+
'INVALID_TICKET'
|
41
|
+
elsif clean_service_url(service) != ticket.service
|
42
|
+
logger.warn "Service ticket '#{ticket.ticket}' is not valid for service '#{service}'"
|
43
|
+
'INVALID_SERVICE'
|
44
|
+
elsif renew && !ticket.issued_from_credentials?
|
45
|
+
logger.info "Service ticket '#{ticket.ticket}' was not issued from credentials but service '#{service}' will only accept a renewed ticket"
|
46
|
+
'INVALID_TICKET'
|
47
|
+
else
|
48
|
+
logger.info "Service ticket '#{ticket.ticket}' for service '#{service}' successfully validated"
|
49
|
+
true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
unless ticket.nil?
|
53
|
+
logger.debug "Consumed ticket '#{ticket.ticket}'"
|
54
|
+
ticket.consumed = true
|
55
|
+
ticket.save!
|
56
|
+
end
|
57
|
+
result
|
58
|
+
end
|
59
|
+
|
60
|
+
def service_ticket_valid_for_service?(ticket, service, renew = false)
|
61
|
+
validate_service_ticket_for_service(ticket, service, renew) == true
|
62
|
+
end
|
29
63
|
end
|
30
64
|
end
|
31
65
|
end
|
data/lib/casino_core/helper.rb
CHANGED
@@ -6,6 +6,7 @@ module CASinoCore
|
|
6
6
|
autoload :Browser, 'casino_core/helper/browser.rb'
|
7
7
|
autoload :Logger, 'casino_core/helper/logger.rb'
|
8
8
|
autoload :LoginTickets, 'casino_core/helper/login_tickets.rb'
|
9
|
+
autoload :ProxyGrantingTickets, 'casino_core/helper/proxy_granting_tickets.rb'
|
9
10
|
autoload :ServiceTickets, 'casino_core/helper/service_tickets.rb'
|
10
11
|
autoload :Tickets, 'casino_core/helper/tickets.rb'
|
11
12
|
autoload :TicketGrantingTickets, 'casino_core/helper/ticket_granting_tickets.rb'
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'casino_core/model'
|
2
2
|
|
3
3
|
class CASinoCore::Model::ProxyGrantingTicket < ActiveRecord::Base
|
4
|
-
attr_accessible :iou, :ticket, :
|
4
|
+
attr_accessible :iou, :ticket, :service_ticket_id
|
5
5
|
validates :ticket, uniqueness: true
|
6
6
|
validates :iou, uniqueness: true
|
7
|
-
belongs_to :
|
7
|
+
belongs_to :service_ticket
|
8
8
|
end
|
@@ -9,6 +9,7 @@ class CASinoCore::Model::ServiceTicket < ActiveRecord::Base
|
|
9
9
|
validates :ticket, uniqueness: true
|
10
10
|
belongs_to :ticket_granting_ticket
|
11
11
|
before_destroy :send_single_sing_out_notification
|
12
|
+
has_many :proxy_granting_tickets
|
12
13
|
|
13
14
|
def self.cleanup_unconsumed
|
14
15
|
self.delete_all(['created_at < ? AND consumed = ?', CASinoCore::Settings.service_ticket[:lifetime_unconsumed].seconds.ago, false])
|
@@ -5,7 +5,6 @@ class CASinoCore::Model::TicketGrantingTicket < ActiveRecord::Base
|
|
5
5
|
serialize :extra_attributes, Hash
|
6
6
|
validates :ticket, uniqueness: true
|
7
7
|
has_many :service_tickets
|
8
|
-
has_many :proxy_granting_tickets
|
9
8
|
|
10
9
|
def browser_info
|
11
10
|
user_agent = UserAgent.parse(self.user_agent)
|
@@ -8,48 +8,17 @@ class CASinoCore::Processor::LegacyValidator < CASinoCore::Processor
|
|
8
8
|
include CASinoCore::Helper::ServiceTickets
|
9
9
|
|
10
10
|
# This method will call `#validation_succeeded` or `#validation_failed`. In both cases, it supplies
|
11
|
-
# a string as argument. The
|
11
|
+
# a string as argument. The web application should present that string (and nothing else) to the
|
12
12
|
# requestor.
|
13
13
|
#
|
14
14
|
# @param [Hash] params parameters supplied by requestor (a service)
|
15
15
|
def process(params = nil)
|
16
16
|
params ||= {}
|
17
17
|
ticket = CASinoCore::Model::ServiceTicket.where(ticket: params[:ticket]).first
|
18
|
-
if
|
18
|
+
if service_ticket_valid_for_service?(ticket, params[:service], !!params[:renew])
|
19
19
|
@listener.validation_succeeded("yes\n#{ticket.ticket_granting_ticket.username}\n")
|
20
20
|
else
|
21
21
|
@listener.validation_failed("no\n\n")
|
22
22
|
end
|
23
23
|
end
|
24
|
-
|
25
|
-
private
|
26
|
-
def ticket_valid_for_service?(ticket, service, renew = false)
|
27
|
-
ticket_valid = if service.nil? or ticket.nil?
|
28
|
-
logger.warn 'Invalid validate request: no valid ticket or no valid service given'
|
29
|
-
false
|
30
|
-
else
|
31
|
-
if ticket.consumed?
|
32
|
-
logger.warn "Service ticket '#{ticket.ticket}' already consumed"
|
33
|
-
false
|
34
|
-
elsif Time.now - ticket.created_at > CASinoCore::Settings.service_ticket[:lifetime_unconsumed]
|
35
|
-
logger.warn "Service ticket '#{ticket.ticket}' has expired"
|
36
|
-
false
|
37
|
-
elsif clean_service_url(service) != ticket.service
|
38
|
-
logger.warn "Service ticket '#{ticket.ticket}' is not valid for service '#{service}'"
|
39
|
-
false
|
40
|
-
elsif renew && !ticket.issued_from_credentials?
|
41
|
-
logger.info "Service ticket '#{ticket.ticket}' was not issued from credentials but service '#{service}' will only accept a renewed ticket"
|
42
|
-
false
|
43
|
-
else
|
44
|
-
logger.info "Service ticket '#{ticket.ticket}' for service '#{service}' successfully validated"
|
45
|
-
true
|
46
|
-
end
|
47
|
-
end
|
48
|
-
unless ticket.nil?
|
49
|
-
logger.debug "Consumed ticket '#{ticket.ticket}'"
|
50
|
-
ticket.consumed = true
|
51
|
-
ticket.save!
|
52
|
-
end
|
53
|
-
ticket_valid
|
54
|
-
end
|
55
24
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'builder'
|
2
|
+
require 'casino_core/processor'
|
3
|
+
require 'casino_core/helper'
|
4
|
+
require 'casino_core/model'
|
5
|
+
|
6
|
+
# The ServiceTicketValidator processor should be used to handle GET requests to /serviceValidate
|
7
|
+
class CASinoCore::Processor::ServiceTicketValidator < CASinoCore::Processor
|
8
|
+
include CASinoCore::Helper::ServiceTickets
|
9
|
+
include CASinoCore::Helper::ProxyGrantingTickets
|
10
|
+
|
11
|
+
# This method will call `#validation_succeeded` or `#validation_failed`. In both cases, it supplies
|
12
|
+
# a string as argument. The web application should present that string (and nothing else) to the
|
13
|
+
# requestor. The Content-Type should be set to 'text/xml; charset=utf-8'
|
14
|
+
#
|
15
|
+
# @param [Hash] params parameters delivered by the client
|
16
|
+
def process(params = nil)
|
17
|
+
params ||= {}
|
18
|
+
ticket = CASinoCore::Model::ServiceTicket.where(ticket: params[:ticket]).first
|
19
|
+
validation_result = validate_service_ticket_for_service(ticket, params[:service], !!params[:renew])
|
20
|
+
if validation_result == true
|
21
|
+
options = { service_ticket: ticket }
|
22
|
+
unless params[:pgtUrl].nil?
|
23
|
+
options[:proxy_granting_ticket] = acquire_proxy_granting_ticket(params[:pgtUrl], ticket)
|
24
|
+
end
|
25
|
+
@listener.validation_succeeded(build_xml(true, options))
|
26
|
+
else
|
27
|
+
@listener.validation_failed(build_xml(false, error_code: validation_result, error_message: 'Validation failed'))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def build_xml(success, options = {})
|
33
|
+
xml = Builder::XmlMarkup.new(indent: 2)
|
34
|
+
xml.cas :serviceResponse, 'xmlns:cas' => 'http://www.yale.edu/tp/cas' do |service_response|
|
35
|
+
if success
|
36
|
+
ticket_granting_ticket = options[:service_ticket].ticket_granting_ticket
|
37
|
+
service_response.cas :authenticationSuccess do |authentication_success|
|
38
|
+
authentication_success.cas :user, ticket_granting_ticket.username
|
39
|
+
unless ticket_granting_ticket.extra_attributes.blank?
|
40
|
+
authentication_success.cas :attributes do |attributes|
|
41
|
+
ticket_granting_ticket.extra_attributes.each do |key, value|
|
42
|
+
serialize_extra_attribute(attributes, key, value)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
if options[:proxy_granting_ticket]
|
47
|
+
proxy_granting_ticket = options[:proxy_granting_ticket]
|
48
|
+
authentication_success.cas :proxyGrantingTicket, proxy_granting_ticket.iou
|
49
|
+
end
|
50
|
+
end
|
51
|
+
else
|
52
|
+
service_response.cas :authenticationFailure, options[:error_message], code: options[:error_code]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
xml.target!
|
56
|
+
end
|
57
|
+
|
58
|
+
def serialize_extra_attribute(builder, key, value)
|
59
|
+
if value.kind_of?(String) || value.kind_of?(Numeric) || value.kind_of?(Symbol)
|
60
|
+
builder.cas key, "#{value}"
|
61
|
+
elsif value.kind_of?(Numeric)
|
62
|
+
builder.cas key, value.to_s
|
63
|
+
else
|
64
|
+
builder.cas key do
|
65
|
+
builder.cdata! value.to_yaml
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -6,6 +6,7 @@ module CASinoCore
|
|
6
6
|
autoload :LoginCredentialAcceptor, 'casino_core/processor/login_credential_acceptor.rb'
|
7
7
|
autoload :LoginCredentialRequestor, 'casino_core/processor/login_credential_requestor.rb'
|
8
8
|
autoload :Logout, 'casino_core/processor/logout.rb'
|
9
|
+
autoload :ServiceTicketValidator, 'casino_core/processor/service_ticket_validator.rb'
|
9
10
|
autoload :SessionDestroyer, 'casino_core/processor/session_destroyer.rb'
|
10
11
|
autoload :SessionOverview, 'casino_core/processor/session_overview.rb'
|
11
12
|
|
data/lib/casino_core/railtie.rb
CHANGED
@@ -7,8 +7,12 @@ module CASinoCore
|
|
7
7
|
CASinoCore::RakeTasks.load_tasks
|
8
8
|
end
|
9
9
|
|
10
|
-
initializer
|
10
|
+
initializer 'casino_core.load_configuration' do
|
11
11
|
CASinoCore.setup Rails.env
|
12
12
|
end
|
13
|
+
|
14
|
+
initializer 'casino_core.setup_logger' do
|
15
|
+
CASinoCore::Settings.logger = Rails.logger
|
16
|
+
end
|
13
17
|
end
|
14
18
|
end
|
data/lib/casino_core/settings.rb
CHANGED
@@ -3,7 +3,7 @@ require 'casino_core/authenticator'
|
|
3
3
|
module CASinoCore
|
4
4
|
class Settings
|
5
5
|
class << self
|
6
|
-
attr_accessor :login_ticket, :service_ticket, :authenticators
|
6
|
+
attr_accessor :login_ticket, :service_ticket, :authenticators, :logger
|
7
7
|
def init(config = {})
|
8
8
|
config.each do |key,value|
|
9
9
|
if respond_to?("#{key}=")
|
@@ -12,6 +12,10 @@ module CASinoCore
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
+
def logger
|
16
|
+
@logger ||= ::Logger.new(STDOUT)
|
17
|
+
end
|
18
|
+
|
15
19
|
def authenticators=(authenticators)
|
16
20
|
@authenticators = []
|
17
21
|
authenticators.each do |authenticator|
|
@@ -13,4 +13,11 @@ describe CASinoCore::Model::LoginTicket do
|
|
13
13
|
described_class.find_by_ticket('LT-12345').should be_false
|
14
14
|
end
|
15
15
|
end
|
16
|
+
|
17
|
+
describe '#to_s' do
|
18
|
+
it 'returns the ticket identifier' do
|
19
|
+
ticket = described_class.new ticket: 'LT-12345'
|
20
|
+
"#{ticket}".should == ticket.ticket
|
21
|
+
end
|
22
|
+
end
|
16
23
|
end
|
@@ -37,18 +37,18 @@ describe CASinoCore::Processor::LegacyValidator do
|
|
37
37
|
end
|
38
38
|
|
39
39
|
context 'with renew flag' do
|
40
|
-
let(:
|
40
|
+
let(:parameters_with_renew) { parameters.merge renew: 'true' }
|
41
41
|
|
42
42
|
context 'with a service ticket without issued_from_credentials flag' do
|
43
43
|
it 'consumes the service ticket' do
|
44
|
-
processor.process(
|
44
|
+
processor.process(parameters_with_renew)
|
45
45
|
service_ticket.reload
|
46
46
|
service_ticket.consumed.should == true
|
47
47
|
end
|
48
48
|
|
49
49
|
it 'calls the #validation_failed method on the listener' do
|
50
50
|
listener.should_receive(:validation_failed).with("no\n\n")
|
51
|
-
processor.process(
|
51
|
+
processor.process(parameters_with_renew)
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
@@ -59,14 +59,14 @@ describe CASinoCore::Processor::LegacyValidator do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
it 'consumes the service ticket' do
|
62
|
-
processor.process(
|
62
|
+
processor.process(parameters_with_renew)
|
63
63
|
service_ticket.reload
|
64
64
|
service_ticket.consumed.should == true
|
65
65
|
end
|
66
66
|
|
67
67
|
it 'calls the #validation_succeeded method on the listener' do
|
68
68
|
listener.should_receive(:validation_succeeded).with("yes\ntest\n")
|
69
|
-
processor.process(
|
69
|
+
processor.process(parameters_with_renew)
|
70
70
|
end
|
71
71
|
end
|
72
72
|
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CASinoCore::Processor::ServiceTicketValidator do
|
4
|
+
describe '#process' do
|
5
|
+
let(:listener) { Object.new }
|
6
|
+
let(:processor) { described_class.new(listener) }
|
7
|
+
let(:user_agent) { 'TestBrowser 1.0' }
|
8
|
+
let(:ticket_granting_ticket) {
|
9
|
+
CASinoCore::Model::TicketGrantingTicket.create!({
|
10
|
+
ticket: 'TGC-HXdkW233TsRtiqYGq4b8U7',
|
11
|
+
username: 'test',
|
12
|
+
extra_attributes: nil,
|
13
|
+
user_agent: user_agent
|
14
|
+
})
|
15
|
+
}
|
16
|
+
let(:service) { 'https://example.com/cas-service' }
|
17
|
+
let(:service_ticket) { ticket_granting_ticket.service_tickets.create! ticket: 'ST-2nOcXx56dtPTsB069yYf0h', service: service }
|
18
|
+
let(:parameters) { { service: service, ticket: service_ticket.ticket }}
|
19
|
+
|
20
|
+
let(:regex_failure) { /\A\<cas\:serviceResponse.*\n.*authenticationFailure/ }
|
21
|
+
let(:regex_success) { /\A\<cas\:serviceResponse.*\n.*authenticationSuccess/ }
|
22
|
+
|
23
|
+
before(:each) do
|
24
|
+
listener.stub(:validation_failed)
|
25
|
+
listener.stub(:validation_succeeded)
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'with an unconsumed service ticket' do
|
29
|
+
context 'without renew flag' do
|
30
|
+
it 'consumes the service ticket' do
|
31
|
+
processor.process(parameters)
|
32
|
+
service_ticket.reload
|
33
|
+
service_ticket.consumed.should == true
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'calls the #validation_succeeded method on the listener' do
|
37
|
+
listener.should_receive(:validation_succeeded).with(regex_success)
|
38
|
+
processor.process(parameters)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'with renew flag' do
|
43
|
+
let(:parameters_with_renew) { parameters.merge renew: 'true' }
|
44
|
+
|
45
|
+
context 'with a service ticket without issued_from_credentials flag' do
|
46
|
+
it 'consumes the service ticket' do
|
47
|
+
processor.process(parameters_with_renew)
|
48
|
+
service_ticket.reload
|
49
|
+
service_ticket.consumed.should == true
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'calls the #validation_failed method on the listener' do
|
53
|
+
listener.should_receive(:validation_failed).with(regex_failure)
|
54
|
+
processor.process(parameters_with_renew)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'with a service ticket with issued_from_credentials flag' do
|
59
|
+
before(:each) do
|
60
|
+
service_ticket.issued_from_credentials = true
|
61
|
+
service_ticket.save!
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'consumes the service ticket' do
|
65
|
+
processor.process(parameters_with_renew)
|
66
|
+
service_ticket.reload
|
67
|
+
service_ticket.consumed.should == true
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'calls the #validation_succeeded method on the listener' do
|
71
|
+
listener.should_receive(:validation_succeeded).with(regex_success)
|
72
|
+
processor.process(parameters_with_renew)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'with proxy-granting ticket callback server' do
|
78
|
+
let(:parameters_with_pgt_url) { parameters.merge pgtUrl: 'https://www.example.com/' }
|
79
|
+
|
80
|
+
before(:each) do
|
81
|
+
stub_request(:get, /https:\/\/www\.example\.com\/\?pgtId=[^&]+&pgtIou=[^&]+/)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'calls the #validation_succeeded method on the listener' do
|
85
|
+
listener.should_receive(:validation_succeeded).with(regex_success)
|
86
|
+
processor.process(parameters_with_pgt_url)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'includes the PGTIOU in the response' do
|
90
|
+
listener.should_receive(:validation_succeeded).with(/\<cas\:proxyGrantingTicket\>\n?\s*PGTIOU-.+/)
|
91
|
+
processor.process(parameters_with_pgt_url)
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'creates a proxy-granting ticket' do
|
95
|
+
lambda do
|
96
|
+
processor.process(parameters_with_pgt_url)
|
97
|
+
end.should change(service_ticket.proxy_granting_tickets, :count).by(1)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'contacts the callback server' do
|
101
|
+
processor.process(parameters_with_pgt_url)
|
102
|
+
proxy_granting_ticket = CASinoCore::Model::ProxyGrantingTicket.last
|
103
|
+
WebMock.should have_requested(:get, 'https://www.example.com').with(query: {
|
104
|
+
pgtId: proxy_granting_ticket.ticket,
|
105
|
+
pgtIou: proxy_granting_ticket.iou
|
106
|
+
})
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'with a consumed service ticket' do
|
112
|
+
before(:each) do
|
113
|
+
service_ticket.consumed = true
|
114
|
+
service_ticket.save!
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'calls the #validation_failed method on the listener' do
|
118
|
+
listener.should_receive(:validation_failed).with(regex_failure)
|
119
|
+
processor.process(parameters)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
-
require 'casino_core'
|
2
1
|
require 'database_cleaner'
|
2
|
+
require 'logger'
|
3
|
+
require 'webmock/rspec'
|
4
|
+
require 'casino_core'
|
5
|
+
require 'simplecov'
|
3
6
|
|
4
7
|
# This file was generated by the `rspec --init` command. Conventionally, all
|
5
8
|
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
@@ -16,7 +19,10 @@ RSpec.configure do |config|
|
|
16
19
|
# --seed 1234
|
17
20
|
config.order = 'random'
|
18
21
|
|
22
|
+
SimpleCov.start
|
23
|
+
|
19
24
|
CASinoCore.setup 'test'
|
25
|
+
CASinoCore::Settings.logger.level = ::Logger::Severity::UNKNOWN
|
20
26
|
|
21
27
|
config.before(:suite) do
|
22
28
|
DatabaseCleaner.strategy = :transaction
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: casino_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Nils Caspar
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-12-
|
13
|
+
date: 2012-12-24 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -133,6 +133,17 @@ dependencies:
|
|
133
133
|
type: :development
|
134
134
|
prerelease: false
|
135
135
|
version_requirements: *id011
|
136
|
+
- !ruby/object:Gem::Dependency
|
137
|
+
name: webmock
|
138
|
+
requirement: &id012 !ruby/object:Gem::Requirement
|
139
|
+
none: false
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: "0"
|
144
|
+
type: :development
|
145
|
+
prerelease: false
|
146
|
+
version_requirements: *id012
|
136
147
|
description: A CAS server core library.
|
137
148
|
email: ncaspar@me.com
|
138
149
|
executables: []
|
@@ -167,6 +178,7 @@ files:
|
|
167
178
|
- db/migrate/20121125091934_add_issued_from_credentials_to_service_tickets.rb
|
168
179
|
- db/migrate/20121125185415_create_proxy_granting_tickets.rb
|
169
180
|
- db/migrate/20121125190013_tickets_should_be_unique.rb
|
181
|
+
- db/migrate/20121223135227_proxy_granting_tickets_belongs_to_service_ticket.rb
|
170
182
|
- db/schema.rb
|
171
183
|
- lib/casino_core.rb
|
172
184
|
- lib/casino_core/authenticator.rb
|
@@ -175,6 +187,7 @@ files:
|
|
175
187
|
- lib/casino_core/helper/browser.rb
|
176
188
|
- lib/casino_core/helper/logger.rb
|
177
189
|
- lib/casino_core/helper/login_tickets.rb
|
190
|
+
- lib/casino_core/helper/proxy_granting_tickets.rb
|
178
191
|
- lib/casino_core/helper/service_tickets.rb
|
179
192
|
- lib/casino_core/helper/ticket_granting_tickets.rb
|
180
193
|
- lib/casino_core/helper/tickets.rb
|
@@ -189,6 +202,7 @@ files:
|
|
189
202
|
- lib/casino_core/processor/login_credential_acceptor.rb
|
190
203
|
- lib/casino_core/processor/login_credential_requestor.rb
|
191
204
|
- lib/casino_core/processor/logout.rb
|
205
|
+
- lib/casino_core/processor/service_ticket_validator.rb
|
192
206
|
- lib/casino_core/processor/session_destroyer.rb
|
193
207
|
- lib/casino_core/processor/session_overview.rb
|
194
208
|
- lib/casino_core/railtie.rb
|
@@ -203,6 +217,7 @@ files:
|
|
203
217
|
- spec/processor/login_credential_acceptor_spec.rb
|
204
218
|
- spec/processor/login_credential_requestor_spec.rb
|
205
219
|
- spec/processor/logout_spec.rb
|
220
|
+
- spec/processor/service_ticket_validator_spec.rb
|
206
221
|
- spec/processor/session_destroyer_spec.rb
|
207
222
|
- spec/processor/session_overview_spec.rb
|
208
223
|
- spec/spec_helper.rb
|
@@ -219,7 +234,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
219
234
|
requirements:
|
220
235
|
- - ">="
|
221
236
|
- !ruby/object:Gem::Version
|
222
|
-
hash:
|
237
|
+
hash: 209769528785287815
|
223
238
|
segments:
|
224
239
|
- 0
|
225
240
|
version: "0"
|