prx_auth-rails 4.2.1 → 5.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1852c166da48f2df9481fa8d2343e8e5e378875cd8ceda9b1bb459a78ee91e3a
4
- data.tar.gz: b8cdc9d9ef469dbcb7b25ff606842763c3008fa8d33ed9291ad1729c821e6427
3
+ metadata.gz: bf94b7a4117fd51ed8b81e97822613f25ef10d9cd634b2d5d976809c2e50c281
4
+ data.tar.gz: 4830822f96f9526bdf828b611ed1d4920a4919f27feed31ac259b51c32777516
5
5
  SHA512:
6
- metadata.gz: cfe2defaa2d06e944e4926a984140d47c1e7687976843d0c93f44133f6bea5fd7700317128dad8d150fb1cc424ace31700a528d1a24dc1be6b7fec7f8a698c11
7
- data.tar.gz: b72915c790ec4d918f388b626704a5996e9afa0c83a52b6d2a4c1d01f217a07c22fad448820b8fc80145a8ba04727e75080fce3a1266f45b8fa6d722e704c9a5
6
+ metadata.gz: 8cdfcac52bffd86c335598f97fe76d93acceba591d4b709493374f7776eaf2eb7c10c1f4c57de17e0dbb6c40246fbb84c085972bd2d1e9800aacf73b1da0017a
7
+ data.tar.gz: e28b6dc7e0255a764ca7eb9469b7f28d8727f9804fd6a750e9905c2fe11799935665d6b67bee441c8bb2081bb3c5f4f58e642336e634d55f74d9974ff4d0fd61
@@ -17,7 +17,7 @@ jobs:
17
17
  - name: Install Ruby and gems
18
18
  uses: ruby/setup-ruby@v1
19
19
  with:
20
- ruby-version: '3.0'
20
+ ruby-version: '3.4'
21
21
  bundler-cache: true
22
22
  - name: Lint Ruby files
23
23
  run: bundle exec standardrb
@@ -2,34 +2,31 @@
2
2
 
3
3
  module PrxAuth::Rails
4
4
  class SessionsController < ApplicationController
5
- include PrxAuth::Rails::Engine.routes.url_helpers
6
-
7
- skip_before_action :authenticate!, raise: false
5
+ skip_before_action :set_after_sign_in_path, :authenticate!, raise: false
8
6
 
9
7
  before_action :set_nonce!, only: [:new, :show]
10
- before_action :set_after_sign_in_path
11
8
 
12
9
  ID_NONCE_SESSION_KEY = "id_prx_openid_nonce"
13
- DEFAULT_SCOPES = "openid apps"
10
+ WILDCARD_SESSION_KEY = "prx.auth.wildcard"
11
+ DEFAULT_SCOPES = "openid"
14
12
 
15
13
  def new
16
14
  config = PrxAuth::Rails.configuration
17
15
 
18
- scope =
19
- if config.prx_scope.present?
20
- "#{DEFAULT_SCOPES} #{config.prx_scope}"
21
- else
22
- DEFAULT_SCOPES
23
- end
24
-
25
16
  id_auth_params = {
26
17
  client_id: config.prx_client_id,
27
18
  nonce: fetch_nonce,
28
19
  response_type: "id_token token",
29
- scope: scope,
20
+ scope: "#{DEFAULT_SCOPES} #{config.prx_scope}".strip,
30
21
  prompt: "necessary"
31
22
  }
32
23
 
24
+ if session[WILDCARD_SESSION_KEY]
25
+ id_auth_params[:account] = "*"
26
+ # TODO: what if they need more than _just_ read-private?
27
+ id_auth_params[:scope] = "#{DEFAULT_SCOPES} read-private" if session[WILDCARD_SESSION_KEY] == "readonly"
28
+ end
29
+
33
30
  url = "//" + config.id_host + "/authorize?" + id_auth_params.to_query
34
31
 
35
32
  redirect_to url, allow_other_host: true
@@ -38,9 +35,7 @@ module PrxAuth::Rails
38
35
  def show
39
36
  end
40
37
 
41
- def destroy
42
- sign_out_user
43
- redirect_to after_sign_out_path
38
+ def access_error
44
39
  end
45
40
 
46
41
  def auth_error
@@ -55,10 +50,29 @@ module PrxAuth::Rails
55
50
  sign_in_user(access_token)
56
51
  redirect_to after_sign_in_path_for(current_user)
57
52
  else
53
+ session.delete(WILDCARD_SESSION_KEY)
58
54
  redirect_to auth_error_sessions_path(error: params[:error] || "unknown_error")
59
55
  end
60
56
  end
61
57
 
58
+ def destroy
59
+ sign_out_user
60
+ redirect_to after_sign_out_path, allow_other_host: true
61
+ end
62
+
63
+ def logout
64
+ sign_out_user
65
+ redirect_to "//#{id_host}/session/sign_out", allow_other_host: true
66
+ end
67
+
68
+ def refresh
69
+ wildcard = params[:wildcard] if current_user_admin?
70
+ sign_out_user
71
+ session[WILDCARD_SESSION_KEY] = wildcard
72
+
73
+ redirect_to new_sessions_path
74
+ end
75
+
62
76
  private
63
77
 
64
78
  def after_sign_in_path_for(_)
@@ -0,0 +1,27 @@
1
+ module PrxAuth::Rails
2
+ module SessionsHelper
3
+ def current_user_app?(name)
4
+ current_user && current_user_app(name).present?
5
+ end
6
+
7
+ def current_user_app(name)
8
+ current_user_apps.find { |key, url| key.downcase.include?(name) }&.last
9
+ end
10
+
11
+ def current_user_id_profile
12
+ "https://#{PrxAuth::Rails.configuration.id_host}/profile"
13
+ end
14
+
15
+ def current_user_id_accounts
16
+ "https://#{PrxAuth::Rails.configuration.id_host}/accounts"
17
+ end
18
+
19
+ def current_user_image?
20
+ current_user && current_user_image.present?
21
+ end
22
+
23
+ def current_user_image
24
+ current_user_info["image_href"]
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,20 @@
1
+ <div class="row">
2
+
3
+ <div class="col-lg-3"></div>
4
+
5
+ <div class="col-lg-6 my-5">
6
+ <div class="card">
7
+ <div class="card-body my-2">
8
+ <h1 class="card-title text-center">Not Authorized</h1>
9
+ <p class="card-text text-center">
10
+ <%= link_to "Your accounts", current_user_id_accounts %> are not authorized to use this PRX application.
11
+ <br/>
12
+ If you believe this to be in error, please <a href="https://help.prx.org/hc/en-us">contact PRX support.</a>
13
+ </p>
14
+ </div>
15
+ </div>
16
+ </div>
17
+
18
+ <div class="col-lg-3"></div>
19
+
20
+ </div>
@@ -1,8 +1,20 @@
1
- <div class='main'>
2
- <section>
3
- <h3>Not authorized for this application.</h3>
4
- <p>
5
- <a href="<%= new_sessions_path %>">Try logging in again</a>
6
- </p>
7
- </section>
1
+ <div class="row">
2
+
3
+ <div class="col-lg-3"></div>
4
+
5
+ <div class="col-lg-6 my-5">
6
+ <div class="card">
7
+ <div class="card-body my-2">
8
+ <h1 class="card-title text-center"><%= @auth_error_message&.titleize || "Unknown" %> Error</h1>
9
+ <p class="card-text text-center">
10
+ Something went terribly wrong - please <%= link_to "try logging in again", new_sessions_path %>.
11
+ <br/>
12
+ If the problem persists, <a href="https://help.prx.org/hc/en-us">contact PRX support.</a>
13
+ </p>
14
+ </div>
15
+ </div>
16
+ </div>
17
+
18
+ <div class="col-lg-3"></div>
19
+
8
20
  </div>
@@ -1,5 +1,5 @@
1
1
  <div style="display:none;">
2
- <%= form_for(:sessions, :url => PrxAuth::Rails::Engine.routes.url_helpers.sessions_path) do |f| %>
2
+ <%= form_for(:sessions, url: sessions_path) do |f| %>
3
3
  <%= hidden_field_tag :access_token, '', id: 'access-token-field' %>
4
4
  <%= hidden_field_tag :id_token, '', id: 'id-token-field' %>
5
5
  <%= hidden_field_tag :error, '', id: 'error-field' %>
@@ -1 +1,3 @@
1
- Rails.application.config.assets.precompile << %w[prx_auth-rails_manifest.js]
1
+ if defined?(Rails.application.config.assets)
2
+ Rails.application.config.assets.precompile << %w[prx_auth-rails_manifest.js]
3
+ end
data/config/routes.rb CHANGED
@@ -1,7 +1,10 @@
1
- PrxAuth::Rails::Engine.routes.draw do
2
- scope module: "prx_auth/rails" do
3
- resource "sessions", except: :index, defaults: {format: "html"} do
1
+ Rails.application.routes.draw do
2
+ scope module: "prx_auth/rails", path: "auth" do
3
+ resource "sessions", except: %w[edit update] do
4
+ get "access_error", to: "sessions#access_error"
4
5
  get "auth_error", to: "sessions#auth_error"
6
+ get "logout", to: "sessions#logout"
7
+ get "refresh", to: "sessions#refresh"
5
8
  end
6
9
  end
7
10
  end
@@ -4,6 +4,7 @@ module PrxAuth
4
4
  config.to_prepare do
5
5
  ::ApplicationController.helper_method [
6
6
  :current_user, :prx_jwt,
7
+ :current_user_access?, :current_user_admin?, :current_user_wildcard?,
7
8
  :current_user_info, :current_user_name, :current_user_apps,
8
9
  :account_name_for, :account_for, :accounts_for
9
10
  ]
@@ -0,0 +1,51 @@
1
+ require "open-uri"
2
+
3
+ module PrxAuth
4
+ module Rails
5
+ module AccountInfo
6
+ PRX_ACCOUNT_MAPPING_SESSION_KEY = "prx.auth.account.mapping".freeze
7
+
8
+ def account_name_for(account_id)
9
+ account_for(account_id).try(:[], "name")
10
+ end
11
+
12
+ def account_for(account_id)
13
+ lookup_accounts([account_id]).first
14
+ end
15
+
16
+ def accounts_for(account_ids)
17
+ lookup_accounts(account_ids)
18
+ end
19
+
20
+ private
21
+
22
+ def lookup_accounts(ids)
23
+ return fetch_accounts(ids) unless defined?(session)
24
+
25
+ session[PRX_ACCOUNT_MAPPING_SESSION_KEY] ||= {}
26
+
27
+ # fetch any accounts we don't have yet
28
+ missing = ids - session[PRX_ACCOUNT_MAPPING_SESSION_KEY].keys
29
+ if missing.present?
30
+ fetch_accounts(missing).each do |account|
31
+ minimal = account.slice("name", "type")
32
+ session[PRX_ACCOUNT_MAPPING_SESSION_KEY][account["id"]] = minimal
33
+ end
34
+ end
35
+
36
+ ids.map { |id| session[PRX_ACCOUNT_MAPPING_SESSION_KEY][id] }
37
+ end
38
+
39
+ def fetch_accounts(ids)
40
+ ids_param = ids.map(&:to_s).join(",")
41
+ path = "/api/v1/accounts?account_ids=#{ids_param}"
42
+ url = "https://#{PrxAuth::Rails.configuration.id_host}#{path}"
43
+
44
+ options = {}
45
+ options[:ssl_verify_mode] = OpenSSL::SSL::VERIFY_NONE if ::Rails.env.development?
46
+ resp = JSON.parse(URI.open(url, options).read) # standard:disable Security/Open
47
+ resp.try(:[], "_embedded").try(:[], "prx:items") || []
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,62 @@
1
+ require "open-uri"
2
+
3
+ module PrxAuth
4
+ module Rails
5
+ module UserInfo
6
+ PRX_USER_INFO_SESSION_KEY = "prx.auth.info".freeze
7
+ PRX_ADMIN_SCOPE = "prxadmin".freeze
8
+
9
+ def current_user
10
+ prx_auth_token
11
+ end
12
+
13
+ def current_user_access?(scope = :read_private)
14
+ current_user&.globally_authorized?(scope) || current_user&.authorized_account_ids(scope)&.any?
15
+ end
16
+
17
+ def current_user_info
18
+ session[PRX_USER_INFO_SESSION_KEY] ||= begin
19
+ info = fetch_userinfo
20
+ info.slice("name", "preferred_username", "email", "image_href", "apps")
21
+ end
22
+ end
23
+
24
+ def current_user_name
25
+ current_user_info["name"] || current_user_info["preferred_username"] || current_user_info["email"]
26
+ end
27
+
28
+ def current_user_apps
29
+ apps = (current_user_info.try(:[], "apps") || []).map do |name, url|
30
+ label = name.sub(/^https?:\/\//, "").sub(/\..+/, "").capitalize
31
+ ["PRX #{label}", url]
32
+ end
33
+
34
+ # only return entire list in development
35
+ if ::Rails.env.production? || ::Rails.env.staging?
36
+ apps.to_h.select { |k, v| v.match?(/\.(org|tech)/) }
37
+ else
38
+ apps.to_h
39
+ end
40
+ end
41
+
42
+ def current_user_admin?
43
+ current_user&.scopes&.include?(PRX_ADMIN_SCOPE)
44
+ end
45
+
46
+ def current_user_wildcard?
47
+ current_user&.globally_authorized?(:read_private)
48
+ end
49
+
50
+ private
51
+
52
+ def fetch_userinfo
53
+ path = "/userinfo?scope=apps+email+profile"
54
+ url = "https://#{PrxAuth::Rails.configuration.id_host}#{path}"
55
+ options = {}
56
+ options[:ssl_verify_mode] = OpenSSL::SSL::VERIFY_NONE if ::Rails.env.development?
57
+ options["Authorization"] = "Bearer #{prx_jwt}"
58
+ JSON.parse(URI.open(url, options).read) # standard:disable Security/Open
59
+ end
60
+ end
61
+ end
62
+ end
@@ -1,19 +1,26 @@
1
+ require "active_support/concern"
1
2
  require "prx_auth/rails/token"
2
- require "open-uri"
3
+ require "prx_auth/rails/ext/controller/account_info"
4
+ require "prx_auth/rails/ext/controller/user_info"
3
5
 
4
6
  module PrxAuth
5
7
  module Rails
6
8
  module Controller
9
+ extend ActiveSupport::Concern
10
+ include PrxAuth::Rails::AccountInfo
11
+ include PrxAuth::Rails::UserInfo
12
+
7
13
  class SessionTokenExpiredError < RuntimeError; end
8
14
 
9
15
  PRX_AUTH_ENV_KEY = "prx.auth".freeze
10
16
  PRX_JWT_SESSION_KEY = "prx.auth.jwt".freeze
11
- # subtracted from the JWT ttl
12
- PRX_JWT_REFRESH_TTL = 300
13
- PRX_ACCOUNT_MAPPING_SESSION_KEY = "prx.auth.account.mapping".freeze
14
- PRX_USER_INFO_SESSION_KEY = "prx.auth.info".freeze
17
+ PRX_JWT_REFRESH_TTL = 60
15
18
  PRX_REFRESH_BACK_KEY = "prx.auth.back".freeze
16
19
 
20
+ included do
21
+ before_action :set_after_sign_in_path, :authenticate!
22
+ end
23
+
17
24
  def prx_auth_token
18
25
  env_token || session_token
19
26
  rescue SessionTokenExpiredError
@@ -24,8 +31,6 @@ module PrxAuth
24
31
  end
25
32
 
26
33
  def set_after_sign_in_path
27
- return if instance_of?(PrxAuth::Rails::SessionsController)
28
-
29
34
  session[PRX_REFRESH_BACK_KEY] = request.fullpath
30
35
  end
31
36
 
@@ -38,41 +43,23 @@ module PrxAuth
38
43
  end
39
44
 
40
45
  def authenticate!
41
- return true if current_user.present?
42
-
43
- redirect_to PrxAuth::Rails::Engine.routes.url_helpers.new_sessions_path
44
- end
45
-
46
- def prx_auth_needs_refresh?(jwt_ttl)
47
- request.get? && jwt_ttl < PRX_JWT_REFRESH_TTL
48
- end
49
-
50
- def current_user
51
- prx_auth_token
52
- end
53
-
54
- def current_user_info
55
- session[PRX_USER_INFO_SESSION_KEY] ||= begin
56
- info = fetch_userinfo
57
- info.slice("name", "preferred_username", "email", "image_href", "apps")
46
+ if !current_user
47
+ redirect_to new_sessions_path
48
+ elsif !current_user_access?
49
+ redirect_to access_error_sessions_path
50
+ else
51
+ true
58
52
  end
59
53
  end
60
54
 
61
- def current_user_name
62
- current_user_info["name"] || current_user_info["preferred_username"] || current_user_info["email"]
63
- end
64
-
65
- def current_user_apps
66
- apps = (current_user_info.try(:[], "apps") || []).map do |name, url|
67
- label = name.sub(/^https?:\/\//, "").sub(/\..+/, "").capitalize
68
- ["PRX #{label}", url]
69
- end
70
-
71
- # only return entire list in development
72
- if ::Rails.env.production? || ::Rails.env.staging?
73
- apps.to_h.select { |k, v| v.match?(/\.(org|tech)/) }
55
+ # trigger refresh on a non-turbo GET request, if possible
56
+ def prx_auth_needs_refresh?(jwt_ttl)
57
+ if jwt_ttl < 0
58
+ true
59
+ elsif jwt_ttl < PRX_JWT_REFRESH_TTL
60
+ request.get? && !request.headers["Turbo-Frame"]
74
61
  else
75
- apps.to_h
62
+ false
76
63
  end
77
64
  end
78
65
 
@@ -89,53 +76,8 @@ module PrxAuth
89
76
  reset_session
90
77
  end
91
78
 
92
- def account_name_for(account_id)
93
- account_for(account_id).try(:[], "name")
94
- end
95
-
96
- def account_for(account_id)
97
- lookup_accounts([account_id]).first
98
- end
99
-
100
- def accounts_for(account_ids)
101
- lookup_accounts(account_ids)
102
- end
103
-
104
79
  private
105
80
 
106
- def lookup_accounts(ids)
107
- session[PRX_ACCOUNT_MAPPING_SESSION_KEY] ||= {}
108
-
109
- # fetch any accounts we don't have yet
110
- missing = ids - session[PRX_ACCOUNT_MAPPING_SESSION_KEY].keys
111
- if missing.present?
112
- fetch_accounts(missing).each do |account|
113
- minimal = account.slice("name", "type")
114
- session[PRX_ACCOUNT_MAPPING_SESSION_KEY][account["id"]] = minimal
115
- end
116
- end
117
-
118
- ids.map { |id| session[PRX_ACCOUNT_MAPPING_SESSION_KEY][id] }
119
- end
120
-
121
- def fetch_accounts(ids)
122
- ids_param = ids.map(&:to_s).join(",")
123
- resp = fetch("/api/v1/accounts?account_ids=#{ids_param}")
124
- resp.try(:[], "_embedded").try(:[], "prx:items") || []
125
- end
126
-
127
- def fetch_userinfo
128
- fetch("/userinfo?scope=apps+email+profile", prx_jwt)
129
- end
130
-
131
- def fetch(path, token = nil)
132
- url = "https://#{PrxAuth::Rails.configuration.id_host}#{path}"
133
- options = {}
134
- options[:ssl_verify_mode] = OpenSSL::SSL::VERIFY_NONE if ::Rails.env.development?
135
- options["Authorization"] = "Bearer #{token}" if token
136
- JSON.parse(URI.open(url, options).read) # standard:disable Security/Open
137
- end
138
-
139
81
  # token from data set by prx_auth rack middleware
140
82
  def env_token
141
83
  @env_token_data ||= if request.env[PRX_AUTH_ENV_KEY]
@@ -2,6 +2,6 @@
2
2
 
3
3
  module PrxAuth
4
4
  module Rails
5
- VERSION = "4.2.1"
5
+ VERSION = "5.0.0"
6
6
  end
7
7
  end
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency "guard"
27
27
  spec.add_development_dependency "guard-minitest"
28
28
  spec.add_development_dependency "m", "~> 1.5"
29
- spec.add_development_dependency "rails", "~> 6.1.0"
29
+ spec.add_development_dependency "rails", "~> 8.0.1"
30
30
  spec.add_development_dependency "pry"
31
31
  spec.add_development_dependency "sqlite3"
32
32
  spec.add_development_dependency "webmock"
@@ -1,6 +1,4 @@
1
1
  class ApplicationController < ActionController::Base
2
- before_action :authenticate!
3
-
4
2
  def index
5
3
  end
6
4
 
@@ -1,7 +1,7 @@
1
1
  # Be sure to restart your server when you modify this file.
2
2
 
3
3
  # Version of your assets, change this if you want to expire all your assets.
4
- Rails.application.config.assets.version = "1.0"
4
+ # Rails.application.config.assets.version = "1.0"
5
5
 
6
6
  # Add additional assets to the asset load path.
7
7
  # Rails.application.config.assets.paths << Emoji.images_path
@@ -1,5 +1,4 @@
1
1
  Rails.application.routes.draw do
2
2
  get "index", to: "application#index"
3
3
  put "index", to: "application#index"
4
- mount PrxAuth::Rails::Engine => "/prx_auth-rails"
5
4
  end
@@ -7,16 +7,19 @@ module PrxAuth::Rails::Ext
7
7
  @jwt_session_key = ApplicationController::PRX_JWT_SESSION_KEY
8
8
  @user_info_key = ApplicationController::PRX_USER_INFO_SESSION_KEY
9
9
  @account_mapping_key = ApplicationController::PRX_ACCOUNT_MAPPING_SESSION_KEY
10
- @stub_claims = {"iat" => Time.now.to_i, "exp" => Time.now.to_i + 3600}
10
+ @stub_aur = {"1234" => "test_app:read-private"}
11
+ @stub_claims = {"iat" => Time.now.to_i, "exp" => Time.now.to_i + 3600, "aur" => @stub_aur}
11
12
  end
12
13
 
13
14
  # stub auth and init controller+session by getting a page
14
15
  def with_stubbed_auth(jwt)
15
16
  session[@jwt_session_key] = "some-jwt"
16
- @controller.stub(:prx_auth_needs_refresh?, false) do
17
- get :index
18
- assert_equal response.code, "200"
19
- yield
17
+ JSON::JWT.stub(:decode, @stub_claims) do
18
+ @controller.stub(:prx_auth_needs_refresh?, false) do
19
+ get :index
20
+ assert_equal response.code, "200"
21
+ yield
22
+ end
20
23
  end
21
24
  end
22
25
 
@@ -26,6 +29,16 @@ module PrxAuth::Rails::Ext
26
29
  assert response.headers["Location"].ends_with?("/sessions/new")
27
30
  end
28
31
 
32
+ test "redirects unless you have read-private in this namespace" do
33
+ session[@jwt_session_key] = "some-jwt"
34
+ @stub_claims["aur"]["1234"] = "other_app:read-private"
35
+ JSON::JWT.stub(:decode, @stub_claims) do
36
+ get :index
37
+ assert_equal response.code, "302"
38
+ assert_includes response.location, "auth/sessions/access_error"
39
+ end
40
+ end
41
+
29
42
  test "uses a valid session token" do
30
43
  session[@jwt_session_key] = "some-jwt"
31
44
  JSON::JWT.stub(:decode, @stub_claims) do
@@ -3,9 +3,10 @@ require "test_helper"
3
3
  module PrxAuth::Rails
4
4
  class SessionsControllerTest < ActionController::TestCase
5
5
  setup do
6
- @routes = PrxAuth::Rails::Engine.routes
6
+ @jwt_key = SessionsController::PRX_JWT_SESSION_KEY
7
7
  @nonce_session_key = SessionsController::ID_NONCE_SESSION_KEY
8
8
  @refresh_back_key = SessionsController::PRX_REFRESH_BACK_KEY
9
+ @wildcard_key = SessionsController::WILDCARD_SESSION_KEY
9
10
  @token_params = {id_token: "idtok", access_token: "accesstok"}
10
11
  @stub_claims = {"nonce" => "123", "sub" => "1"}
11
12
  @stub_token = PrxAuth::Rails::Token.new(Rack::PrxAuth::TokenData.new)
@@ -31,13 +32,30 @@ module PrxAuth::Rails
31
32
  assert nonce1 == nonce2
32
33
  end
33
34
 
35
+ test "new includes scopes and accounts" do
36
+ get :new
37
+ assert response.code == "302"
38
+ assert_includes response.location, "scope=openid"
39
+
40
+ PrxAuth::Rails.configuration.prx_scope = "feeder:*"
41
+ get :new
42
+ assert response.code == "302"
43
+ assert_includes response.location, "scope=openid+feeder%3A%2A"
44
+
45
+ session[@wildcard_key] = "true"
46
+ get :new
47
+ assert response.code == "302"
48
+ assert_includes response.location, "scope=openid"
49
+ assert_includes response.location, "account=%2A"
50
+ end
51
+
34
52
  test "create should validate a token and set the session variable" do
35
- session[SessionsController::PRX_JWT_SESSION_KEY] = nil
53
+ session[@jwt_key] = nil
36
54
  @controller.stub(:validate_token, @stub_claims) do
37
55
  @controller.stub(:session_token, @stub_token) do
38
56
  session[@nonce_session_key] = "123"
39
57
  post :create, params: @token_params, format: :json
40
- assert session[SessionsController::PRX_JWT_SESSION_KEY] == "accesstok"
58
+ assert session[@jwt_key] == "accesstok"
41
59
  end
42
60
  end
43
61
  end
@@ -58,7 +76,7 @@ module PrxAuth::Rails
58
76
 
59
77
  assert session[@nonce_session_key].nil?
60
78
  assert response.code == "302"
61
- assert response.body.match?(/after-sign-in-path/)
79
+ assert response.headers["Location"].match?(/after-sign-in-path/)
62
80
  end
63
81
  end
64
82
  end
@@ -85,14 +103,14 @@ module PrxAuth::Rails
85
103
  session[@nonce_session_key] = "nonce-does-not-match"
86
104
  post :create, params: @token_params, format: :json
87
105
  assert response.code == "302"
88
- assert response.body.match(/auth_error\?error=verification_failed/)
106
+ assert response.headers["Location"].match(/auth_error\?error=verification_failed/)
89
107
  end
90
108
  end
91
109
 
92
110
  test "auth_error should return a formatted error message to the user" do
93
- get :auth_error, params: {error: "error_message"}
111
+ get :auth_error, params: {error: "bad_things"}
94
112
  assert response.code == "200"
95
- assert response.body.match?(/Not authorized/)
113
+ assert response.body.match?(/Bad Things Error/)
96
114
  end
97
115
 
98
116
  test "auth_error should expect the error param" do
@@ -109,15 +127,42 @@ module PrxAuth::Rails
109
127
  post :create, params: @token_params, format: :json
110
128
 
111
129
  assert response.code == "302"
112
- assert response.body.match?(/error=verification_failed/)
130
+ assert response.headers["Location"].match?(/error=verification_failed/)
113
131
  end
114
132
  end
115
133
  end
116
134
 
117
135
  test "should clear the user token on sign out" do
118
- session[SessionsController::PRX_JWT_SESSION_KEY] = "some-token"
136
+ session[@jwt_key] = "some-token"
119
137
  post :destroy
120
- assert session[SessionsController::PRX_JWT_SESSION_KEY].nil?
138
+ assert session[@jwt_key].nil?
139
+ end
140
+
141
+ test "should clear the user token and send to ID on logout" do
142
+ session[@jwt_key] = "some-token"
143
+ get :logout
144
+ assert session[@jwt_key].nil?
145
+ assert response.code == "302"
146
+ assert_equal "//id.prx.test/session/sign_out", response.location
147
+ end
148
+
149
+ test "refreshes auth" do
150
+ session[@jwt_key] = "some-token"
151
+ get :refresh
152
+ assert session[@jwt_key].nil?
153
+ assert response.code == "302"
154
+ assert_includes response.location, new_sessions_path
155
+ end
156
+
157
+ test "refreshes wildcard auth for admins" do
158
+ @controller.stub(:current_user_admin?, true) do
159
+ session[@jwt_key] = "some-token"
160
+ get :refresh, params: {wildcard: true}
161
+ assert session[@jwt_key].nil?
162
+ assert session[@wildcard_key] = "true"
163
+ assert response.code == "302"
164
+ assert_includes response.location, new_sessions_path
165
+ end
121
166
  end
122
167
  end
123
168
  end
@@ -0,0 +1,71 @@
1
+ require "test_helper"
2
+
3
+ class TestHelper
4
+ attr_accessor :current_user, :current_user_apps, :current_user_info
5
+ include PrxAuth::Rails::SessionsHelper
6
+ end
7
+
8
+ describe PrxAuth::Rails::SessionsHelper do
9
+ let(:helper) { TestHelper.new }
10
+
11
+ describe "#current_user_app?" do
12
+ it "makes sure there is a current user" do
13
+ helper.current_user = nil
14
+ refute helper.current_user_app?("foo")
15
+ refute helper.current_user_app?("bar")
16
+ end
17
+
18
+ it "determines if you have an app or not" do
19
+ helper.current_user = {}
20
+ helper.current_user_apps = {
21
+ "app for BAR" => "https://bar.prx.org",
22
+ "and then BAZ" => "https://baz.staging.prx.tech"
23
+ }
24
+
25
+ refute helper.current_user_app?("foo")
26
+ assert helper.current_user_app?("bar")
27
+ assert helper.current_user_app?("baz")
28
+ end
29
+ end
30
+
31
+ describe "#current_user_app" do
32
+ it "returns app urls" do
33
+ helper.current_user = {}
34
+ helper.current_user_apps = {
35
+ "dev domain" => "https://foo.prx.dev",
36
+ "real Bar domain" => "https://bar.prx.org",
37
+ "staging Baz domain" => "https://baz.staging.prx.tech"
38
+ }
39
+
40
+ assert_nil helper.current_user_app("foo")
41
+ assert_equal "https://bar.prx.org", helper.current_user_app("bar")
42
+ assert_equal "https://baz.staging.prx.tech", helper.current_user_app("baz")
43
+ end
44
+ end
45
+
46
+ describe "#current_user_id_profile" do
47
+ it "returns the ID host" do
48
+ assert_includes helper.current_user_id_profile, PrxAuth::Rails.configuration.id_host
49
+ end
50
+ end
51
+
52
+ describe "#current_user_image?" do
53
+ it "checks if the user has an image" do
54
+ refute helper.current_user_image?
55
+
56
+ helper.current_user = {}
57
+ helper.current_user_info = {"image_href" => ""}
58
+ refute helper.current_user_image?
59
+
60
+ helper.current_user_info = {"image_href" => "http://some.where/img"}
61
+ assert helper.current_user_image?
62
+ end
63
+ end
64
+
65
+ describe "#current_user_image" do
66
+ it "returns the user image url" do
67
+ helper.current_user_info = {"image_href" => "http://some.where/img"}
68
+ assert_equal "http://some.where/img", helper.current_user_image
69
+ end
70
+ end
71
+ end
@@ -12,7 +12,7 @@ describe PrxAuth::Rails do
12
12
  end
13
13
 
14
14
  it "installs and configures prx_auth middleware" do
15
- mw = MiniTest::Mock.new
15
+ mw = Minitest::Mock.new
16
16
  mw.expect :insert_after, nil do |c1, c2, cert_location:, issuer:|
17
17
  assert_equal Rack::Head, c1
18
18
  assert_equal Rack::PrxAuth, c2
@@ -20,7 +20,7 @@ describe PrxAuth::Rails do
20
20
  assert_equal "id.prx.test", issuer
21
21
  end
22
22
 
23
- app = MiniTest::Mock.new
23
+ app = Minitest::Mock.new
24
24
  app.expect :middleware, mw
25
25
 
26
26
  subject.install_middleware!(app)
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prx_auth-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.1
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Rhoden
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2023-08-29 00:00:00.000000000 Z
10
+ date: 2025-04-07 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: actionpack
@@ -114,14 +113,14 @@ dependencies:
114
113
  requirements:
115
114
  - - "~>"
116
115
  - !ruby/object:Gem::Version
117
- version: 6.1.0
116
+ version: 8.0.1
118
117
  type: :development
119
118
  prerelease: false
120
119
  version_requirements: !ruby/object:Gem::Requirement
121
120
  requirements:
122
121
  - - "~>"
123
122
  - !ruby/object:Gem::Version
124
- version: 6.1.0
123
+ version: 8.0.1
125
124
  - !ruby/object:Gem::Dependency
126
125
  name: pry
127
126
  requirement: !ruby/object:Gem::Requirement
@@ -208,6 +207,8 @@ files:
208
207
  - README.md
209
208
  - Rakefile
210
209
  - app/controllers/prx_auth/rails/sessions_controller.rb
210
+ - app/helpers/prx_auth/rails/sessions_helper.rb
211
+ - app/views/prx_auth/rails/sessions/access_error.html.erb
211
212
  - app/views/prx_auth/rails/sessions/auth_error.html.erb
212
213
  - app/views/prx_auth/rails/sessions/show.html.erb
213
214
  - config/initializers/assets.rb
@@ -216,6 +217,8 @@ files:
216
217
  - lib/prx_auth/rails/configuration.rb
217
218
  - lib/prx_auth/rails/engine.rb
218
219
  - lib/prx_auth/rails/ext/controller.rb
220
+ - lib/prx_auth/rails/ext/controller/account_info.rb
221
+ - lib/prx_auth/rails/ext/controller/user_info.rb
219
222
  - lib/prx_auth/rails/railtie.rb
220
223
  - lib/prx_auth/rails/token.rb
221
224
  - lib/prx_auth/rails/version.rb
@@ -280,6 +283,7 @@ files:
280
283
  - test/prx_auth/rails/configuration_test.rb
281
284
  - test/prx_auth/rails/ext/controller_test.rb
282
285
  - test/prx_auth/rails/sessions_controller_test.rb
286
+ - test/prx_auth/rails/sessions_helper_test.rb
283
287
  - test/prx_auth/rails/token_test.rb
284
288
  - test/prx_auth/rails_test.rb
285
289
  - test/test_helper.rb
@@ -287,7 +291,6 @@ homepage: https://github.com/PRX/prx_auth-rails
287
291
  licenses:
288
292
  - MIT
289
293
  metadata: {}
290
- post_install_message:
291
294
  rdoc_options: []
292
295
  require_paths:
293
296
  - lib
@@ -302,8 +305,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
302
305
  - !ruby/object:Gem::Version
303
306
  version: '0'
304
307
  requirements: []
305
- rubygems_version: 3.3.3
306
- signing_key:
308
+ rubygems_version: 3.6.2
307
309
  specification_version: 4
308
310
  summary: Rails integration for next generation PRX Authorization system.
309
311
  test_files: []