omniauth-rails 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +71 -0
- data/Rakefile +41 -0
- data/app/assets/config/omniauth_rails_manifest.js +1 -0
- data/app/assets/stylesheets/omniauth/rails/application.css +19 -0
- data/app/controllers/omniauth/rails/application_controller.rb +8 -0
- data/app/controllers/omniauth/rails/flash.rb +46 -0
- data/app/controllers/omniauth/rails/require_authentication.rb +26 -0
- data/app/controllers/omniauth/rails/require_authorization.rb +32 -0
- data/app/controllers/omniauth/rails/sessions_controller.rb +55 -0
- data/app/helpers/omniauth/rails/application_helper.rb +16 -0
- data/app/models/omniauth/rails/authentication_data_store.rb +31 -0
- data/app/models/omniauth/rails/authentication_request.rb +28 -0
- data/app/models/omniauth/rails/authentication_session.rb +53 -0
- data/app/models/omniauth/rails/authorization_checker.rb +28 -0
- data/app/models/omniauth/rails/authorization_types/base.rb +17 -0
- data/app/models/omniauth/rails/authorization_types/domains.rb +22 -0
- data/app/models/omniauth/rails/authorization_types/emails.rb +18 -0
- data/app/models/omniauth/rails/authorization_types/regex.rb +18 -0
- data/app/models/omniauth/rails/omni_auth_route_builder.rb +18 -0
- data/app/views/omniauth/rails/sessions/destroy.html.erb +6 -0
- data/config/initializers/omniauth_rails.rb +35 -0
- data/config/routes.rb +6 -0
- data/lib/omniauth/rails/configuration.rb +15 -0
- data/lib/omniauth/rails/engine.rb +22 -0
- data/lib/omniauth/rails/test/controller_helpers.rb +17 -0
- data/lib/omniauth/rails/test/request_helpers.rb +25 -0
- data/lib/omniauth/rails/version.rb +6 -0
- data/lib/omniauth/rails.rb +9 -0
- data/spec/controllers/application_controller_spec.rb +9 -0
- data/spec/examples.txt +19 -0
- data/spec/models/omniauth/rails/authorization_types/emails_spec.rb +28 -0
- data/spec/models/omniauth/rails/authorization_types/regex_spec.rb +28 -0
- data/spec/omniauth_rails_spec.rb +10 -0
- data/spec/rails_helper_for_engine.rb +62 -0
- data/spec/spec_helper.rb +93 -0
- data/spec/test_app/Rakefile +12 -0
- data/spec/test_app/app/assets/config/manifest.js +4 -0
- data/spec/test_app/app/assets/javascripts/application.js +13 -0
- data/spec/test_app/app/assets/stylesheets/application.css +15 -0
- data/spec/test_app/app/controllers/application_controller.rb +4 -0
- data/spec/test_app/app/controllers/private_controller.rb +9 -0
- data/spec/test_app/app/controllers/public_controller.rb +6 -0
- data/spec/test_app/app/helpers/application_helper.rb +3 -0
- data/spec/test_app/app/mailers/application_mailer.rb +5 -0
- data/spec/test_app/app/models/application_record.rb +4 -0
- data/spec/test_app/app/views/layouts/application.html.erb +24 -0
- data/spec/test_app/app/views/private/show.html.erb +1 -0
- data/spec/test_app/app/views/public/show.html.erb +1 -0
- data/spec/test_app/bin/bundle +4 -0
- data/spec/test_app/bin/rails +5 -0
- data/spec/test_app/bin/rake +5 -0
- data/spec/test_app/bin/setup +35 -0
- data/spec/test_app/bin/update +30 -0
- data/spec/test_app/config/application.rb +23 -0
- data/spec/test_app/config/boot.rb +6 -0
- data/spec/test_app/config/environment.rb +6 -0
- data/spec/test_app/config/environments/development.rb +55 -0
- data/spec/test_app/config/environments/production.rb +89 -0
- data/spec/test_app/config/environments/test.rb +43 -0
- data/spec/test_app/config/initializers/application_controller_renderer.rb +7 -0
- data/spec/test_app/config/initializers/assets.rb +12 -0
- data/spec/test_app/config/initializers/backtrace_silencers.rb +10 -0
- data/spec/test_app/config/initializers/cookies_serializer.rb +6 -0
- data/spec/test_app/config/initializers/filter_parameter_logging.rb +5 -0
- data/spec/test_app/config/initializers/inflections.rb +17 -0
- data/spec/test_app/config/initializers/mime_types.rb +5 -0
- data/spec/test_app/config/initializers/session_store.rb +4 -0
- data/spec/test_app/config/initializers/wrap_parameters.rb +15 -0
- data/spec/test_app/config/locales/en.yml +23 -0
- data/spec/test_app/config/omniauth_rails.yml +16 -0
- data/spec/test_app/config/puma.rb +48 -0
- data/spec/test_app/config/routes.rb +8 -0
- data/spec/test_app/config/secrets.yml +22 -0
- data/spec/test_app/config/spring.rb +7 -0
- data/spec/test_app/config.ru +6 -0
- data/spec/test_app/log/development.log +4451 -0
- data/spec/test_app/log/test.log +7601 -0
- data/spec/test_app/public/404.html +67 -0
- data/spec/test_app/public/422.html +67 -0
- data/spec/test_app/public/500.html +66 -0
- data/spec/test_app/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/test_app/public/apple-touch-icon.png +0 -0
- data/spec/test_app/public/favicon.ico +0 -0
- data/spec/test_app/spec/controllers/private_controller_spec.rb +19 -0
- data/spec/test_app/spec/rails_helper.rb +54 -0
- data/spec/test_app/spec/requests/private_controller_spec.rb +26 -0
- data/spec/test_app/spec/requests/public_controller_spec.rb +13 -0
- data/spec/test_app/spec/requests/sessions_controller_spec.rb +87 -0
- data/spec/test_app/spec/spec_helper.rb +99 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/-5/-528MPRmC3ByNiAzVD1hs-NG3Muhf9FsYPaDbo4qIpI.cache +1 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/3v/3voyTxS8FmTTGPrz-QQ23N6AgGate2o7X5ZnZeTkQbs.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/5V/5VAABbvE5t5bCDKmKjLivvfe1CqYdD4n4vtZQiMa4I0.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/64/64siRwVaDPAW5fTe1O4rlGaq-0ExxAWA0-csPcik-uM.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/Aa/AasprW2BgqWDcmZnsPRxs-R5D0VGpL7dHYMwtsC1tmE.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/An/An3DVlfO1pzT7FAnm09q3Ok_2PmGYhiAvxuW9OgG9wc.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/C-/C-_kx_I8fFV2TrLPw8CNFy1uLrN6G4yLPg_4vOhlohQ.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/EG/EGN6771mS8m_7wi-Cr-GgFKv9U9IE3gpo9JQ-N3AYlQ.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/Hl/HlzBaGDQ4NV3ctlz-qlmStUWDCELhxzVK1-SgLkPCH0.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/IB/IBoXb9_P8EU8f7aPVNE8cWJybcus8fS7KGvi4HxKdMU.cache +1 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/K2/K28c2b37N3eRA-Pckb3MO3D3BvGXfbxDGNeRYIXG8Cg.cache +1 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/KJ/KJdFFU6zb4YpQWEm8bsXxx8kdQ01BdK0F0h6TTzpOiY.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/KW/KWwCiQwwI6oqiIHZg_Qg2nrs1zXJISos9799GIL5viU.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/Kh/KhKDGOFwOEJlSwLMaG8Yak8AktHsnEr-fUwLpl9d0tc.cache +1 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/NX/NXZl3HljnPNJmh2CNpp0skcYvQx4eSEp6vuG5o3lqqY.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/NX/nxTv3sKVUQZADJyM3dPaVmUA78MIsMLD_K279yN_GsI.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/Ob/ObDGu7gmDzQuH86CeAdhWRPf0sfv9Qo3CoxGK3VOYWI.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/QG/QGjnK1OGVhAWzpma8R60Qdcr6v46sAWmpwQpeoWltX8.cache +1 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/Qn/Qn2TRz8mMz8dPVvXgHUfqXC19EPZQgG3XDqm5W_E-A0.cache +1 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/WC/WCTd8gm1KmkPKRB14gd1wwFv3x9NwMsmquXet4Z1DTU.cache +2 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/Z-/Z-3hfqbx8r350iW9zFPz_OdVHX0X4Z4bMk9YbS1eha8.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/Z2/Z2DJdVm4jsJXg0HzuQVyAAmjJbVdzKntXlmd14iNVbU.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/ZA/ZAzUlqsc-uLa_zcjt1t6EBkPqI8PkEoxz40i4FgrRlQ.cache +1 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/bN/bNCmkb6T3JKDzd6s7ZxOLn_WdC6gUnRARnBDHrMFS7o.cache +1 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/b_/b_Itlk9QZZd7Rvf8kcA4yLP1R5Acu7jB-m1xQiSU0qE.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/d6/d6PosAq3dbPqxxvjAcaLgePkRuQ8w__EA-M42WarK_0.cache +1 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/fD/fDbKpwc4jlsYlnxTT3vnhsiBcSJF3imnAGUBp9nq_Bw.cache +1 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/fE/fEHvM7gLiXuJB6lDj2KNzgAx5L3BBn2NSsuodvPAryI.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/fg/fgbqfgH_CvzP2H744Q3ywDzlqLRSgSw0AH6ifkC7roo.cache +1 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/g4/g4TbkEUbvKBMpO8z4ioPbq8ArdLl-scuF3pVaLJhmVI.cache +1 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/id/idcyFsf20F5Vd3GC1XtM_PxlNnROM6CxO1j11NG3RWk.cache +1 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/ih/ihflBRw1ToLzP0q8oKAJl_a6EHHbTdJUcVR5DANsIuA.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/jz/jzXohzOyfczV5wKfQVQWgE1H0IMN4jaxEM3XlhHNgvk.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/lH/lHLoBOtMavo_6UnfOn0DVLI2JQBT1W9sGR3IZzOD6o8.cache +2 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/mD/mDmWU5fLvNY4uggphc1wqYVQDn_w_U6Jz2XRSf59jDc.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/mX/mX1nlsL_SWOB4y22W5FheRX0YEONKyOY7xUeIvRiHco.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/n5/n5FDaqgvLV4Rc1Xm6TykMEFanDhSJJ77HPuPCEgCDQM.cache +1 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/n9/n9Nzbk_dEL3fNO-u56owqnrG7YQmhcvDgJ2fWWE_9jE.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/nU/nUDR2L4CaIx5IszaYaaaACw519TTTzvpxsp7NMl6KyQ.cache +1 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/n_/n_xYqQYhwEMQknb3jFQnjlxxBE9TzMNHCdJ-bEyZFIw.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/pc/pcFf9fij5Xa__QoHi-QzN_0Q_UGLhv6gihTXnoFX3sg.cache +1 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/q-/q-721tFv_0DZO9GZ_kHYUD_jn6GNRC09vb51mwyxbuI.cache +1 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/r6/r6saZ-BJCnX2-U353od1DgtZIGy5kXrCuXatXntMcTE.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/wY/wYWiPwDGlToFGYId__oKg8QMPEeuRZoP1FhQahshfOo.cache +1 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/yD/yDj60NQvsiwl1QWQXH-iC4pgF1cmHkUFo-kkXBSjsIQ.cache +1 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/ym/ymCwqEVBkEs6bYteLf70KCA5pCKZtqjQ3TbZQzrIs3M.cache +0 -0
- data/spec/test_app/tmp/cache/assets/sprockets/v3.0/z0/z041WxjoEQvRhtSLORbkRlsNTgi68Rwx7XUyaDbPn0M.cache +1 -0
- data/spec/test_app/tmp/pids/server.pid +1 -0
- metadata +453 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d56083f2dbbbb8598f6740095b9df4dd967269be
|
4
|
+
data.tar.gz: 905900d024010eee45dc8025a958e80a167ea269
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 418f5a1cafc19fd179bd4bb78b80ec45962c410a3f9aef1f41dc5eaa6aaaddf83b65cb13d0d51234d484d6a5535df8f0c5b6a2f7ae3594f654d6e57449414d29
|
7
|
+
data.tar.gz: 69b3d71ee4887a09f8283c0304391901483b921384f9976805b80b10e109e6149364365cd189dce427cf5133a80a0cd529b873c8f8100ff29e437d4bfcbfc306
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2016 Dan Rabinowitz
|
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.md
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# Omniauth::Rails
|
2
|
+
A Rails Engine to make it as easy as possible to add oauth authentication to a Rails app.
|
3
|
+
|
4
|
+
The canonical use case is this:
|
5
|
+
You build a simple Rails app for your company. It is for internal use only. Your company uses Google Apps for gmail.
|
6
|
+
|
7
|
+
Most existing authentication and authorization systems, like Devise, require a table of Users, and permissions. That requires that users maintain a separate password, and it requires someone to disable an account when an employee leaves.
|
8
|
+
|
9
|
+
OmniAuth solves these problems, but can take some effort to configure properly. It is highly flexible and customizable. But adding it can require updates to controllers, the routes file, an initializer. The biggest challenge is that after it authenticates the user, it leaves *persisting* that user's identify as something for the developer to handle.
|
10
|
+
|
11
|
+
OmniAuth::Rails makes it as easy as possible to create an admin site. See Usage, below.
|
12
|
+
|
13
|
+
Authorization is handled separately.
|
14
|
+
|
15
|
+
## TODO
|
16
|
+
|
17
|
+
* Add a "dev mode" override which simply skips all authentication.
|
18
|
+
|
19
|
+
* Search for "TODO" in the code.
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
1. Add the gem to your Gemfile
|
24
|
+
gem 'omniauth-rails'
|
25
|
+
|
26
|
+
2. Add a config/omniauth_rails.yml with something like this:
|
27
|
+
```yml
|
28
|
+
development:
|
29
|
+
providers:
|
30
|
+
google_oauth2:
|
31
|
+
client_id: <%= ENV["CLIENT_ID"] %>
|
32
|
+
client_secret: <%= ENV["CLIENT_SECRET"] %>
|
33
|
+
authenticated_root: "/private"
|
34
|
+
unauthenticated_root: "/public"
|
35
|
+
session_duration_in_seconds: 5 # The default is 3600 (which is 1 hour)
|
36
|
+
test:
|
37
|
+
providers:
|
38
|
+
google_oauth2:
|
39
|
+
client_id: 1
|
40
|
+
client_secret: 2
|
41
|
+
authenticated_root: "/private"
|
42
|
+
unauthenticated_root: "/public"
|
43
|
+
session_duration_in_seconds: 5 # The default is 3600 (which is 1 hour)
|
44
|
+
production:
|
45
|
+
providers:
|
46
|
+
google_oauth2:
|
47
|
+
client_id: <%= ENV["CLIENT_ID"] %>
|
48
|
+
client_secret: <%= ENV["CLIENT_SECRET"] %>
|
49
|
+
authenticated_root: "/private"
|
50
|
+
unauthenticated_root: "/public"
|
51
|
+
session_duration_in_seconds: 3600 # The default is 3600 (which is 1 hour)
|
52
|
+
```
|
53
|
+
|
54
|
+
3. In any controllers which require authentication, add this line:
|
55
|
+
```ruby
|
56
|
+
include Omniauth::Rails::RequireAuthentication
|
57
|
+
```
|
58
|
+
|
59
|
+
## Logging out
|
60
|
+
|
61
|
+
In general, there's not much point in "logging out". It wipes the Omniauth::Rails session,
|
62
|
+
but the browser is still logged in to the provider, which has granted access to the application
|
63
|
+
(generally) with no expiration. So logging back in requires no credentials.
|
64
|
+
|
65
|
+
Bottom line: There's usually no reason to have a logout button when using Omniauth::Rails
|
66
|
+
|
67
|
+
## Contributing
|
68
|
+
PRs are welcome!
|
69
|
+
|
70
|
+
## License
|
71
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
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
|
+
|
8
|
+
require "rdoc/task"
|
9
|
+
|
10
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
11
|
+
rdoc.rdoc_dir = "rdoc"
|
12
|
+
rdoc.title = "Omniauth::Rails"
|
13
|
+
rdoc.options << "--line-numbers"
|
14
|
+
rdoc.rdoc_files.include("README.md")
|
15
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
16
|
+
end
|
17
|
+
|
18
|
+
APP_RAKEFILE = File.expand_path("../spec/test_app/Rakefile", __FILE__)
|
19
|
+
load "rails/tasks/engine.rake"
|
20
|
+
|
21
|
+
load "rails/tasks/statistics.rake"
|
22
|
+
|
23
|
+
require "bundler/gem_tasks"
|
24
|
+
|
25
|
+
require "rspec/core"
|
26
|
+
require "rspec/core/rake_task"
|
27
|
+
|
28
|
+
desc "Run all specs in spec directory (excluding plugin specs)"
|
29
|
+
task("spec").clear
|
30
|
+
RSpec::Core::RakeTask.new do |t|
|
31
|
+
t.verbose = false
|
32
|
+
end
|
33
|
+
|
34
|
+
require "rubocop/rake_task"
|
35
|
+
desc "Run RuboCop"
|
36
|
+
RuboCop::RakeTask.new(:rubocop) do |tsk|
|
37
|
+
tsk.fail_on_error = true
|
38
|
+
tsk.options = ["-DR", "--format=html", "--out=tmp/rubocop.html", "--format=progress"]
|
39
|
+
end
|
40
|
+
|
41
|
+
task default: [:spec, :rubocop]
|
@@ -0,0 +1 @@
|
|
1
|
+
//= link_directory ../stylesheets/omniauth/rails .css
|
@@ -0,0 +1,19 @@
|
|
1
|
+
form.button_to {
|
2
|
+
display: inline;
|
3
|
+
margin: 0;
|
4
|
+
padding: 0;
|
5
|
+
}
|
6
|
+
form.button_to div { display: inline; }
|
7
|
+
form.button_to input[type=submit] {
|
8
|
+
margin: 0;
|
9
|
+
padding: 0;
|
10
|
+
-webkit-appearance: caret;
|
11
|
+
background: none;
|
12
|
+
border: none;
|
13
|
+
font-size: inherit;
|
14
|
+
font-family: inherit;
|
15
|
+
cursor: pointer;
|
16
|
+
text-decoration: underline;
|
17
|
+
color: #0000FF;
|
18
|
+
}
|
19
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Omniauth
|
3
|
+
module Rails
|
4
|
+
module Flash
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
def set_url_to_return_to_after_authentication
|
8
|
+
# TODO: Sanitize these urls, to avoid phishing attacks
|
9
|
+
# See https://www.owasp.org/index.php/Unvalidated_Redirects_and_Forwards_Cheat_Sheet
|
10
|
+
flash[:url_to_return_to_after_authentication] =
|
11
|
+
# url_to_return_to_after_authentication_from_params ||
|
12
|
+
url_to_return_to_after_authentication_from_flash ||
|
13
|
+
# url_to_return_to_after_authentication_from_referer ||
|
14
|
+
default_url_to_return_to_after_authentication
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# def url_to_return_to_after_authentication_from_params
|
20
|
+
# return nil unless allow_url_to_return_to_after_authentication_from_params?
|
21
|
+
# params[:return_to]
|
22
|
+
# end
|
23
|
+
|
24
|
+
# def allow_url_to_return_to_after_authentication_from_params?
|
25
|
+
# false
|
26
|
+
# end
|
27
|
+
|
28
|
+
def url_to_return_to_after_authentication_from_flash
|
29
|
+
flash[:url_to_return_to_after_authentication]
|
30
|
+
end
|
31
|
+
|
32
|
+
# def url_to_return_to_after_authentication_from_referer
|
33
|
+
# return nil unless allow_url_to_return_to_after_authentication_from_referer?
|
34
|
+
# request.referer
|
35
|
+
# end
|
36
|
+
|
37
|
+
# def allow_url_to_return_to_after_authentication_from_referer?
|
38
|
+
# false
|
39
|
+
# end
|
40
|
+
|
41
|
+
def default_url_to_return_to_after_authentication
|
42
|
+
Configuration.authenticated_root
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Omniauth
|
3
|
+
module Rails
|
4
|
+
module RequireAuthentication
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
include Omniauth::Rails::ApplicationHelper
|
9
|
+
|
10
|
+
# TODO: Do not add this before_action in dev_mode
|
11
|
+
before_action :require_authentication
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def require_authentication
|
17
|
+
redirect_to_sign_in_url unless authenticated?
|
18
|
+
end
|
19
|
+
|
20
|
+
def redirect_to_sign_in_url
|
21
|
+
flash[:url_to_return_to_after_authentication] = request.original_url
|
22
|
+
redirect_to omniauth_rails.sign_in_url
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Omniauth
|
3
|
+
module Rails
|
4
|
+
module RequireAuthorization
|
5
|
+
def self.included(klass)
|
6
|
+
klass.include Omniauth::Rails::RequireAuthentication
|
7
|
+
klass.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
private
|
12
|
+
|
13
|
+
def require_authorization(params)
|
14
|
+
# TODO: Do not add this before_action in dev_mode
|
15
|
+
before_action { |c| c.require_authorization(params) }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def require_authorization(params)
|
22
|
+
redirect_to_sign_in_url unless authorized?(params)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def authorized?(params)
|
28
|
+
AuthorizationChecker.new(email: authenticated_email, params: params).authorized?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Omniauth
|
3
|
+
module Rails
|
4
|
+
class SessionsController < ApplicationController
|
5
|
+
include Omniauth::Rails::ApplicationHelper
|
6
|
+
include Omniauth::Rails::Flash
|
7
|
+
|
8
|
+
# GET /sign_in
|
9
|
+
def new
|
10
|
+
# Set a flash variable, so we know where to go after a successful authentication.
|
11
|
+
set_url_to_return_to_after_authentication
|
12
|
+
|
13
|
+
# If we are already authenticated, do not attempt to authenticate again.
|
14
|
+
# Instead, redirect to where we would go after authentication
|
15
|
+
if authenticated?
|
16
|
+
redirect_to flash[:url_to_return_to_after_authentication]
|
17
|
+
else
|
18
|
+
redirect_to omniauth_route
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# DELETE /sign_out
|
23
|
+
def destroy
|
24
|
+
authentication_session.reset
|
25
|
+
|
26
|
+
if Configuration.unauthenticated_root.present?
|
27
|
+
redirect_to Configuration.unauthenticated_root
|
28
|
+
else
|
29
|
+
render layout: false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# GET /:provider/callback
|
34
|
+
def create
|
35
|
+
persist_authentication_data
|
36
|
+
redirect_to flash[:url_to_return_to_after_authentication] ||
|
37
|
+
default_url_to_return_to_after_authentication
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def omniauth_route
|
43
|
+
OmniAuthRouteBuilder.new.route
|
44
|
+
end
|
45
|
+
|
46
|
+
def persist_authentication_data
|
47
|
+
authentication_request.persist(authentication_session)
|
48
|
+
end
|
49
|
+
|
50
|
+
def authentication_request
|
51
|
+
AuthenticationRequest.new(request)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Omniauth
|
3
|
+
module Rails
|
4
|
+
module ApplicationHelper
|
5
|
+
delegate :authenticated?, to: :authentication_session
|
6
|
+
|
7
|
+
def authenticated_email
|
8
|
+
authentication_session.email
|
9
|
+
end
|
10
|
+
|
11
|
+
def authentication_session
|
12
|
+
AuthenticationSession.new(session)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Omniauth
|
3
|
+
module Rails
|
4
|
+
class AuthenticationDataStore
|
5
|
+
SCOPE = "OmniauthRailsAuthData"
|
6
|
+
|
7
|
+
def initialize(session)
|
8
|
+
@session = session
|
9
|
+
freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(key)
|
13
|
+
return nil if session[SCOPE].nil?
|
14
|
+
session[SCOPE][key]
|
15
|
+
end
|
16
|
+
|
17
|
+
def set(key, value)
|
18
|
+
session[SCOPE] ||= {}
|
19
|
+
session[SCOPE][key] = value
|
20
|
+
end
|
21
|
+
|
22
|
+
def reset
|
23
|
+
session[SCOPE] = {}
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_reader :session
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Omniauth
|
3
|
+
module Rails
|
4
|
+
class AuthenticationRequest
|
5
|
+
def initialize(request)
|
6
|
+
@request = request
|
7
|
+
end
|
8
|
+
|
9
|
+
def persist(authentication_session)
|
10
|
+
# TODO: Store the provider in the session
|
11
|
+
authentication_session.email = email
|
12
|
+
authentication_session.expire_in(session_duration)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_reader :request
|
18
|
+
|
19
|
+
def email
|
20
|
+
request.env["omniauth.auth"].info.email
|
21
|
+
end
|
22
|
+
|
23
|
+
def session_duration
|
24
|
+
Configuration.session_duration
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Omniauth
|
3
|
+
module Rails
|
4
|
+
class AuthenticationSession
|
5
|
+
EMAIL_KEY = "email"
|
6
|
+
EXPIRE_AT_KEY = "expire_at"
|
7
|
+
|
8
|
+
def initialize(session)
|
9
|
+
@session = session
|
10
|
+
reset if expired?
|
11
|
+
freeze
|
12
|
+
end
|
13
|
+
|
14
|
+
delegate :reset, to: :data_store
|
15
|
+
|
16
|
+
def authenticated?
|
17
|
+
email.present?
|
18
|
+
end
|
19
|
+
|
20
|
+
def email
|
21
|
+
data_store.get(EMAIL_KEY)
|
22
|
+
end
|
23
|
+
|
24
|
+
def email=(email)
|
25
|
+
data_store.set(EMAIL_KEY, email)
|
26
|
+
end
|
27
|
+
|
28
|
+
def expire_in(duration)
|
29
|
+
self.expire_at = (Time.now.to_i + duration)
|
30
|
+
end
|
31
|
+
|
32
|
+
def expire_at
|
33
|
+
data_store.get(EXPIRE_AT_KEY)
|
34
|
+
end
|
35
|
+
|
36
|
+
def expire_at=(expire_at)
|
37
|
+
data_store.set(EXPIRE_AT_KEY, expire_at)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
attr_reader :session
|
43
|
+
|
44
|
+
def data_store
|
45
|
+
@data_store ||= AuthenticationDataStore.new(session)
|
46
|
+
end
|
47
|
+
|
48
|
+
def expired?
|
49
|
+
expire_at.present? && expire_at < Time.now.to_i
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Omniauth
|
3
|
+
module Rails
|
4
|
+
class AuthorizationChecker
|
5
|
+
AUTHORIZATION_TYPES = {
|
6
|
+
domains: AuthorizationTypes::Domains,
|
7
|
+
emails: AuthorizationTypes::Emails,
|
8
|
+
regex: AuthorizationTypes::Regex,
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
def initialize(email:, params:)
|
12
|
+
@email = email
|
13
|
+
@params = params
|
14
|
+
end
|
15
|
+
|
16
|
+
def authorized?
|
17
|
+
params.map do |key, value|
|
18
|
+
raise "Invalid key for authorization constraint" unless AUTHORIZATION_TYPES.key?(key)
|
19
|
+
AUTHORIZATION_TYPES[key].new(email: email, value: value).authorized?
|
20
|
+
end.all?
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_reader :email, :params
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Omniauth
|
3
|
+
module Rails
|
4
|
+
module AuthorizationTypes
|
5
|
+
class Base
|
6
|
+
def initialize(email:, value:)
|
7
|
+
@email = email
|
8
|
+
@value = value
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
attr_reader :email, :value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Omniauth
|
3
|
+
module Rails
|
4
|
+
module AuthorizationTypes
|
5
|
+
class Domains < Base
|
6
|
+
def authorized?
|
7
|
+
domains.any? { |domain| email_domain.casecmp(domain).zero? }
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def email_domain
|
13
|
+
@email_domain ||= email.split("@").last.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
def domains
|
17
|
+
value
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Omniauth
|
3
|
+
module Rails
|
4
|
+
module AuthorizationTypes
|
5
|
+
class Emails < Base
|
6
|
+
def authorized?
|
7
|
+
emails.any? { |allowed_email| allowed_email.to_s.casecmp(email).zero? }
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def emails
|
13
|
+
value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Omniauth
|
3
|
+
module Rails
|
4
|
+
class OmniAuthRouteBuilder
|
5
|
+
def initialize
|
6
|
+
@provider = "google_oauth2"
|
7
|
+
end
|
8
|
+
|
9
|
+
def route
|
10
|
+
"/auth/#{provider}"
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
attr_reader :provider
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
config_hash = YAML.load(ERB.new(File.read("#{Rails.root}/config/omniauth_rails.yml")).result)[Rails.env]
|
4
|
+
|
5
|
+
OmniAuth.config.logger = Rails.logger
|
6
|
+
|
7
|
+
# TODO
|
8
|
+
# OmniAuth.config.path_prefix = "/auth"
|
9
|
+
|
10
|
+
Rails.application.config.middleware.use OmniAuth::Builder do
|
11
|
+
if config_hash.present?
|
12
|
+
raise "You must provide at least one oauth provider" unless config_hash["providers"]
|
13
|
+
config_hash["providers"].each do |provider, provider_config|
|
14
|
+
case provider
|
15
|
+
when "google_oauth2"
|
16
|
+
raise "Provider #{provider} requires a client_id" unless provider_config["client_id"]
|
17
|
+
raise "Provider #{provider} requires a client_secret" unless provider_config["client_secret"]
|
18
|
+
|
19
|
+
provider(:google_oauth2, provider_config["client_id"], provider_config["client_secret"],
|
20
|
+
access_type: "online", approval_prompt: "auto")
|
21
|
+
else
|
22
|
+
raise "#{provider} is not currently handled by omniauth_rails."
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
if config_hash["session_duration_in_seconds"].present?
|
29
|
+
Omniauth::Rails::Configuration.session_duration = config_hash["session_duration_in_seconds"].seconds
|
30
|
+
end
|
31
|
+
|
32
|
+
raise "authenticated_root is required" if config_hash["authenticated_root"].blank?
|
33
|
+
Omniauth::Rails::Configuration.authenticated_root = config_hash["authenticated_root"]
|
34
|
+
raise "unauthenticated_root is required" if config_hash["unauthenticated_root"].blank?
|
35
|
+
Omniauth::Rails::Configuration.unauthenticated_root = config_hash["unauthenticated_root"]
|
data/config/routes.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Omniauth
|
3
|
+
module Rails
|
4
|
+
class Configuration
|
5
|
+
ATTRIBUTES = %i(authenticated_root unauthenticated_root session_duration logger).freeze
|
6
|
+
|
7
|
+
@session_duration = 1.hour
|
8
|
+
@logger = ::Rails.logger
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_accessor(*ATTRIBUTES)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|