Class: Warden::Proxy

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Mixins::Common
Defined in:
lib/warden/proxy.rb,
lib/warden/errors.rb

Defined Under Namespace

Classes: Errors

Constant Summary collapse

ENV_WARDEN_ERRORS =
'warden.errors'.freeze
ENV_SESSION_OPTIONS =
'rack.session.options'.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Mixins::Common

#params, #request, #reset_session!, #warden_cookies

Constructor Details

#initialize(env, manager) ⇒ Proxy

:nodoc:


28
29
30
31
32
# File 'lib/warden/proxy.rb', line 28

def initialize(env, manager) #:nodoc:
  @env, @users, @winning_strategies, @locked = env, {}, {}, false
  @manager, @config = manager, manager.config.dup
  @strategies = Hash.new { |h,k| h[k] = {} }
end

Instance Attribute Details

#configObject (readonly)

An accessor to the rack env hash, the proxy owner and its config :api: public


14
15
16
# File 'lib/warden/proxy.rb', line 14

def config
  @config
end

#envObject (readonly)

An accessor to the rack env hash, the proxy owner and its config :api: public


14
15
16
# File 'lib/warden/proxy.rb', line 14

def env
  @env
end

#managerObject (readonly)

An accessor to the rack env hash, the proxy owner and its config :api: public


14
15
16
# File 'lib/warden/proxy.rb', line 14

def manager
  @manager
end

#winning_strategiesObject (readonly)

An accessor to the rack env hash, the proxy owner and its config :api: public


14
15
16
# File 'lib/warden/proxy.rb', line 14

def winning_strategies
  @winning_strategies
end

#winning_strategyObject

An accessor to the winning strategy :api: private


10
11
12
# File 'lib/warden/proxy.rb', line 10

def winning_strategy
  @winning_strategy
end

Instance Method Details

#asset_request?Boolean

Check to see if this is an asset request :api: public

Returns:

  • (Boolean)

314
315
316
# File 'lib/warden/proxy.rb', line 314

def asset_request?
  ::Warden::asset_paths.any? { |r| env['PATH_INFO'].to_s.match(r) }
end

#authenticate(*args) ⇒ Object

Run the authentication strategies for the given strategies. If there is already a user logged in for a given scope, the strategies are not run This does not halt the flow of control and is a passive attempt to authenticate only When scope is not specified, the default_scope is assumed.

Parameters:

args - a list of symbols (labels) that name the strategies to attempt
opts - an options hash that contains the :scope of the user to check

Example:

env['warden'].authenticate(:password, :basic, :scope => :sudo)

:api: public


109
110
111
112
# File 'lib/warden/proxy.rb', line 109

def authenticate(*args)
  user, _opts = _perform_authentication(*args)
  user
end

#authenticate!(*args) ⇒ Object

The same as authenticate except on failure it will throw an :warden symbol causing the request to be halted and rendered through the failure_app

Example

env['warden'].authenticate!(:password, :scope => :publisher) # throws if it cannot authenticate

:api: public


132
133
134
135
136
# File 'lib/warden/proxy.rb', line 132

def authenticate!(*args)
  user, opts = _perform_authentication(*args)
  throw(:warden, opts) unless user
  user
end

#authenticate?(*args) ⇒ Boolean

Same API as authenticate, but returns a boolean instead of a user. The difference between this method (authenticate?) and authenticated? is that the former will run strategies if the user has not yet been authenticated, and the second relies on already performed ones. :api: public

Returns:

  • (Boolean)

119
120
121
122
123
# File 'lib/warden/proxy.rb', line 119

def authenticate?(*args)
  result = !!authenticate(*args)
  yield if result && block_given?
  result
end

#authenticated?(scope = @config.default_scope) ⇒ Boolean

Check to see if there is an authenticated user for the given scope. This brings the user from the session, but does not run strategies before doing so. If you want strategies to be run, please check authenticate?.

Parameters:

scope - the scope to check for authentication. Defaults to default_scope

Example:

env['warden'].authenticated?(:admin)

:api: public

Returns:

  • (Boolean)

149
150
151
152
153
# File 'lib/warden/proxy.rb', line 149

def authenticated?(scope = @config.default_scope)
  result = !!user(scope)
  yield if block_given? && result
  result
end

#clear_strategies_cache!(*args) ⇒ Object

Clear the cache of performed strategies so far. Warden runs each strategy just once during the request lifecycle. You can clear the strategies cache if you want to allow a strategy to be run more than once.

This method has the same API as authenticate, allowing you to clear specific strategies for given scope:

Parameters:

args - a list of symbols (labels) that name the strategies to attempt
opts - an options hash that contains the :scope of the user to check

Example:

# Clear all strategies for the configured default_scope
env['warden'].clear_strategies_cache!

# Clear all strategies for the :admin scope
env['warden'].clear_strategies_cache!(:scope => :admin)

# Clear password strategy for the :admin scope
env['warden'].clear_strategies_cache!(:password, :scope => :admin)

:api: public


77
78
79
80
81
82
83
84
# File 'lib/warden/proxy.rb', line 77

def clear_strategies_cache!(*args)
  scope, _opts = _retrieve_scope_and_opts(args)

  @winning_strategies.delete(scope)
  @strategies[scope].each do |k, v|
    v.clear! if args.empty? || args.include?(k)
  end
end

#custom_failure!Object

Provides a way to return a 401 without warden deferring to the failure app The result is a direct passthrough of your own response :api: public


298
299
300
# File 'lib/warden/proxy.rb', line 298

def custom_failure!
  @custom_failure = true
end

#custom_failure?Boolean

Check to see if the custom failure flag has been set :api: public

Returns:

  • (Boolean)

304
305
306
307
308
309
310
# File 'lib/warden/proxy.rb', line 304

def custom_failure?
  if instance_variable_defined?(:@custom_failure)
    !!@custom_failure
  else
    false
  end
end

#errorsObject

Lazily initiate errors object in session. :api: public


42
43
44
# File 'lib/warden/proxy.rb', line 42

def errors
  @env[ENV_WARDEN_ERRORS] ||= Errors.new
end

#inspect(*args) ⇒ Object


318
319
320
# File 'lib/warden/proxy.rb', line 318

def inspect(*args)
  "Warden::Proxy:#{object_id} @config=#{@config.inspect}"
end

#lock!Object

Locks the proxy so new users cannot authenticate during the request lifecycle. This is useful when the request cannot be verified (for example, using a CSRF verification token). Notice that already authenticated users are kept as so.

:api: public


92
93
94
# File 'lib/warden/proxy.rb', line 92

def lock!
  @locked = true
end

#logout(*scopes) ⇒ Object

Provides logout functionality. The logout also manages any authenticated data storage and clears it when a user logs out.

Parameters:

scopes - a list of scopes to logout

Example:

# Logout everyone and clear the session
env['warden'].logout

# Logout the default user but leave the rest of the session alone
env['warden'].logout(:default)

# Logout the :publisher and :admin user
env['warden'].logout(:publisher, :admin)

:api: public


266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/warden/proxy.rb', line 266

def logout(*scopes)
  if scopes.empty?
    scopes = @users.keys
    reset_session = true
  end

  scopes.each do |scope|
    user = @users.delete(scope)
    manager._run_callbacks(:before_logout, user, self, :scope => scope)

    raw_session.delete("warden.user.#{scope}.session") unless raw_session.nil?
    session_serializer.delete(scope, user)
  end

  reset_session! if reset_session
end

#messageObject

Proxy through to the authentication strategy to find out the message that was generated. :api: public


291
292
293
# File 'lib/warden/proxy.rb', line 291

def message
  winning_strategy && winning_strategy.message
end

#on_requestObject

Run the on_request callbacks :api: private


36
37
38
# File 'lib/warden/proxy.rb', line 36

def on_request
  manager._run_callbacks(:on_request, self)
end

#resultObject

proxy methods through to the winning strategy :api: private


285
286
287
# File 'lib/warden/proxy.rb', line 285

def result # :nodoc:
  winning_strategy && winning_strategy.result
end

#session(scope = @config.default_scope) ⇒ Object

Provides a scoped session data for authenticated users. Warden manages clearing out this data when a user logs out

Example

# default scope
env['warden'].session[:foo] = "bar"

# :sudo scope
env['warden'].session(:sudo)[:foo] = "bar"

:api: public

Raises:


244
245
246
247
# File 'lib/warden/proxy.rb', line 244

def session(scope = @config.default_scope)
  raise NotAuthenticated, "#{scope.inspect} user is not logged in" unless authenticated?(scope)
  raw_session["warden.user.#{scope}.session"] ||= {}
end

#session_serializerObject

Points to a SessionSerializer instance responsible for handling everything related with storing, fetching and removing the user session. :api: public


50
51
52
# File 'lib/warden/proxy.rb', line 50

def session_serializer
  @session_serializer ||= Warden::SessionSerializer.new(@env)
end

#set_user(user, opts = {}) ⇒ Object

Manually set the user into the session and auth proxy

Parameters:

user - An object that has been setup to serialize into and out of the session.
opts - An options hash.  Use the :scope option to set the scope of the user, set the :store option to false to skip serializing into the session, set the :run_callbacks to false to skip running the callbacks (the default is true).

:api: public


170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/warden/proxy.rb', line 170

def set_user(user, opts = {})
  scope = (opts[:scope] ||= @config.default_scope)

  # Get the default options from the master configuration for the given scope
  opts = (@config[:scope_defaults][scope] || {}).merge(opts)
  opts[:event] ||= :set_user
  @users[scope] = user

  if opts[:store] != false && opts[:event] != :fetch
    options = env[ENV_SESSION_OPTIONS]
    if options
      if options.frozen?
        env[ENV_SESSION_OPTIONS] = options.merge(:renew => true).freeze
      else
        options[:renew] = true
      end
    end
    session_serializer.store(user, scope)
  end

  run_callbacks = opts.fetch(:run_callbacks, true)
  manager._run_callbacks(:after_set_user, user, self, opts) if run_callbacks

  @users[scope]
end

#to_s(*args) ⇒ Object


322
323
324
# File 'lib/warden/proxy.rb', line 322

def to_s(*args)
  inspect(*args)
end

#unauthenticated?(scope = @config.default_scope) ⇒ Boolean

Same API as authenticated?, but returns false when authenticated. :api: public

Returns:

  • (Boolean)

157
158
159
160
161
# File 'lib/warden/proxy.rb', line 157

def unauthenticated?(scope = @config.default_scope)
  result = !authenticated?(scope)
  yield if block_given? && result
  result
end

#user(argument = {}) ⇒ Object

Provides access to the user object in a given scope for a request. Will be nil if not logged in. Please notice that this method does not perform strategies.

Example:

 # without scope (default user)
 env['warden'].user

 # with scope
 env['warden'].user(:admin)

 # as a Hash
 env['warden'].user(:scope => :admin)

 # with default scope and run_callbacks option
 env['warden'].user(:run_callbacks => false)

# with a scope and run_callbacks option
env['warden'].user(:scope => :admin, :run_callbacks => true)

:api: public


217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/warden/proxy.rb', line 217

def user(argument = {})
  opts  = argument.is_a?(Hash) ? argument : { :scope => argument }
  scope = (opts[:scope] ||= @config.default_scope)

  if @users.has_key?(scope)
    @users[scope]
  else
    unless user = session_serializer.fetch(scope)
      run_callbacks = opts.fetch(:run_callbacks, true)
      manager._run_callbacks(:after_failed_fetch, user, self, :scope => scope) if run_callbacks
    end

    @users[scope] = user ? set_user(user, opts.merge(:event => :fetch)) : nil
  end
end