hooks.rb 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. # encoding: utf-8
  2. module Warden
  3. module Hooks
  4. # Hook to _run_callbacks asserting for conditions.
  5. def _run_callbacks(kind, *args) #:nodoc:
  6. options = args.last # Last callback arg MUST be a Hash
  7. send("_#{kind}").each do |callback, conditions|
  8. invalid = conditions.find do |key, value|
  9. value.is_a?(Array) ? !value.include?(options[key]) : (value != options[key])
  10. end
  11. callback.call(*args) unless invalid
  12. end
  13. end
  14. # A callback hook set to run every time after a user is set.
  15. # This callback is triggered the first time one of those three events happens
  16. # during a request: :authentication, :fetch (from session) and :set_user (when manually set).
  17. # You can supply as many hooks as you like, and they will be run in order of decleration.
  18. #
  19. # If you want to run the callbacks for a given scope and/or event, you can specify them as options.
  20. # See parameters and example below.
  21. #
  22. # Parameters:
  23. # <options> Some options which specify when the callback should be executed
  24. # scope - Executes the callback only if it maches the scope(s) given
  25. # only - Executes the callback only if it matches the event(s) given
  26. # except - Executes the callback except if it matches the event(s) given
  27. # <block> A block where you can set arbitrary logic to run every time a user is set
  28. # Block Parameters: |user, auth, opts|
  29. # user - The user object that is being set
  30. # auth - The raw authentication proxy object.
  31. # opts - any options passed into the set_user call includeing :scope
  32. #
  33. # Example:
  34. # Warden::Manager.after_set_user do |user,auth,opts|
  35. # scope = opts[:scope]
  36. # if auth.session["#{scope}.last_access"].to_i > (Time.now - 5.minutes)
  37. # auth.logout(scope)
  38. # throw(:warden, :scope => scope, :reason => "Times Up")
  39. # end
  40. # auth.session["#{scope}.last_access"] = Time.now
  41. # end
  42. #
  43. # Warden::Manager.after_set_user :except => :fetch do |user,auth,opts|
  44. # user.login_count += 1
  45. # end
  46. #
  47. # :api: public
  48. def after_set_user(options = {}, method = :push, &block)
  49. raise BlockNotGiven unless block_given?
  50. if options.key?(:only)
  51. options[:event] = options.delete(:only)
  52. elsif options.key?(:except)
  53. options[:event] = [:set_user, :authentication, :fetch] - Array(options.delete(:except))
  54. end
  55. _after_set_user.send(method, [block, options])
  56. end
  57. # Provides access to the array of after_set_user blocks to run
  58. # :api: private
  59. def _after_set_user # :nodoc:
  60. @_after_set_user ||= []
  61. end
  62. # after_authentication is just a wrapper to after_set_user, which is only invoked
  63. # when the user is set through the authentication path. The options and yielded arguments
  64. # are the same as in after_set_user.
  65. #
  66. # :api: public
  67. def after_authentication(options = {}, method = :push, &block)
  68. after_set_user(options.merge(:event => :authentication), method, &block)
  69. end
  70. # after_fetch is just a wrapper to after_set_user, which is only invoked
  71. # when the user is fetched from sesion. The options and yielded arguments
  72. # are the same as in after_set_user.
  73. #
  74. # :api: public
  75. def after_fetch(options = {}, method = :push, &block)
  76. after_set_user(options.merge(:event => :fetch), method, &block)
  77. end
  78. # A callback that runs just prior to the failur application being called.
  79. # This callback occurs after PATH_INFO has been modified for the failure (default /unauthenticated)
  80. # In this callback you can mutate the environment as required by the failure application
  81. # If a Rails controller were used for the failure_app for example, you would need to set request[:params][:action] = :unauthenticated
  82. #
  83. # Parameters:
  84. # <options> Some options which specify when the callback should be executed
  85. # scope - Executes the callback only if it maches the scope(s) given
  86. # <block> A block to contain logic for the callback
  87. # Block Parameters: |env, opts|
  88. # env - The rack env hash
  89. # opts - any options passed into the authenticate call includeing :scope
  90. #
  91. # Example:
  92. # Warden::Manager.before_failure do |env, opts|
  93. # params = Rack::Request.new(env).params
  94. # params[:action] = :unauthenticated
  95. # params[:warden_failure] = opts
  96. # end
  97. #
  98. # :api: public
  99. def before_failure(options = {}, method = :push, &block)
  100. raise BlockNotGiven unless block_given?
  101. _before_failure.send(method, [block, options])
  102. end
  103. # Provides access to the callback array for before_failure
  104. # :api: private
  105. def _before_failure
  106. @_before_failure ||= []
  107. end
  108. # A callback that runs if no user could be fetched, meaning there is now no user logged in.
  109. #
  110. # Parameters:
  111. # <options> Some options which specify when the callback should be executed
  112. # scope - Executes the callback only if it maches the scope(s) given
  113. # <block> A block to contain logic for the callback
  114. # Block Parameters: |user, auth, scope|
  115. # user - The authenticated user for the current scope
  116. # auth - The warden proxy object
  117. # opts - any options passed into the authenticate call including :scope
  118. #
  119. # Example:
  120. # Warden::Manager.after_failed_fetch do |user, auth, opts|
  121. # I18n.locale = :en
  122. # end
  123. #
  124. # :api: public
  125. def after_failed_fetch(options = {}, method = :push, &block)
  126. raise BlockNotGiven unless block_given?
  127. _after_failed_fetch.send(method, [block, options])
  128. end
  129. # Provides access to the callback array for after_failed_fetch
  130. # :api: private
  131. def _after_failed_fetch
  132. @_after_failed_fetch ||= []
  133. end
  134. # A callback that runs just prior to the logout of each scope.
  135. #
  136. # Parameters:
  137. # <options> Some options which specify when the callback should be executed
  138. # scope - Executes the callback only if it maches the scope(s) given
  139. # <block> A block to contain logic for the callback
  140. # Block Parameters: |user, auth, scope|
  141. # user - The authenticated user for the current scope
  142. # auth - The warden proxy object
  143. # opts - any options passed into the authenticate call including :scope
  144. #
  145. # Example:
  146. # Warden::Manager.before_logout do |user, auth, opts|
  147. # user.forget_me!
  148. # end
  149. #
  150. # :api: public
  151. def before_logout(options = {}, method = :push, &block)
  152. raise BlockNotGiven unless block_given?
  153. _before_logout.send(method, [block, options])
  154. end
  155. # Provides access to the callback array for before_logout
  156. # :api: private
  157. def _before_logout
  158. @_before_logout ||= []
  159. end
  160. # A callback that runs on each request, just after the proxy is initialized
  161. #
  162. # Parameters:
  163. # <block> A block to contain logic for the callback
  164. # Block Parameters: |proxy|
  165. # proxy - The warden proxy object for the request
  166. #
  167. # Example:
  168. # user = "A User"
  169. # Warden::Manager.on_request do |proxy|
  170. # proxy.set_user = user
  171. # end
  172. #
  173. # :api: public
  174. def on_request(options = {}, method = :push, &block)
  175. raise BlockNotGiven unless block_given?
  176. _on_request.send(method, [block, options])
  177. end
  178. # Provides access to the callback array for before_logout
  179. # :api: private
  180. def _on_request
  181. @_on_request ||= []
  182. end
  183. # Add prepend filters version
  184. %w(after_set_user after_authentication after_fetch on_request
  185. before_failure before_logout).each do |filter|
  186. class_eval <<-METHOD, __FILE__, __LINE__ + 1
  187. def prepend_#{filter}(options={}, &block)
  188. #{filter}(options, :unshift, &block)
  189. end
  190. METHOD
  191. end
  192. end # Hooks
  193. end # Warden