gds-sso 15.0.0 → 15.0.1
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/Rakefile +11 -6
- data/app/controllers/api/user_controller.rb +30 -28
- data/app/controllers/authentications_controller.rb +3 -5
- data/config/routes.rb +6 -5
- data/lib/gds-sso.rb +24 -23
- data/lib/gds-sso/api_access.rb +1 -1
- data/lib/gds-sso/bearer_token.rb +24 -24
- data/lib/gds-sso/config.rb +9 -5
- data/lib/gds-sso/controller_methods.rb +5 -6
- data/lib/gds-sso/failure_app.rb +7 -7
- data/lib/gds-sso/lint/user_spec.rb +24 -25
- data/lib/gds-sso/lint/user_test.rb +28 -28
- data/lib/gds-sso/user.rb +12 -12
- data/lib/gds-sso/version.rb +1 -1
- data/lib/gds-sso/warden_config.rb +21 -31
- data/spec/controller/api_user_controller_spec.rb +40 -37
- data/spec/controller/controller_methods_spec.rb +28 -28
- data/spec/internal/app/controllers/application_controller.rb +1 -1
- data/spec/internal/app/controllers/example_controller.rb +1 -2
- data/spec/internal/config/initializers/gds-sso.rb +2 -2
- data/spec/internal/config/routes.rb +2 -2
- data/spec/internal/db/combustion_test.sqlite +0 -0
- data/spec/internal/db/schema.rb +5 -5
- data/spec/internal/log/test.log +1079 -1079
- data/spec/requests/end_to_end_spec.rb +44 -45
- data/spec/spec_helper.rb +12 -13
- data/spec/support/signon_integration_helpers.rb +9 -7
- data/spec/support/timecop.rb +1 -1
- data/spec/unit/api_access_spec.rb +7 -7
- data/spec/unit/bearer_token_spec.rb +14 -15
- data/spec/unit/config_spec.rb +5 -5
- data/spec/unit/mock_bearer_token_spec.rb +4 -4
- data/spec/unit/session_serialisation_spec.rb +5 -5
- data/spec/unit/user_spec.rb +22 -23
- metadata +71 -57
@@ -17,58 +17,58 @@ module GDS
|
|
17
17
|
#
|
18
18
|
class UserTest < ActiveSupport::TestCase
|
19
19
|
def user_class
|
20
|
-
raise
|
20
|
+
raise "Reopen `GDS::SSO::Lint::UserTest` and add `#user_class` to return the class including `GDS::SSO::User`"
|
21
21
|
end
|
22
22
|
|
23
23
|
setup do
|
24
|
-
@lint_user = user_class.new(uid:
|
24
|
+
@lint_user = user_class.new(uid: "12345")
|
25
25
|
end
|
26
26
|
|
27
|
-
test
|
28
|
-
result = user_class.where(uid:
|
27
|
+
test "implement #where" do
|
28
|
+
result = user_class.where(uid: "123")
|
29
29
|
assert result.respond_to?(:first)
|
30
30
|
end
|
31
31
|
|
32
|
-
test
|
32
|
+
test "implement #update_attribute" do
|
33
33
|
@lint_user.update_attribute(:remotely_signed_out, true)
|
34
34
|
assert @lint_user.remotely_signed_out?
|
35
35
|
end
|
36
36
|
|
37
|
-
test
|
38
|
-
@lint_user.update!(email:
|
39
|
-
assert_equal @lint_user.email,
|
37
|
+
test "implement #update!" do
|
38
|
+
@lint_user.update!(email: "test@example.com")
|
39
|
+
assert_equal @lint_user.email, "test@example.com"
|
40
40
|
end
|
41
41
|
|
42
|
-
test
|
42
|
+
test "implement #create!" do
|
43
43
|
assert user_class.respond_to?(:create!)
|
44
44
|
end
|
45
45
|
|
46
|
-
test
|
46
|
+
test "verify the User class and GDS::SSO::User work together" do
|
47
47
|
auth_hash = {
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
"uid" => "12345",
|
49
|
+
"info" => {
|
50
|
+
"name" => "Joe Smith",
|
51
|
+
"email" => "joe.smith@example.com",
|
52
|
+
},
|
53
|
+
"extra" => {
|
54
|
+
"user" => {
|
55
|
+
"disabled" => false,
|
56
|
+
"permissions" => %w[signin],
|
57
|
+
"organisation_slug" => "cabinet-office",
|
58
|
+
"organisation_content_id" => "91e57ad9-29a3-4f94-9ab4-5e9ae6d13588",
|
59
|
+
},
|
52
60
|
},
|
53
|
-
'extra' => {
|
54
|
-
'user' => {
|
55
|
-
'disabled' => false,
|
56
|
-
'permissions' => ['signin'],
|
57
|
-
'organisation_slug' => 'cabinet-office',
|
58
|
-
'organisation_content_id' => '91e57ad9-29a3-4f94-9ab4-5e9ae6d13588',
|
59
|
-
}
|
60
|
-
}
|
61
61
|
}
|
62
62
|
|
63
63
|
user = user_class.find_for_gds_oauth(auth_hash)
|
64
64
|
assert_equal user_class, user.class
|
65
|
-
assert_equal
|
66
|
-
assert_equal
|
67
|
-
assert_equal
|
65
|
+
assert_equal "12345", user.uid
|
66
|
+
assert_equal "Joe Smith", user.name
|
67
|
+
assert_equal "joe.smith@example.com", user.email
|
68
68
|
assert_equal false, user.disabled
|
69
|
-
assert_equal [
|
70
|
-
assert_equal
|
71
|
-
assert_equal
|
69
|
+
assert_equal %w[signin], user.permissions
|
70
|
+
assert_equal "cabinet-office", user.organisation_slug
|
71
|
+
assert_equal "91e57ad9-29a3-4f94-9ab4-5e9ae6d13588", user.organisation_content_id
|
72
72
|
end
|
73
73
|
end
|
74
74
|
end
|
data/lib/gds-sso/user.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "active_support/concern"
|
2
2
|
|
3
3
|
module GDS
|
4
4
|
module SSO
|
@@ -21,29 +21,29 @@ module GDS
|
|
21
21
|
|
22
22
|
def self.user_params_from_auth_hash(auth_hash)
|
23
23
|
{
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
"uid" => auth_hash["uid"],
|
25
|
+
"email" => auth_hash["info"]["email"],
|
26
|
+
"name" => auth_hash["info"]["name"],
|
27
|
+
"permissions" => auth_hash["extra"]["user"]["permissions"],
|
28
|
+
"organisation_slug" => auth_hash["extra"]["user"]["organisation_slug"],
|
29
|
+
"organisation_content_id" => auth_hash["extra"]["user"]["organisation_content_id"],
|
30
|
+
"disabled" => auth_hash["extra"]["user"]["disabled"],
|
31
31
|
}
|
32
32
|
end
|
33
33
|
|
34
34
|
def clear_remotely_signed_out!
|
35
|
-
|
35
|
+
update_attribute(:remotely_signed_out, false)
|
36
36
|
end
|
37
37
|
|
38
38
|
def set_remotely_signed_out!
|
39
|
-
|
39
|
+
update_attribute(:remotely_signed_out, true)
|
40
40
|
end
|
41
41
|
|
42
42
|
module ClassMethods
|
43
43
|
def find_for_gds_oauth(auth_hash)
|
44
44
|
user_params = GDS::SSO::User.user_params_from_auth_hash(auth_hash.to_hash)
|
45
|
-
user =
|
46
|
-
|
45
|
+
user = where(uid: user_params["uid"]).first ||
|
46
|
+
where(email: user_params["email"]).first
|
47
47
|
|
48
48
|
if user
|
49
49
|
user.update!(user_params)
|
data/lib/gds-sso/version.rb
CHANGED
@@ -1,63 +1,55 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "warden"
|
2
|
+
require "warden-oauth2"
|
3
|
+
require "gds-sso/bearer_token"
|
4
4
|
|
5
5
|
def logger
|
6
|
-
|
7
|
-
Rails.logger
|
8
|
-
else
|
9
|
-
env['rack.logger']
|
10
|
-
end
|
6
|
+
Rails.logger || env["rack.logger"]
|
11
7
|
end
|
12
8
|
|
13
|
-
Warden::Manager.after_authentication do |user,
|
9
|
+
Warden::Manager.after_authentication do |user, _auth, _opts|
|
14
10
|
# We've successfully signed in.
|
15
11
|
# If they were remotely signed out, clear the flag as they're no longer suspended
|
16
12
|
user.clear_remotely_signed_out!
|
17
13
|
end
|
18
14
|
|
19
15
|
Warden::Manager.serialize_into_session do |user|
|
20
|
-
if user.respond_to?(:uid)
|
16
|
+
if user.respond_to?(:uid) && user.uid
|
21
17
|
[user.uid, Time.now.utc.iso8601]
|
22
|
-
else
|
23
|
-
nil
|
24
18
|
end
|
25
19
|
end
|
26
20
|
|
27
21
|
Warden::Manager.serialize_from_session do |(uid, auth_timestamp)|
|
28
22
|
# This will reject old sessions that don't have a previous login timestamp
|
29
23
|
if auth_timestamp.is_a?(String)
|
30
|
-
|
31
|
-
Time.parse(auth_timestamp)
|
24
|
+
begin
|
25
|
+
auth_timestamp = Time.parse(auth_timestamp)
|
32
26
|
rescue ArgumentError
|
33
|
-
nil
|
27
|
+
auth_timestamp = nil
|
34
28
|
end
|
35
29
|
end
|
36
30
|
|
37
|
-
if auth_timestamp
|
38
|
-
GDS::SSO::Config.user_klass.where(:
|
39
|
-
else
|
40
|
-
nil
|
31
|
+
if auth_timestamp && ((auth_timestamp + GDS::SSO::Config.auth_valid_for) > Time.now.utc)
|
32
|
+
GDS::SSO::Config.user_klass.where(uid: uid, remotely_signed_out: false).first
|
41
33
|
end
|
42
34
|
end
|
43
35
|
|
44
36
|
Warden::Strategies.add(:gds_sso) do
|
45
37
|
def valid?
|
46
|
-
|
38
|
+
!::GDS::SSO::ApiAccess.api_call?(env)
|
47
39
|
end
|
48
40
|
|
49
41
|
def authenticate!
|
50
42
|
logger.debug("Authenticating with gds_sso strategy")
|
51
43
|
|
52
|
-
if request.env[
|
44
|
+
if request.env["omniauth.auth"].nil?
|
53
45
|
fail!("No credentials, bub")
|
54
46
|
else
|
55
|
-
user = prep_user(request.env[
|
47
|
+
user = prep_user(request.env["omniauth.auth"])
|
56
48
|
success!(user)
|
57
49
|
end
|
58
50
|
end
|
59
51
|
|
60
|
-
|
52
|
+
private
|
61
53
|
|
62
54
|
def prep_user(auth_hash)
|
63
55
|
user = GDS::SSO::Config.user_klass.find_for_gds_oauth(auth_hash)
|
@@ -73,27 +65,25 @@ Warden::Strategies.add(:gds_bearer_token, Warden::OAuth2::Strategies::Bearer)
|
|
73
65
|
|
74
66
|
Warden::Strategies.add(:mock_gds_sso) do
|
75
67
|
def valid?
|
76
|
-
|
68
|
+
!::GDS::SSO::ApiAccess.api_call?(env)
|
77
69
|
end
|
78
70
|
|
79
71
|
def authenticate!
|
80
72
|
logger.warn("Authenticating with mock_gds_sso strategy")
|
81
73
|
|
82
74
|
test_user = GDS::SSO.test_user
|
83
|
-
test_user ||= ENV[
|
75
|
+
test_user ||= ENV["GDS_SSO_MOCK_INVALID"].present? ? nil : GDS::SSO::Config.user_klass.first
|
84
76
|
if test_user
|
85
77
|
# Brute force ensure test user has correct perms to signin
|
86
|
-
|
78
|
+
unless test_user.has_permission?("signin")
|
87
79
|
permissions = test_user.permissions || []
|
88
80
|
test_user.update_attribute(:permissions, permissions << "signin")
|
89
81
|
end
|
90
82
|
success!(test_user)
|
83
|
+
elsif Rails.env.test? && ENV["GDS_SSO_MOCK_INVALID"].present?
|
84
|
+
fail!(:invalid)
|
91
85
|
else
|
92
|
-
|
93
|
-
fail!(:invalid)
|
94
|
-
else
|
95
|
-
raise "GDS-SSO running in mock mode and no test user found. Normally we'd load the first user in the database. Create a user in the database."
|
96
|
-
end
|
86
|
+
raise "GDS-SSO running in mock mode and no test user found. Normally we'd load the first user in the database. Create a user in the database."
|
97
87
|
end
|
98
88
|
end
|
99
89
|
end
|
@@ -10,24 +10,25 @@ def user_update_json
|
|
10
10
|
"organisation_slug" => "justice-league",
|
11
11
|
"organisation_content_id" => "aae1319e-5788-4677-998c-f1a53af528d0",
|
12
12
|
"disabled" => false,
|
13
|
-
}
|
13
|
+
},
|
14
14
|
}.to_json
|
15
15
|
end
|
16
16
|
|
17
17
|
describe Api::UserController, type: :controller do
|
18
|
-
|
19
18
|
before :each do
|
20
19
|
user_to_update_attrs = [{
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
20
|
+
uid: "a1s2d3#{rand(10_000)}",
|
21
|
+
email: "old@domain.com",
|
22
|
+
name: "Moshua Jarshall",
|
23
|
+
permissions: %w[signin],
|
24
|
+
}]
|
25
|
+
|
26
|
+
signon_sso_push_user_attrs = [{
|
27
|
+
uid: "a1s2d3#{rand(10_000)}",
|
28
|
+
email: "ssopushuser@legit.com",
|
29
|
+
name: "SSO Push user",
|
30
|
+
permissions: %w[signin user_update_permission],
|
31
|
+
}]
|
31
32
|
|
32
33
|
@user_to_update = User.create!(*user_to_update_attrs)
|
33
34
|
@signon_sso_push_user = User.create!(*signon_sso_push_user_attrs)
|
@@ -36,13 +37,14 @@ describe Api::UserController, type: :controller do
|
|
36
37
|
describe "PUT update" do
|
37
38
|
it "should deny access to anybody but the API user (or a user with 'user_update_permission')" do
|
38
39
|
malicious_user = User.new({
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
uid: "2",
|
41
|
+
name: "User",
|
42
|
+
permissions: %w[signin],
|
43
|
+
})
|
42
44
|
|
43
|
-
request.env[
|
45
|
+
request.env["warden"] = double("stub warden", authenticate!: true, authenticated?: true, user: malicious_user)
|
44
46
|
|
45
|
-
request.env[
|
47
|
+
request.env["RAW_POST_DATA"] = user_update_json
|
46
48
|
put :update, body: user_update_json, params: { uid: @user_to_update.uid }
|
47
49
|
|
48
50
|
expect(response.status).to eq(403)
|
@@ -50,12 +52,12 @@ describe Api::UserController, type: :controller do
|
|
50
52
|
|
51
53
|
it "should create/update the user record in the same way as the OAuth callback" do
|
52
54
|
# Test that it authenticates
|
53
|
-
request.env[
|
54
|
-
expect(request.env[
|
55
|
-
expect(request.env[
|
56
|
-
expect(request.env[
|
55
|
+
request.env["warden"] = double("mock warden")
|
56
|
+
expect(request.env["warden"]).to receive(:authenticate!).at_least(:once).and_return(true)
|
57
|
+
expect(request.env["warden"]).to receive(:authenticated?).at_least(:once).and_return(true)
|
58
|
+
expect(request.env["warden"]).to receive(:user).at_least(:once).and_return(@signon_sso_push_user)
|
57
59
|
|
58
|
-
request.env[
|
60
|
+
request.env["RAW_POST_DATA"] = user_update_json
|
59
61
|
put :update, body: user_update_json, params: { uid: @user_to_update.uid }
|
60
62
|
|
61
63
|
@user_to_update.reload
|
@@ -64,18 +66,19 @@ describe Api::UserController, type: :controller do
|
|
64
66
|
expect(@user_to_update.permissions).to eq(["signin", "new permission"])
|
65
67
|
expect(@user_to_update.organisation_slug).to eq("justice-league")
|
66
68
|
expect(@user_to_update.organisation_content_id).to eq("aae1319e-5788-4677-998c-f1a53af528d0")
|
67
|
-
expect(response.content_type).to eq(
|
69
|
+
expect(response.content_type).to eq("text/plain")
|
68
70
|
end
|
69
71
|
end
|
70
72
|
|
71
73
|
describe "POST reauth" do
|
72
74
|
it "should deny access to anybody but the API user (or a user with 'user_update_permission')" do
|
73
75
|
malicious_user = User.new({
|
74
|
-
|
75
|
-
|
76
|
-
|
76
|
+
uid: "2",
|
77
|
+
name: "User",
|
78
|
+
permissions: %w[signin],
|
79
|
+
})
|
77
80
|
|
78
|
-
request.env[
|
81
|
+
request.env["warden"] = double("stub warden", authenticate!: true, authenticated?: true, user: malicious_user)
|
79
82
|
|
80
83
|
post :reauth, params: { uid: @user_to_update.uid }
|
81
84
|
|
@@ -83,29 +86,29 @@ describe Api::UserController, type: :controller do
|
|
83
86
|
end
|
84
87
|
|
85
88
|
it "should return success if user record doesn't exist" do
|
86
|
-
request.env[
|
87
|
-
expect(request.env[
|
88
|
-
expect(request.env[
|
89
|
-
expect(request.env[
|
89
|
+
request.env["warden"] = double("mock warden")
|
90
|
+
expect(request.env["warden"]).to receive(:authenticate!).at_least(:once).and_return(true)
|
91
|
+
expect(request.env["warden"]).to receive(:authenticated?).at_least(:once).and_return(true)
|
92
|
+
expect(request.env["warden"]).to receive(:user).at_least(:once).and_return(@signon_sso_push_user)
|
90
93
|
|
91
94
|
post :reauth, params: { uid: "nonexistent-user" }
|
92
95
|
|
93
96
|
expect(response.status).to eq(200)
|
94
|
-
expect(response.content_type).to eq(
|
97
|
+
expect(response.content_type).to eq("text/plain")
|
95
98
|
end
|
96
99
|
|
97
100
|
it "should set remotely_signed_out to true on the user" do
|
98
101
|
# Test that it authenticates
|
99
|
-
request.env[
|
100
|
-
expect(request.env[
|
101
|
-
expect(request.env[
|
102
|
-
expect(request.env[
|
102
|
+
request.env["warden"] = double("mock warden")
|
103
|
+
expect(request.env["warden"]).to receive(:authenticate!).at_least(:once).and_return(true)
|
104
|
+
expect(request.env["warden"]).to receive(:authenticated?).at_least(:once).and_return(true)
|
105
|
+
expect(request.env["warden"]).to receive(:user).at_least(:once).and_return(@signon_sso_push_user)
|
103
106
|
|
104
107
|
post :reauth, params: { uid: @user_to_update.uid }
|
105
108
|
|
106
109
|
@user_to_update.reload
|
107
110
|
expect(@user_to_update).to be_remotely_signed_out
|
108
|
-
expect(response.content_type).to eq(
|
111
|
+
expect(response.content_type).to eq("text/plain")
|
109
112
|
end
|
110
113
|
end
|
111
114
|
end
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
|
-
RSpec.describe GDS::SSO::ControllerMethods,
|
3
|
+
RSpec.describe GDS::SSO::ControllerMethods, "#authorise_user!" do
|
4
4
|
class ControllerSpy < ApplicationController
|
5
5
|
include GDS::SSO::ControllerMethods
|
6
6
|
|
@@ -18,54 +18,54 @@ RSpec.describe GDS::SSO::ControllerMethods, '#authorise_user!' do
|
|
18
18
|
let(:current_user) { double }
|
19
19
|
let(:expected_error) { GDS::SSO::ControllerMethods::PermissionDeniedException }
|
20
20
|
|
21
|
-
context
|
22
|
-
it
|
23
|
-
allow(current_user).to receive(:has_permission?).with(
|
21
|
+
context "with a single string permission argument" do
|
22
|
+
it "permits users with the required permission" do
|
23
|
+
allow(current_user).to receive(:has_permission?).with("good").and_return(true)
|
24
24
|
|
25
|
-
expect { ControllerSpy.new(current_user).authorise_user!(
|
25
|
+
expect { ControllerSpy.new(current_user).authorise_user!("good") }.not_to raise_error
|
26
26
|
end
|
27
27
|
|
28
|
-
it
|
29
|
-
allow(current_user).to receive(:has_permission?).with(
|
28
|
+
it "does not permit the users without the required permission" do
|
29
|
+
allow(current_user).to receive(:has_permission?).with("good").and_return(false)
|
30
30
|
|
31
|
-
expect { ControllerSpy.new(current_user).authorise_user!(
|
31
|
+
expect { ControllerSpy.new(current_user).authorise_user!("good") }.to raise_error(expected_error)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
context
|
36
|
-
it
|
37
|
-
allow(current_user).to receive(:has_permission?).with(
|
38
|
-
allow(current_user).to receive(:has_permission?).with(
|
35
|
+
context "with the `all_of` option" do
|
36
|
+
it "permits users with all of the required permissions" do
|
37
|
+
allow(current_user).to receive(:has_permission?).with("good").and_return(true)
|
38
|
+
allow(current_user).to receive(:has_permission?).with("bad").and_return(true)
|
39
39
|
|
40
|
-
expect { ControllerSpy.new(current_user).authorise_user!(all_of: %w
|
40
|
+
expect { ControllerSpy.new(current_user).authorise_user!(all_of: %w[good bad]) }.not_to raise_error
|
41
41
|
end
|
42
42
|
|
43
|
-
it
|
44
|
-
allow(current_user).to receive(:has_permission?).with(
|
45
|
-
allow(current_user).to receive(:has_permission?).with(
|
43
|
+
it "does not permit users without all of the required permissions" do
|
44
|
+
allow(current_user).to receive(:has_permission?).with("good").and_return(false)
|
45
|
+
allow(current_user).to receive(:has_permission?).with("bad").and_return(true)
|
46
46
|
|
47
|
-
expect { ControllerSpy.new(current_user).authorise_user!(all_of: %w
|
47
|
+
expect { ControllerSpy.new(current_user).authorise_user!(all_of: %w[good bad]) }.to raise_error(expected_error)
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
context
|
52
|
-
it
|
53
|
-
allow(current_user).to receive(:has_permission?).with(
|
54
|
-
allow(current_user).to receive(:has_permission?).with(
|
51
|
+
context "with the `any_of` option" do
|
52
|
+
it "permits users with any of the required permissions" do
|
53
|
+
allow(current_user).to receive(:has_permission?).with("good").and_return(true)
|
54
|
+
allow(current_user).to receive(:has_permission?).with("bad").and_return(false)
|
55
55
|
|
56
|
-
expect { ControllerSpy.new(current_user).authorise_user!(any_of: %w
|
56
|
+
expect { ControllerSpy.new(current_user).authorise_user!(any_of: %w[good bad]) }.not_to raise_error
|
57
57
|
end
|
58
58
|
|
59
|
-
it
|
59
|
+
it "does not permit users without any of the required permissions" do
|
60
60
|
allow(current_user).to receive(:has_permission?).and_return(false)
|
61
61
|
|
62
|
-
expect { ControllerSpy.new(current_user).authorise_user!(any_of: %w
|
62
|
+
expect { ControllerSpy.new(current_user).authorise_user!(any_of: %w[good bad]) }.to raise_error(expected_error)
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
-
context
|
67
|
-
it
|
68
|
-
expect { ControllerSpy.new(current_user).authorise_user!(whoops:
|
66
|
+
context "with none of `any_of` or `all_of`" do
|
67
|
+
it "raises an `ArgumentError`" do
|
68
|
+
expect { ControllerSpy.new(current_user).authorise_user!(whoops: "bad") }.to raise_error(ArgumentError)
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|