prx_auth-rails 1.2.0 → 1.3.0

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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/README.md +25 -6
  4. data/Rakefile +12 -4
  5. data/app/controllers/prx_auth/rails/sessions_controller.rb +108 -0
  6. data/app/views/prx_auth/rails/sessions/auth_error.html.erb +15 -0
  7. data/app/views/prx_auth/rails/sessions/show.html.erb +38 -0
  8. data/config/routes.rb +7 -0
  9. data/lib/prx_auth/rails.rb +1 -0
  10. data/lib/prx_auth/rails/configuration.rb +15 -4
  11. data/lib/prx_auth/rails/engine.rb +5 -0
  12. data/lib/prx_auth/rails/ext/controller.rb +29 -4
  13. data/lib/prx_auth/rails/token.rb +5 -1
  14. data/lib/prx_auth/rails/version.rb +1 -1
  15. data/prx_auth-rails.gemspec +3 -1
  16. data/test/dummy/Rakefile +6 -0
  17. data/test/dummy/app/assets/config/manifest.js +2 -0
  18. data/test/dummy/app/assets/images/.keep +0 -0
  19. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  20. data/test/dummy/app/channels/application_cable/channel.rb +4 -0
  21. data/test/dummy/app/channels/application_cable/connection.rb +4 -0
  22. data/test/dummy/app/controllers/application_controller.rb +8 -0
  23. data/test/dummy/app/controllers/concerns/.keep +0 -0
  24. data/test/dummy/app/helpers/application_helper.rb +2 -0
  25. data/test/dummy/app/javascript/packs/application.js +15 -0
  26. data/test/dummy/app/jobs/application_job.rb +7 -0
  27. data/test/dummy/app/mailers/application_mailer.rb +4 -0
  28. data/test/dummy/app/models/application_record.rb +3 -0
  29. data/test/dummy/app/models/concerns/.keep +0 -0
  30. data/test/dummy/app/views/layouts/application.html.erb +15 -0
  31. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  32. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  33. data/test/dummy/bin/rails +5 -0
  34. data/test/dummy/bin/rake +5 -0
  35. data/test/dummy/bin/setup +33 -0
  36. data/test/dummy/bin/spring +10 -0
  37. data/test/dummy/config.ru +6 -0
  38. data/test/dummy/config/application.rb +22 -0
  39. data/test/dummy/config/boot.rb +5 -0
  40. data/test/dummy/config/cable.yml +10 -0
  41. data/test/dummy/config/database.yml +25 -0
  42. data/test/dummy/config/environment.rb +5 -0
  43. data/test/dummy/config/environments/development.rb +76 -0
  44. data/test/dummy/config/environments/production.rb +120 -0
  45. data/test/dummy/config/environments/test.rb +60 -0
  46. data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
  47. data/test/dummy/config/initializers/assets.rb +12 -0
  48. data/test/dummy/config/initializers/backtrace_silencers.rb +8 -0
  49. data/test/dummy/config/initializers/content_security_policy.rb +28 -0
  50. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  51. data/test/dummy/config/initializers/filter_parameter_logging.rb +6 -0
  52. data/test/dummy/config/initializers/inflections.rb +16 -0
  53. data/test/dummy/config/initializers/mime_types.rb +4 -0
  54. data/test/dummy/config/initializers/permissions_policy.rb +11 -0
  55. data/test/dummy/config/initializers/prx_auth.rb +8 -0
  56. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  57. data/test/dummy/config/locales/en.yml +33 -0
  58. data/test/dummy/config/puma.rb +43 -0
  59. data/test/dummy/config/routes.rb +3 -0
  60. data/test/dummy/config/spring.rb +6 -0
  61. data/test/dummy/config/storage.yml +34 -0
  62. data/test/dummy/lib/assets/.keep +0 -0
  63. data/test/dummy/log/.keep +0 -0
  64. data/test/dummy/public/404.html +67 -0
  65. data/test/dummy/public/422.html +67 -0
  66. data/test/dummy/public/500.html +66 -0
  67. data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
  68. data/test/dummy/public/apple-touch-icon.png +0 -0
  69. data/test/dummy/public/favicon.ico +0 -0
  70. data/test/dummy/storage/.keep +0 -0
  71. data/test/prx_auth/rails/configuration_test.rb +18 -12
  72. data/test/prx_auth/rails/sessions_controller_test.rb +94 -0
  73. data/test/prx_auth/rails/token_test.rb +1 -1
  74. data/test/test_helper.rb +20 -9
  75. metadata +153 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5204c5e69c74ec1fa4d6acf36b64c62700ba72d5308a020deee0526ff4dd5499
4
- data.tar.gz: c5bbf5402868c36ba3e2c011eb4eb906d895e3b5237975a329099047f39a8cb3
3
+ metadata.gz: 3405e4e72d2c39585111bef4fca339a73ce11ec86a2c288f5c82d8934c0620fe
4
+ data.tar.gz: 3450063f4c4fdae2464f755222fafee08c627eda3aa8fee1d267db1474db58de
5
5
  SHA512:
6
- metadata.gz: 0d3c3f2ba128a55921138c56e1c052ef6dfd030f720886daa5b77d831545ae9c093ac6c19cbc9887c41b17003142fe2c6eedbf18f6a102ce5e08ec7179556b49
7
- data.tar.gz: cedc895cbe9b69bd7f87c365c7a0bf606236291e7572a7da5395c110612adf1e4164e40ed02e1f00517ee89da3e7c26563329b82bdb7026db4b563c113758fcf
6
+ metadata.gz: edf33f5cf4bc105818bb069554506f0b2d9ef5b8bb18cd1602b2ceb6384991804b5b3268c6bd5c519c08e8503df51c132a9bec045f13995c1d55088194fff489
7
+ data.tar.gz: 4aa62706ee892c2335756e2c3ae61171b77acc69bfe0ec06433449726f8e884cee4af2031e55e418c6780e9aedc8bfb1c78359c072c089389422a2d4aa15c95b
data/.gitignore CHANGED
@@ -14,6 +14,10 @@ rdoc
14
14
  spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
+ test/dummy/db/
18
+ test/dummy/log/development.log
19
+ test/dummy/log/test.log
20
+ test/log/test.log
17
21
  tmp
18
22
  .ruby-version
19
23
  .DS_Store
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # PrxAuth::Rails
2
2
 
3
- Rails integration for next generation PRX Authorization system.
3
+ Rails integration for next generation PRX Authorization system. This
4
+ provides common OpenId authorization patterns used in PRX apps.
4
5
 
5
6
  ## Installation
6
7
 
@@ -14,17 +15,32 @@ And then execute:
14
15
 
15
16
  ## Usage
16
17
 
17
- Installing the gem in a Rails project will automatically add the appropriate Rack middleware to your Rails application and add two methods to your controllers. These methods are:
18
+ Installing the gem in a Rails project will automatically add the
19
+ appropriate Rack middleware to your Rails application and add two
20
+ methods to your controllers. These methods are:
18
21
 
19
- * `prx_auth_token`: returns a token (similar to PrxAuth::Token) which automatically namespaces queries. The main methods you will be interested in are `authorized?`, `globally_authorized?` and `resources`. More information can be found in PrxAuth.
22
+ * `prx_auth_token`: returns a token (similar to PrxAuth::Token) which
23
+ automatically namespaces queries. The main methods you will be
24
+ interested in are `authorized?`, `globally_authorized?` and `resources`.
25
+ More information can be found in PrxAuth.
20
26
 
21
- * `prx_authenticated?`: returns whether or not this request includes a valid PrxAuth token.
27
+ * `prx_authenticated?`: returns whether or not this request includes a
28
+ valid PrxAuth token.
29
+
30
+ This will let set up the Rails app to be ready for HTTP requests
31
+ associated with an OpenId access token.
22
32
 
23
33
  ### Configuration
24
34
 
25
- Generally, configuration is not required and the gem aims for great defaults, but you can override some settings if you need to change the default behavior.
35
+ Generally, configuration is not required and the gem aims for great
36
+ defaults, but you can override some settings if you need to change the
37
+ default behavior.
38
+
39
+ If you're using the Rails server-side session flow, you must supply the
40
+ client_id via configuration.
26
41
 
27
- In your rails app, add a file to config/initializers called `prx_auth.rb`:
42
+ In your rails app, add a file to config/initializers called
43
+ `prx_auth.rb`:
28
44
 
29
45
  ```ruby
30
46
  PrxAuth::Rails.configure do |config|
@@ -36,6 +52,9 @@ PrxAuth::Rails.configure do |config|
36
52
  # as .authorized?(:my_great_ns, :foo). Has no impact on unscoped queries.
37
53
  config.namespace = :my_great_ns # default: derived from Rails::Application name.
38
54
  # e.g. class Feeder < Rails::Application => :feeder
55
+
56
+ # Set up the PRX OpenID client_id if using the backend rails sessions flow.
57
+ config.client_id = '<some client id>'
39
58
  end
40
59
  ```
41
60
 
data/Rakefile CHANGED
@@ -1,10 +1,18 @@
1
- require 'bundler/gem_tasks'
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
2
9
  require 'rake'
3
- require 'rake/testtask'
10
+ require "rake/testtask"
4
11
 
5
- Rake::TestTask.new do |t|
12
+ Rake::TestTask.new(:test) do |t|
6
13
  t.libs << 'test'
7
- t.pattern = 'test/**/*test.rb'
14
+ t.pattern = 'test/**/*_test.rb'
15
+ t.verbose = false
8
16
  end
9
17
 
10
18
  task default: :test
@@ -0,0 +1,108 @@
1
+ require 'open-uri'
2
+
3
+ module PrxAuth::Rails
4
+ class SessionsController < ApplicationController
5
+ include PrxAuth::Rails::Engine.routes.url_helpers
6
+
7
+ skip_before_action :authenticate!
8
+
9
+ before_action :set_nonce!, only: :show
10
+
11
+ ID_NONCE_SESSION_KEY = 'id_prx_openid_nonce'.freeze
12
+
13
+ def new
14
+ set_nonce! unless fetch_nonce.present?
15
+
16
+ config = PrxAuth::Rails.configuration
17
+
18
+ id_auth_params = {
19
+ client_id: config.prx_client_id,
20
+ nonce: fetch_nonce,
21
+ response_type: 'id_token token',
22
+ scope: 'openid apps',
23
+ prompt: 'necessary'
24
+ }
25
+
26
+ redirect_to '//' + config.id_host + '/authorize?' + id_auth_params.to_query
27
+ end
28
+
29
+ def show
30
+ end
31
+
32
+ def auth_error
33
+ @auth_error_message = params.require(:error)
34
+ end
35
+
36
+ def create
37
+ jwt_id_claims = id_claims
38
+ jwt_access_claims = access_claims
39
+
40
+ jwt_access_claims['id_token'] = jwt_id_claims.as_json
41
+
42
+ result_path = if valid_nonce?(jwt_id_claims['nonce']) &&
43
+ users_match?(jwt_id_claims, jwt_access_claims)
44
+ sign_in_user(jwt_access_claims)
45
+ after_sign_in_path_for(current_user)
46
+ else
47
+ auth_error_sessions_path(error: 'verification_failed')
48
+ end
49
+ reset_nonce!
50
+
51
+ redirect_to result_path
52
+ end
53
+
54
+ private
55
+
56
+ def after_sign_in_path_for(_)
57
+ return super if defined?(super)
58
+
59
+ "/"
60
+ end
61
+
62
+ def id_claims
63
+ id_token = params.require('id_token')
64
+ validate_token(id_token)
65
+ end
66
+
67
+ def access_claims
68
+ access_token = params.require('access_token')
69
+ validate_token(access_token)
70
+ end
71
+
72
+ def reset_nonce!
73
+ session[ID_NONCE_SESSION_KEY] = nil
74
+ end
75
+
76
+ def set_nonce!
77
+ n = session[ID_NONCE_SESSION_KEY]
78
+ return n if n.present?
79
+
80
+ session[ID_NONCE_SESSION_KEY] = SecureRandom.hex
81
+ end
82
+
83
+ def fetch_nonce
84
+ session[ID_NONCE_SESSION_KEY]
85
+ end
86
+
87
+ def valid_nonce?(nonce)
88
+ return false if fetch_nonce.nil?
89
+
90
+ fetch_nonce == nonce
91
+ end
92
+
93
+ def users_match?(claims1, claims2)
94
+ return false if claims1['sub'].nil? || claims2['sub'].nil?
95
+
96
+ claims1['sub'] == claims2['sub']
97
+ end
98
+
99
+ def validate_token(token)
100
+ id_host = PrxAuth::Rails.configuration.id_host
101
+ prx_auth_cert = Rack::PrxAuth::Certificate.new("https://#{id_host}/api/v1/certs")
102
+ auth_validator = Rack::PrxAuth::AuthValidator.new(token, prx_auth_cert, id_host)
103
+ auth_validator.
104
+ claims.
105
+ with_indifferent_access
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,15 @@
1
+ <div class='main'>
2
+ <section>
3
+ <h3>Not authorized for this application.</h3>
4
+
5
+ <p>Message was: <pre><%= @auth_error_message %></pre>
6
+ <% if @auth_error_message == 'invalid_scope' %>
7
+ Did you add a row in the account_applications table on id.prx?
8
+ <% end %>
9
+ </p>
10
+
11
+ <p>
12
+ <a href="<%= new_sessions_path %>">Try logging in again</a>
13
+ </p>
14
+ </section>
15
+ </div>
@@ -0,0 +1,38 @@
1
+ <div style="display:none;">
2
+ <%= form_for(:sessions, :url => PrxAuth::Rails::Engine.routes.url_helpers.sessions_path) do |f| %>
3
+ <%= hidden_field_tag :access_token, '', id: 'access-token-field' %>
4
+ <%= hidden_field_tag :id_token, '', id: 'id-token-field' %>
5
+ <%= f.submit id: 'sessions-form-submit' %>
6
+ <% end %>
7
+ </div>
8
+
9
+ <script type='application/javascript'>
10
+
11
+ function parseURLFragment() {
12
+ let hashParams = {};
13
+ let e,
14
+ a = /\+/g, // Regex for replacing addition symbol with a space
15
+ r = /([^&;=]+)=?([^&;]*)/g,
16
+ d = function (s) { return decodeURIComponent(s.replace(a, " ")); },
17
+ q = window.location.hash.substring(1);
18
+
19
+ while (e = r.exec(q))
20
+ hashParams[d(e[1])] = d(e[2]);
21
+
22
+ return hashParams;
23
+ }
24
+
25
+ window.addEventListener("load", () => {
26
+ var idToken = document.querySelector("#id-token-field");
27
+ var accessToken = document.querySelector("#access-token-field");
28
+ var submit = document.querySelector("input#sessions-form-submit[type=submit]");
29
+
30
+ var hashParams = parseURLFragment();
31
+
32
+ accessToken.value = hashParams['access_token'];
33
+ idToken.value = hashParams['id_token'];
34
+
35
+ submit.click();
36
+ });
37
+
38
+ </script>
@@ -0,0 +1,7 @@
1
+ PrxAuth::Rails::Engine.routes.draw do
2
+ scope module: 'prx_auth/rails' do
3
+ resource 'sessions', except: :index, :defaults => { :format => 'html' } do
4
+ get 'auth_error', to: 'sessions#auth_error'
5
+ end
6
+ end
7
+ end
@@ -1,6 +1,7 @@
1
1
  require "prx_auth/rails/version"
2
2
  require "prx_auth/rails/configuration"
3
3
  require "prx_auth/rails/railtie" if defined?(Rails)
4
+ require "prx_auth/rails/engine" if defined?(Rails)
4
5
 
5
6
  module PrxAuth
6
7
  module Rails
@@ -1,17 +1,28 @@
1
1
  class PrxAuth::Rails::Configuration
2
- attr_accessor :install_middleware, :namespace
2
+ attr_accessor :install_middleware,
3
+ :namespace,
4
+ :prx_client_id,
5
+ :id_host
6
+
3
7
 
4
8
  def initialize
5
9
  @install_middleware = true
6
10
  if defined?(::Rails)
7
11
  klass = ::Rails.application.class
8
- klass_name = if klass.parent_name.present?
9
- klass.parent_name
12
+ parent_name = if ::Rails::VERSION::MAJOR >= 6
13
+ klass.module_parent_name
14
+ else
15
+ klass.parent_name
16
+ end
17
+ klass_name = if parent_name.present?
18
+ parent_name
10
19
  else
11
20
  klass.name
12
21
  end
13
22
 
14
23
  @namespace = klass_name.underscore.intern
24
+ @prx_client_id = nil
25
+ @id_host = nil
15
26
  end
16
27
  end
17
- end
28
+ end
@@ -0,0 +1,5 @@
1
+ module PrxAuth
2
+ module Rails
3
+ class Engine < ::Rails::Engine; end
4
+ end
5
+ end
@@ -4,16 +4,41 @@ module PrxAuth
4
4
  module Rails
5
5
  module Controller
6
6
  def prx_auth_token
7
+ rack_auth_token = env_prx_auth_token
8
+ return rack_auth_token if rack_auth_token.present?
9
+
10
+ session['prx.auth'] && Rack::PrxAuth::TokenData.new(session['prx.auth'])
11
+ end
12
+
13
+ def prx_authenticated?
14
+ !!prx_auth_token
15
+ end
16
+
17
+ def authenticate!
18
+ return true if current_user.present?
19
+
20
+ redirect_to PrxAuth::Rails::Engine.routes.url_helpers.new_sessions_path
21
+ end
22
+
23
+ def current_user
24
+ return if prx_auth_token.nil?
25
+
26
+ PrxAuth::Rails::Token.new(prx_auth_token)
27
+ end
28
+
29
+ def sign_in_user(token)
30
+ session['prx.auth'] = token
31
+ end
32
+
33
+ private
34
+
35
+ def env_prx_auth_token
7
36
  if !defined? @_prx_auth_token
8
37
  @_prx_auth_token = request.env['prx.auth'] && PrxAuth::Rails::Token.new(request.env['prx.auth'])
9
38
  else
10
39
  @_prx_auth_token
11
40
  end
12
41
  end
13
-
14
- def prx_authenticated?
15
- !!prx_auth_token
16
- end
17
42
  end
18
43
  end
19
44
  end
@@ -28,4 +28,8 @@ class PrxAuth::Rails::Token
28
28
  def user_id
29
29
  @token_data.user_id
30
30
  end
31
- end
31
+
32
+ def authorized_account_ids(scope)
33
+ @token_data.authorized_account_ids(scope)
34
+ end
35
+ end
@@ -1,5 +1,5 @@
1
1
  module PrxAuth
2
2
  module Rails
3
- VERSION = "1.2.0"
3
+ VERSION = "1.3.0"
4
4
  end
5
5
  end
@@ -29,7 +29,9 @@ Gem::Specification.new do |spec|
29
29
  spec.add_development_dependency 'coveralls', '~> 0'
30
30
  spec.add_development_dependency 'guard'
31
31
  spec.add_development_dependency 'guard-minitest'
32
- spec.add_development_dependency 'rails'
32
+ spec.add_development_dependency "rails", "~> 6.1.0"
33
+ spec.add_development_dependency 'pry'
34
+ spec.add_development_dependency 'sqlite3'
33
35
 
34
36
 
35
37
 
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require_relative "config/application"
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,2 @@
1
+ //= link_tree ../images
2
+ //= link_directory ../stylesheets .css
File without changes
@@ -0,0 +1,15 @@
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 any plugin's vendor/assets/stylesheets directory 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 bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Channel < ActionCable::Channel::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Connection < ActionCable::Connection::Base
3
+ end
4
+ end