casino 1.3.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (166) hide show
  1. data.tar.gz.sig +0 -0
  2. data/.gitignore +3 -0
  3. data/.travis.yml +1 -1
  4. data/README.md +1 -8
  5. data/Rakefile +0 -2
  6. data/app/assets/javascripts/casino/application.js +1 -0
  7. data/app/assets/javascripts/casino/index.js +0 -2
  8. data/app/assets/javascripts/casino/sessions.js +32 -0
  9. data/app/authenticators/casino/static_authenticator.rb +23 -0
  10. data/app/builders/casino/ticket_validation_response_builder.rb +84 -0
  11. data/app/controllers/casino/api/v1/tickets_controller.rb +7 -4
  12. data/app/controllers/casino/application_controller.rb +2 -3
  13. data/{lib/casino/listener/legacy_validator.rb → app/listeners/casino/legacy_validator_listener.rb} +2 -2
  14. data/app/listeners/casino/listener.rb +16 -0
  15. data/{lib/casino/listener/login_credential_acceptor.rb → app/listeners/casino/login_credential_acceptor_listener.rb} +2 -2
  16. data/{lib/casino/listener/login_credential_requestor.rb → app/listeners/casino/login_credential_requestor_listener.rb} +2 -2
  17. data/{lib/casino/listener/logout.rb → app/listeners/casino/logout_listener.rb} +2 -2
  18. data/{lib/casino/listener/other_sessions_destroyer.rb → app/listeners/casino/other_sessions_destroyer_listener.rb} +2 -2
  19. data/{lib/casino/listener/proxy_ticket_provider.rb → app/listeners/casino/proxy_ticket_provider_listener.rb} +2 -2
  20. data/{lib/casino/listener/second_factor_authentication_acceptor.rb → app/listeners/casino/second_factor_authentication_acceptor_listener.rb} +2 -2
  21. data/{lib/casino/listener/session_destroyer.rb → app/listeners/casino/session_destroyer_listener.rb} +2 -2
  22. data/{lib/casino/listener/session_overview.rb → app/listeners/casino/session_overview_listener.rb} +2 -2
  23. data/{lib/casino/listener/ticket_validator.rb → app/listeners/casino/ticket_validator_listener.rb} +2 -2
  24. data/{lib/casino/listener/two_factor_authenticator_activator.rb → app/listeners/casino/two_factor_authenticator_activator_listener.rb} +2 -2
  25. data/{lib/casino/listener/two_factor_authenticator_destroyer.rb → app/listeners/casino/two_factor_authenticator_destroyer_listener.rb} +2 -2
  26. data/{lib/casino/listener/two_factor_authenticator_overview.rb → app/listeners/casino/two_factor_authenticator_overview_listener.rb} +2 -2
  27. data/{lib/casino/listener/two_factor_authenticator_registrator.rb → app/listeners/casino/two_factor_authenticator_registrator_listener.rb} +2 -2
  28. data/app/models/casino/login_ticket.rb +12 -0
  29. data/app/models/casino/proxy_granting_ticket.rb +8 -0
  30. data/app/models/casino/proxy_ticket.rb +25 -0
  31. data/app/models/casino/service_rule.rb +27 -0
  32. data/app/models/casino/service_ticket.rb +43 -0
  33. data/app/models/casino/service_ticket/single_sign_out_notifier.rb +44 -0
  34. data/app/models/casino/ticket_granting_ticket.rb +57 -0
  35. data/app/models/casino/two_factor_authenticator.rb +18 -0
  36. data/app/models/casino/user.rb +12 -0
  37. data/app/models/casino/validation_result.rb +5 -0
  38. data/app/processors/casino/api/login_credential_acceptor_processor.rb +46 -0
  39. data/app/processors/casino/api/logout_processor.rb +17 -0
  40. data/app/processors/casino/api/service_ticket_provider_processor.rb +69 -0
  41. data/app/processors/casino/legacy_validator_processor.rb +19 -0
  42. data/app/processors/casino/login_credential_acceptor_processor.rb +63 -0
  43. data/app/processors/casino/login_credential_requestor_processor.rb +66 -0
  44. data/app/processors/casino/logout_processor.rb +23 -0
  45. data/app/processors/casino/other_sessions_destroyer_processor.rb +26 -0
  46. data/app/processors/casino/processor.rb +5 -0
  47. data/app/processors/casino/processor_concern/authentication.rb +87 -0
  48. data/app/processors/casino/processor_concern/browser.rb +14 -0
  49. data/app/processors/casino/processor_concern/login_tickets.rb +28 -0
  50. data/app/processors/casino/processor_concern/proxy_granting_tickets.rb +43 -0
  51. data/app/processors/casino/processor_concern/proxy_tickets.rb +56 -0
  52. data/app/processors/casino/processor_concern/service_tickets.rb +50 -0
  53. data/app/processors/casino/processor_concern/ticket_granting_tickets.rb +65 -0
  54. data/app/processors/casino/processor_concern/tickets.rb +17 -0
  55. data/app/processors/casino/processor_concern/two_factor_authenticators.rb +22 -0
  56. data/app/processors/casino/proxy_ticket_provider_processor.rb +41 -0
  57. data/app/processors/casino/proxy_ticket_validator_processor.rb +22 -0
  58. data/app/processors/casino/second_factor_authentication_acceptor_processor.rb +45 -0
  59. data/app/processors/casino/service_ticket_validator_processor.rb +46 -0
  60. data/app/processors/casino/session_destroyer_processor.rb +25 -0
  61. data/app/processors/casino/session_overview_processor.rb +21 -0
  62. data/app/processors/casino/two_factor_authenticator_activator_processor.rb +41 -0
  63. data/app/processors/casino/two_factor_authenticator_destroyer_processor.rb +33 -0
  64. data/app/processors/casino/two_factor_authenticator_overview_processor.rb +20 -0
  65. data/app/processors/casino/two_factor_authenticator_registrator_processor.rb +24 -0
  66. data/app/views/casino/application/_footer.html.erb +1 -1
  67. data/app/views/casino/sessions/new.html.erb +2 -1
  68. data/app/views/casino/sessions/validate_otp.html.erb +1 -1
  69. data/app/views/casino/two_factor_authenticators/new.html.erb +2 -2
  70. data/app/views/layouts/application.html.erb +1 -1
  71. data/casino.gemspec +9 -4
  72. data/db/migrate/20130809135400_create_core_schema.rb +117 -0
  73. data/db/migrate/20130809135401_rename_base_models.rb +101 -0
  74. data/db/migrate/20131022110146_cleanup_indexes.rb +27 -0
  75. data/db/migrate/20131022110246_fix_long_index_names.rb +12 -0
  76. data/db/migrate/20131022110346_change_service_to_text.rb +6 -0
  77. data/lib/casino.rb +47 -3
  78. data/lib/casino/authenticator.rb +9 -0
  79. data/lib/casino/engine.rb +26 -0
  80. data/lib/casino/inflections.rb +7 -0
  81. data/lib/casino/tasks.rb +1 -0
  82. data/lib/casino/tasks/cleanup.rake +59 -0
  83. data/lib/casino/tasks/service_rule.rake +49 -0
  84. data/lib/casino/version.rb +1 -1
  85. data/lib/generators/casino/install/USAGE +13 -0
  86. data/lib/generators/casino/install/install_generator.rb +47 -0
  87. data/lib/generators/casino/{templates → install/templates}/README +3 -4
  88. data/lib/generators/casino/{templates → install/templates}/cas.yml +2 -2
  89. data/lib/generators/casino/{templates → install/templates}/casino_and_overrides.scss +0 -0
  90. data/lib/generators/casino/templates/casino_core.rb +1 -1
  91. data/spec/authenticator/base_spec.rb +13 -0
  92. data/spec/authenticator/static_spec.rb +42 -0
  93. data/spec/controllers/api/v1/tickets_controller_spec.rb +15 -15
  94. data/spec/controllers/listener/legacy_validator_spec.rb +1 -1
  95. data/spec/controllers/listener/login_credential_acceptor_spec.rb +1 -1
  96. data/spec/controllers/listener/login_credential_requestor_spec.rb +1 -1
  97. data/spec/controllers/listener/logout_spec.rb +1 -1
  98. data/spec/controllers/listener/other_sessions_destroyer_spec.rb +1 -1
  99. data/spec/controllers/listener/proxy_ticket_provider_spec.rb +1 -1
  100. data/spec/controllers/listener/second_factor_authentication_acceptor_spec.rb +1 -1
  101. data/spec/controllers/listener/session_destroyer_spec.rb +1 -1
  102. data/spec/controllers/listener/session_overview_spec.rb +1 -1
  103. data/spec/controllers/listener/ticket_validator_spec.rb +1 -1
  104. data/spec/controllers/listener/two_factor_authenticator_activator_spec.rb +1 -1
  105. data/spec/controllers/listener/two_factor_authenticator_destroyer_spec.rb +1 -1
  106. data/spec/controllers/listener/two_factor_authenticator_overview_spec.rb +1 -1
  107. data/spec/controllers/listener/two_factor_authenticator_registrator_spec.rb +1 -1
  108. data/spec/controllers/proxy_tickets_controller_spec.rb +4 -4
  109. data/spec/controllers/service_tickets_controller_spec.rb +4 -4
  110. data/spec/controllers/sessions_controller_spec.rb +15 -15
  111. data/spec/controllers/two_factor_authenticators_controller_spec.rb +6 -6
  112. data/spec/dummy/app/assets/stylesheets/casino_and_overrides.scss +13 -0
  113. data/spec/dummy/config/cas.yml +11 -11
  114. data/spec/dummy/config/routes.rb +1 -2
  115. data/spec/dummy/db/migrate/20130910094259_create_base_models.casino.rb +95 -0
  116. data/spec/dummy/db/schema.rb +107 -0
  117. data/spec/model/login_ticket_spec.rb +23 -0
  118. data/spec/model/proxy_ticket_spec.rb +63 -0
  119. data/spec/model/service_rule_spec.rb +65 -0
  120. data/spec/model/service_ticket/single_sign_out_notifier_spec.rb +61 -0
  121. data/spec/model/service_ticket_spec.rb +124 -0
  122. data/spec/model/ticket_granting_ticket_spec.rb +204 -0
  123. data/spec/model/two_factor_authenticator_spec.rb +31 -0
  124. data/spec/processor/api/login_credential_acceptor_spec.rb +52 -0
  125. data/spec/processor/api/logout_spec.rb +34 -0
  126. data/spec/processor/api/service_ticket_provider_spec.rb +61 -0
  127. data/spec/processor/legacy_validator_spec.rb +78 -0
  128. data/spec/processor/login_credential_acceptor_spec.rb +164 -0
  129. data/spec/processor/login_credential_requestor_spec.rb +135 -0
  130. data/spec/processor/logout_other_sessions_spec.rb +53 -0
  131. data/spec/processor/logout_spec.rb +72 -0
  132. data/spec/processor/processor_concern/service_tickets_spec.rb +49 -0
  133. data/spec/processor/proxy_ticket_provider_spec.rb +66 -0
  134. data/spec/processor/proxy_ticket_validator_spec.rb +65 -0
  135. data/spec/processor/second_factor_authenticaton_acceptor_spec.rb +94 -0
  136. data/spec/processor/session_destroyer_spec.rb +75 -0
  137. data/spec/processor/session_overview_spec.rb +49 -0
  138. data/spec/processor/ticket_validator_spec.rb +199 -0
  139. data/spec/processor/two_factor_authenticator_activator_spec.rb +122 -0
  140. data/spec/processor/two_factor_authenticator_destroyer_spec.rb +71 -0
  141. data/spec/processor/two_factor_authenticator_overview_spec.rb +56 -0
  142. data/spec/processor/two_factor_authenticator_registrator_spec.rb +48 -0
  143. data/spec/spec_helper.rb +8 -19
  144. data/spec/support/casino.rb +12 -0
  145. data/spec/support/factories/login_ticket_factory.rb +16 -0
  146. data/spec/support/factories/proxy_granting_ticket_factory.rb +16 -0
  147. data/spec/support/factories/proxy_ticket_factory.rb +17 -0
  148. data/spec/support/factories/service_rule_factory.rb +16 -0
  149. data/spec/support/factories/service_ticket_factory.rb +17 -0
  150. data/spec/support/factories/ticket_granting_ticket_factory.rb +15 -0
  151. data/spec/support/factories/two_factor_authenticator_factory.rb +16 -0
  152. data/spec/support/factories/user_factory.rb +11 -0
  153. data/spec/support/rspec.rb +8 -0
  154. data/spec/support/sqlite3.rb +4 -0
  155. metadata +284 -48
  156. metadata.gz.sig +2 -0
  157. data/.powrc +0 -4
  158. data/Gemfile.lock +0 -149
  159. data/app/assets/javascripts/casino/application.js.coffee +0 -5
  160. data/app/assets/javascripts/casino/sessions.js.coffee +0 -15
  161. data/config/initializers/frontend_config.rb +0 -9
  162. data/config/initializers/inflections.rb +0 -19
  163. data/config/initializers/yaml.rb +0 -1
  164. data/lib/casino/listener.rb +0 -31
  165. data/lib/generators/casino/install_generator.rb +0 -35
  166. data/spec/dummy/config/initializers/casino_core.rb +0 -1
@@ -0,0 +1,27 @@
1
+
2
+ class CASino::ServiceRule < ActiveRecord::Base
3
+ attr_accessible :enabled, :order, :name, :url, :regex
4
+ validates :name, presence: true
5
+ validates :url, uniqueness: true, presence: true
6
+
7
+ def self.allowed?(service_url)
8
+ rules = self.where(enabled: true)
9
+ if rules.empty?
10
+ true
11
+ else
12
+ rules.any? { |rule| rule.allows?(service_url) }
13
+ end
14
+ end
15
+
16
+ def allows?(service_url)
17
+ if self.regex?
18
+ regex = Regexp.new self.url, true
19
+ if regex =~ service_url
20
+ return true
21
+ end
22
+ elsif self.url == service_url
23
+ return true
24
+ end
25
+ false
26
+ end
27
+ end
@@ -0,0 +1,43 @@
1
+ require 'addressable/uri'
2
+
3
+ class CASino::ServiceTicket < ActiveRecord::Base
4
+ attr_accessible :ticket, :service, :issued_from_credentials
5
+ validates :ticket, uniqueness: true
6
+ belongs_to :ticket_granting_ticket
7
+ before_destroy :send_single_sing_out_notification, if: :consumed?
8
+ has_many :proxy_granting_tickets, as: :granter, dependent: :destroy
9
+
10
+ def self.cleanup_unconsumed
11
+ self.delete_all(['created_at < ? AND consumed = ?', CASino.config.service_ticket[:lifetime_unconsumed].seconds.ago, false])
12
+ end
13
+
14
+ def self.cleanup_consumed
15
+ self.destroy_all(['(ticket_granting_ticket_id IS NULL OR created_at < ?) AND consumed = ?', CASino.config.service_ticket[:lifetime_consumed].seconds.ago, true])
16
+ end
17
+
18
+ def self.cleanup_consumed_hard
19
+ self.delete_all(['created_at < ? AND consumed = ?', (CASino.config.service_ticket[:lifetime_consumed].seconds * 2).ago, true])
20
+ end
21
+
22
+ def service_with_ticket_url
23
+ service_uri = Addressable::URI.parse(self.service)
24
+ service_uri.query_values = (service_uri.query_values(Array) || []) << ['ticket', self.ticket]
25
+ service_uri.to_s
26
+ end
27
+
28
+ def expired?
29
+ lifetime = if consumed?
30
+ CASino.config.service_ticket[:lifetime_consumed]
31
+ else
32
+ CASino.config.service_ticket[:lifetime_unconsumed]
33
+ end
34
+ (Time.now - (self.created_at || Time.now)) > lifetime
35
+ end
36
+
37
+ private
38
+ def send_single_sing_out_notification
39
+ notifier = SingleSignOutNotifier.new(self)
40
+ notifier.notify
41
+ true
42
+ end
43
+ end
@@ -0,0 +1,44 @@
1
+ require 'builder'
2
+ require 'faraday'
3
+
4
+ class CASino::ServiceTicket::SingleSignOutNotifier
5
+ def initialize(service_ticket)
6
+ @service_ticket = service_ticket
7
+ end
8
+
9
+ def notify
10
+ send_notification @service_ticket.service, build_xml
11
+ end
12
+
13
+ private
14
+ def build_xml
15
+ xml = Builder::XmlMarkup.new(indent: 2)
16
+ xml.samlp :LogoutRequest,
17
+ 'xmlns:samlp' => 'urn:oasis:names:tc:SAML:2.0:protocol',
18
+ 'xmlns:saml' => 'urn:oasis:names:tc:SAML:2.0:assertion',
19
+ ID: SecureRandom.uuid,
20
+ Version: '2.0',
21
+ IssueInstant: Time.now do |logout_request|
22
+ logout_request.saml :NameID, '@NOT_USED@'
23
+ logout_request.samlp :SessionIndex, @service_ticket.ticket
24
+ end
25
+ xml.target!
26
+ end
27
+
28
+ def send_notification(url, xml)
29
+ Rails.logger.info "Sending Single Sign Out notification for ticket '#{@service_ticket.ticket}'"
30
+ result = Faraday.post(url, logoutRequest: xml) do |request|
31
+ request.options[:timeout] = CASino.config.service_ticket[:single_sign_out_notification][:timeout]
32
+ end
33
+ if result.success?
34
+ Rails.logger.info "Logout notification successfully posted to #{url}."
35
+ true
36
+ else
37
+ Rails.logger.warn "Service #{url} responed to logout notification with code '#{result.status}'!"
38
+ false
39
+ end
40
+ rescue Faraday::Error::ClientError => error
41
+ Rails.logger.warn "Failed to send logout notification to service #{url} due to #{error}"
42
+ false
43
+ end
44
+ end
@@ -0,0 +1,57 @@
1
+ require 'user_agent'
2
+
3
+ class CASino::TicketGrantingTicket < ActiveRecord::Base
4
+ attr_accessible :ticket, :user_agent, :awaiting_two_factor_authentication, :long_term
5
+ validates :ticket, uniqueness: true
6
+
7
+ belongs_to :user
8
+ has_many :service_tickets, dependent: :destroy
9
+
10
+ def self.cleanup(user = nil)
11
+ if user.nil?
12
+ base = self
13
+ else
14
+ base = user.ticket_granting_tickets
15
+ end
16
+ tgts = base.where([
17
+ '(created_at < ? AND awaiting_two_factor_authentication = ?) OR (created_at < ? AND long_term = ?) OR created_at < ?',
18
+ CASino.config.two_factor_authenticator[:timeout].seconds.ago,
19
+ true,
20
+ CASino.config.ticket_granting_ticket[:lifetime].seconds.ago,
21
+ false,
22
+ CASino.config.ticket_granting_ticket[:lifetime_long_term].seconds.ago
23
+ ])
24
+ CASino::ServiceTicket.where(ticket_granting_ticket_id: tgts).destroy_all
25
+ tgts.destroy_all
26
+ end
27
+
28
+ def browser_info
29
+ unless self.user_agent.blank?
30
+ user_agent = UserAgent.parse(self.user_agent)
31
+ if user_agent.platform.nil?
32
+ "#{user_agent.browser}"
33
+ else
34
+ "#{user_agent.browser} (#{user_agent.platform})"
35
+ end
36
+ end
37
+ end
38
+
39
+ def same_user?(other_ticket)
40
+ if other_ticket.nil?
41
+ false
42
+ else
43
+ other_ticket.user_id == self.user_id
44
+ end
45
+ end
46
+
47
+ def expired?
48
+ if awaiting_two_factor_authentication?
49
+ lifetime = CASino.config.two_factor_authenticator[:timeout]
50
+ elsif long_term?
51
+ lifetime = CASino.config.ticket_granting_ticket[:lifetime_long_term]
52
+ else
53
+ lifetime = CASino.config.ticket_granting_ticket[:lifetime]
54
+ end
55
+ (Time.now - (self.created_at || Time.now)) > lifetime
56
+ end
57
+ end
@@ -0,0 +1,18 @@
1
+
2
+ class CASino::TwoFactorAuthenticator < ActiveRecord::Base
3
+ attr_accessible :secret
4
+
5
+ belongs_to :user
6
+
7
+ def self.cleanup
8
+ self.delete_all(['(created_at < ?) AND active = ?', self.lifetime.ago, false])
9
+ end
10
+
11
+ def self.lifetime
12
+ CASino.config.two_factor_authenticator[:lifetime_inactive].seconds
13
+ end
14
+
15
+ def expired?
16
+ !self.active? && (Time.now - (self.created_at || Time.now)) > self.class.lifetime
17
+ end
18
+ end
@@ -0,0 +1,12 @@
1
+
2
+ class CASino::User < ActiveRecord::Base
3
+ attr_accessible :authenticator, :username, :extra_attributes
4
+ serialize :extra_attributes, Hash
5
+
6
+ has_many :ticket_granting_tickets
7
+ has_many :two_factor_authenticators
8
+
9
+ def active_two_factor_authenticator
10
+ self.two_factor_authenticators.where(active: true).first
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ class CASino::ValidationResult < Struct.new(:error_code, :error_message, :error_severity)
2
+ def success?
3
+ self.error_code.nil?
4
+ end
5
+ end
@@ -0,0 +1,46 @@
1
+ # This processor should be used for API calls: POST /cas/v1/tickets
2
+ class CASino::API::LoginCredentialAcceptorProcessor < CASino::Processor
3
+ include CASino::ProcessorConcern::ServiceTickets
4
+ include CASino::ProcessorConcern::Authentication
5
+ include CASino::ProcessorConcern::TicketGrantingTickets
6
+
7
+ # Use this method to process the request. It expects the username in the parameter "username" and the password
8
+ # in "password".
9
+ #
10
+ # The method will call one of the following methods on the listener:
11
+ # * `#user_logged_in_via_api`: First and only argument is a String with the TGT-id
12
+ # * `#invalid_login_credentials_via_api`: No argument
13
+ #
14
+ # @param [Hash] login_data parameters supplied by user (username and password)
15
+ def process(login_data, user_agent = nil)
16
+ @login_data = login_data
17
+ @user_agent = user_agent
18
+
19
+ validate_login_data
20
+
21
+ unless @authentication_result.nil?
22
+ generate_ticket_granting_ticket
23
+ callback_user_logged_in
24
+ else
25
+ callback_invalid_login_credentials
26
+ end
27
+ end
28
+
29
+ private
30
+ def validate_login_data
31
+ @authentication_result = validate_login_credentials(@login_data[:username], @login_data[:password])
32
+ end
33
+
34
+ def callback_user_logged_in
35
+ @listener.user_logged_in_via_api @ticket_granting_ticket.ticket
36
+ end
37
+
38
+ def generate_ticket_granting_ticket
39
+ @ticket_granting_ticket = acquire_ticket_granting_ticket(@authentication_result, @user_agent)
40
+ end
41
+
42
+ def callback_invalid_login_credentials
43
+ @listener.invalid_login_credentials_via_api
44
+ end
45
+
46
+ end
@@ -0,0 +1,17 @@
1
+ # The Logout processor should be used to process API DELETE requests to /cas/v1/tickets/<ticket_granting_ticket>
2
+ class CASino::API::LogoutProcessor < CASino::Processor
3
+ include CASino::ProcessorConcern::TicketGrantingTickets
4
+
5
+ # This method will call `#user_logged_out_via_api` on the listener.
6
+ #
7
+ # @param [String] ticket_granting_ticket Ticket-granting ticket to logout
8
+ def process(ticket_granting_ticket, user_agent = nil)
9
+ remove_ticket_granting_ticket(ticket_granting_ticket, user_agent)
10
+ callback_user_logged_out
11
+ end
12
+
13
+ def callback_user_logged_out
14
+ @listener.user_logged_out_via_api
15
+ end
16
+
17
+ end
@@ -0,0 +1,69 @@
1
+ # The ServiceTicketProvider processor should be used to handle API calls: POST requests to /cas/v1/tickets/<ticket_granting_ticket>
2
+ class CASino::API::ServiceTicketProviderProcessor < CASino::Processor
3
+ include CASino::ProcessorConcern::ServiceTickets
4
+ include CASino::ProcessorConcern::TicketGrantingTickets
5
+
6
+ # Use this method to process the request.
7
+ #
8
+ # The method will call one of the following methods on the listener:
9
+ # * `#granted_service_ticket_via_api`: First and only argument is a String with the service ticket.
10
+ # The service ticket (and nothing else) should be displayed.
11
+ # * `#invalid_ticket_granting_ticket_via_api`: No argument. The application should respond with status "400 Bad Request"
12
+ # * `#no_service_provided_via_api`: No argument. The application should respond with status "400 Bad Request"
13
+ # * `#service_not_allowed_via_api`: The user tried to access a service that this CAS server is not allowed to serve.
14
+ #
15
+ # @param [String] ticket_granting_ticket ticket_granting_ticket supplied by the user in the URL
16
+ # @param [Hash] parameters parameters supplied by user (`service` in particular)
17
+ # @param [String] user_agent user-agent delivered by the client
18
+ def process(ticket_granting_ticket, parameters = nil, user_agent = nil)
19
+ parameters ||= {}
20
+ @client_ticket_granting_ticket = ticket_granting_ticket
21
+ @service_url = parameters[:service]
22
+ @user_agent = user_agent
23
+
24
+ fetch_valid_ticket_granting_ticket
25
+ handle_ticket_granting_ticket
26
+ end
27
+
28
+ private
29
+ def fetch_valid_ticket_granting_ticket
30
+ @ticket_granting_ticket = find_valid_ticket_granting_ticket(@client_ticket_granting_ticket, @user_agent)
31
+ end
32
+
33
+ def handle_ticket_granting_ticket
34
+ case
35
+ when (@service_url and @ticket_granting_ticket)
36
+ begin
37
+ create_service_ticket
38
+ callback_granted_service_ticket
39
+ rescue ServiceNotAllowedError
40
+ callback_service_not_allowed
41
+ end
42
+ when (@service_url and not @ticket_granting_ticket)
43
+ callback_invalid_tgt
44
+ when (not @service_url and @ticket_granting_ticket)
45
+ callback_empty_service
46
+ end
47
+ end
48
+
49
+ def create_service_ticket
50
+ @service_ticket = acquire_service_ticket(@ticket_granting_ticket, @service_url)
51
+ end
52
+
53
+ def callback_granted_service_ticket
54
+ @listener.granted_service_ticket_via_api @service_ticket.ticket
55
+ end
56
+
57
+ def callback_invalid_tgt
58
+ @listener.invalid_ticket_granting_ticket_via_api
59
+ end
60
+
61
+ def callback_empty_service
62
+ @listener.no_service_provided_via_api
63
+ end
64
+
65
+ def callback_service_not_allowed
66
+ @listener.service_not_allowed_via_api(clean_service_url @service_url)
67
+ end
68
+
69
+ end
@@ -0,0 +1,19 @@
1
+ # The LegacyValidator processor should be used for GET requests to /validate
2
+ class CASino::LegacyValidatorProcessor < CASino::Processor
3
+ include CASino::ProcessorConcern::ServiceTickets
4
+
5
+ # This method will call `#validation_succeeded` or `#validation_failed`. In both cases, it supplies
6
+ # a string as argument. The web application should present that string (and nothing else) to the
7
+ # requestor.
8
+ #
9
+ # @param [Hash] params parameters supplied by requestor (a service)
10
+ def process(params = nil)
11
+ params ||= {}
12
+ ticket = CASino::ServiceTicket.where(ticket: params[:ticket]).first
13
+ if !params[:service].nil? && ticket_valid_for_service?(ticket, params[:service], !!params[:renew])
14
+ @listener.validation_succeeded("yes\n#{ticket.ticket_granting_ticket.user.username}\n")
15
+ else
16
+ @listener.validation_failed("no\n\n")
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,63 @@
1
+ # This processor should be used for POST requests to /login
2
+ class CASino::LoginCredentialAcceptorProcessor < CASino::Processor
3
+ include CASino::ProcessorConcern::LoginTickets
4
+ include CASino::ProcessorConcern::ServiceTickets
5
+ include CASino::ProcessorConcern::Authentication
6
+ include CASino::ProcessorConcern::TicketGrantingTickets
7
+
8
+ # Use this method to process the request. It expects the username in the parameter "username" and the password
9
+ # in "password".
10
+ #
11
+ # The method will call one of the following methods on the listener:
12
+ # * `#user_logged_in`: The first argument (String) is the URL (if any), the user should be redirected to.
13
+ # The second argument (String) is the ticket-granting ticket. It should be stored in a cookie named "tgt".
14
+ # The third argument (Time, optional, default = nil) is for "Remember Me" functionality.
15
+ # This is the cookies expiration date. If it is `nil`, the cookie should be a session cookie.
16
+ # * `#invalid_login_ticket` and `#invalid_login_credentials`: The first argument is a LoginTicket.
17
+ # See {CASino::LoginCredentialRequestorProcessor} for details.
18
+ # * `#service_not_allowed`: The user tried to access a service that this CAS server is not allowed to serve.
19
+ # * `#two_factor_authentication_pending`: The user should be asked to enter his OTP. The first argument (String) is the ticket-granting ticket. The ticket-granting ticket is not active yet. Use SecondFactorAuthenticatonAcceptor to activate it.
20
+ #
21
+ # @param [Hash] params parameters supplied by user
22
+ # @param [String] user_agent user-agent delivered by the client
23
+ def process(params = nil, user_agent = nil)
24
+ @params = params || {}
25
+ @user_agent = user_agent
26
+ if login_ticket_valid?(@params[:lt])
27
+ authenticate_user
28
+ else
29
+ @listener.invalid_login_ticket(acquire_login_ticket)
30
+ end
31
+ end
32
+
33
+ private
34
+ def authenticate_user
35
+ authentication_result = validate_login_credentials(@params[:username], @params[:password])
36
+ if !authentication_result.nil?
37
+ user_logged_in(authentication_result)
38
+ else
39
+ @listener.invalid_login_credentials(acquire_login_ticket)
40
+ end
41
+ end
42
+
43
+ def user_logged_in(authentication_result)
44
+ long_term = @params[:rememberMe]
45
+ ticket_granting_ticket = acquire_ticket_granting_ticket(authentication_result, @user_agent, long_term)
46
+ if ticket_granting_ticket.awaiting_two_factor_authentication?
47
+ @listener.two_factor_authentication_pending(ticket_granting_ticket.ticket)
48
+ else
49
+ begin
50
+ url = unless @params[:service].blank?
51
+ acquire_service_ticket(ticket_granting_ticket, @params[:service], true).service_with_ticket_url
52
+ end
53
+ if long_term
54
+ @listener.user_logged_in(url, ticket_granting_ticket.ticket, CASino.config.ticket_granting_ticket[:lifetime_long_term].seconds.from_now)
55
+ else
56
+ @listener.user_logged_in(url, ticket_granting_ticket.ticket)
57
+ end
58
+ rescue ServiceNotAllowedError => e
59
+ @listener.service_not_allowed(clean_service_url @params[:service])
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,66 @@
1
+ # This processor should be used for GET requests to /login
2
+ class CASino::LoginCredentialRequestorProcessor < CASino::Processor
3
+ include CASino::ProcessorConcern::Browser
4
+ include CASino::ProcessorConcern::LoginTickets
5
+ include CASino::ProcessorConcern::ServiceTickets
6
+ include CASino::ProcessorConcern::TicketGrantingTickets
7
+
8
+ # Use this method to process the request.
9
+ #
10
+ # The method will call one of the following methods on the listener:
11
+ # * `#user_logged_in`: The first argument (String) is the URL (if any), the user should be redirected to.
12
+ # * `#user_not_logged_in`: The first argument is a LoginTicket. It should be stored in a hidden field with name "lt".
13
+ # * `#service_not_allowed`: The user tried to access a service that this CAS server is not allowed to serve.
14
+ #
15
+ # @param [Hash] params parameters supplied by user
16
+ # @param [Hash] cookies cookies supplied by user
17
+ # @param [String] user_agent user-agent delivered by the client
18
+ def process(params = nil, cookies = nil, user_agent = nil)
19
+ @params = params || {}
20
+ @cookies = cookies || {}
21
+ @user_agent = user_agent || {}
22
+ if check_service_allowed
23
+ handle_allowed_service
24
+ end
25
+ end
26
+
27
+ private
28
+ def handle_allowed_service
29
+ if !@params[:renew] && (@ticket_granting_ticket = find_valid_ticket_granting_ticket(@cookies[:tgt], @user_agent))
30
+ handle_logged_in
31
+ else
32
+ handle_not_logged_in
33
+ end
34
+ end
35
+
36
+ def handle_logged_in
37
+ service_url_with_ticket = unless @params[:service].nil?
38
+ acquire_service_ticket(@ticket_granting_ticket, @params[:service], true).service_with_ticket_url
39
+ end
40
+ @listener.user_logged_in(service_url_with_ticket)
41
+ end
42
+
43
+ def handle_not_logged_in
44
+ if gateway_request?
45
+ # we actually lie to the listener to simplify things
46
+ @listener.user_logged_in(@params[:service])
47
+ else
48
+ login_ticket = acquire_login_ticket
49
+ @listener.user_not_logged_in(login_ticket)
50
+ end
51
+ end
52
+
53
+ def check_service_allowed
54
+ service_url = clean_service_url(@params[:service]) unless @params[:service].nil?
55
+ if service_url.nil? || CASino::ServiceRule.allowed?(service_url)
56
+ true
57
+ else
58
+ @listener.service_not_allowed(service_url)
59
+ false
60
+ end
61
+ end
62
+
63
+ def gateway_request?
64
+ @params[:gateway] == 'true' && @params[:service]
65
+ end
66
+ end