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,41 @@
1
+ require 'builder'
2
+
3
+ # The ProxyTicketProvider processor should be used to handle GET requests to /proxy
4
+ class CASino::ProxyTicketProviderProcessor < CASino::Processor
5
+ include CASino::ProcessorConcern::ProxyGrantingTickets
6
+ include CASino::ProcessorConcern::ProxyTickets
7
+
8
+ # This method will call `#request_succeeded` or `#request_failed`. In both cases, it supplies
9
+ # a string as argument. The web application should present that string (and nothing else) to the
10
+ # requestor. The Content-Type should be set to 'text/xml; charset=utf-8'
11
+ #
12
+ # @param [Hash] params parameters delivered by the client
13
+ def process(params = nil)
14
+ if params[:pgt].nil? || params[:targetService].nil?
15
+ @listener.request_failed build_xml false, error_code: 'INVALID_REQUEST', error_message: '"pgt" and "targetService" parameters are both required'
16
+ else
17
+ proxy_granting_ticket = CASino::ProxyGrantingTicket.where(ticket: params[:pgt]).first
18
+ if proxy_granting_ticket.nil?
19
+ @listener.request_failed build_xml false, error_code: 'BAD_PGT', error_message: 'PGT not found'
20
+ else
21
+ proxy_ticket = acquire_proxy_ticket(proxy_granting_ticket, params[:targetService])
22
+ @listener.request_succeeded build_xml true, proxy_ticket: proxy_ticket
23
+ end
24
+ end
25
+ end
26
+
27
+ private
28
+ def build_xml(success, options = {})
29
+ xml = Builder::XmlMarkup.new(indent: 2)
30
+ xml.cas :serviceResponse, 'xmlns:cas' => 'http://www.yale.edu/tp/cas' do |service_response|
31
+ if success
32
+ service_response.cas :proxySuccess do |proxy_success|
33
+ proxy_success.cas :proxyTicket, options[:proxy_ticket].ticket
34
+ end
35
+ else
36
+ service_response.cas :proxyFailure, options[:error_message], code: options[:error_code]
37
+ end
38
+ end
39
+ xml.target!
40
+ end
41
+ end
@@ -0,0 +1,22 @@
1
+ # The ProxyTicketValidator processor should be used to handle GET requests to /proxyValidate
2
+ class CASino::ProxyTicketValidatorProcessor < CASino::ServiceTicketValidatorProcessor
3
+
4
+ # This method will call `#validation_succeeded` or `#validation_failed`. In both cases, it supplies
5
+ # a string as argument. The web application should present that string (and nothing else) to the
6
+ # requestor. The Content-Type should be set to 'text/xml; charset=utf-8'
7
+ #
8
+ # @param [Hash] params parameters delivered by the client
9
+ def process(params = nil)
10
+ params ||= {}
11
+ if request_valid?(params)
12
+ ticket = if params[:ticket].start_with?('PT-')
13
+ CASino::ProxyTicket.where(ticket: params[:ticket]).first
14
+ elsif params[:ticket].start_with?('ST-')
15
+ CASino::ServiceTicket.where(ticket: params[:ticket]).first
16
+ else
17
+ nil
18
+ end
19
+ validate_ticket!(ticket, params)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,45 @@
1
+ # The SecondFactorAuthenticationAcceptor processor can be used to activate a previously generated ticket-granting ticket with pending two-factor authentication.
2
+ #
3
+ # This feature is not described in the CAS specification so it's completly optional
4
+ # to implement this on the web application side.
5
+ class CASino::SecondFactorAuthenticationAcceptorProcessor < CASino::Processor
6
+ include CASino::ProcessorConcern::ServiceTickets
7
+ include CASino::ProcessorConcern::TicketGrantingTickets
8
+ include CASino::ProcessorConcern::TwoFactorAuthenticators
9
+
10
+ # The method will call one of the following methods on the listener:
11
+ # * `#user_not_logged_in`: The user should be redirected to /login.
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
+ # * `#invalid_one_time_password`: The user should be asked for a new OTP.
15
+ #
16
+ # @param [Hash] params parameters supplied by user. The processor will look for keys :otp and :service.
17
+ # @param [String] user_agent user-agent delivered by the client
18
+ def process(params = nil, user_agent = nil)
19
+ cookies ||= {}
20
+ tgt = find_valid_ticket_granting_ticket(params[:tgt], user_agent, true)
21
+ if tgt.nil?
22
+ @listener.user_not_logged_in
23
+ else
24
+ validation_result = validate_one_time_password(params[:otp], tgt.user.active_two_factor_authenticator)
25
+ if validation_result.success?
26
+ tgt.awaiting_two_factor_authentication = false
27
+ tgt.save!
28
+ begin
29
+ url = unless params[:service].blank?
30
+ acquire_service_ticket(tgt, params[:service], true).service_with_ticket_url
31
+ end
32
+ if tgt.long_term?
33
+ @listener.user_logged_in(url, tgt.ticket, CASino.config.ticket_granting_ticket[:lifetime_long_term].seconds.from_now)
34
+ else
35
+ @listener.user_logged_in(url, tgt.ticket)
36
+ end
37
+ rescue ServiceNotAllowedError => e
38
+ @listener.service_not_allowed(clean_service_url params[:service])
39
+ end
40
+ else
41
+ @listener.invalid_one_time_password
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,46 @@
1
+ # The ServiceTicketValidator processor should be used to handle GET requests to /serviceValidate
2
+ class CASino::ServiceTicketValidatorProcessor < CASino::Processor
3
+ include CASino::ProcessorConcern::ServiceTickets
4
+ include CASino::ProcessorConcern::ProxyGrantingTickets
5
+
6
+ # This method will call `#validation_succeeded` or `#validation_failed`. In both cases, it supplies
7
+ # a string as argument. The web application should present that string (and nothing else) to the
8
+ # requestor. The Content-Type should be set to 'text/xml; charset=utf-8'
9
+ #
10
+ # @param [Hash] params parameters delivered by the client
11
+ def process(params = nil)
12
+ params ||= {}
13
+ if request_valid?(params)
14
+ ticket = CASino::ServiceTicket.where(ticket: params[:ticket]).first
15
+ validate_ticket!(ticket, params)
16
+ end
17
+ end
18
+
19
+ protected
20
+ def build_service_response(success, options = {})
21
+ builder = CASino::TicketValidationResponseBuilder.new(success, options)
22
+ builder.build
23
+ end
24
+
25
+ def request_valid?(params)
26
+ if params[:ticket].nil? || params[:service].nil?
27
+ @listener.validation_failed build_service_response(false, error_code: 'INVALID_REQUEST', error_message: '"ticket" and "service" parameters are both required')
28
+ false
29
+ else
30
+ true
31
+ end
32
+ end
33
+
34
+ def validate_ticket!(ticket, params)
35
+ validation_result = validate_ticket_for_service(ticket, params[:service], !!params[:renew])
36
+ if validation_result.success?
37
+ options = { ticket: ticket }
38
+ unless params[:pgtUrl].nil?
39
+ options[:proxy_granting_ticket] = acquire_proxy_granting_ticket(params[:pgtUrl], ticket)
40
+ end
41
+ @listener.validation_succeeded(build_service_response(true, options))
42
+ else
43
+ @listener.validation_failed(build_service_response(false, error_code: validation_result.error_code, error_message: validation_result.error_message))
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,25 @@
1
+ # The SessionDestroyer processor is used to destroy a ticket-granting ticket.
2
+ #
3
+ # This feature is not described in the CAS specification so it's completly optional
4
+ # to implement this on the web application side. It is especially useful in
5
+ # combination with the {CASino::SessionOverviewProcessor} processor.
6
+ class CASino::SessionDestroyerProcessor < CASino::Processor
7
+
8
+ # This method will call `#ticket_not_found` or `#ticket_deleted` on the listener.
9
+ # @param [Hash] params parameters supplied by user (ID of ticket-granting ticket to delete should by in params[:id])
10
+ # @param [Hash] cookies cookies supplied by user
11
+ # @param [String] user_agent user-agent delivered by the client
12
+ def process(params = nil, cookies = nil, user_agent = nil)
13
+ params ||= {}
14
+ cookies ||= {}
15
+ ticket = CASino::TicketGrantingTicket.where(id: params[:id]).first
16
+ owner_ticket = CASino::TicketGrantingTicket.where(ticket: cookies[:tgt]).first
17
+ if ticket.nil? || !ticket.same_user?(owner_ticket)
18
+ @listener.ticket_not_found
19
+ else
20
+ Rails.logger.info "Destroying ticket-granting ticket '#{ticket.ticket}'"
21
+ ticket.destroy
22
+ @listener.ticket_deleted
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ # The SessionOverview processor to list all open session for the currently signed in user.
2
+ #
3
+ # This feature is not described in the CAS specification so it's completly optional
4
+ # to implement this on the web application side.
5
+ class CASino::SessionOverviewProcessor < CASino::Processor
6
+ include CASino::ProcessorConcern::TicketGrantingTickets
7
+
8
+ # This method will call `#user_not_logged_in` or `#ticket_granting_tickets_found(Enumerable)` on the listener.
9
+ # @param [Hash] cookies cookies delivered by the client
10
+ # @param [String] user_agent user-agent delivered by the client
11
+ def process(cookies = nil, user_agent = nil)
12
+ cookies ||= {}
13
+ tgt = find_valid_ticket_granting_ticket(cookies[:tgt], user_agent)
14
+ if tgt.nil?
15
+ @listener.user_not_logged_in
16
+ else
17
+ ticket_granting_tickets = tgt.user.ticket_granting_tickets.where(awaiting_two_factor_authentication: false).order('updated_at DESC')
18
+ @listener.ticket_granting_tickets_found(ticket_granting_tickets)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,41 @@
1
+ # The TwoFactorAuthenticatorActivator processor can be used to activate a previously generated two-factor authenticator.
2
+ #
3
+ # This feature is not described in the CAS specification so it's completly optional
4
+ # to implement this on the web application side.
5
+ class CASino::TwoFactorAuthenticatorActivatorProcessor < CASino::Processor
6
+ include CASino::ProcessorConcern::TicketGrantingTickets
7
+ include CASino::ProcessorConcern::TwoFactorAuthenticators
8
+
9
+ # The method will call one of the following methods on the listener:
10
+ # * `#user_not_logged_in`: The user is not logged in and should be redirected to /login.
11
+ # * `#two_factor_authenticator_activated`: The two-factor authenticator was successfully activated.
12
+ # * `#invalid_two_factor_authenticator`: The two-factor authenticator is not valid.
13
+ # * `#invalid_one_time_password`: The user should be asked for a new OTP.
14
+ #
15
+ # @param [Hash] params parameters supplied by user. The processor will look for keys :otp and :id.
16
+ # @param [Hash] cookies cookies delivered by the client
17
+ # @param [String] user_agent user-agent delivered by the client
18
+ def process(params = nil, cookies = nil, user_agent = nil)
19
+ cookies ||= {}
20
+ params ||= {}
21
+ tgt = find_valid_ticket_granting_ticket(cookies[:tgt], user_agent)
22
+ if tgt.nil?
23
+ @listener.user_not_logged_in
24
+ else
25
+ authenticator = tgt.user.two_factor_authenticators.where(id: params[:id]).first
26
+ validation_result = validate_one_time_password(params[:otp], authenticator)
27
+ if validation_result.success?
28
+ tgt.user.two_factor_authenticators.where(active: true).delete_all
29
+ authenticator.active = true
30
+ authenticator.save!
31
+ @listener.two_factor_authenticator_activated
32
+ else
33
+ if validation_result.error_code == 'INVALID_OTP'
34
+ @listener.invalid_one_time_password(authenticator)
35
+ else
36
+ @listener.invalid_two_factor_authenticator
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,33 @@
1
+ # The TwoFactorAuthenticatorDestroyer processor can be used to deactivate a previously activated two-factor authenticator.
2
+ #
3
+ # This feature is not described in the CAS specification so it's completly optional
4
+ # to implement this on the web application side.
5
+ class CASino::TwoFactorAuthenticatorDestroyerProcessor < CASino::Processor
6
+ include CASino::ProcessorConcern::TicketGrantingTickets
7
+ include CASino::ProcessorConcern::TwoFactorAuthenticators
8
+
9
+ # The method will call one of the following methods on the listener:
10
+ # * `#user_not_logged_in`: The user is not logged in and should be redirected to /login.
11
+ # * `#two_factor_authenticator_destroyed`: The two-factor authenticator was successfully destroyed.
12
+ # * `#invalid_two_factor_authenticator`: The two-factor authenticator is not valid.
13
+ #
14
+ # @param [Hash] params parameters supplied by user. The processor will look for key :id.
15
+ # @param [Hash] cookies cookies delivered by the client
16
+ # @param [String] user_agent user-agent delivered by the client
17
+ def process(params = nil, cookies = nil, user_agent = nil)
18
+ cookies ||= {}
19
+ params ||= {}
20
+ tgt = find_valid_ticket_granting_ticket(cookies[:tgt], user_agent)
21
+ if tgt.nil?
22
+ @listener.user_not_logged_in
23
+ else
24
+ authenticator = tgt.user.two_factor_authenticators.where(id: params[:id]).first
25
+ if authenticator
26
+ authenticator.destroy
27
+ @listener.two_factor_authenticator_destroyed
28
+ else
29
+ @listener.invalid_two_factor_authenticator
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,20 @@
1
+ # The TwoFactorAuthenticatorOverview processor lists registered two factor devices for the currently signed in user.
2
+ #
3
+ # This feature is not described in the CAS specification so it's completly optional
4
+ # to implement this on the web application side.
5
+ class CASino::TwoFactorAuthenticatorOverviewProcessor < CASino::Processor
6
+ include CASino::ProcessorConcern::TicketGrantingTickets
7
+
8
+ # This method will call `#user_not_logged_in` or `#two_factor_authenticators_found(Enumerable)` on the listener.
9
+ # @param [Hash] cookies cookies delivered by the client
10
+ # @param [String] user_agent user-agent delivered by the client
11
+ def process(cookies = nil, user_agent = nil)
12
+ cookies ||= {}
13
+ tgt = find_valid_ticket_granting_ticket(cookies[:tgt], user_agent)
14
+ if tgt.nil?
15
+ @listener.user_not_logged_in
16
+ else
17
+ @listener.two_factor_authenticators_found(tgt.user.two_factor_authenticators.where(active: true))
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,24 @@
1
+ require 'rotp'
2
+
3
+ # The TwoFactorAuthenticatorRegistrator processor can be used as the first step to register a new two-factor authenticator.
4
+ # It is inactive until activated using TwoFactorAuthenticatorActivator.
5
+ #
6
+ # This feature is not described in the CAS specification so it's completly optional
7
+ # to implement this on the web application side.
8
+ class CASino::TwoFactorAuthenticatorRegistratorProcessor < CASino::Processor
9
+ include CASino::ProcessorConcern::TicketGrantingTickets
10
+
11
+ # This method will call `#user_not_logged_in` or `#two_factor_authenticator_registered(two_factor_authenticator)` on the listener.
12
+ # @param [Hash] cookies cookies delivered by the client
13
+ # @param [String] user_agent user-agent delivered by the client
14
+ def process(cookies = nil, user_agent = nil)
15
+ cookies ||= {}
16
+ tgt = find_valid_ticket_granting_ticket(cookies[:tgt], user_agent)
17
+ if tgt.nil?
18
+ @listener.user_not_logged_in
19
+ else
20
+ two_factor_authenticator = tgt.user.two_factor_authenticators.create! secret: ROTP::Base32.random_base32
21
+ @listener.two_factor_authenticator_registered(two_factor_authenticator)
22
+ end
23
+ end
24
+ end
@@ -1,3 +1,3 @@
1
1
  <div id="footer">
2
- <%= CASinoCore::Settings.frontend[:footer_text].html_safe %>
2
+ <%= CASino.config.frontend[:footer_text].html_safe %>
3
3
  </div>
@@ -16,7 +16,7 @@
16
16
  <%= hidden_field_tag :lt, @login_ticket.ticket %>
17
17
  <%= hidden_field_tag :service, params[:service] unless params[:service].nil? %>
18
18
  <%= label_tag :username, t('login.label_username') %>
19
- <%= text_field_tag :username, params[:username] %>
19
+ <%= text_field_tag :username, params[:username], autofocus:true %>
20
20
  <%= label_tag :password, t('login.label_password') %>
21
21
  <%= password_field_tag :password %>
22
22
  <%= label_tag :rememberMe do %>
@@ -28,3 +28,4 @@
28
28
  </div>
29
29
  <%= render 'footer' %>
30
30
  </div>
31
+
@@ -8,7 +8,7 @@
8
8
  <%= hidden_field_tag :tgt, @ticket_granting_ticket || params[:tgt] %>
9
9
  <%= hidden_field_tag :service, params[:service] %>
10
10
  <%= label_tag :code, t('validate_otp.code') %>
11
- <%= text_field_tag :otp, nil, maxlength: 6 %>
11
+ <%= text_field_tag :otp, nil, maxlength: 6, autofocus:true %>
12
12
  <%= button_tag t('validate_otp.submit'), :class => 'button' %>
13
13
  <% end %>
14
14
  </div>
@@ -11,7 +11,7 @@
11
11
  <%= t('two_factor_authenticators.instructions') %>
12
12
  </p>
13
13
  <div id="qr-code">
14
- <img src="https://chart.googleapis.com/chart?cht=qr&chs=250x250&chl=<%= u "otpauth://totp/#{u CASinoCore::Settings.frontend[:sso_name] + ': ' + @two_factor_authenticator.user.username}?secret=#{@two_factor_authenticator.secret}" %>" height="250" width="250"><br />
14
+ <img src="https://chart.googleapis.com/chart?cht=qr&chs=250x250&chl=<%= u "otpauth://totp/#{u CASino.config.frontend[:sso_name] + ': ' + @two_factor_authenticator.user.username}?secret=#{@two_factor_authenticator.secret}" %>" height="250" width="250"><br />
15
15
  </div>
16
16
  <p id="secret">
17
17
  <%= t('two_factor_authenticators.secret') %>: <%= @two_factor_authenticator.secret %>
@@ -22,7 +22,7 @@
22
22
  <%= form_tag(two_factor_authenticators_path, method: :post, id: 'two_factor_authenticators-form') do %>
23
23
  <%= hidden_field_tag :id, @two_factor_authenticator.id %>
24
24
  <%= label_tag :code, t('two_factor_authenticators.code') %>
25
- <%= text_field_tag :otp, nil, maxlength: 6 %>
25
+ <%= text_field_tag :otp, nil, maxlength: 6, autofocus:true %>
26
26
  <%= link_to t('two_factor_authenticators.cancel'), sessions_path, :class => 'secondary button' %>
27
27
  <%= button_tag t('two_factor_authenticators.submit'), :class => 'button' %>
28
28
  <% end %>
@@ -1,7 +1,7 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <title><%= CASinoCore::Settings.frontend[:sso_name] %></title>
4
+ <title><%= CASino.config.frontend[:sso_name] %></title>
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6
6
  <%= stylesheet_link_tag "application", :media => "all" %>
7
7
  <%= javascript_include_tag "application" %>
data/casino.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.homepage = 'http://rbcas.org/'
11
11
  s.license = 'MIT'
12
12
  s.summary = 'A simple CAS server written in Ruby using the Rails framework.'
13
- s.description = 'CASino is a simple CAS (Central Authentication Service) server using CASinoCore as its backend.'
13
+ s.description = 'CASino is a simple CAS (Central Authentication Service) server.'
14
14
 
15
15
  s.files = `git ls-files`.split("\n")
16
16
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -27,11 +27,16 @@ Gem::Specification.new do |s|
27
27
  s.add_development_dependency 'rake', '~> 10.0'
28
28
  s.add_development_dependency 'rspec', '~> 2.12'
29
29
  s.add_development_dependency 'rspec-rails', '~> 2.0'
30
- s.add_development_dependency 'simplecov', '~> 0.7'
31
30
  s.add_development_dependency 'sqlite3', '~> 1.3'
31
+ s.add_development_dependency 'factory_girl', '~> 4.1'
32
+ s.add_development_dependency 'webmock', '~> 1.9'
33
+ s.add_development_dependency 'coveralls', '~> 0.7'
32
34
 
33
35
  s.add_runtime_dependency 'rails', '~> 3.2.9'
34
- s.add_runtime_dependency 'jquery-rails', '~> 2.1'
35
36
  s.add_runtime_dependency 'http_accept_language', '~> 2.0.0.pre'
36
- s.add_runtime_dependency 'casino_core', '~> 1.4.0'
37
+ s.add_runtime_dependency 'addressable', '~> 2.3'
38
+ s.add_runtime_dependency 'terminal-table', '~> 1.4'
39
+ s.add_runtime_dependency 'useragent', '~> 0.4'
40
+ s.add_runtime_dependency 'faraday', '~> 0.8'
41
+ s.add_runtime_dependency 'rotp', '~> 1.4'
37
42
  end
@@ -0,0 +1,117 @@
1
+ # In order to support pre-2.0 installations of CASino that included CASinoCore,
2
+ # we must rebuild the un-namespaced CASinoCore schema so that we can upgrade
3
+ class CreateCoreSchema < ActiveRecord::Migration
4
+ CoreTables = %w{login_tickets proxy_granting_tickets proxy_tickets service_rules service_tickets ticket_granting_tickets two_factor_authenticators users}
5
+
6
+ def up
7
+ CoreTables.each do |table_name|
8
+ if !ActiveRecord::Base.connection.table_exists? table_name
9
+ send "create_#{table_name}"
10
+ end
11
+ end
12
+ end
13
+
14
+ def down
15
+ # No-op
16
+ # Handled by 20130809135401_rename_base_models.rb
17
+ end
18
+
19
+ def create_login_tickets
20
+ create_table :login_tickets do |t|
21
+ t.string :ticket, :null => false
22
+
23
+ t.timestamps
24
+ end
25
+ add_index :login_tickets, :ticket, :unique => true
26
+ end
27
+
28
+ def create_proxy_granting_tickets
29
+ create_table :proxy_granting_tickets do |t|
30
+ t.string :ticket, :null => false
31
+ t.string :iou, :null => false
32
+ t.integer :granter_id, :null => false
33
+ t.string :pgt_url, :null => false
34
+ t.string :granter_type, :null => false
35
+
36
+ t.timestamps
37
+ end
38
+ add_index :proxy_granting_tickets, :ticket, :unique => true
39
+ add_index :proxy_granting_tickets, :iou, :unique => true
40
+ add_index :proxy_granting_tickets, [:granter_type, :granter_id], :name => "index_proxy_granting_tickets_on_granter", :unique => true
41
+ end
42
+
43
+ def create_proxy_tickets
44
+ create_table :proxy_tickets do |t|
45
+ t.string :ticket, :null => false
46
+ t.string :service, :null => false
47
+ t.boolean :consumed, :default => false, :null => false
48
+ t.integer :proxy_granting_ticket_id, :null => false
49
+
50
+ t.timestamps
51
+ end
52
+ add_index :proxy_tickets, :ticket, :unique => true
53
+ add_index :proxy_tickets, :proxy_granting_ticket_id
54
+ end
55
+
56
+ def create_service_rules
57
+ create_table :service_rules do |t|
58
+ t.boolean :enabled, :default => true, :null => false
59
+ t.integer :order, :default => 10, :null => false
60
+ t.string :name, :null => false
61
+ t.string :url, :null => false
62
+ t.boolean :regex, :default => false, :null => false
63
+
64
+ t.timestamps
65
+ end
66
+ add_index :service_rules, :url, :unique => true
67
+ end
68
+
69
+ def create_service_tickets
70
+ create_table :service_tickets do |t|
71
+ t.string :ticket, :null => false
72
+ t.string :service, :null => false
73
+ t.integer :ticket_granting_ticket_id
74
+ t.boolean :consumed, :default => false, :null => false
75
+ t.boolean :issued_from_credentials, :default => false, :null => false
76
+
77
+ t.timestamps
78
+ end
79
+ add_index :service_tickets, :ticket, :unique => true
80
+ add_index :service_tickets, :ticket_granting_ticket_id
81
+ end
82
+
83
+ def create_ticket_granting_tickets
84
+ create_table :ticket_granting_tickets do |t|
85
+ t.string :ticket, :null => false
86
+ t.string :user_agent
87
+ t.integer :user_id, :null => false
88
+ t.boolean :awaiting_two_factor_authentication, :default => false, :null => false
89
+ t.boolean :long_term, :default => false, :null => false
90
+
91
+ t.timestamps
92
+ end
93
+ add_index :ticket_granting_tickets, :ticket, :unique => true
94
+ end
95
+
96
+ def create_two_factor_authenticators
97
+ create_table :two_factor_authenticators do |t|
98
+ t.integer :user_id, :null => false
99
+ t.string :secret, :null => false
100
+ t.boolean :active, :default => false, :null => false
101
+
102
+ t.timestamps
103
+ end
104
+ add_index :two_factor_authenticators, :user_id
105
+ end
106
+
107
+ def create_users
108
+ create_table :users do |t|
109
+ t.string :authenticator, :null => false
110
+ t.string :username, :null => false
111
+ t.text :extra_attributes
112
+
113
+ t.timestamps
114
+ end
115
+ add_index :users, [:authenticator, :username], :unique => true
116
+ end
117
+ end