gds-sso 18.1.0 → 19.1.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 +4 -4
- data/lib/gds-sso/authorise_user.rb +49 -0
- data/lib/gds-sso/authorised_user_constraint.rb +21 -0
- data/lib/gds-sso/config.rb +3 -1
- data/lib/gds-sso/controller_methods.rb +11 -34
- data/lib/gds-sso/failure_app.rb +1 -1
- data/lib/gds-sso/railtie.rb +4 -0
- data/lib/gds-sso/version.rb +1 -1
- data/lib/gds-sso/warden_config.rb +1 -1
- data/lib/gds-sso.rb +8 -4
- data/lib/omniauth/strategies/gds.rb +1 -1
- data/spec/controller/controller_methods_spec.rb +14 -47
- data/spec/internal/app/controllers/example_controller.rb +4 -1
- data/spec/internal/app/models/user.rb +1 -1
- data/spec/internal/config/routes.rb +4 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/test_user.rb +2 -0
- data/spec/system/authentication_and_authorisation_spec.rb +23 -2
- data/spec/unit/authorise_user_spec.rb +69 -0
- data/spec/unit/authorised_user_constraint_spec.rb +50 -0
- data/spec/unit/railtie_spec.rb +19 -0
- metadata +18 -19
- data/app/views/authorisations/cant_signin.html.erb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 71c0501986a461e92a2a6b176ded8dce5c191f2b735465ab4bb0d62fa21692a6
|
4
|
+
data.tar.gz: c4498c2a13b319f7dcdf2f3280a5aeee424c7881c79ed031dc2242bddba4c9bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65e314e7c2d79c2268a391d03cc5a3ce8501c17f2c024890222a434491425ab68c06e28fb4c992f65c1181189ba0c6a7f5a4d9078e9db8905bc90440913e8f0c
|
7
|
+
data.tar.gz: 9191a650b590f2099a73b8d86153ea87c7e3f93ef54b965cf7804257729864e07fa215efff25174881afe53c325ac02d1f49319a5fd10f81d09a61786e7657c9
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module GDS
|
2
|
+
module SSO
|
3
|
+
class AuthoriseUser
|
4
|
+
def self.call(...) = new(...).call
|
5
|
+
|
6
|
+
def initialize(current_user, permissions)
|
7
|
+
@current_user = current_user
|
8
|
+
@permissions = permissions
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
case permissions
|
13
|
+
when String
|
14
|
+
unless current_user.has_permission?(permissions)
|
15
|
+
raise GDS::SSO::PermissionDeniedError, "Sorry, you don't seem to have the #{permissions} permission for this app."
|
16
|
+
end
|
17
|
+
when Hash
|
18
|
+
raise ArgumentError, "Must be either `any_of` or `all_of`" unless permissions.keys.size == 1
|
19
|
+
|
20
|
+
if permissions[:any_of]
|
21
|
+
authorise_user_with_at_least_one_of_permissions!(permissions[:any_of])
|
22
|
+
elsif permissions[:all_of]
|
23
|
+
authorise_user_with_all_permissions!(permissions[:all_of])
|
24
|
+
else
|
25
|
+
raise ArgumentError, "Must be either `any_of` or `all_of`"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_reader :current_user, :permissions
|
33
|
+
|
34
|
+
def authorise_user_with_at_least_one_of_permissions!(permissions)
|
35
|
+
if permissions.none? { |permission| current_user.has_permission?(permission) }
|
36
|
+
raise GDS::SSO::PermissionDeniedError,
|
37
|
+
"Sorry, you don't seem to have any of the permissions: #{permissions.to_sentence} for this app."
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def authorise_user_with_all_permissions!(permissions)
|
42
|
+
unless permissions.all? { |permission| current_user.has_permission?(permission) }
|
43
|
+
raise GDS::SSO::PermissionDeniedError,
|
44
|
+
"Sorry, you don't seem to have all of the permissions: #{permissions.to_sentence} for this app."
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module GDS
|
2
|
+
module SSO
|
3
|
+
class AuthorisedUserConstraint
|
4
|
+
def initialize(permissions)
|
5
|
+
@permissions = permissions
|
6
|
+
end
|
7
|
+
|
8
|
+
def matches?(request)
|
9
|
+
warden = request.env["warden"]
|
10
|
+
warden.authenticate! if !warden.authenticated? || warden.user.remotely_signed_out?
|
11
|
+
|
12
|
+
GDS::SSO::AuthoriseUser.call(warden.user, permissions)
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
attr_reader :permissions
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/gds-sso/config.rb
CHANGED
@@ -26,10 +26,12 @@ module GDS
|
|
26
26
|
@@auth_valid_for = 20 * 3600
|
27
27
|
|
28
28
|
mattr_accessor :cache
|
29
|
-
@@cache = ActiveSupport::Cache::NullStore.new
|
30
29
|
|
31
30
|
mattr_accessor :api_only
|
32
31
|
|
32
|
+
mattr_accessor :intercept_401_responses
|
33
|
+
@@intercept_401_responses = true
|
34
|
+
|
33
35
|
mattr_accessor :additional_mock_permissions_required
|
34
36
|
|
35
37
|
mattr_accessor :connection_opts
|
@@ -1,11 +1,19 @@
|
|
1
1
|
module GDS
|
2
2
|
module SSO
|
3
|
+
class PermissionDeniedError < StandardError
|
4
|
+
end
|
5
|
+
|
3
6
|
module ControllerMethods
|
4
|
-
|
7
|
+
# TODO: remove this for the next major release
|
8
|
+
class PermissionDeniedException < PermissionDeniedError
|
9
|
+
def initialize(...)
|
10
|
+
warn "GDS::SSO::ControllerMethods::PermissionDeniedException is deprecated, please replace with GDS::SSO::PermissionDeniedError"
|
11
|
+
super(...)
|
12
|
+
end
|
5
13
|
end
|
6
14
|
|
7
15
|
def self.included(base)
|
8
|
-
base.rescue_from
|
16
|
+
base.rescue_from PermissionDeniedError do |e|
|
9
17
|
if GDS::SSO::Config.api_only
|
10
18
|
render json: { message: e.message }, status: :forbidden
|
11
19
|
else
|
@@ -24,22 +32,7 @@ module GDS
|
|
24
32
|
# Otherwise current_user might be nil, and we'd error out
|
25
33
|
authenticate_user!
|
26
34
|
|
27
|
-
|
28
|
-
when String
|
29
|
-
unless current_user.has_permission?(permissions)
|
30
|
-
raise PermissionDeniedException, "Sorry, you don't seem to have the #{permissions} permission for this app."
|
31
|
-
end
|
32
|
-
when Hash
|
33
|
-
raise ArgumentError, "Must be either `any_of` or `all_of`" unless permissions.keys.size == 1
|
34
|
-
|
35
|
-
if permissions[:any_of]
|
36
|
-
authorise_user_with_at_least_one_of_permissions!(permissions[:any_of])
|
37
|
-
elsif permissions[:all_of]
|
38
|
-
authorise_user_with_all_permissions!(permissions[:all_of])
|
39
|
-
else
|
40
|
-
raise ArgumentError, "Must be either `any_of` or `all_of`"
|
41
|
-
end
|
42
|
-
end
|
35
|
+
GDS::SSO::AuthoriseUser.call(current_user, permissions)
|
43
36
|
end
|
44
37
|
|
45
38
|
def authenticate_user!
|
@@ -65,22 +58,6 @@ module GDS
|
|
65
58
|
def warden
|
66
59
|
request.env["warden"]
|
67
60
|
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
def authorise_user_with_at_least_one_of_permissions!(permissions)
|
72
|
-
if permissions.none? { |permission| current_user.has_permission?(permission) }
|
73
|
-
raise PermissionDeniedException,
|
74
|
-
"Sorry, you don't seem to have any of the permissions: #{permissions.to_sentence} for this app."
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def authorise_user_with_all_permissions!(permissions)
|
79
|
-
unless permissions.all? { |permission| current_user.has_permission?(permission) }
|
80
|
-
raise PermissionDeniedException,
|
81
|
-
"Sorry, you don't seem to have all of the permissions: #{permissions.to_sentence} for this app."
|
82
|
-
end
|
83
|
-
end
|
84
61
|
end
|
85
62
|
end
|
86
63
|
end
|
data/lib/gds-sso/failure_app.rb
CHANGED
@@ -52,7 +52,7 @@ module GDS
|
|
52
52
|
|
53
53
|
def api_unauthorized(message, bearer_error)
|
54
54
|
headers["WWW-Authenticate"] = %(Bearer error="#{bearer_error}")
|
55
|
-
render json: { message:
|
55
|
+
render json: { message: }, status: :unauthorized
|
56
56
|
end
|
57
57
|
end
|
58
58
|
end
|
data/lib/gds-sso/railtie.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
module GDS
|
2
2
|
module SSO
|
3
3
|
class Railtie < Rails::Railtie
|
4
|
+
config.action_dispatch.rescue_responses.merge!(
|
5
|
+
"GDS::SSO::PermissionDeniedError" => :forbidden,
|
6
|
+
)
|
7
|
+
|
4
8
|
initializer "gds-sso.initializer" do
|
5
9
|
GDS::SSO.config do |config|
|
6
10
|
config.cache = Rails.cache
|
data/lib/gds-sso/version.rb
CHANGED
@@ -29,7 +29,7 @@ Warden::Manager.serialize_from_session do |(uid, auth_timestamp)|
|
|
29
29
|
end
|
30
30
|
|
31
31
|
if auth_timestamp && ((auth_timestamp + GDS::SSO::Config.auth_valid_for) > Time.now.utc)
|
32
|
-
GDS::SSO::Config.user_klass.where(uid
|
32
|
+
GDS::SSO::Config.user_klass.where(uid:, remotely_signed_out: false).first
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
data/lib/gds-sso.rb
CHANGED
@@ -10,10 +10,13 @@ require "gds-sso/railtie" if defined?(Rails)
|
|
10
10
|
|
11
11
|
module GDS
|
12
12
|
module SSO
|
13
|
-
autoload :FailureApp,
|
14
|
-
autoload :ControllerMethods,
|
15
|
-
autoload :User,
|
16
|
-
autoload :ApiAccess,
|
13
|
+
autoload :FailureApp, "gds-sso/failure_app"
|
14
|
+
autoload :ControllerMethods, "gds-sso/controller_methods"
|
15
|
+
autoload :User, "gds-sso/user"
|
16
|
+
autoload :ApiAccess, "gds-sso/api_access"
|
17
|
+
autoload :AuthoriseUser, "gds-sso/authorise_user"
|
18
|
+
autoload :AuthorisedUserConstraint, "gds-sso/authorised_user_constraint"
|
19
|
+
autoload :PermissionDeniedError, "gds-sso/controller_methods"
|
17
20
|
|
18
21
|
# User to return as logged in during tests
|
19
22
|
mattr_accessor :test_user
|
@@ -52,6 +55,7 @@ module GDS
|
|
52
55
|
config.app_middleware.use Warden::Manager do |config|
|
53
56
|
config.default_strategies(*default_strategies)
|
54
57
|
config.failure_app = GDS::SSO::FailureApp
|
58
|
+
config.intercept_401 = GDS::SSO::Config.intercept_401_responses
|
55
59
|
end
|
56
60
|
end
|
57
61
|
end
|
@@ -1,57 +1,24 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
RSpec.describe GDS::SSO::ControllerMethods
|
4
|
-
|
5
|
-
|
3
|
+
RSpec.describe GDS::SSO::ControllerMethods do
|
4
|
+
describe "#authorise_user!" do
|
5
|
+
let(:current_user) { double }
|
6
|
+
let(:expected_error) { GDS::SSO::PermissionDeniedError }
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
context "when the user is authorised" do
|
9
|
+
it "does not raise an error" do
|
10
|
+
allow(current_user).to receive(:has_permission?).with("good").and_return(true)
|
10
11
|
|
11
|
-
|
12
|
+
expect { ControllerSpy.new(current_user).authorise_user!("good") }.not_to raise_error
|
13
|
+
end
|
12
14
|
end
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
+
context "when the user is not authorised" do
|
17
|
+
it "raises an error" do
|
18
|
+
allow(current_user).to receive(:has_permission?).with("bad").and_return(false)
|
16
19
|
|
17
|
-
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
context "with the `all_of` option" do
|
22
|
-
it "permits users with all of the required permissions" do
|
23
|
-
allow(current_user).to receive(:has_permission?).with("good").and_return(true)
|
24
|
-
allow(current_user).to receive(:has_permission?).with("bad").and_return(true)
|
25
|
-
|
26
|
-
expect { ControllerSpy.new(current_user).authorise_user!(all_of: %w[good bad]) }.not_to raise_error
|
27
|
-
end
|
28
|
-
|
29
|
-
it "does not permit users without all of the required permissions" do
|
30
|
-
allow(current_user).to receive(:has_permission?).with("good").and_return(false)
|
31
|
-
allow(current_user).to receive(:has_permission?).with("bad").and_return(true)
|
32
|
-
|
33
|
-
expect { ControllerSpy.new(current_user).authorise_user!(all_of: %w[good bad]) }.to raise_error(expected_error)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
context "with the `any_of` option" do
|
38
|
-
it "permits users with any of the required permissions" do
|
39
|
-
allow(current_user).to receive(:has_permission?).with("good").and_return(true)
|
40
|
-
allow(current_user).to receive(:has_permission?).with("bad").and_return(false)
|
41
|
-
|
42
|
-
expect { ControllerSpy.new(current_user).authorise_user!(any_of: %w[good bad]) }.not_to raise_error
|
43
|
-
end
|
44
|
-
|
45
|
-
it "does not permit users without any of the required permissions" do
|
46
|
-
allow(current_user).to receive(:has_permission?).and_return(false)
|
47
|
-
|
48
|
-
expect { ControllerSpy.new(current_user).authorise_user!(any_of: %w[good bad]) }.to raise_error(expected_error)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
context "with none of `any_of` or `all_of`" do
|
53
|
-
it "raises an `ArgumentError`" do
|
54
|
-
expect { ControllerSpy.new(current_user).authorise_user!(whoops: "bad") }.to raise_error(ArgumentError)
|
20
|
+
expect { ControllerSpy.new(current_user).authorise_user!("bad") }.to raise_error(expected_error)
|
21
|
+
end
|
55
22
|
end
|
56
23
|
end
|
57
24
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
class ExampleController < ApplicationController
|
2
2
|
before_action :authenticate_user!, except: :not_restricted
|
3
3
|
before_action -> { authorise_user!("execute") }, only: :this_requires_execute_permission
|
4
|
-
|
5
4
|
def not_restricted
|
6
5
|
render body: "jabberwocky"
|
7
6
|
end
|
@@ -13,4 +12,8 @@ class ExampleController < ApplicationController
|
|
13
12
|
def this_requires_execute_permission
|
14
13
|
render body: "you have execute permission"
|
15
14
|
end
|
15
|
+
|
16
|
+
def constraint_restricted
|
17
|
+
render body: "constraint restricted"
|
18
|
+
end
|
16
19
|
end
|
@@ -4,4 +4,8 @@ Rails.application.routes.draw do
|
|
4
4
|
get "/not-restricted" => "example#not_restricted"
|
5
5
|
get "/restricted" => "example#restricted"
|
6
6
|
get "/this-requires-execute-permission" => "example#this_requires_execute_permission"
|
7
|
+
|
8
|
+
constraints(GDS::SSO::AuthorisedUserConstraint.new("execute")) do
|
9
|
+
get "/constraint-restricted" => "example#constraint_restricted"
|
10
|
+
end
|
7
11
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/support/test_user.rb
CHANGED
@@ -119,6 +119,27 @@ RSpec.describe "Authenication and authorisation" do
|
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
122
|
+
context "when accessing a route that is restricted by the authorised user constraint" do
|
123
|
+
it "allows access when an authenticated user has correct permissions" do
|
124
|
+
stub_signon_authenticated(permissions: %w[execute])
|
125
|
+
visit "/constraint-restricted"
|
126
|
+
expect(page).to have_content("constraint restricted")
|
127
|
+
end
|
128
|
+
|
129
|
+
it "redirects an unauthenticated request to signon" do
|
130
|
+
visit "/constraint-restricted"
|
131
|
+
expect(page.response_headers["Location"]).to match("/auth/gds")
|
132
|
+
visit page.response_headers["Location"]
|
133
|
+
expect(page.response_headers["Location"]).to match("http://signon/oauth/authorize")
|
134
|
+
end
|
135
|
+
|
136
|
+
it "restricts access when an authenticated user does not have the correct permissions" do
|
137
|
+
stub_signon_authenticated(permissions: %w[no-access])
|
138
|
+
visit "/constraint-restricted"
|
139
|
+
expect(page.status_code).to eq(403)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
122
143
|
def stub_signon_authenticated(permissions: [])
|
123
144
|
# visit restricted page to trigger redirect URL to record state attribute
|
124
145
|
visit "/auth/gds"
|
@@ -129,7 +150,7 @@ RSpec.describe "Authenication and authorisation" do
|
|
129
150
|
.to_return(body: { access_token: "token" }.to_json,
|
130
151
|
headers: { content_type: "application/json" })
|
131
152
|
|
132
|
-
stub_signon_user_request(permissions:
|
153
|
+
stub_signon_user_request(permissions:)
|
133
154
|
|
134
155
|
visit "/auth/gds/callback?code=code&state=#{state}"
|
135
156
|
end
|
@@ -142,7 +163,7 @@ RSpec.describe "Authenication and authorisation" do
|
|
142
163
|
uid: "123",
|
143
164
|
email: "test-user@example.com",
|
144
165
|
name: "Test User",
|
145
|
-
permissions
|
166
|
+
permissions:,
|
146
167
|
},
|
147
168
|
}.to_json,
|
148
169
|
headers: { content_type: "application/json" },
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "gds-sso/authorise_user"
|
3
|
+
|
4
|
+
describe GDS::SSO::AuthoriseUser do
|
5
|
+
describe "#call" do
|
6
|
+
let(:current_user) { double }
|
7
|
+
|
8
|
+
context "with a single string permission argument" do
|
9
|
+
let(:permissions) { "admin" }
|
10
|
+
let(:expected_error) { GDS::SSO::PermissionDeniedError }
|
11
|
+
|
12
|
+
it "permits users with the required permission" do
|
13
|
+
allow(current_user).to receive(:has_permission?).with("admin").and_return(true)
|
14
|
+
|
15
|
+
expect { described_class.call(current_user, permissions) }.not_to raise_error
|
16
|
+
end
|
17
|
+
|
18
|
+
it "does not permit the users without the required permission" do
|
19
|
+
allow(current_user).to receive(:has_permission?).with("admin").and_return(false)
|
20
|
+
|
21
|
+
expect { described_class.call(current_user, permissions) }.to raise_error(expected_error)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "with the `all_of` option" do
|
26
|
+
let(:permissions) { { all_of: %w[admin editor] } }
|
27
|
+
let(:expected_error) { GDS::SSO::PermissionDeniedError }
|
28
|
+
|
29
|
+
it "permits users with all of the required permissions" do
|
30
|
+
allow(current_user).to receive(:has_permission?).with("admin").and_return(true)
|
31
|
+
allow(current_user).to receive(:has_permission?).with("editor").and_return(true)
|
32
|
+
|
33
|
+
expect { described_class.call(current_user, permissions) }.not_to raise_error
|
34
|
+
end
|
35
|
+
|
36
|
+
it "does not permit users without all of the required permissions" do
|
37
|
+
allow(current_user).to receive(:has_permission?).with("admin").and_return(false)
|
38
|
+
allow(current_user).to receive(:has_permission?).with("editor").and_return(true)
|
39
|
+
|
40
|
+
expect { described_class.call(current_user, permissions) }.to raise_error(expected_error)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "with the `any_of` option" do
|
45
|
+
let(:permissions) { { any_of: %w[admin editor] } }
|
46
|
+
let(:expected_error) { GDS::SSO::PermissionDeniedError }
|
47
|
+
|
48
|
+
it "permits users with any of the required permissions" do
|
49
|
+
allow(current_user).to receive(:has_permission?).with("admin").and_return(true)
|
50
|
+
allow(current_user).to receive(:has_permission?).with("editor").and_return(false)
|
51
|
+
|
52
|
+
expect { described_class.call(current_user, permissions) }.not_to raise_error
|
53
|
+
end
|
54
|
+
|
55
|
+
it "does not permit users without any of the required permissions" do
|
56
|
+
allow(current_user).to receive(:has_permission?).and_return(false)
|
57
|
+
|
58
|
+
expect { described_class.call(current_user, permissions) }.to raise_error(expected_error)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "with none of `any_of` or `all_of`" do
|
63
|
+
it "raises an `ArgumentError`" do
|
64
|
+
expect { described_class.call(current_user, { admin: true }) }
|
65
|
+
.to raise_error(ArgumentError)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "gds-sso/authorised_user_constraint"
|
3
|
+
|
4
|
+
describe GDS::SSO::AuthorisedUserConstraint do
|
5
|
+
before do
|
6
|
+
allow(GDS::SSO::AuthoriseUser).to receive(:call).and_return(true)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#matches?" do
|
10
|
+
let(:user) { double("user", remotely_signed_out?: remotely_signed_out) }
|
11
|
+
let(:warden) do
|
12
|
+
double(
|
13
|
+
"warden",
|
14
|
+
authenticated?: user_authenticated,
|
15
|
+
user:,
|
16
|
+
authenticate!: nil,
|
17
|
+
)
|
18
|
+
end
|
19
|
+
let(:user_authenticated) { true }
|
20
|
+
let(:remotely_signed_out) { false }
|
21
|
+
let(:request) { double("request", env: { "warden" => warden }) }
|
22
|
+
|
23
|
+
it "authorises the user" do
|
24
|
+
expect(GDS::SSO::AuthoriseUser).to receive(:call).with(warden.user, %w[signin])
|
25
|
+
expect(warden).not_to receive(:authenticate!)
|
26
|
+
|
27
|
+
described_class.new(%w[signin]).matches?(request)
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when the user is not authenticated" do
|
31
|
+
let(:user_authenticated) { false }
|
32
|
+
|
33
|
+
it "authenticates the user" do
|
34
|
+
expect(warden).to receive(:authenticate!)
|
35
|
+
|
36
|
+
described_class.new(%w[signin]).matches?(request)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when the user is remotely signed out" do
|
41
|
+
let(:remotely_signed_out) { true }
|
42
|
+
|
43
|
+
it "authenticates the user" do
|
44
|
+
expect(warden).to receive(:authenticate!)
|
45
|
+
|
46
|
+
described_class.new(%w[signin]).matches?(request)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/spec/unit/railtie_spec.rb
CHANGED
@@ -11,4 +11,23 @@ RSpec.describe GDS::SSO::Railtie do
|
|
11
11
|
it "honours API only setting" do
|
12
12
|
expect(GDS::SSO::Config.api_only).to eq false
|
13
13
|
end
|
14
|
+
|
15
|
+
describe "configuring intercept_401_responses" do
|
16
|
+
it "sets warden intercept_401 to false when the configuration option is set to false" do
|
17
|
+
allow(GDS::SSO::Config).to receive(:intercept_401_responses).and_return(false)
|
18
|
+
|
19
|
+
expect(warden_manager.config[:intercept_401]).to be(false)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "sets warden intercept_401 to true when the configuration option is set to true" do
|
23
|
+
allow(GDS::SSO::Config).to receive(:intercept_401_responses).and_return(true)
|
24
|
+
|
25
|
+
expect(warden_manager.config[:intercept_401]).to be(true)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def warden_manager
|
30
|
+
middleware = Rails.application.config.middleware.find { |m| m.name.include?("Warden::Manager") }
|
31
|
+
Warden::Manager.new(nil, &middleware.block)
|
32
|
+
end
|
14
33
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gds-sso
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 19.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GOV.UK Dev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-04-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: oauth2
|
@@ -58,34 +58,28 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
62
|
-
- - "<"
|
63
|
-
- !ruby/object:Gem::Version
|
64
|
-
version: '6'
|
61
|
+
version: '5'
|
65
62
|
type: :runtime
|
66
63
|
prerelease: false
|
67
64
|
version_requirements: !ruby/object:Gem::Requirement
|
68
65
|
requirements:
|
69
66
|
- - ">="
|
70
67
|
- !ruby/object:Gem::Version
|
71
|
-
version: '
|
72
|
-
- - "<"
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
version: '6'
|
68
|
+
version: '5'
|
75
69
|
- !ruby/object:Gem::Dependency
|
76
70
|
name: rails
|
77
71
|
requirement: !ruby/object:Gem::Requirement
|
78
72
|
requirements:
|
79
73
|
- - ">="
|
80
74
|
- !ruby/object:Gem::Version
|
81
|
-
version: '
|
75
|
+
version: '7'
|
82
76
|
type: :runtime
|
83
77
|
prerelease: false
|
84
78
|
version_requirements: !ruby/object:Gem::Requirement
|
85
79
|
requirements:
|
86
80
|
- - ">="
|
87
81
|
- !ruby/object:Gem::Version
|
88
|
-
version: '
|
82
|
+
version: '7'
|
89
83
|
- !ruby/object:Gem::Dependency
|
90
84
|
name: warden
|
91
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -174,16 +168,16 @@ dependencies:
|
|
174
168
|
name: rubocop-govuk
|
175
169
|
requirement: !ruby/object:Gem::Requirement
|
176
170
|
requirements:
|
177
|
-
- -
|
171
|
+
- - '='
|
178
172
|
- !ruby/object:Gem::Version
|
179
|
-
version:
|
173
|
+
version: 4.16.1
|
180
174
|
type: :development
|
181
175
|
prerelease: false
|
182
176
|
version_requirements: !ruby/object:Gem::Requirement
|
183
177
|
requirements:
|
184
|
-
- -
|
178
|
+
- - '='
|
185
179
|
- !ruby/object:Gem::Version
|
186
|
-
version:
|
180
|
+
version: 4.16.1
|
187
181
|
- !ruby/object:Gem::Dependency
|
188
182
|
name: sqlite3
|
189
183
|
requirement: !ruby/object:Gem::Requirement
|
@@ -239,12 +233,13 @@ files:
|
|
239
233
|
- app/controllers/api/user_controller.rb
|
240
234
|
- app/controllers/authentications_controller.rb
|
241
235
|
- app/views/authentications/failure.html.erb
|
242
|
-
- app/views/authorisations/cant_signin.html.erb
|
243
236
|
- app/views/authorisations/unauthorised.html.erb
|
244
237
|
- app/views/layouts/unauthorised.html.erb
|
245
238
|
- config/routes.rb
|
246
239
|
- lib/gds-sso.rb
|
247
240
|
- lib/gds-sso/api_access.rb
|
241
|
+
- lib/gds-sso/authorise_user.rb
|
242
|
+
- lib/gds-sso/authorised_user_constraint.rb
|
248
243
|
- lib/gds-sso/bearer_token.rb
|
249
244
|
- lib/gds-sso/config.rb
|
250
245
|
- lib/gds-sso/controller_methods.rb
|
@@ -273,6 +268,8 @@ files:
|
|
273
268
|
- spec/support/timecop.rb
|
274
269
|
- spec/system/authentication_and_authorisation_spec.rb
|
275
270
|
- spec/unit/api_access_spec.rb
|
271
|
+
- spec/unit/authorise_user_spec.rb
|
272
|
+
- spec/unit/authorised_user_constraint_spec.rb
|
276
273
|
- spec/unit/bearer_token_spec.rb
|
277
274
|
- spec/unit/config_spec.rb
|
278
275
|
- spec/unit/mock_bearer_token_spec.rb
|
@@ -291,14 +288,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
291
288
|
requirements:
|
292
289
|
- - ">="
|
293
290
|
- !ruby/object:Gem::Version
|
294
|
-
version: '3.
|
291
|
+
version: '3.1'
|
295
292
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
296
293
|
requirements:
|
297
294
|
- - ">="
|
298
295
|
- !ruby/object:Gem::Version
|
299
296
|
version: '0'
|
300
297
|
requirements: []
|
301
|
-
rubygems_version: 3.
|
298
|
+
rubygems_version: 3.5.9
|
302
299
|
signing_key:
|
303
300
|
specification_version: 4
|
304
301
|
summary: Client for GDS' OAuth 2-based SSO
|
@@ -320,6 +317,8 @@ test_files:
|
|
320
317
|
- spec/support/timecop.rb
|
321
318
|
- spec/system/authentication_and_authorisation_spec.rb
|
322
319
|
- spec/unit/api_access_spec.rb
|
320
|
+
- spec/unit/authorise_user_spec.rb
|
321
|
+
- spec/unit/authorised_user_constraint_spec.rb
|
323
322
|
- spec/unit/bearer_token_spec.rb
|
324
323
|
- spec/unit/config_spec.rb
|
325
324
|
- spec/unit/mock_bearer_token_spec.rb
|
@@ -1,6 +0,0 @@
|
|
1
|
-
<h1>Sorry, you don't have permission to access this application</h1>
|
2
|
-
|
3
|
-
<p>Please contact your Delivery Manager or main GDS contact if you need access.</p>
|
4
|
-
|
5
|
-
<p>If you think something is wrong, try <%= link_to "signing out", gds_sign_out_path %> and then back in.</p>
|
6
|
-
|