prx_auth-rails 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/README.md +25 -6
- data/Rakefile +12 -4
- data/app/controllers/prx_auth/rails/sessions_controller.rb +108 -0
- data/app/views/prx_auth/rails/sessions/auth_error.html.erb +15 -0
- data/app/views/prx_auth/rails/sessions/show.html.erb +38 -0
- data/config/routes.rb +7 -0
- data/lib/prx_auth/rails.rb +1 -0
- data/lib/prx_auth/rails/configuration.rb +15 -4
- data/lib/prx_auth/rails/engine.rb +5 -0
- data/lib/prx_auth/rails/ext/controller.rb +29 -4
- data/lib/prx_auth/rails/token.rb +5 -1
- data/lib/prx_auth/rails/version.rb +1 -1
- data/prx_auth-rails.gemspec +3 -1
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/config/manifest.js +2 -0
- data/test/dummy/app/assets/images/.keep +0 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/channels/application_cable/channel.rb +4 -0
- data/test/dummy/app/channels/application_cable/connection.rb +4 -0
- data/test/dummy/app/controllers/application_controller.rb +8 -0
- data/test/dummy/app/controllers/concerns/.keep +0 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/javascript/packs/application.js +15 -0
- data/test/dummy/app/jobs/application_job.rb +7 -0
- data/test/dummy/app/mailers/application_mailer.rb +4 -0
- data/test/dummy/app/models/application_record.rb +3 -0
- data/test/dummy/app/models/concerns/.keep +0 -0
- data/test/dummy/app/views/layouts/application.html.erb +15 -0
- data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/test/dummy/bin/rails +5 -0
- data/test/dummy/bin/rake +5 -0
- data/test/dummy/bin/setup +33 -0
- data/test/dummy/bin/spring +10 -0
- data/test/dummy/config.ru +6 -0
- data/test/dummy/config/application.rb +22 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/cable.yml +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +76 -0
- data/test/dummy/config/environments/production.rb +120 -0
- data/test/dummy/config/environments/test.rb +60 -0
- data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
- data/test/dummy/config/initializers/assets.rb +12 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +8 -0
- data/test/dummy/config/initializers/content_security_policy.rb +28 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +6 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/permissions_policy.rb +11 -0
- data/test/dummy/config/initializers/prx_auth.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +33 -0
- data/test/dummy/config/puma.rb +43 -0
- data/test/dummy/config/routes.rb +3 -0
- data/test/dummy/config/spring.rb +6 -0
- data/test/dummy/config/storage.yml +34 -0
- data/test/dummy/lib/assets/.keep +0 -0
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/test/dummy/public/apple-touch-icon.png +0 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/storage/.keep +0 -0
- data/test/prx_auth/rails/configuration_test.rb +18 -12
- data/test/prx_auth/rails/sessions_controller_test.rb +94 -0
- data/test/prx_auth/rails/token_test.rb +1 -1
- data/test/test_helper.rb +20 -9
- metadata +153 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3405e4e72d2c39585111bef4fca339a73ce11ec86a2c288f5c82d8934c0620fe
|
4
|
+
data.tar.gz: 3450063f4c4fdae2464f755222fafee08c627eda3aa8fee1d267db1474db58de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: edf33f5cf4bc105818bb069554506f0b2d9ef5b8bb18cd1602b2ceb6384991804b5b3268c6bd5c519c08e8503df51c132a9bec045f13995c1d55088194fff489
|
7
|
+
data.tar.gz: 4aa62706ee892c2335756e2c3ae61171b77acc69bfe0ec06433449726f8e884cee4af2031e55e418c6780e9aedc8bfb1c78359c072c089389422a2d4aa15c95b
|
data/.gitignore
CHANGED
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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/**/*
|
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>
|
data/config/routes.rb
ADDED
data/lib/prx_auth/rails.rb
CHANGED
@@ -1,17 +1,28 @@
|
|
1
1
|
class PrxAuth::Rails::Configuration
|
2
|
-
attr_accessor :install_middleware,
|
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
|
-
|
9
|
-
|
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
|
@@ -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
|
data/lib/prx_auth/rails/token.rb
CHANGED
data/prx_auth-rails.gemspec
CHANGED
@@ -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
|
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
|
|
data/test/dummy/Rakefile
ADDED
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
|
+
*/
|