gds-sso 20.0.0 → 21.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.
@@ -0,0 +1,264 @@
1
+ require "spec_helper"
2
+
3
+ describe "Integration tests with a demo app", type: :request do
4
+ describe "accessing a route that doesn't require authentication" do
5
+ it "allows access" do
6
+ get "/not-restricted"
7
+ expect(response).to have_http_status(:success)
8
+ expect(response.body).to eq("jabberwocky")
9
+ end
10
+ end
11
+
12
+ describe "accessing a route the requires authentication" do
13
+ context "when GDS::SSO isn't configured to treat this as an explicit API request" do
14
+ it "redirects an unauthenticated request to sign-in" do
15
+ get "/restricted"
16
+ expect(response).to redirect_to("/auth/gds")
17
+ end
18
+
19
+ it "responds successfully for an authenticated user" do
20
+ authenticate_with_stub_signon
21
+
22
+ get "/restricted"
23
+ expect(response).to have_http_status(:success)
24
+ expect(response.body).to eq("restricted kablooie")
25
+ end
26
+
27
+ it "redirects to sign-in if a user is authenticated but remotely signed out" do
28
+ authenticate_with_stub_signon
29
+ User.last.set_remotely_signed_out!
30
+
31
+ get "/restricted"
32
+ expect(response).to redirect_to("/auth/gds")
33
+ end
34
+
35
+ it "redirects to sign-in if a user's session has expired" do
36
+ authenticate_with_stub_signon
37
+
38
+ travel_to(Time.now.utc + GDS::SSO::Config.auth_valid_for + 1.second) do
39
+ get "/restricted"
40
+ expect(response).to redirect_to("/auth/gds")
41
+ end
42
+ end
43
+
44
+ it "allows access when given a valid bearer token" do
45
+ stub_successful_signon_user_request
46
+
47
+ get "/restricted", headers: { "Authorization" => "Bearer 123" }
48
+ expect(response).to have_http_status(:success)
49
+ expect(response.body).to eq("restricted kablooie")
50
+ end
51
+
52
+ it "restricts access when given an invalid bearer token" do
53
+ stub_failed_signon_user_request
54
+
55
+ get "/restricted", headers: { "Authorization" => "Bearer invalid" }
56
+ expect(response).to have_http_status(:unauthorized)
57
+ expect_invalid_bearer_token_response(response)
58
+ end
59
+ end
60
+
61
+ context "when an application is configured as API only" do
62
+ before { allow(GDS::SSO::Config).to receive(:api_only).and_return(true) }
63
+
64
+ it "allows access when given a valid bearer token" do
65
+ stub_successful_signon_user_request
66
+
67
+ get "/restricted", headers: { "Authorization" => "Bearer 123" }
68
+ expect(response).to have_http_status(:success)
69
+ expect(response.body).to eq("restricted kablooie")
70
+ end
71
+
72
+ it "rejects a request without a bearer token" do
73
+ get "/restricted"
74
+ expect(response).to have_http_status(:unauthorized)
75
+ expect_missing_bearer_token_response(response)
76
+ end
77
+
78
+ it "restricts access for an invalid bearer token" do
79
+ stub_failed_signon_user_request
80
+
81
+ get "/restricted", headers: { "Authorization" => "Bearer invalid" }
82
+ expect(response).to have_http_status(:unauthorized)
83
+ expect_invalid_bearer_token_response(response)
84
+ end
85
+ end
86
+
87
+ context "when API requests are differentiated by api_request_matcher" do
88
+ it "treats a match as an API request" do
89
+ allow(GDS::SSO::Config)
90
+ .to receive(:api_request_matcher)
91
+ .and_return(->(request) { request.path == "/restricted" })
92
+
93
+ get "/restricted"
94
+ expect(response).to have_http_status(:unauthorized)
95
+ expect_missing_bearer_token_response(response)
96
+ end
97
+
98
+ it "treats a non-match as a non-API request" do
99
+ allow(GDS::SSO::Config)
100
+ .to receive(:api_request_matcher)
101
+ .and_return(->(_request) { false })
102
+
103
+ get "/restricted"
104
+ expect(response).to redirect_to("/auth/gds")
105
+ end
106
+ end
107
+ end
108
+
109
+ describe "when accessing routes without authentication and using the mock strategies" do
110
+ before { use_mock_strategies }
111
+
112
+ it "allows a user access without authentication" do
113
+ # non-bearer token mock requests require a user to exist
114
+ User.create!(
115
+ uid: SecureRandom.uuid,
116
+ email: "user@example.com",
117
+ name: "Example User",
118
+ permissions: [],
119
+ )
120
+
121
+ get "/restricted"
122
+ expect(response).to have_http_status(:success)
123
+ expect(response.body).to eq("restricted kablooie")
124
+ end
125
+
126
+ it "can be configured to fail authentication with an env var" do
127
+ ClimateControl.modify("GDS_SSO_MOCK_INVALID" => "1") do
128
+ get "/restricted"
129
+ expect(response).to redirect_to("/auth/gds")
130
+ end
131
+ end
132
+
133
+ it "allows an API request without a bearer token" do
134
+ allow(GDS::SSO::Config).to receive(:api_only).and_return(true)
135
+
136
+ get "/restricted"
137
+ expect(response).to have_http_status(:success)
138
+ expect(response.body).to eq("restricted kablooie")
139
+ end
140
+
141
+ it "can be configured to fail API authentication with an env var" do
142
+ allow(GDS::SSO::Config).to receive(:api_only).and_return(true)
143
+
144
+ ClimateControl.modify("GDS_SSO_MOCK_INVALID" => "1") do
145
+ get "/restricted"
146
+ expect(response).to have_http_status(:unauthorized)
147
+ end
148
+ end
149
+ end
150
+
151
+ describe "when accessing a route that requires permission" do
152
+ context "when GDS::SSO isn't configured to treat this as an explicit API request" do
153
+ it "allows a user with the permission to access the resource" do
154
+ authenticate_with_stub_signon(permissions: %w[execute])
155
+
156
+ get "/this-requires-execute-permission"
157
+ expect(response).to have_http_status(:success)
158
+ expect(response.body).to eq("you have execute permission")
159
+ end
160
+
161
+ it "restricts a user lacking the permission" do
162
+ authenticate_with_stub_signon
163
+
164
+ get "/this-requires-execute-permission"
165
+ expect(response).to have_http_status(:forbidden)
166
+ expect(response.body).to include("Sorry, you don't seem to have the execute permission for this app.")
167
+ end
168
+ end
169
+
170
+ context "when GDS::SSO is configured to treat the request as an API request" do
171
+ before { allow(GDS::SSO::Config).to receive(:api_only).and_return(true) }
172
+
173
+ it "allows a user with the permission to access the resource" do
174
+ stub_successful_signon_user_request(permissions: %w[execute])
175
+
176
+ get "/this-requires-execute-permission", headers: { "Authorization" => "Bearer 123" }
177
+ expect(response).to have_http_status(:success)
178
+ expect(response.body).to eq("you have execute permission")
179
+ end
180
+
181
+ it "restricts a user lacking the permission" do
182
+ stub_successful_signon_user_request
183
+
184
+ get "/this-requires-execute-permission", headers: { "Authorization" => "Bearer 123" }
185
+ expect(response).to have_http_status(:forbidden)
186
+ expect_json_response(response, { "message" => "Sorry, you don't seem to have the execute permission for this app." })
187
+ end
188
+ end
189
+
190
+ context "when using bearer token for auth with the mock strategy" do
191
+ before { use_mock_strategies }
192
+
193
+ it "automatically grants permissions configured in GDS:SSO::Config.additional_mock_permissions_required" do
194
+ allow(GDS::SSO::Config).to receive(:additional_mock_permissions_required).and_return(%w[execute])
195
+
196
+ stub_successful_signon_user_request
197
+
198
+ get "/this-requires-execute-permission", headers: { "Authorization" => "Bearer 123" }
199
+ expect(response).to have_http_status(:success)
200
+ expect(response.body).to eq("you have execute permission")
201
+ end
202
+
203
+ it "doesn't grant access without that config" do
204
+ allow(GDS::SSO::Config).to receive(:additional_mock_permissions_required).and_return(nil)
205
+
206
+ stub_successful_signon_user_request
207
+
208
+ get "/this-requires-execute-permission", headers: { "Authorization" => "Bearer 123" }
209
+ expect(response).to have_http_status(:forbidden)
210
+ expect_json_response(response, { "message" => "Sorry, you don't seem to have the execute permission for this app." })
211
+ end
212
+ end
213
+ end
214
+
215
+ context "when accessing a route that is restricted by the authorised user constraint" do
216
+ it "allows access when an authenticated user has correct permissions" do
217
+ authenticate_with_stub_signon(permissions: %w[constraint])
218
+
219
+ get "/constraint-restricted"
220
+ expect(response).to have_http_status(:success)
221
+ expect(response.body).to eq("constraint restricted")
222
+ end
223
+
224
+ it "redirects an unauthenticated request to signon" do
225
+ get "/constraint-restricted"
226
+
227
+ expect(response).to redirect_to("/auth/gds")
228
+ end
229
+
230
+ it "restricts access when an authenticated user does not have the correct permissions" do
231
+ authenticate_with_stub_signon
232
+
233
+ get "/constraint-restricted"
234
+ expect(response).to have_http_status(:forbidden)
235
+ end
236
+ end
237
+
238
+ def expect_missing_bearer_token_response(response)
239
+ expect(response.headers).to include("WWW-Authenticate" => 'Bearer error="invalid_request"')
240
+ expect_json_response(response, { "message" => "No bearer token was provided" })
241
+ end
242
+
243
+ def expect_invalid_bearer_token_response(response)
244
+ expect(response.headers).to include("WWW-Authenticate" => 'Bearer error="invalid_token"')
245
+ expect_json_response(response, { "message" => "Bearer token does not appear to be valid" })
246
+ end
247
+
248
+ def expect_json_response(response, json)
249
+ expect(response.media_type).to eq("application/json")
250
+ expect(response.parsed_body).to eq(json)
251
+ end
252
+
253
+ def use_mock_strategies
254
+ # Using allow_any_instance_of because it's hard to access the instance
255
+ # of the class used within the Rails middleware
256
+ allow_any_instance_of(Warden::Config).to receive(:[]).and_call_original
257
+ allow_any_instance_of(Warden::Config)
258
+ .to receive(:[])
259
+ .with(:default_strategies)
260
+ .and_return({ _all: %i[mock_gds_sso gds_bearer_token] })
261
+
262
+ allow(Warden::OAuth2.config).to receive(:token_model).and_return(GDS::SSO::MockBearerToken)
263
+ end
264
+ end
data/spec/spec_helper.rb CHANGED
@@ -2,7 +2,7 @@
2
2
  # Bad things happen if we don't ;-)
3
3
  ENV["GDS_SSO_STRATEGY"] = "real"
4
4
 
5
- require "capybara/rspec"
5
+ require "climate_control"
6
6
  require "webmock/rspec"
7
7
  require "combustion"
8
8
 
@@ -12,15 +12,10 @@ Combustion.initialize! :all do
12
12
  end
13
13
 
14
14
  require "rspec/rails"
15
- require "capybara/rails"
16
15
  WebMock.disable_net_connect!
17
16
 
18
17
  Dir[File.join(File.dirname(__FILE__), "support/**/*.rb")].sort.each { |f| require f }
19
18
 
20
- Capybara.register_driver :rack_test do |app|
21
- Capybara::RackTest::Driver.new(app, follow_redirects: false)
22
- end
23
-
24
19
  RSpec.configure do |config|
25
20
  config.run_all_when_everything_filtered = true
26
21
  config.filter_run :focus
@@ -32,6 +27,20 @@ RSpec.configure do |config|
32
27
  # --seed 1234
33
28
  config.order = "random"
34
29
 
30
+ config.include ActiveSupport::Testing::TimeHelpers
35
31
  config.include Warden::Test::Helpers
36
- config.include Capybara::DSL
32
+ config.include RequestHelpers, type: :request
33
+ config.before(:each, type: :request) do
34
+ # we reload routes each test as GDS::SSO::Config affects what routes are
35
+ # available, we only want to run this once routes are loaded otherwise
36
+ # we can lose app routes
37
+ routes_reloader = Rails.application.routes_reloader
38
+
39
+ # Routes changed in Rails 8 to be lazily loaded so this wasn't a problem
40
+ # before Rails 8.
41
+ # TODO: remove this line once Rails 7 support is removed
42
+ next unless routes_reloader.respond_to?(:loaded)
43
+
44
+ routes_reloader.reload! if routes_reloader.loaded
45
+ end
37
46
  end
@@ -0,0 +1,45 @@
1
+ module RequestHelpers
2
+ def authenticate_with_stub_signon(permissions: [])
3
+ state = request_to_establish_oauth_state
4
+
5
+ stub_signon_oauth_token_request
6
+ stub_successful_signon_user_request(permissions:)
7
+
8
+ get "/auth/gds/callback?code=code&state=#{state}"
9
+ expect(response).to have_http_status(:redirect)
10
+ end
11
+
12
+ def request_to_establish_oauth_state
13
+ get "/auth/gds"
14
+ expect(response).to have_http_status(:redirect)
15
+ location = URI.parse(response.location)
16
+ query = Rack::Utils.parse_query(location.query)
17
+ query.fetch("state")
18
+ end
19
+
20
+ def stub_signon_oauth_token_request
21
+ stub_request(:post, "http://signon/oauth/access_token")
22
+ .to_return(body: { access_token: "token" }.to_json,
23
+ headers: { content_type: "application/json" })
24
+ end
25
+
26
+ def stub_successful_signon_user_request(permissions: [])
27
+ stub_request(:get, "http://signon/user.json?client_id=gds-sso-test")
28
+ .to_return(
29
+ body: {
30
+ user: {
31
+ uid: "123",
32
+ email: "test-user@example.com",
33
+ name: "Test User",
34
+ permissions:,
35
+ },
36
+ }.to_json,
37
+ headers: { content_type: "application/json" },
38
+ )
39
+ end
40
+
41
+ def stub_failed_signon_user_request
42
+ stub_request(:get, "http://signon/user.json?client_id=gds-sso-test")
43
+ .to_return(status: 401)
44
+ end
45
+ end
@@ -1,17 +1,89 @@
1
1
  require "spec_helper"
2
2
  require "gds-sso/api_access"
3
+ require "rack/mock_request"
3
4
 
4
5
  describe GDS::SSO::ApiAccess do
5
- it "should not consider IE7 accept header as an api call" do
6
- ie7_accept_header = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, " \
7
- "application/x-shockwave-flash, application/xaml+xml, application/x-ms-xbap, " \
8
- "application/x-ms-application, */*"
9
- expect(GDS::SSO::ApiAccess.api_call?("HTTP_ACCEPT" => ie7_accept_header)).to be_falsey
6
+ describe ".api_call?" do
7
+ it "returns true if the rack env has already been tagged as an api_call" do
8
+ expect(described_class.api_call?({ "gds_sso.api_call" => true })).to be(true)
9
+ end
10
+
11
+ it "returns false if the rack env has already been tagged as not an api_call" do
12
+ expect(described_class.api_call?({ "gds_sso.api_call" => false })).to be(false)
13
+ end
14
+
15
+ it "returns true if GDS::SSO has been configured as api_only" do
16
+ allow(GDS::SSO::Config).to receive(:api_only).and_return(true)
17
+
18
+ expect(described_class.api_call?({})).to be(true)
19
+ end
20
+
21
+ context "when an api_request_matcher has been configured" do
22
+ before do
23
+ allow(GDS::SSO::Config)
24
+ .to receive(:api_request_matcher)
25
+ .and_return(->(request) { request.path == "/api" })
26
+ end
27
+
28
+ it "returns true if the request matches the api_request_matcher" do
29
+ env = Rack::MockRequest.env_for("/api")
30
+ expect(described_class.api_call?(env)).to be(true)
31
+ end
32
+
33
+ it "returns true if the request is for GDS SSO API at default location" do
34
+ env = Rack::MockRequest.env_for("/auth/gds/api/#{SecureRandom.uuid}")
35
+ expect(described_class.api_call?(env)).to be(true)
36
+ end
37
+
38
+ it "returns true if it matches a configured gds_sso_api_request_matcher" do
39
+ allow(GDS::SSO::Config)
40
+ .to receive(:gds_sso_api_request_matcher)
41
+ .and_return(->(request) { request.path == "/special/gds-sso/route" })
42
+
43
+ env = Rack::MockRequest.env_for("/special/gds-sso/route")
44
+ expect(described_class.api_call?(env)).to be(true)
45
+ end
46
+
47
+ it "returns false if the request doesn't match the gds_sso_api_request_matcher or api_request_matcher" do
48
+ allow(GDS::SSO::Config).to receive(:gds_sso_api_request_matcher).and_return(nil)
49
+
50
+ env = Rack::MockRequest.env_for("/other")
51
+ expect(described_class.api_call?(env)).to be(false)
52
+ end
53
+ end
54
+
55
+ context "when an api_request_matcher has not been configured" do
56
+ it "returns true if a bearer token is present" do
57
+ env = { "HTTP_AUTHORIZATION" => "Bearer 1234:5678" }
58
+ expect(described_class.api_call?(env)).to be(true)
59
+ end
60
+
61
+ it "returns false if nothing indicates an API call" do
62
+ expect(described_class.api_call?({})).to be(false)
63
+ end
64
+ end
10
65
  end
11
66
 
12
- context "with a bearer token" do
13
- it "it is considered an api call" do
14
- expect(GDS::SSO::ApiAccess.api_call?("HTTP_AUTHORIZATION" => "Bearer deadbeef12345678")).to be_truthy
67
+ describe ".bearer_token" do
68
+ it "returns a bearer token set in a HTTP_AUTHORIZATION header" do
69
+ env = { "HTTP_AUTHORIZATION" => "Bearer 1234:5678" }
70
+ expect(described_class.bearer_token(env)).to eq("1234:5678")
71
+ end
72
+
73
+ it "returns nil for an empty bearer token in the HTTP_AUTHORIZATION header" do
74
+ env = { "HTTP_AUTHORIZATION" => "Bearer " }
75
+ expect(described_class.bearer_token(env)).to be_nil
76
+ end
77
+
78
+ it "supports all the authorization headers configured in Rack::Auth::AbstractRequest::AUTHORIZATION_KEYS" do
79
+ Rack::Auth::AbstractRequest::AUTHORIZATION_KEYS.each do |header|
80
+ env = { header => "Bearer 1234" }
81
+ expect(described_class.bearer_token(env)).to eq("1234")
82
+ end
83
+ end
84
+
85
+ it "returns nil if a bearer token isn't set" do
86
+ expect(described_class.bearer_token({})).to be_nil
15
87
  end
16
88
  end
17
89
  end
@@ -3,48 +3,25 @@ require "gds-sso/authorised_user_constraint"
3
3
 
4
4
  describe GDS::SSO::AuthorisedUserConstraint do
5
5
  before do
6
+ allow(GDS::SSO).to receive(:authenticate_user!).and_return(user)
6
7
  allow(GDS::SSO::AuthoriseUser).to receive(:call).and_return(true)
7
8
  end
8
9
 
9
10
  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 }
11
+ let(:user) { TestUser.new }
12
+ let(:warden) { instance_double("Warden::Proxy") }
21
13
  let(:request) { double("request", env: { "warden" => warden }) }
22
14
 
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!)
15
+ it "authenticates the user" do
16
+ expect(GDS::SSO).to receive(:authenticate_user!).with(warden)
26
17
 
27
18
  described_class.new(%w[signin]).matches?(request)
28
19
  end
29
20
 
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!)
21
+ it "authorises the user" do
22
+ expect(GDS::SSO::AuthoriseUser).to receive(:call).with(user, %w[signin])
45
23
 
46
- described_class.new(%w[signin]).matches?(request)
47
- end
24
+ described_class.new(%w[signin]).matches?(request)
48
25
  end
49
26
  end
50
27
  end
@@ -25,5 +25,13 @@ describe GDS::SSO::BearerToken do
25
25
 
26
26
  expect(same_user_again.id).to eql(created_user.id)
27
27
  end
28
+
29
+ it "returns nil for a nil token string" do
30
+ expect(described_class.locate(nil)).to be_nil
31
+ end
32
+
33
+ it "returns nil for an empty token string" do
34
+ expect(described_class.locate("")).to be_nil
35
+ end
28
36
  end
29
37
  end
@@ -0,0 +1,37 @@
1
+ require "spec_helper"
2
+
3
+ describe GDS::SSO do
4
+ describe "#authenticate_user!" do
5
+ let(:user) { TestUser.new }
6
+ let(:warden) do
7
+ instance_double("Warden::Proxy",
8
+ authenticate!: true,
9
+ authenticated?: false,
10
+ user:)
11
+ end
12
+
13
+ context "when a user is not already authenticated" do
14
+ it "authenticates the user and returns the user object" do
15
+ expect(described_class.authenticate_user!(warden)).to be(user)
16
+ expect(warden).to have_received(:authenticate!)
17
+ end
18
+ end
19
+
20
+ context "when a user is already authenticated and not remotely signed out" do
21
+ it "doesn't reauthenticate the user" do
22
+ allow(warden).to receive(:authenticated?).and_return(true)
23
+ expect(described_class.authenticate_user!(warden)).to be(user)
24
+
25
+ expect(warden).not_to have_received(:authenticate!)
26
+ end
27
+ end
28
+
29
+ context "when a user is already authenticated and remotely signed out" do
30
+ it "authenticates the user again" do
31
+ user.remotely_signed_out = true
32
+ expect(described_class.authenticate_user!(warden)).to be(user)
33
+ expect(warden).to have_received(:authenticate!)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -2,21 +2,60 @@ require "spec_helper"
2
2
  require "gds-sso/bearer_token"
3
3
 
4
4
  describe GDS::SSO::MockBearerToken do
5
- it "updates the permissions of the user" do
6
- # setup - ensure extra mock permissions required are nil and
7
- # call .locate to create the dummy user initially
8
- GDS::SSO::Config.additional_mock_permissions_required = nil
9
- dummy_user = subject.locate("ABC")
10
- expect(dummy_user.permissions).to match_array(%w[signin])
11
-
12
- # add an extra permission
13
- GDS::SSO::Config.additional_mock_permissions_required = "extra_permission"
14
-
15
- # ensure the dummy user is returned
16
- expect(GDS::SSO).to receive(:test_user).and_return(dummy_user)
17
-
18
- # call .locate again...this should update our permissions
19
- dummy_user_two = subject.locate("ABC")
20
- expect(dummy_user_two.permissions).to match_array(%w[signin extra_permission])
5
+ describe ".locate" do
6
+ it "returns a GDS::SSO.test_user if one is set" do
7
+ test_user = TestUser.new
8
+ allow(GDS::SSO).to receive(:test_user).and_return(test_user)
9
+
10
+ expect(described_class.locate("anything")).to be(test_user)
11
+ end
12
+
13
+ it "returns nil if ENV['GDS_SSO_MOCK_INVALID'] is set" do
14
+ ClimateControl.modify("GDS_SSO_MOCK_INVALID" => "1") do
15
+ expect(described_class.locate("anything")).to be_nil
16
+ end
17
+ end
18
+
19
+ it "doesn't modify the permissions of GDS::SSO.test_user" do
20
+ test_user = TestUser.new(permissions: [])
21
+ allow(GDS::SSO).to receive(:test_user).and_return(test_user)
22
+ allow(GDS::SSO::Config).to receive(:permissions_for_dummy_api_user)
23
+ .and_return(%w[signin extra_permission])
24
+
25
+ expect(described_class.locate("anything")).to be(test_user)
26
+ expect(test_user.permissions).not_to include("extra_permission")
27
+ end
28
+
29
+ it "returns a user with dummyapiuser@domain.com if one exists" do
30
+ test_user = TestUser.new
31
+ allow(GDS::SSO::Config).to receive(:user_klass).and_return(TestUser)
32
+ allow(TestUser).to receive(:where).and_return([test_user])
33
+
34
+ expect(described_class.locate("anything")).to be(test_user)
35
+ expect(TestUser).to have_received(:where).with(email: "dummyapiuser@domain.com")
36
+ end
37
+
38
+ it "creates a user with dummyapiuser@domain.com if one does not exist" do
39
+ allow(GDS::SSO::Config).to receive(:user_klass).and_return(TestUser)
40
+ allow(GDS::SSO::Config).to receive(:additional_mock_permissions_required).and_return(nil)
41
+ allow(TestUser).to receive(:where).and_return([])
42
+
43
+ test_user = described_class.locate("anything")
44
+ expect(test_user).to be_an_instance_of(TestUser)
45
+ expect(test_user).to have_attributes(email: "dummyapiuser@domain.com",
46
+ name: "Dummy API user created by gds-sso",
47
+ permissions: %w[signin])
48
+ end
49
+
50
+ it "uses GDS::SSO::Config to overwrite any existing permissions" do
51
+ test_user = TestUser.new(permissions: %w[signin other_permission])
52
+ allow(GDS::SSO::Config).to receive(:user_klass).and_return(TestUser)
53
+ allow(TestUser).to receive(:where).and_return([test_user])
54
+ allow(GDS::SSO::Config).to receive(:permissions_for_dummy_api_user)
55
+ .and_return(%w[signin extra_permission])
56
+
57
+ test_user = described_class.locate("anything")
58
+ expect(test_user.permissions).to match_array(%w[signin extra_permission])
59
+ end
21
60
  end
22
61
  end
@@ -14,11 +14,12 @@ describe Warden::SessionSerializer do
14
14
 
15
15
  describe "serializing a user" do
16
16
  it "should return the uid and an ISO 8601 string timestamp" do
17
- Timecop.freeze
18
- result = @serializer.serialize(@user)
17
+ freeze_time do
18
+ result = @serializer.serialize(@user)
19
19
 
20
- expect(result).to eq([1234, Time.now.utc.iso8601])
21
- expect(result.last).to be_a(String)
20
+ expect(result).to eq([1234, Time.now.utc.iso8601])
21
+ expect(result.last).to be_a(String)
22
+ end
22
23
  end
23
24
 
24
25
  it "should return nil if the user has no uid" do