sso_provyder 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,33 @@
1
+ A Rails Engine providing an Omniauth provider with single sign on features in a minute.
2
+
3
+ Based on Devise, Authentifyd and joshsoftware/sso-devise-omniauth-provider. Parts directly taken from https://github.com/joshsoftware/sso-devise-omniauth-provider
4
+
5
+ See sso_clyent for the client part.
6
+
7
+ = Uses Authentifyd
8
+ Devise + Omniauth Authentication encapsulated in an Engine
9
+
10
+ == Installation
11
+
12
+ * gem 'sso_provyder'
13
+ * rake sso_provyder:initialize
14
+ * rake sso_provyder:install:migrations
15
+ * rake db:migrate
16
+ * in config/routes.rb add:
17
+ * mount SsoProvyder::Engine => "/#{your root for sso_provyder}"
18
+ * you can also configure Authentifyd::Engine root inside SsoProvyder::Engine by defining SsoProvyder.authentifyd_path in an initializer file. (default to aut/ => sign_in_path = /#{your root for sso_provyder}/aut/users/sign_in)
19
+ * NB: don't mount Engine on root "/". This could be a feature added in the future but for the moment this possibility is not implemented.
20
+
21
+ * Configure Devise: copy paste http://raw.github.com/plataformatec/devise/master/lib/generators/templates/devise.rb in config/initializers/devise.rb. Edit it.
22
+ * NB: set "config.pepper".
23
+ ex: require 'securerandom' -> SecureRandom.hex(64)
24
+ * Add Facebook and Twitter config files
25
+ * Example
26
+ staging:
27
+ app_id: APP ID FOR STAGING ENV
28
+ app_secret: APP SECRET FOR STAGING ENV
29
+ development: &development
30
+ app_id: APP ID FOR DEV ENV
31
+ app_secret: APP SECRET FOR DEV ENV
32
+ test:
33
+ <<: *development
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'SsoProvyder'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+
24
+
25
+
26
+ Bundler::GemHelper.install_tasks
27
+
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // the compiled file.
9
+ //
10
+ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
+ // GO AFTER THE REQUIRES BELOW.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require_tree .
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,6 @@
1
+ module SsoProvyder
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery
4
+
5
+ end
6
+ end
@@ -0,0 +1,41 @@
1
+ class SsoProvyder::AuthApiController < SsoProvyder::AuthController
2
+ skip_before_filter :verify_authenticity_token, :only => [:valid_current_api_client, :valid_current_api_client_user]
3
+ before_filter :authenticate_app
4
+ before_filter :authenticate_api_client_app
5
+
6
+ # is called by sso_api_clyent
7
+ # to check a client app is registered in sso_provyder
8
+ #
9
+ def valid_current_api_client
10
+ render :json => { :app => application_api_json(@application) }
11
+ end
12
+
13
+ # is called by sso_api_clyent
14
+ # to check a client app is registered in sso_provyder
15
+ # and identify the current_user
16
+ #
17
+ def valid_current_api_client_user
18
+ access_grant = SsoProvyder::AccessGrant.authenticate_with({:access_token => params[:access_token], :client_id => @application.id})
19
+ if access_grant.nil?
20
+ render :json => {:error => "Could not authenticate Client App User"}
21
+ return
22
+ end
23
+
24
+ render :json => { :app => application_api_json(@application), :user => user_api_json(access_grant.user) }
25
+ end
26
+
27
+ private
28
+
29
+ def application_api_json(app = nil)
30
+ { :name => app.try(:name), :id => app.try(:id) }
31
+ end
32
+
33
+ def user_api_json(user = nil)
34
+ { :uid => user.try(:id) }
35
+ end
36
+
37
+ def authenticate_api_client_app
38
+ args = { :app_id => params[:api_client_id], :app_secret => params[:api_client_secret] }
39
+ authenticate_application(args, "Api Client")
40
+ end
41
+ end
@@ -0,0 +1,21 @@
1
+ # parent to auth web and auth api
2
+ class SsoProvyder::AuthController < SsoProvyder::ApplicationController
3
+ def authenticate_app
4
+ args = { :app_id => params[:client_id], :app_secret => params[:client_secret] }
5
+ authenticate_application(args, "Client")
6
+ end
7
+
8
+ # role can be "Client" (Direct client) or "Api client" (Client calling the client)
9
+ #
10
+ def authenticate_application(args = {}, role = "Client")
11
+ @application = SsoProvyder::Client.authenticate(args[:app_id], args[:app_secret])
12
+
13
+ unless !!@application
14
+ render :json => {:error => "Could not find #{role} application"}
15
+ return
16
+ end
17
+
18
+ end
19
+
20
+
21
+ end
@@ -0,0 +1,64 @@
1
+ class SsoProvyder::AuthWebController < SsoProvyder::AuthController
2
+ before_filter :authenticate_user!, :except => [:access_token]
3
+ skip_before_filter :verify_authenticity_token, :only => [:access_token]
4
+
5
+ def authorize
6
+ SsoProvyder::AccessGrant.prune!
7
+ access_grant = current_user.access_grants.create({ :client => application,
8
+ :state => params[:state] },
9
+ :without_protection => true)
10
+ redirect_to access_grant.redirect_uri_for(params[:redirect_uri])
11
+ end
12
+
13
+ def access_token
14
+ authenticate_app
15
+
16
+ access_grant = SsoProvyder::AccessGrant.authenticate_with({:code => params[:code], :client_id => @application.id})
17
+ if access_grant.nil?
18
+ render :json => {:error => "Could not authenticate access code"}
19
+ return
20
+ end
21
+
22
+ access_grant = access_grant.start_expiry_period!
23
+ render :json => {:access_token => access_grant.access_token, :refresh_token => access_grant.refresh_token, :expires_in => (access_grant.access_token_expires_at - Time.now).to_i}
24
+ end
25
+
26
+ # IDEA: we could provide a way to customize this in options
27
+ # + extend Authentifyd user model attributes
28
+ #
29
+ def user
30
+ hash = {
31
+ :provider => 'sso',
32
+ :id => current_user.id.to_s,
33
+ :info => { :email => current_user.email },
34
+ :extra => {}
35
+ }
36
+
37
+ render :json => hash.to_json
38
+ end
39
+
40
+ # Not Implemented ! (from josh software implementation)
41
+ # Incase, we need to check timeout of the session from a different application!
42
+ # This will be called ONLY if the user is authenticated and token is valid
43
+ # Extend the UserManager session
44
+ # def isalive
45
+ # warden.set_user(current_user, :scope => :user)
46
+ # response = { 'status' => 'ok' }
47
+ #
48
+ # respond_to do |format|
49
+ # format.any { render :json => response.to_json }
50
+ # end
51
+ # end
52
+
53
+ # Not Implemented ! (from josh software implementation)
54
+ # def failure
55
+ # render :text => "ERROR: #{params[:message]}"
56
+ # end
57
+
58
+ protected
59
+
60
+ def application
61
+ @application ||= SsoProvyder::Client.find_by_app_id(params[:client_id])
62
+ end
63
+
64
+ end
@@ -0,0 +1,6 @@
1
+ class SsoProvyder::RegistrationsController < Authentifyd::RegistrationsController
2
+
3
+ def after_update_path_for(scope)
4
+ session[:referrer] ? session[:referrer] : root_path
5
+ end
6
+ end
@@ -0,0 +1,4 @@
1
+ module SsoProvyder
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,33 @@
1
+ class SsoProvyder::AccessGrant < ActiveRecord::Base
2
+ belongs_to :user, :class_name => (SsoProvyder.authentifyd_user_class.try(:to_s) || "User")
3
+ belongs_to :client
4
+ before_create :generate_tokens
5
+
6
+
7
+ def self.prune!
8
+ delete_all(["created_at < ?", 3.days.ago])
9
+ end
10
+
11
+ def self.authenticate_with(args = {})
12
+ where(args).first
13
+ end
14
+
15
+ def generate_tokens
16
+ self.code, self.access_token, self.refresh_token = SecureRandom.hex(16), SecureRandom.hex(16), SecureRandom.hex(16)
17
+ end
18
+
19
+ def redirect_uri_for(redirect_uri)
20
+ redirect_uri.match(/(\?.*)$/)
21
+ redirect_uri + "#{ !!$1 ? $1+'&' : '?' }code=#{code}&response_type=code&state=#{state}"
22
+ end
23
+
24
+ # Note: This is currently configured through Devise,
25
+ # backed up by default value in SsoProvyder config
26
+ def start_expiry_period!
27
+ _expires_at = Time.now + (Devise.timeout_in || SsoProvyder.timeout_in)
28
+ self.update_attribute(:access_token_expires_at, _expires_at)
29
+ return self
30
+ end
31
+
32
+ attr_accessible :access_token_expires_at
33
+ end
@@ -0,0 +1,8 @@
1
+ class SsoProvyder::Client < ActiveRecord::Base
2
+
3
+ def self.authenticate(app_id, app_secret)
4
+ where(["app_id = ? AND app_secret = ?", app_id, app_secret]).first
5
+ end
6
+
7
+ attr_accessible :app_id, :app_secret
8
+ end
@@ -0,0 +1,5 @@
1
+ module SsoProvyder
2
+ def self.table_name_prefix
3
+ "sso_provyder_"
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>SsoProvyder</title>
5
+ <%= stylesheet_link_tag "sso_provyder/application", :media => "all" %>
6
+ <%= javascript_include_tag "sso_provyder/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,22 @@
1
+ Authentifyd.devise_config = { :registrations_controller => "SsoProvyder::Registrations" }
2
+ Authentifyd.path = SsoProvyder.authentifyd_path
3
+ Authentifyd.path_prefix = SsoProvyder.path
4
+ Authentifyd.custom_css = SsoProvyder.custom_css
5
+
6
+ module SsoProvyder
7
+ class Engine < Rails::Engine
8
+ config.after_initialize do
9
+ klass = SsoProvyder.authentifyd_user_class.constantize
10
+ klass.send(:has_many, :access_grants, :dependent => :delete_all, :class_name => "SsoProvyder::AccessGrant")
11
+ klass.send(:token_authentication_key=, "oauth_token")
12
+ klass.send(:define_singleton_method, :find_for_token_authentication) do |conditions|
13
+ where([%|sso_provyder_access_grants.access_token = ? AND
14
+ (sso_provyder_access_grants.access_token_expires_at IS NULL OR
15
+ sso_provyder_access_grants.access_token_expires_at > ?)|,
16
+ conditions[token_authentication_key], Time.now]).
17
+ joins(:access_grants).
18
+ select("#{klass.table_name}.*").first
19
+ end
20
+ end
21
+ end
22
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,14 @@
1
+ SsoProvyder::Engine.routes.draw do
2
+ root :to => redirect { |p, req| req.flash.keep; "#{SsoProvyder.default_root}" }
3
+ mount Authentifyd::Engine => Authentifyd.path
4
+
5
+ match 'auth/sso/authorize' => 'auth_web#authorize'
6
+ match 'auth/sso/access_token' => 'auth_web#access_token'
7
+ match 'auth/sso/user' => 'auth_web#user'
8
+ match 'oauth/token' => 'auth_web#access_token'
9
+
10
+ match 'auth/sso/valid_current_api_client' => 'auth_api#valid_current_api_client'
11
+ match 'auth/sso/valid_current_api_client_user' => 'auth_api#valid_current_api_client_user'
12
+
13
+ match "logout" => redirect {|params,request| "#{SsoProvyder.path}#{Authentifyd.path}/users/sign_out" + request.url[/\?.*$/]}
14
+ end
@@ -0,0 +1,19 @@
1
+ class CreateAccessGrants < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :sso_provyder_access_grants do |t|
4
+ t.string :code
5
+ t.string :access_token
6
+ t.string :refresh_token
7
+ t.datetime :access_token_expires_at
8
+ t.integer :user_id
9
+ t.integer :client_id
10
+ t.string :state
11
+
12
+ t.timestamps
13
+ end
14
+ end
15
+
16
+ def self.down
17
+ drop_table :access_grants
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ class CreateClients < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :sso_provyder_clients do |t|
4
+ t.string :name
5
+ t.string :app_id
6
+ t.string :app_secret
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+
12
+ def self.down
13
+ drop_table :clients
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ module SsoProvyder
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace SsoProvyder
4
+
5
+ config.generators do |g|
6
+ g.test_framework :rspec, :view_specs => false
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module SsoProvyder
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,32 @@
1
+ require "sso_provyder/engine"
2
+ require 'authentifyd'
3
+
4
+ module SsoProvyder
5
+ mattr_accessor :authentifyd_user_class, :authentifyd_path
6
+ def self.authentifyd_user_class
7
+ @@authentifyd_user_class ||= "Authentifyd::User"
8
+ end
9
+ def self.authentifyd_path
10
+ @@authentifyd_path ||= "/aut"
11
+ end
12
+
13
+ # needed to palliate Devise.timeout_in if missing
14
+ # used for Access Grant expiration
15
+ mattr_accessor :timeout_in
16
+ def self.timeout_in
17
+ @@timeout_in ||= 1.days
18
+ end
19
+
20
+ mattr_accessor :path
21
+ def self.path
22
+ @@path ||= "/sso"
23
+ end
24
+
25
+ mattr_accessor :default_root
26
+ def self.default_root
27
+ @@default_root ||= "/"
28
+ end
29
+
30
+ mattr_accessor :custom_css
31
+ end
32
+
@@ -0,0 +1,20 @@
1
+ # desc "Explaining what the task does"
2
+ # task :sso_provyder do
3
+ # # Task goes here
4
+ # end
5
+ namespace :sso_provyder do
6
+ desc "Initialize db"
7
+ task :initialize => :environment do
8
+ ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[Rails.env])
9
+ unless ActiveRecord::Base.connection.table_exists? 'authentifyd_users'
10
+ %x(rake authentifyd:install:migrations)
11
+ # %x(rake db:migrate)
12
+ puts "\n"
13
+ puts '---------------------------------------------------------------------------------------------------'
14
+ puts "Added migrations for Authentifyd tables"
15
+ puts '---------------------------------------------------------------------------------------------------'
16
+ # and ran rake db:migrate on #{Rails.env} environement"
17
+ puts "\n"
18
+ end
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,150 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sso_provyder
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - NicoArbogast
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 3.2.8
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 3.2.8
30
+ - !ruby/object:Gem::Dependency
31
+ name: omniauth
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: authentifyd
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - '='
52
+ - !ruby/object:Gem::Version
53
+ version: 1.0.3
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 1.0.3
62
+ - !ruby/object:Gem::Dependency
63
+ name: mysql2
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rspec-rails
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ description: Based on Devise, Authentifyd and joshsoftware/sso-devise-omniauth-provider.
95
+ Parts directly taken from https://github.com/joshsoftware/sso-devise-omniauth-provider
96
+ email:
97
+ - nicolas.arbogast@gmail.com
98
+ executables: []
99
+ extensions: []
100
+ extra_rdoc_files: []
101
+ files:
102
+ - app/assets/javascripts/sso_provyder/application.js
103
+ - app/assets/stylesheets/sso_provyder/application.css
104
+ - app/controllers/sso_provyder/application_controller.rb
105
+ - app/controllers/sso_provyder/auth_api_controller.rb
106
+ - app/controllers/sso_provyder/auth_controller.rb
107
+ - app/controllers/sso_provyder/auth_web_controller.rb
108
+ - app/controllers/sso_provyder/registrations_controller.rb
109
+ - app/helpers/sso_provyder/application_helper.rb
110
+ - app/models/sso_provyder/access_grant.rb
111
+ - app/models/sso_provyder/client.rb
112
+ - app/models/sso_provyder.rb
113
+ - app/views/layouts/sso_provyder/application.html.erb
114
+ - config/initializers/authentifyd.rb
115
+ - config/routes.rb
116
+ - db/migrate/20121123091659_create_access_grants.rb
117
+ - db/migrate/20121123091700_create_clients.rb
118
+ - lib/sso_provyder/engine.rb
119
+ - lib/sso_provyder/version.rb
120
+ - lib/sso_provyder.rb
121
+ - lib/tasks/sso_provyder_tasks.rake
122
+ - MIT-LICENSE
123
+ - Rakefile
124
+ - README.rdoc
125
+ homepage: https://github.com/NicoArbogast/sso_client
126
+ licenses: []
127
+ post_install_message:
128
+ rdoc_options: []
129
+ require_paths:
130
+ - lib
131
+ required_ruby_version: !ruby/object:Gem::Requirement
132
+ none: false
133
+ requirements:
134
+ - - ! '>='
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ requirements: []
144
+ rubyforge_project:
145
+ rubygems_version: 1.8.24
146
+ signing_key:
147
+ specification_version: 3
148
+ summary: A Rails Engine providing an Omniauth provider with single sign on features
149
+ in a minute.
150
+ test_files: []