Module: OmniAuth::Strategy

Included in:
OmniAuth::Strategies::Developer
Defined in:
lib/omniauth/strategy.rb

Overview

The Strategy is the base unit of OmniAuth's ability to wrangle multiple providers. Each strategy provided by OmniAuth includes this mixin to gain the default functionality necessary to be compatible with the OmniAuth library.

Defined Under Namespace

Modules: ClassMethods Classes: Options

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
# File 'lib/omniauth/strategy.rb', line 11

def self.included(base)
  OmniAuth.strategies << base

  base.extend ClassMethods
  base.class_eval do
    attr_reader :app, :env, :options, :response

    option :setup, false
    option :skip_info, false
  end
end

Instance Method Details

#auth_hashObject



324
325
326
327
328
329
330
# File 'lib/omniauth/strategy.rb', line 324

def auth_hash
  hash = AuthHash.new(:provider => name, :uid => uid)
  hash.info = info unless skip_info?
  hash.credentials = credentials if credentials
  hash.extra = extra if extra
  hash
end

#call(env) ⇒ Object

Duplicates this instance and runs #call! on it.

Parameters:

  • The (Hash)

    Rack environment.



156
157
158
# File 'lib/omniauth/strategy.rb', line 156

def call(env)
  dup.call!(env)
end

#call!(env) ⇒ Object

The logic for dispatching any additional actions that need to be taken. For instance, calling the request phase if the request path is recognized.

Parameters:

  • env (Hash)

    The Rack environment.

Raises:



165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/omniauth/strategy.rb', line 165

def call!(env)
  raise OmniAuth::NoSessionError.new("You must provide a session to use OmniAuth.") unless env['rack.session']

  @env = env
  @env['omniauth.strategy'] = self if on_auth_path?

  return mock_call!(env) if OmniAuth.config.test_mode

  return options_call if on_auth_path? && options_request?
  return request_call if on_request_path? && OmniAuth.config.allowed_request_methods.include?(request.request_method.downcase.to_sym)
  return callback_call if on_callback_path?
  return other_phase if respond_to?(:other_phase)
  @app.call(env)
end

#call_app!(env = @env) ⇒ Object



391
392
393
# File 'lib/omniauth/strategy.rb', line 391

def call_app!(env = @env)
  @app.call(env)
end

#callback_callObject

Performs the steps necessary to run the callback phase of a strategy.



212
213
214
215
216
217
218
219
220
# File 'lib/omniauth/strategy.rb', line 212

def callback_call
  setup_phase

  log :info, "Callback phase initiated."
  @env['omniauth.origin'] = session.delete('omniauth.origin')
  @env['omniauth.origin'] = nil if env['omniauth.origin'] == ''
  @env['omniauth.params'] = session.delete('omniauth.params') || {}
  callback_phase
end

#callback_pathObject



375
376
377
# File 'lib/omniauth/strategy.rb', line 375

def callback_path
  options[:callback_path].is_a?(String) ? options[:callback_path] : (custom_path(:request_path) || "#{path_prefix}/#{name}/callback")
end

#callback_phaseObject



352
353
354
355
# File 'lib/omniauth/strategy.rb', line 352

def callback_phase
  self.env['omniauth.auth'] = auth_hash
  call_app!
end

#callback_urlObject



411
412
413
# File 'lib/omniauth/strategy.rb', line 411

def callback_url
  full_host + script_name + callback_path + query_string
end

#credentialsObject



316
317
318
# File 'lib/omniauth/strategy.rb', line 316

def credentials
  merge_stack(self.class.credentials_stack(self))
end

#current_pathObject



383
384
385
# File 'lib/omniauth/strategy.rb', line 383

def current_path
  request.path_info.downcase.sub(/\/$/,'')
end

#custom_path(kind) ⇒ Object



361
362
363
364
365
366
367
368
369
# File 'lib/omniauth/strategy.rb', line 361

def custom_path(kind)
  if options[kind].respond_to?(:call)
    result = options[kind].call(env) 
    return nil unless result.is_a?(String)
    result
  else
    options[kind]
  end
end

#extraObject



320
321
322
# File 'lib/omniauth/strategy.rb', line 320

def extra
  merge_stack(self.class.extra_stack(self))
end

#fail!(message_key, exception = nil) ⇒ Object



446
447
448
449
450
451
452
453
454
455
456
457
458
# File 'lib/omniauth/strategy.rb', line 446

def fail!(message_key, exception = nil)
  self.env['omniauth.error'] = exception
  self.env['omniauth.error.type'] = message_key.to_sym
  self.env['omniauth.error.strategy'] = self

  if exception
    log :error, "Authentication failure! #{message_key}: #{exception.class.to_s}, #{exception.message}"
  else
    log :error, "Authentication failure! #{message_key} encountered."
  end

  OmniAuth.config.on_failure.call(self.env)
end

#full_hostObject



395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
# File 'lib/omniauth/strategy.rb', line 395

def full_host
  case OmniAuth.config.full_host
    when String
      OmniAuth.config.full_host
    when Proc
      OmniAuth.config.full_host.call(env)
    else
      uri = URI.parse(request.url.gsub(/\?.*$/,''))
      uri.path = ''
      uri.query = nil
      #sometimes the url is actually showing http inside rails because the other layers (like nginx) have handled the ssl termination.
      uri.scheme = 'https' if(request.env['HTTP_X_FORWARDED_PROTO'] == 'https')          
      uri.to_s
  end
end

#infoObject



312
313
314
# File 'lib/omniauth/strategy.rb', line 312

def info
  merge_stack(self.class.info_stack(self))
end

#new(app, options = {}) ⇒ Object #new(app, *args, options = {}) ⇒ Object

Initializes the strategy by passing in the Rack endpoint, the unique URL segment name for this strategy, and any additional arguments. An options hash is automatically created from the last argument if it is a hash.

Overloads:

  • #new(app, options = {}) ⇒ Object

    If nothing but a hash is supplied, initialized with the supplied options overriding the strategy's default options via a deep merge.

  • #new(app, *args, options = {}) ⇒ Object

    If the strategy has supplied custom arguments that it accepts, they may will be passed through and set to the appropriate values.

Parameters:

  • app (Rack application)

    The application on which this middleware is applied.

Yields:

  • (Options)

    Yields options to block for further configuration.

Raises:

  • (ArgumentError)


124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/omniauth/strategy.rb', line 124

def initialize(app, *args, &block)
  @app = app
  @options = self.class.default_options.dup

  options.deep_merge!(args.pop) if args.last.is_a?(Hash)
  options.name ||= self.class.to_s.split('::').last.downcase

  self.class.args.each do |arg|
    options[arg] = args.shift
  end

  # Make sure that all of the args have been dealt with, otherwise error out.
  raise ArgumentError, "Received wrong number of arguments. #{args.inspect}" unless args.empty?

  yield options if block_given?
end

#inspectObject



141
142
143
# File 'lib/omniauth/strategy.rb', line 141

def inspect
  "#<#{self.class.to_s}>"
end

#log(level, message) ⇒ Object

Direct access to the OmniAuth logger, automatically prefixed with this strategy's name.

Examples:

log :warn, "This is a warning."


150
151
152
# File 'lib/omniauth/strategy.rb', line 150

def log(level, message)
  OmniAuth.logger.send(level, "(#{name}) #{message}")
end

#mock_call!(env) ⇒ Object

This is called in lieu of the normal request process in the event that OmniAuth has been configured to be in test mode.



255
256
257
258
259
# File 'lib/omniauth/strategy.rb', line 255

def mock_call!(env)
  return mock_request_call if on_request_path?
  return mock_callback_call if on_callback_path?
  call_app!
end

#mock_callback_callObject



272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/omniauth/strategy.rb', line 272

def mock_callback_call
  setup_phase
  mocked_auth = OmniAuth.mock_auth_for(name.to_s)
  if mocked_auth.is_a?(Symbol)
    fail!(mocked_auth)
  else
    @env['omniauth.auth'] = mocked_auth
    @env['omniauth.params'] = session.delete('query_params') || {}
    @env['omniauth.origin'] = session.delete('omniauth.origin')
    @env['omniauth.origin'] = nil if env['omniauth.origin'] == ''
    call_app!
  end
end

#mock_request_callObject



261
262
263
264
265
266
267
268
269
270
# File 'lib/omniauth/strategy.rb', line 261

def mock_request_call
  setup_phase

  if request.params['origin']
    @env['rack.session']['omniauth.origin'] = request.params['origin']
  elsif env['HTTP_REFERER'] && !env['HTTP_REFERER'].match(/#{request_path}$/)
    @env['rack.session']['omniauth.origin'] = env['HTTP_REFERER']
  end
  redirect(script_name + callback_path + query_string)
end

#nameObject



427
428
429
# File 'lib/omniauth/strategy.rb', line 427

def name
  options.name
end

#on_auth_path?Boolean

Returns true if the environment recognizes either the request or callback path.

Returns:

  • (Boolean)


224
225
226
# File 'lib/omniauth/strategy.rb', line 224

def on_auth_path?
  on_request_path? || on_callback_path?
end

#on_callback_path?Boolean

Returns:

  • (Boolean)


236
237
238
239
240
241
242
# File 'lib/omniauth/strategy.rb', line 236

def on_callback_path?
  if options.callback_path.respond_to?(:call)
    options.callback_path.call(env)
  else
    on_path?(callback_path)
  end
end

#on_path?(path) ⇒ Boolean

Returns:

  • (Boolean)


244
245
246
# File 'lib/omniauth/strategy.rb', line 244

def on_path?(path)
  current_path.casecmp(path) == 0
end

#on_request_path?Boolean

Returns:

  • (Boolean)


228
229
230
231
232
233
234
# File 'lib/omniauth/strategy.rb', line 228

def on_request_path?
  if options.request_path.respond_to?(:call)
    options.request_path.call(env)
  else
    on_path?(request_path)
  end
end

#options_callObject

Responds to an OPTIONS request.



181
182
183
184
# File 'lib/omniauth/strategy.rb', line 181

def options_call
  verbs = OmniAuth.config.allowed_request_methods.map(&:to_s).map(&:upcase).join(', ')
  return [ 200, { 'Allow' => verbs }, [] ]
end

#options_request?Boolean

Returns:

  • (Boolean)


248
249
250
# File 'lib/omniauth/strategy.rb', line 248

def options_request?
  request.request_method == 'OPTIONS'
end

#path_prefixObject



357
358
359
# File 'lib/omniauth/strategy.rb', line 357

def path_prefix
  options[:path_prefix] || OmniAuth.config.path_prefix
end

#query_stringObject



387
388
389
# File 'lib/omniauth/strategy.rb', line 387

def query_string
  request.query_string.empty? ? "" : "?#{request.query_string}"
end

#redirect(uri) ⇒ Object



431
432
433
434
435
436
437
438
439
440
441
442
# File 'lib/omniauth/strategy.rb', line 431

def redirect(uri)
  r = Rack::Response.new

  if options[:iframe]
    r.write("<script type='text/javascript' charset='utf-8'>top.location.href = '#{uri}';</script>")
  else
    r.write("Redirecting to #{uri}...")
    r.redirect(uri)
  end

  r.finish
end

#requestObject



423
424
425
# File 'lib/omniauth/strategy.rb', line 423

def request
  @request ||= Rack::Request.new(@env)
end

#request_callObject

Performs the steps necessary to run the request phase of a strategy.



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/omniauth/strategy.rb', line 187

def request_call
  setup_phase

  log :info, "Request phase initiated."

  #store query params from the request url, extracted in the callback_phase
  session['omniauth.params'] = request.params

  if options.form.respond_to?(:call)
    log :info, "Rendering form from supplied Rack endpoint."
    options.form.call(env)
  elsif options.form
    log :info, "Rendering form from underlying application."
    call_app!
  else
    if request.params['origin']
      env['rack.session']['omniauth.origin'] = request.params['origin']
    elsif env['HTTP_REFERER'] && !env['HTTP_REFERER'].match(/#{request_path}$/)
      env['rack.session']['omniauth.origin'] = env['HTTP_REFERER']
    end
    request_phase
  end
end

#request_pathObject



371
372
373
# File 'lib/omniauth/strategy.rb', line 371

def request_path
  options[:request_path].is_a?(String) ? options[:request_path] : "#{path_prefix}/#{name}"
end

#request_phaseObject

This method is abstract.

This method is called when the user is on the request path. You should

perform any information gathering you need to be able to authenticate the user in this phase.

Raises:

  • (NotImplementedError)


304
305
306
# File 'lib/omniauth/strategy.rb', line 304

def request_phase
  raise NotImplementedError
end

#script_nameObject



415
416
417
# File 'lib/omniauth/strategy.rb', line 415

def script_name
  @env['SCRIPT_NAME'] || ''
end

#sessionObject



419
420
421
# File 'lib/omniauth/strategy.rb', line 419

def session
  @env['rack.session']
end

#setup_pathObject



379
380
381
# File 'lib/omniauth/strategy.rb', line 379

def setup_path
  options[:setup_path] || "#{path_prefix}/#{name}/setup"
end

#setup_phaseObject

The setup phase looks for the :setup option to exist and, if it is, will call either the Rack endpoint supplied to the :setup option or it will call out to the setup path of the underlying application. This will default to /auth/:provider/setup.



290
291
292
293
294
295
296
297
298
299
# File 'lib/omniauth/strategy.rb', line 290

def setup_phase
  if options[:setup].respond_to?(:call)
    log :info, "Setup endpoint detected, running now."
    options[:setup].call(env)
  elsif options.setup?
    log :info, "Calling through to underlying application for setup."
    setup_env = env.merge('PATH_INFO' => setup_path, 'REQUEST_METHOD' => 'GET')
    call_app!(setup_env)
  end
end

#skip_info?Boolean

Determines whether or not user info should be retrieved. This allows some strategies to save a call to an external API service for existing users. You can use it either by setting the :skip_info to true or by setting :skip_info to a Proc that takes a uid and evaluates to true when you would like to skip info.

Examples:


use MyStrategy, :skip_info => lambda{|uid| User.find_by_uid(uid)}

Returns:

  • (Boolean)


341
342
343
344
345
346
347
348
349
350
# File 'lib/omniauth/strategy.rb', line 341

def skip_info?
  if options.skip_info?
    if options.skip_info.respond_to?(:call)
      return options.skip_info.call(uid)
    else
      return true
    end
  end
  false
end

#uidObject



308
309
310
# File 'lib/omniauth/strategy.rb', line 308

def uid
  self.class.uid_stack(self).last
end

#user_infoObject



444
# File 'lib/omniauth/strategy.rb', line 444

def ; {} end