cassette 1.0.18 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +89 -12
  3. data/lib/cassette/authentication/authorities.rb +34 -30
  4. data/lib/cassette/authentication/cache.rb +22 -18
  5. data/lib/cassette/authentication/filter.rb +52 -33
  6. data/lib/cassette/authentication/user.rb +20 -16
  7. data/lib/cassette/authentication.rb +39 -27
  8. data/lib/cassette/cache.rb +2 -2
  9. data/lib/cassette/client/cache.rb +39 -35
  10. data/lib/cassette/client.rb +5 -4
  11. data/lib/cassette/http/parsed_response.rb +20 -0
  12. data/lib/cassette/http/request.rb +44 -0
  13. data/lib/cassette/http/ticket_response.rb +48 -0
  14. data/lib/cassette/http.rb +8 -0
  15. data/lib/cassette/rubycas/helper.rb +2 -8
  16. data/lib/cassette/rubycas/routing_constraint.rb +23 -0
  17. data/lib/cassette/rubycas/single_sign_out_constraint.rb +8 -8
  18. data/lib/cassette/rubycas/user_factory.rb +14 -0
  19. data/lib/cassette/rubycas.rb +2 -0
  20. data/lib/cassette/version.rb +2 -2
  21. data/lib/cassette.rb +12 -50
  22. data/spec/cassette/authentication/authorities_spec.rb +1 -1
  23. data/spec/cassette/authentication/cache_spec.rb +40 -4
  24. data/spec/cassette/authentication/filter_spec.rb +106 -36
  25. data/spec/cassette/authentication/user_factory_spec.rb +42 -0
  26. data/spec/cassette/authentication/user_spec.rb +4 -3
  27. data/spec/cassette/authentication_spec.rb +24 -12
  28. data/spec/cassette/cache_spec.rb +0 -2
  29. data/spec/cassette/client/cache_spec.rb +1 -1
  30. data/spec/cassette/client_spec.rb +319 -0
  31. data/spec/cassette/errors_spec.rb +1 -1
  32. data/spec/cassette/http/parsed_response_spec.rb +27 -0
  33. data/spec/cassette/http/request_spec.rb +41 -0
  34. data/spec/cassette/http/ticket_response_spec.rb +41 -0
  35. data/spec/cassette/rubycas/routing_constraint_spec.rb +84 -0
  36. data/spec/cassette_spec.rb +36 -0
  37. data/spec/integration/cas/client_spec.rb +0 -3
  38. data/spec/spec_helper.rb +5 -0
  39. data/spec/support/controllers/controller_mock.rb +19 -0
  40. metadata +98 -36
  41. data/spec/cas_spec.rb +0 -78
@@ -1,27 +1,39 @@
1
1
  # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
2
  describe Cassette::Authentication do
6
3
  let(:cache) { instance_double(Cassette::Authentication::Cache) }
7
4
  let(:http) { class_double(Cassette) }
8
5
 
9
- subject do
6
+ subject(:authentication) do
10
7
  Cassette::Authentication.new(cache: cache, http_client: http)
11
8
  end
12
9
 
13
10
  describe '#ticket_user' do
11
+ subject(:ticket_user) { authentication.ticket_user(ticket) }
12
+
13
+ let(:ticket) { 'ticket' }
14
+ let(:cached_value) { 'cached_value' }
15
+ let(:service) { 'test-api.example.org' }
16
+
14
17
  context 'when cached' do
15
- it 'returns the cached value when cached' do
16
- cached = double('cached')
18
+ before do
19
+ allow(cache).to receive(:fetch_authentication)
20
+ .and_return(cached_value)
21
+ end
22
+
23
+ it { is_expected.to eql(cached_value) }
24
+ it 'calls Cache#fetch_authentication with ticket and service' do
25
+ expect(cache).to receive(:fetch_authentication)
26
+ .with(ticket, service)
27
+
28
+ ticket_user
29
+ end
17
30
 
18
- expect(cache).to receive(:fetch_authentication) do |ticket, &block|
19
- expect(ticket).to eql('ticket')
31
+ it 'passes a block to Cache#fetch_authentication' do
32
+ expect(cache).to receive(:fetch_authentication) do |*, &block|
20
33
  expect(block).to be_present
21
- cached
22
34
  end
23
35
 
24
- expect(subject.ticket_user('ticket')).to eql(cached)
36
+ ticket_user
25
37
  end
26
38
  end
27
39
 
@@ -44,7 +56,7 @@ describe Cassette::Authentication do
44
56
  end
45
57
 
46
58
  it 'returns nil' do
47
- expect(subject.ticket_user('ticket')).to be_nil
59
+ expect(ticket_user).to be_nil
48
60
  end
49
61
  end
50
62
 
@@ -55,7 +67,7 @@ describe Cassette::Authentication do
55
67
  end
56
68
 
57
69
  it 'returns an User' do
58
- expect(subject.ticket_user('ticket')).to be_instance_of(Cassette::Authentication::User)
70
+ expect(ticket_user).to be_instance_of(Cassette::Authentication::User)
59
71
  end
60
72
  end
61
73
  end
@@ -1,7 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Cassette::Cache do
6
4
  subject do
7
5
  c = Class.new
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'spec_helper'
3
+
4
4
 
5
5
  describe Cassette::Client::Cache do
6
6
  pending
@@ -0,0 +1,319 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Cassette::Client do
6
+ let(:http) { class_double(Cassette) }
7
+ let(:cache) { instance_double(Cassette::Client::Cache) }
8
+ let(:options) do
9
+ {
10
+ http_client: http,
11
+ cache: cache,
12
+ }
13
+ end
14
+
15
+ let(:client) do
16
+ Cassette::Client.new(options)
17
+ end
18
+
19
+ describe '#health_check' do
20
+ subject { client.health_check }
21
+
22
+ it 'raises any Error' do
23
+ expect(client).to receive(:st_for).with(anything).and_raise('Failure')
24
+
25
+ expect { subject }.to raise_error('Failure')
26
+ end
27
+
28
+ it 'tries to generate a ST' do
29
+ expect(client).to receive(:st_for).with(an_instance_of(String)).and_return('ST-Something')
30
+
31
+ expect(subject).to eq 'ST-Something'
32
+ end
33
+ end
34
+
35
+ describe '#tgt' do
36
+ subject { client.tgt('user', 'pass', force) }
37
+
38
+ context 'http client interactions' do
39
+ let(:force) { true }
40
+ let(:response) { Faraday::Response.new }
41
+
42
+ before do
43
+ allow(cache).to receive(:fetch_tgt).and_yield
44
+ allow(http).to receive(:post) { response }
45
+ end
46
+
47
+ it 'extracts the tgt from the Location header' do
48
+ tgt = 'TGT-something'
49
+ allow(response).to receive(:headers).and_return('Location' => "/tickets/#{tgt}")
50
+
51
+ expect(subject).to eq tgt
52
+ end
53
+
54
+ it 'posts the username and password' do
55
+ subject
56
+ expect(http).to have_received(:post).with(anything, username: 'user', password: 'pass')
57
+ end
58
+
59
+ it 'posts to a /v1/tickets uri' do
60
+ subject
61
+ expect(http).to have_received(:post).with(%r{/v1/tickets\z}, instance_of(Hash))
62
+ end
63
+ end
64
+
65
+ context 'when tgt is not cached' do
66
+ let(:tgt) { 'TGT-Something-example' }
67
+ let(:force) { false }
68
+
69
+ before do
70
+ allow(cache).to receive(:fetch_tgt) do |opts, &_block|
71
+ expect(opts[:force]).to eq false
72
+ tgt
73
+ end
74
+
75
+ allow(http).to receive(:post)
76
+ end
77
+
78
+ it { is_expected.to eq tgt }
79
+ end
80
+
81
+ context 'with a cached tgt' do
82
+ let(:tgt) { 'TGT-Something-example' }
83
+
84
+ before do
85
+ allow(cache).to receive(:fetch_tgt).with(hash_including(force: force))
86
+ .and_return(tgt)
87
+
88
+ allow(http).to receive(:post)
89
+ end
90
+
91
+ shared_context 'force control' do
92
+ it { is_expected.to eq tgt }
93
+
94
+ it 'forwards force to the cache' do
95
+ subject
96
+ expect(cache).to have_received(:fetch_tgt).with(hash_including(force: force))
97
+ end
98
+ end
99
+
100
+ context 'and no force' do
101
+ let(:force) { false }
102
+
103
+ include_context 'force control'
104
+ end
105
+
106
+ context 'and using the force' do
107
+ let(:force) { true }
108
+
109
+ include_context 'force control'
110
+ end
111
+ end
112
+ end
113
+
114
+ describe '#st' do
115
+ subject { client.st(tgt_param, service, force) }
116
+ let(:service) { 'example.org' }
117
+ let(:tgt) { 'TGT-Example' }
118
+ let(:st) { 'ST-Something-example' }
119
+ let(:tgt_param) { tgt }
120
+
121
+ shared_context 'http client interactions' do
122
+ let(:force) { true }
123
+ let(:response) { Faraday::Response.new }
124
+
125
+ before do
126
+ allow(cache).to receive(:fetch_st).and_yield
127
+ allow(http).to receive(:post) { response }
128
+ end
129
+
130
+ it 'extracts the tgt from the Location header' do
131
+ allow(response).to receive(:body) { st }
132
+
133
+ expect(subject).to eq st
134
+ end
135
+
136
+ it 'posts the service' do
137
+ subject
138
+
139
+ expect(http).to have_received(:post).with(anything, service: service)
140
+ end
141
+
142
+ it 'posts to the tgt uri' do
143
+ subject
144
+
145
+ expect(http).to have_received(:post).with(%r{/#{tgt}\z}, instance_of(Hash))
146
+ end
147
+ end
148
+
149
+ context 'when tgt is a string' do
150
+ let(:tgt_param) { tgt }
151
+
152
+ it_behaves_like 'http client interactions'
153
+ end
154
+
155
+ context 'when tgt is a callable' do
156
+ let(:tgt_param) { ->{ tgt } }
157
+
158
+ it_behaves_like 'http client interactions'
159
+ end
160
+
161
+ context 'cache control' do
162
+ before do
163
+ allow(cache).to receive(:fetch_st).with(service, hash_including(force: force))
164
+ .and_return(st)
165
+ end
166
+
167
+ shared_context 'controlling the force' do
168
+ it { is_expected.to eq st }
169
+
170
+ it 'forwards force to the cache' do
171
+ subject
172
+
173
+ expect(cache).to have_received(:fetch_st).with(service, hash_including(force: force))
174
+ end
175
+ end
176
+
177
+ context 'not using the force' do
178
+ let(:force) { false }
179
+
180
+ include_context 'controlling the force'
181
+ end
182
+
183
+ context 'using the force' do
184
+ let(:force) { true }
185
+
186
+ include_context 'controlling the force'
187
+ end
188
+ end
189
+ end
190
+
191
+ describe '#st_for' do
192
+ subject { client.st_for(service) }
193
+ let(:service) { 'example.org' }
194
+ let(:cached_tgt) { 'TGT-Something' }
195
+ let(:tgt) { 'TGT-Something-NEW' }
196
+ let(:st) { 'ST-For-Something' }
197
+
198
+ context 'when tgt and st are not cached' do
199
+ before do
200
+ allow(cache).to receive(:fetch_tgt).with(hash_including(force: false)).and_yield
201
+ allow(cache).to receive(:fetch_st).with(service, hash_including(force: false)).and_yield
202
+
203
+ allow(http).to receive(:post)
204
+ .with(%r{/v1/tickets\z}, username: Cassette.config.username, password: Cassette.config.password)
205
+ .and_return(tgt_response)
206
+
207
+ allow(http).to receive(:post).with(%r{/v1/tickets/#{tgt}\z}, service: service)
208
+ .and_return(st_response)
209
+ end
210
+
211
+ let(:st_response) { Faraday::Response.new(body: st) }
212
+ let(:tgt_response) { Faraday::Response.new(response_headers: {'Location' => "/v1/tickets/#{tgt}"}) }
213
+
214
+ it 'returns the generated st' do
215
+ expect(subject).to eq st
216
+ end
217
+
218
+ it 'generates an ST' do
219
+ subject
220
+
221
+ expect(http).to have_received(:post).with(%r{/v1/tickets/#{tgt}\z}, service: service)
222
+ end
223
+
224
+ it 'generates a TGT' do
225
+ subject
226
+
227
+ expect(http).to have_received(:post)
228
+ .with(%r{/v1/tickets\z}, username: Cassette.config.username, password: Cassette.config.password)
229
+ end
230
+ end
231
+
232
+ context 'when tgt is cached but st is not' do
233
+ before do
234
+ allow(cache).to receive(:fetch_tgt).with(hash_including(force: false)).and_return(tgt)
235
+ allow(cache).to receive(:fetch_st).with(service, hash_including(force: false)).and_yield
236
+
237
+ allow(http).to receive(:post).with(%r{/v1/tickets/#{tgt}\z}, service: service)
238
+ .and_return(st_response)
239
+ end
240
+
241
+ let(:st_response) { Faraday::Response.new(body: st) }
242
+
243
+ it 'returns the generated st' do
244
+ expect(subject).to eq st
245
+ end
246
+
247
+ it 'generates an ST' do
248
+ subject
249
+
250
+ expect(http).to have_received(:post).with(%r{/v1/tickets/#{tgt}\z}, service: service)
251
+ end
252
+ end
253
+
254
+ context 'when st is cached' do
255
+ before do
256
+ allow(cache).to receive(:fetch_st).with(service, hash_including(force: false)).and_return(st)
257
+ end
258
+
259
+ it 'returns the cached value' do
260
+ expect(subject).to eq st
261
+ end
262
+ end
263
+
264
+ context 'when tgt is expired' do
265
+ before do
266
+ allow(cache).to receive(:fetch_tgt).with(hash_including(force: false)).and_return(cached_tgt)
267
+ allow(cache).to receive(:fetch_tgt).with(hash_including(force: true)).and_yield
268
+ allow(cache).to receive(:fetch_st).and_yield
269
+
270
+ allow(http).to receive(:post).with(%r{/v1/tickets/#{cached_tgt}\z}, service: service)
271
+ .and_raise(Cassette::Errors::NotFound)
272
+
273
+ allow(http).to receive(:post)
274
+ .with(%r{/v1/tickets\z}, username: Cassette.config.username, password: Cassette.config.password)
275
+ .and_return(tgt_response)
276
+
277
+ allow(http).to receive(:post).with(%r{/v1/tickets/#{tgt}\z}, service: service)
278
+ .and_return(st_response)
279
+ end
280
+
281
+ let(:tgt_response) { Faraday::Response.new(response_headers: {'Location' => "/v1/tickets/#{tgt}"}) }
282
+ let(:st_response) { Faraday::Response.new(body: st) }
283
+
284
+ it 'calls #fetch_st twice' do
285
+ subject
286
+
287
+ expect(cache).to have_received(:fetch_st).twice
288
+ end
289
+
290
+ it 'calls #fetch_tgt without forcing' do
291
+ subject
292
+
293
+ expect(cache).to have_received(:fetch_tgt).with(force: false)
294
+ end
295
+
296
+ it 'calls #fetch_tgt forcing' do
297
+ subject
298
+
299
+ expect(cache).to have_received(:fetch_tgt).with(force: true)
300
+ end
301
+
302
+ it 'tries to generate a ST with the expired TGT' do
303
+ subject
304
+
305
+ expect(http).to have_received(:post).with(%r{/v1/tickets/#{cached_tgt}\z}, service: service)
306
+ end
307
+
308
+ it 'retries to generate a ST with the new TGT' do
309
+ subject
310
+
311
+ expect(http).to have_received(:post).with(%r{/v1/tickets/#{tgt}\z}, service: service)
312
+ end
313
+
314
+ it 'returns a brand new tgt' do
315
+ expect(subject).to eq st
316
+ end
317
+ end
318
+ end
319
+ end
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'spec_helper'
3
+
4
4
 
5
5
  describe Cassette::Errors do
6
6
  describe Cassette::Errors::Base do
@@ -0,0 +1,27 @@
1
+ describe Cassette::Http::ParsedResponse do
2
+ subject(:parsed_response) { described_class.new(xml_response) }
3
+
4
+ let(:xml_response) { fixture('cas/success.xml') }
5
+
6
+ let(:hash_response) do
7
+ {
8
+ "serviceResponse" => {
9
+ "authenticationSuccess" => {
10
+ "user"=> {
11
+ "__content__" => "test-user"
12
+ },
13
+ "attributes" => {
14
+ "authorities" => {
15
+ "__content__" => "[CUPOM, AUDITING,]"
16
+ },
17
+ "cn" => {
18
+ "__content__" => "Test System"
19
+ }
20
+ }
21
+ }
22
+ }
23
+ }
24
+ end
25
+
26
+ it { is_expected.to eq(hash_response) }
27
+ end
@@ -0,0 +1,41 @@
1
+ describe Cassette::Http::Request do
2
+ subject(:request) { described_class }
3
+
4
+ describe '.post' do
5
+ subject(:post) { request.post(uri, payload) }
6
+
7
+ let(:uri) { 'http://example.org/' }
8
+ let(:payload) { { ping: :pong } }
9
+ let(:response) do
10
+ {
11
+ headers: { 'Content-Type' => 'application/json' },
12
+ body: { ok: :true }.to_json,
13
+ status: 200
14
+ }
15
+ end
16
+
17
+ before { stub_request(:post, uri).to_return(response) }
18
+
19
+ it 'performs a http post request with the proper params'do
20
+ post
21
+
22
+ expect(a_request(:post, uri).with(body: 'ping=pong')).to have_been_made
23
+ end
24
+
25
+ it do
26
+ is_expected.to have_attributes(
27
+ headers: { 'Content-Type' => 'application/json' },
28
+ body: '{"ok":"true"}',
29
+ status: 200
30
+ )
31
+ end
32
+
33
+ context 'when response has an error status code' do
34
+ let(:response) { { status: 500 } }
35
+
36
+ it 'raises an exception' do
37
+ expect { post }.to raise_error(Cassette::Errors::InternalServerError)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ describe Cassette::Http::TicketResponse do
2
+ subject(:ticket_response) { described_class.new(xml_response) }
3
+
4
+ let(:xml_response) { fixture('cas/success.xml') }
5
+
6
+ describe '#login' do
7
+ subject(:login) { ticket_response.login }
8
+
9
+ it { is_expected.to eq('test-user') }
10
+
11
+ context "when response isn't successful" do
12
+ let(:xml_response) { fixture('cas/fail.xml') }
13
+
14
+ it { is_expected.to be_nil }
15
+ end
16
+ end
17
+
18
+ describe '#name' do
19
+ subject(:name) { ticket_response.name }
20
+
21
+ it { is_expected.to eq('Test System') }
22
+
23
+ context "when response isn't successful" do
24
+ let(:xml_response) { fixture('cas/fail.xml') }
25
+
26
+ it { is_expected.to be_nil }
27
+ end
28
+ end
29
+
30
+ describe '#authorities' do
31
+ subject(:authorities) { ticket_response.authorities }
32
+
33
+ it { is_expected.to eq('[CUPOM, AUDITING,]') }
34
+
35
+ context "when response isn't successful" do
36
+ let(:xml_response) { fixture('cas/fail.xml') }
37
+
38
+ it { is_expected.to be_nil }
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,84 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Cassette::Rubycas::RoutingConstraint do
6
+ describe '#matches?' do
7
+ let(:request) do
8
+ OpenStruct.new(session: session)
9
+ end
10
+
11
+ let(:user) { instance_double(Cassette::Authentication::User) }
12
+ let(:constraint) { described_class.new(role, options) }
13
+
14
+ subject { constraint.matches?(request) }
15
+
16
+ before do
17
+ allow(constraint).to receive(:from_session).with(session).and_return(user)
18
+ end
19
+
20
+ let(:session) do
21
+ {
22
+ cas_user: 'test.user',
23
+ cas_extra_attributes: {
24
+ cn: 'test user',
25
+ email: 'test.user@example.org'
26
+ }
27
+ }
28
+ end
29
+
30
+ context 'with no options' do
31
+ let(:role) { :admin }
32
+ let(:options) { {} }
33
+ let(:has_role) { true }
34
+
35
+ before do
36
+ allow(user).to receive(:has_role?).with(role).and_return(has_role)
37
+ end
38
+
39
+ it 'checks the User role' do
40
+ subject
41
+ expect(user).to have_received(:has_role?).with(role)
42
+ end
43
+
44
+ context 'when user has the role' do
45
+ let(:has_role) { true }
46
+
47
+ it { is_expected.to eq(true) }
48
+ end
49
+
50
+ context 'when user does not have the role' do
51
+ let(:has_role) { false }
52
+
53
+ it { is_expected.to eq(false) }
54
+ end
55
+ end
56
+
57
+ context 'when options[:raw] = true' do
58
+ let(:role) { 'API_ADMIN' }
59
+ let(:options) { { raw: true } }
60
+ let(:has_role) { true }
61
+
62
+ before do
63
+ allow(user).to receive(:has_raw_role?).with(role).and_return(has_role)
64
+ end
65
+
66
+ it 'checks the User role' do
67
+ subject
68
+ expect(user).to have_received(:has_raw_role?).with(role)
69
+ end
70
+
71
+ context 'when user has the role' do
72
+ let(:has_role) { true }
73
+
74
+ it { is_expected.to eq(true) }
75
+ end
76
+
77
+ context 'when user does not have the role' do
78
+ let(:has_role) { false }
79
+
80
+ it { is_expected.to eq(false) }
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,36 @@
1
+
2
+
3
+ describe Cassette do
4
+ def keeping_logger(&block)
5
+ original_logger = Cassette.logger
6
+ block.call
7
+ Cassette.logger = original_logger
8
+ end
9
+
10
+ describe '.logger' do
11
+ it 'returns a default instance' do
12
+ expect(Cassette.logger).not_to be_nil
13
+ expect(Cassette.logger.is_a?(Logger)).to eql(true)
14
+ end
15
+
16
+ it 'returns rails logger when Rails is available' do
17
+ keeping_logger do
18
+ Cassette.logger = nil
19
+ rails = double('Rails')
20
+ expect(rails).to receive(:logger).and_return(rails).at_least(:once)
21
+ stub_const('Rails', rails)
22
+ expect(Cassette.logger).to eql(rails)
23
+ end
24
+ end
25
+ end
26
+
27
+ describe '.logger=' do
28
+ let(:logger) { Logger.new(STDOUT) }
29
+ it 'defines the logger instance' do
30
+ keeping_logger do
31
+ Cassette.logger = logger
32
+ expect(Cassette.logger).to eq(logger)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,7 +1,4 @@
1
1
  # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
2
  RSpec.describe 'Cassette::Client, Cassette::Authentication integration' do
6
3
  shared_examples_for 'a Cassette client and validator' do
7
4
  let(:config) { fail 'implement config!' }
data/spec/spec_helper.rb CHANGED
@@ -2,6 +2,11 @@ require 'simplecov'
2
2
  require 'simplecov-rcov'
3
3
  require 'simplecov-gem-adapter'
4
4
  require 'yaml'
5
+ require 'webmock/rspec'
6
+ require 'rspec/its'
7
+ require 'faker'
8
+
9
+ Dir['spec/support/**/*.rb'].each { |f| load f }
5
10
 
6
11
  module Fixtures
7
12
  def fixture(name)
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ require 'active_support/core_ext/hash/indifferent_access'
4
+
5
+ def ControllerMock(*mods)
6
+ mods.inject(Class.new(ControllerMock)) do |c, mod|
7
+ c.send(:include, mod)
8
+ end
9
+ end
10
+
11
+ class ControllerMock
12
+ attr_accessor :params, :request, :current_user
13
+ def self.before_filter(*); end
14
+
15
+ def initialize(params = {}, headers = {})
16
+ self.params = params.with_indifferent_access
17
+ self.request = OpenStruct.new(headers: headers.with_indifferent_access)
18
+ end
19
+ end