ey_gatekeeper 0.1.34

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,192 @@
1
+ require 'spec_helper'
2
+
3
+ describe EY::GateKeeper::AccessControlList do
4
+ context "with a control for a collection" do
5
+ it "allows access to the collection" do
6
+ acl('xdna://foobar' => 'GET').allow?('GET', '/foobar').should be_true
7
+ end
8
+
9
+ it "denies access to the collection for a method that's not listed" do
10
+ acl('xdna://foobar' => 'GET').allow?('POST', '/foobar').should be_false
11
+ end
12
+
13
+ it "denies access to a collection with a longer name" do
14
+ acl('xdna://foobarbaz' => 'GET').allow?('GET', '/foobar').should be_false
15
+ end
16
+ end
17
+
18
+ context "with conflicting controls" do
19
+ it "allows access based on the more specific control" do
20
+ acl('xdna://foobar' => [], 'xdna://foobar/baz' => 'GET').allow?('GET', '/foobar/baz').should be_true
21
+ end
22
+
23
+ it "denies access based on the less specific control" do
24
+ acl = acl('xdna://foobar' => [], 'xdna://foobar/baz' => 'GET')
25
+ acl.allow?('GET', '/foobar').should be_false
26
+ acl.allow?('GET', '/foobar/foo').should be_false
27
+ end
28
+ end
29
+
30
+ context "with a control requiring the search parameter" do
31
+ it "allows access to the collection when the search parameter is specified" do
32
+ acl('xdna://foobar?search' => 'GET').allow?('GET', '/foobar?search=foo').should be_true
33
+ end
34
+
35
+ it "allows access to the collection when the search parameter is specified with other parameters" do
36
+ acl('xdna://foobar?search' => 'GET').allow?('GET', '/foobar?search=foo&limit=10').should be_true
37
+ end
38
+
39
+ it "denies access to the collection when the search parameter is not specified" do
40
+ acl('xdna://foobar?search' => 'GET').allow?('GET', '/foobar').should be_false
41
+ end
42
+
43
+ it "denies access to the collection when a parameter other than search is specified" do
44
+ acl('xdna://foobar?search' => 'GET').allow?('GET', '/foobar?limit=10').should be_false
45
+ end
46
+ end
47
+
48
+ context "with a control requiring the search and derp parameters" do
49
+ it "allows access to the collection when the both parameters are specified" do
50
+ acl('xdna://foobar?search&derp' => 'GET').allow?('GET', '/foobar?search=foo&derp=bar').should be_true
51
+ end
52
+
53
+ it "allows access to the collection when both parameters are specified with other parameters" do
54
+ acl('xdna://foobar?search&derp' => 'GET').allow?('GET', '/foobar?search=foo&derp=bar&limit=10').should be_true
55
+ end
56
+
57
+ it "denies access to the collection when both parameters are not specified" do
58
+ acl('xdna://foobar?search&derp' => 'GET').allow?('GET', '/foobar').should be_false
59
+ end
60
+
61
+ it "denies access to the collection when a parameter other than the required two are specified" do
62
+ acl('xdna://foobar?search&derp' => 'GET').allow?('GET', '/foobar?limit=10').should be_false
63
+ end
64
+ end
65
+
66
+ context "with a global control" do
67
+ it "allows access" do
68
+ acl('xdna://' => 'GET').allow?('GET', '/whatever').should be_true
69
+ end
70
+ end
71
+
72
+ context "with underscores" do
73
+ it "doesn't barf" do
74
+ expect {
75
+ acl('xdna://cloudkit_token_auth_tokens?foo' => 'GET').allow?('GET', '/cloudkit_token_auth_tokens?foo=bar')
76
+ }.to_not raise_error
77
+ end
78
+ end
79
+
80
+ context "with spaces" do
81
+ it "doesn't barf" do
82
+ expect {
83
+ acl('xdna://pools' => 'GET').allow?('GET', '/pools/Foo Bar')
84
+ }.to_not raise_error
85
+ end
86
+ end
87
+
88
+ describe "intersection" do
89
+ context "with 2 basic acls sets that match" do
90
+ subject { acl('xdna://foo' => 'GET') & acl('xdna://foo' => 'GET') }
91
+
92
+ it "should produce an acl with the same methods" do
93
+ subject.to_hash.should == { 'xdna://foo' => ['GET'] }
94
+ end
95
+ end
96
+
97
+ context "with 2 basic acls sets where one has no methods" do
98
+ subject { acl('xdna://foo' => 'GET') & acl('xdna://foo' => []) }
99
+
100
+ it "should produce an acl with no permissions" do
101
+ subject.to_hash.should == { 'xdna://foo' => [] }
102
+ end
103
+ end
104
+
105
+ context "with 2 different acl sets with the same paths, but different methods" do
106
+ subject do
107
+ acl('xdna://foo' => 'GET') & acl('xdna://foo' => ['GET','PUT'])
108
+ end
109
+
110
+ it "should produce an acl set with the least permissive methods" do
111
+ subject.to_hash.should == { 'xdna://foo' => ['GET'] }
112
+ end
113
+ end
114
+
115
+ context "with 2 different acl sets with different path" do
116
+ subject do
117
+ acl('xdna://foo' => 'GET') & acl('xdna://bar' => ['GET','PUT'])
118
+ end
119
+
120
+ it "should produce an empty list" do
121
+ subject.to_hash.should == {}
122
+ end
123
+ end
124
+
125
+ context "with multiple acess controls in each list" do
126
+ subject do
127
+ acl('xdna://foo' => 'GET', 'xdna://bar' => 'GET') &
128
+ acl('xdna://bar' => ['GET','PUT'])
129
+ end
130
+
131
+ it "should produce an acl set with the least permissive methods" do
132
+ subject.to_hash.should == {
133
+ 'xdna://bar' => ['GET']
134
+ }
135
+ end
136
+ end
137
+
138
+ context "with paths that are subpaths of others" do
139
+ context "in an easy case" do
140
+ subject do
141
+ acl('xdna://' => ['GET', 'PUT']) &
142
+ acl('xdna://foos' => 'GET')
143
+ end
144
+
145
+ it "should produce an acl set that allows GET on /foos" do
146
+ subject.to_hash.should == {
147
+ 'xdna://foos' => ['GET']
148
+ }
149
+ end
150
+ end
151
+
152
+ context "with a more interesting case" do
153
+ subject do
154
+ acl('xdna://' => ['GET', 'PUT']) &
155
+ acl('xdna://foos' => 'GET', 'xdna://foos/bar' => 'PUT')
156
+ end
157
+
158
+ it "should produce an acl set that allows things" do
159
+ subject.to_hash.should == {
160
+ 'xdna://foos' => ['GET'],
161
+ 'xdna://foos/bar' => ['PUT']
162
+ }
163
+ end
164
+ end
165
+
166
+ context "with a path that starts with part of a another path" do
167
+ subject do
168
+ acl('xdna://foos' => ['GET']) &
169
+ acl('xdna://foosbars' => ['GET'])
170
+ end
171
+
172
+ it "should produce the right acl set" do
173
+ subject.to_hash.should == {}
174
+ end
175
+ end
176
+ end
177
+ end
178
+
179
+ describe "#to_hash" do
180
+ it "converts to a hash" do
181
+ acl('xdna://foo' => ['GET', 'PUT'], 'xdna://bar' => [], 'xdna://baz?foo' => ['POST']).to_hash.should == {
182
+ 'xdna://foo' => ['GET', 'PUT'],
183
+ 'xdna://bar' => [],
184
+ 'xdna://baz?foo' => ['POST']
185
+ }
186
+ end
187
+ end
188
+
189
+ def acl(data)
190
+ described_class.new(data)
191
+ end
192
+ end
@@ -0,0 +1,332 @@
1
+ require 'spec_helper'
2
+
3
+ describe "authentication and authorization behavior" do
4
+ context "with roles" do
5
+ before { create_test_roles }
6
+
7
+ context "a key with the role Test1" do
8
+ before do
9
+ create_key_with_roles("Test1")
10
+ end
11
+
12
+ let(:key) { find_key(test_key, test_secret) }
13
+
14
+ specify { key['access_controls'].should == { "xdna://" => [] } }
15
+ specify { key['gatekeeper_roles'].should == ["/gatekeeper_roles/Test1"] }
16
+
17
+ let(:token) { find_token(get_token(test_key, test_secret)["token"]).parsed_content }
18
+
19
+ specify { token['access_controls'].should == test_role_1_access_controls.merge(key['access_controls']) }
20
+ end
21
+
22
+ context "a key with the roles [Test1, Test2]" do
23
+ before do
24
+ create_key_with_roles("Test1","Test2")
25
+ end
26
+
27
+ let(:key) { find_key(test_key, test_secret) }
28
+
29
+ specify { key['access_controls'].should == { "xdna://" => [] } }
30
+ specify { key['gatekeeper_roles'].should == ["/gatekeeper_roles/Test1", "/gatekeeper_roles/Test2"] }
31
+
32
+ let(:token) { find_token(get_token(test_key, test_secret)["token"]).parsed_content }
33
+
34
+ specify { token['access_controls'].should == test_role_1_access_controls.merge(test_role_2_access_controls.merge(key['access_controls'])) }
35
+ end
36
+
37
+ context "a key with the roles [Test2, Test1]" do
38
+ before do
39
+ create_key_with_roles("Test2","Test1")
40
+ end
41
+
42
+ let(:key) { find_key(test_key, test_secret) }
43
+
44
+ specify { key['access_controls'].should == { "xdna://" => [] } }
45
+ specify { key['gatekeeper_roles'].should == ["/gatekeeper_roles/Test2", "/gatekeeper_roles/Test1"] }
46
+
47
+ let(:token) { find_token(get_token(test_key, test_secret)["token"]).parsed_content }
48
+
49
+ specify { token['access_controls'].should == test_role_2_access_controls.merge(test_role_1_access_controls.merge(key['access_controls'])) }
50
+ end
51
+ end
52
+
53
+ it "allows a request to /cloudkit-meta with no token" do
54
+ get '/cloudkit-meta'
55
+
56
+ last_response.status.should == 200
57
+ end
58
+
59
+ it "allows a request to /cloudkit-meta with a token that has no access" do
60
+ token_data = get_token
61
+ restrict_token(token_data['token'])
62
+
63
+ get '/cloudkit-meta', {}, {
64
+ 'HTTP_AUTH_TOKEN' => token_data['token']
65
+ }
66
+
67
+ last_response.status.should == 200
68
+ end
69
+
70
+ it "returns 401 with a header set when invalid authentication info is given" do
71
+ get '/_authenticate', {}, {
72
+ 'HTTP_AUTHORIZATION' => 'foobar'
73
+ }
74
+
75
+ last_response.status.should == 401
76
+ last_response.headers['X-Gatekeeper-Authentication-Error'].should == 'invalid authentication info'
77
+ end
78
+
79
+ it "returns 401 with a header set when no authentication info is given" do
80
+ get '/_authenticate'
81
+
82
+ last_response.status.should == 401
83
+ last_response.headers['X-Gatekeeper-Authentication-Error'].should == 'no authentication info'
84
+ end
85
+
86
+ it "returns 200 with token data when valid authentication info is given" do
87
+ token_data = get_token
88
+ token_data.should include('expires')
89
+ token_data.should include('token')
90
+ end
91
+
92
+ it "returns 401 with a header set when no token is specifed" do
93
+ get '/foobars'
94
+
95
+ last_response.status.should == 401
96
+ last_response.headers['X-Gatekeeper-Authentication-Error'].should == 'no token specified'
97
+ end
98
+
99
+ it "returns 401 with a header set when an invalid token is specified" do
100
+ get '/foobars', {}, {
101
+ 'HTTP_AUTH_TOKEN' => 'foobar'
102
+ }
103
+
104
+ last_response.status.should == 401
105
+ last_response.headers['X-Gatekeeper-Authentication-Error'].should == 'invalid token specified'
106
+ end
107
+
108
+ it "passes the request through when a valid token is specified" do
109
+ token_data = get_token
110
+
111
+ get '/domains', {}, {
112
+ 'HTTP_AUTH_TOKEN' => token_data['token']
113
+ }
114
+
115
+ last_response.status.should == 200
116
+ end
117
+
118
+ it "passes the request through when a valid impersonation token is specified" do
119
+ token_data = get_token
120
+ impersonation_token_data = get_token
121
+
122
+ get '/domains', {}, {
123
+ 'HTTP_AUTH_TOKEN' => token_data['token'],
124
+ 'HTTP_X_IMPERSONATION_TOKEN' => impersonation_token_data['token']
125
+ }
126
+
127
+ last_response.status.should == 200
128
+ end
129
+
130
+ it "returns 401 with a header set when an invalid impersonation token is specified" do
131
+ token_data = get_token
132
+
133
+ get '/domains', {}, {
134
+ 'HTTP_AUTH_TOKEN' => token_data['token'],
135
+ 'HTTP_X_IMPERSONATION_TOKEN' => 'foobar'
136
+ }
137
+
138
+ last_response.status.should == 401
139
+ last_response.headers['X-Gatekeeper-Authentication-Error'].should == 'invalid impersonation token specified'
140
+ end
141
+
142
+ it "returns 401 with a header set when an invalid token is specified with a valid impersonation token" do
143
+ impersonation_token_data = get_token
144
+
145
+ get '/domains', {}, {
146
+ 'HTTP_AUTH_TOKEN' => 'foobar',
147
+ 'HTTP_X_IMPERSONATION_TOKEN' => impersonation_token_data['token']
148
+ }
149
+
150
+ last_response.status.should == 401
151
+ last_response.headers['X-Gatekeeper-Authentication-Error'].should == 'invalid token specified'
152
+ end
153
+
154
+ it "returns 401 with a header set when an expired token is specified" do
155
+ token_data = get_token
156
+
157
+ expire_token(token_data['token'])
158
+
159
+ get '/domains', {}, {
160
+ 'HTTP_AUTH_TOKEN' => token_data['token'],
161
+ }
162
+
163
+ last_response.status.should == 401
164
+ last_response.headers['X-Gatekeeper-Authentication-Error'].should == 'expired token specified'
165
+ end
166
+
167
+ it "returns 401 with a header set when an expired impersonation token is specified" do
168
+ token_data = get_token
169
+ impersonation_token_data = get_token
170
+ expire_token(impersonation_token_data['token'])
171
+
172
+ get '/domains', {}, {
173
+ 'HTTP_AUTH_TOKEN' => token_data['token'],
174
+ 'HTTP_X_IMPERSONATION_TOKEN' => impersonation_token_data['token']
175
+ }
176
+
177
+ last_response.status.should == 401
178
+ last_response.headers['X-Gatekeeper-Authentication-Error'].should == 'expired impersonation token specified'
179
+ end
180
+
181
+ it "returns 401 with a header set when an expired token and a non-expired impersonation token are specified" do
182
+ token_data = get_token
183
+ impersonation_token_data = get_token
184
+ expire_token(token_data['token'])
185
+
186
+ get '/domains', {}, {
187
+ 'HTTP_AUTH_TOKEN' => token_data['token'],
188
+ 'HTTP_X_IMPERSONATION_TOKEN' => impersonation_token_data['token']
189
+ }
190
+
191
+ last_response.status.should == 401
192
+ last_response.headers['X-Gatekeeper-Authentication-Error'].should == 'expired token specified'
193
+ end
194
+
195
+ it "returns 401 with a header set when using a valid token without sufficient access" do
196
+ token_data = get_token
197
+ restrict_token(token_data['token'])
198
+
199
+ get '/domains', {}, {
200
+ 'HTTP_AUTH_TOKEN' => token_data['token']
201
+ }
202
+
203
+ last_response.status.should == 401
204
+ last_response.headers['X-Gatekeeper-Authentication-Error'].should == 'token has insufficient access'
205
+ end
206
+
207
+ it "returns 401 with a header set when using a valid impersonation token without sufficient access" do
208
+ token_data = get_token
209
+ impersonation_token_data = get_token
210
+ restrict_token(impersonation_token_data['token'])
211
+
212
+ get '/domains', {}, {
213
+ 'HTTP_AUTH_TOKEN' => token_data['token'],
214
+ 'HTTP_X_IMPERSONATION_TOKEN' => impersonation_token_data['token']
215
+ }
216
+
217
+ last_response.status.should == 401
218
+ last_response.headers['X-Gatekeeper-Authentication-Error'].should == 'impersonation token has insufficient access'
219
+ end
220
+
221
+ describe "/_effective_access_controls" do
222
+ it "returns the effective access controls when given a valid token" do
223
+ token_data = get_token
224
+
225
+ get '/_effective_access_controls', {}, {
226
+ 'HTTP_AUTH_TOKEN' => token_data['token']
227
+ }
228
+
229
+ last_response.status.should == 200
230
+ last_response.content_type.should == 'application/json'
231
+ JSON.parse(last_response.body).should == {
232
+ "xdna://"=>["GET", "HEAD", "PUT", "POST", "DELETE", "OPTIONS"]
233
+ }
234
+ end
235
+
236
+ it "returns the effective access controls when given a valid token and a valid impersonation token" do
237
+ token_data = get_token
238
+ impersonation_token_data = get_token
239
+ restrict_token(impersonation_token_data['token'])
240
+
241
+ get '/_effective_access_controls', {}, {
242
+ 'HTTP_AUTH_TOKEN' => token_data['token'],
243
+ 'HTTP_X_IMPERSONATION_TOKEN' => impersonation_token_data['token']
244
+ }
245
+
246
+ last_response.status.should == 200
247
+ last_response.content_type.should == 'application/json'
248
+ JSON.parse(last_response.body).should == {}
249
+ end
250
+
251
+ it "returns 401 with a header set when no token is specifed" do
252
+ get '/_effective_access_controls'
253
+
254
+ last_response.status.should == 401
255
+ last_response.headers['X-Gatekeeper-Authentication-Error'].should == 'no token specified'
256
+ end
257
+
258
+ it "returns 401 with a header set when an invalid token is specified" do
259
+ get '/_effective_access_controls', {}, {
260
+ 'HTTP_AUTH_TOKEN' => 'foobar'
261
+ }
262
+
263
+ last_response.status.should == 401
264
+ last_response.headers['X-Gatekeeper-Authentication-Error'].should == 'invalid token specified'
265
+ end
266
+
267
+ it "returns 401 with a header set when an invalid impersonation token is specified" do
268
+ token_data = get_token
269
+
270
+ get '/_effective_access_controls', {}, {
271
+ 'HTTP_AUTH_TOKEN' => token_data['token'],
272
+ 'HTTP_X_IMPERSONATION_TOKEN' => 'foobar'
273
+ }
274
+
275
+ last_response.status.should == 401
276
+ last_response.headers['X-Gatekeeper-Authentication-Error'].should == 'invalid impersonation token specified'
277
+ end
278
+
279
+ it "returns 401 with a header set when an invalid token is specified with a valid impersonation token" do
280
+ impersonation_token_data = get_token
281
+
282
+ get '/_effective_access_controls', {}, {
283
+ 'HTTP_AUTH_TOKEN' => 'foobar',
284
+ 'HTTP_X_IMPERSONATION_TOKEN' => impersonation_token_data['token']
285
+ }
286
+
287
+ last_response.status.should == 401
288
+ last_response.headers['X-Gatekeeper-Authentication-Error'].should == 'invalid token specified'
289
+ end
290
+
291
+ it "returns 401 with a header set when an expired token is specified" do
292
+ token_data = get_token
293
+
294
+ expire_token(token_data['token'])
295
+
296
+ get '/_effective_access_controls', {}, {
297
+ 'HTTP_AUTH_TOKEN' => token_data['token'],
298
+ }
299
+
300
+ last_response.status.should == 401
301
+ last_response.headers['X-Gatekeeper-Authentication-Error'].should == 'expired token specified'
302
+ end
303
+
304
+ it "returns 401 with a header set when an expired impersonation token is specified" do
305
+ token_data = get_token
306
+ impersonation_token_data = get_token
307
+ expire_token(impersonation_token_data['token'])
308
+
309
+ get '/_effective_access_controls', {}, {
310
+ 'HTTP_AUTH_TOKEN' => token_data['token'],
311
+ 'HTTP_X_IMPERSONATION_TOKEN' => impersonation_token_data['token']
312
+ }
313
+
314
+ last_response.status.should == 401
315
+ last_response.headers['X-Gatekeeper-Authentication-Error'].should == 'expired impersonation token specified'
316
+ end
317
+
318
+ it "returns 401 with a header set when an expired token and a non-expired impersonation token are specified" do
319
+ token_data = get_token
320
+ impersonation_token_data = get_token
321
+ expire_token(token_data['token'])
322
+
323
+ get '/_effective_access_controls', {}, {
324
+ 'HTTP_AUTH_TOKEN' => token_data['token'],
325
+ 'HTTP_X_IMPERSONATION_TOKEN' => impersonation_token_data['token']
326
+ }
327
+
328
+ last_response.status.should == 401
329
+ last_response.headers['X-Gatekeeper-Authentication-Error'].should == 'expired token specified'
330
+ end
331
+ end
332
+ end
@@ -0,0 +1,80 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe EY::GateKeeper::Client::Consumer do
4
+ subject { EY::GateKeeper.new }
5
+
6
+ it "properly authenticates with the master user" do
7
+ subject.get('/domains').status.should == 200
8
+ end
9
+
10
+ it "properly clears the mock store" do
11
+ subject.post('/test_class', {}, { 'foo' => 'bar' }.to_json)
12
+ JSON.parse(subject.get('/test_class').body)['total'].should == 1
13
+
14
+ EY::GateKeeper.reset!
15
+
16
+ subject.get('/test_class').status.should == 401
17
+ end
18
+
19
+ it "automatically fetches a new token when the client sees it has expired" do
20
+ subject.get('/domains').status.should == 200
21
+ first_token = subject.token.token
22
+
23
+ subject.token.token_data['expires'] = 0
24
+
25
+ subject.get('/domains').status.should == 200
26
+ subject.token.token.should_not == first_token
27
+ end
28
+
29
+ it "automatically fetches a new token when the server says it has expired" do
30
+ subject.get('/domains').status.should == 200
31
+ first_token = subject.token.token
32
+
33
+ expire_token(first_token)
34
+
35
+ subject.get('/domains').status.should == 200
36
+ subject.token.token.should_not == first_token
37
+ end
38
+
39
+ it "doesn't automatically fetch a new token when the server says it has insufficient access" do
40
+ subject.get('/domains').status.should == 200
41
+ token = subject.token.token
42
+
43
+ restrict_token(token)
44
+
45
+ subject.get('/domains').status.should == 401
46
+ subject.token.token.should == token
47
+ end
48
+
49
+ it "doesn't automatically fetch a new token when the server says the impersonation token has insufficient access" do
50
+ impersonation_token_data = get_token
51
+ subject.impersonate! impersonation_token_data['token']
52
+
53
+ subject.get('/domains').status.should == 200
54
+ token = subject.token.token
55
+
56
+ restrict_token(impersonation_token_data['token'])
57
+
58
+ subject.get('/domains').status.should == 401
59
+ subject.token.token.should == token
60
+ end
61
+
62
+ describe "#effective_access_controls" do
63
+ it "returns the effective access controls of the session" do
64
+ subject.effective_access_controls.should == {
65
+ "xdna://"=>["GET", "HEAD", "PUT", "POST", "DELETE", "OPTIONS"]
66
+ }
67
+ end
68
+
69
+ it "returns an empty hash if something goes wrong" do
70
+ subject.get('/domains').status.should == 200
71
+ subject.token.token_data['token'] = 'foobar'
72
+
73
+ subject.effective_access_controls.should == {}
74
+ end
75
+ end
76
+
77
+ def auth_store
78
+ @store ||= EY::GateKeeper::AuthStore.new
79
+ end
80
+ end
@@ -0,0 +1,76 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe EY::GateKeeper::Client::Consumer do
4
+
5
+ context "with invalid credentials" do
6
+ subject { EY::GateKeeper.new('foo', 'bar') }
7
+ it "responds with a 401" do
8
+ subject.get('/domains').status.should == 401
9
+ end
10
+ end
11
+
12
+ context "with the master credentials" do
13
+ subject { EY::GateKeeper.new }
14
+ it "responds with a 200" do
15
+ subject.get('/domains').status.should == 200
16
+ end
17
+ end
18
+
19
+ context "with valid credentials" do
20
+ subject { EY::GateKeeper.new('foo','bar') }
21
+ before do
22
+ key_data = {
23
+ 'key' => 'foo',
24
+ 'secret' => 'bar',
25
+ 'access_controls' => {
26
+ 'xdna://domains' => ['GET'],
27
+ 'xdna://domains/1' => ['GET', 'PUT'],
28
+ 'xdna://domains/2' => ['PUT'],
29
+ 'xdna://pools?search' => ['GET'],
30
+ 'xdna://pools/1' => ['PUT', 'GET'],
31
+ 'xdna://pools/2' => ['PUT']
32
+ },
33
+ 'cloudkit_user' => 'xcloud',
34
+ 'user' => 'id://foo'
35
+ }.to_json
36
+ store = EY::GateKeeper::AuthStore.new
37
+ store.post('/gatekeeper_credentials', :json => key_data)
38
+ end
39
+
40
+ context "with permissions to get a collection" do
41
+ it "responds with a 200" do
42
+ subject.get('/domains').status.should == 200
43
+ end
44
+
45
+ it "filters results" do
46
+ subject.put('/domains/1', {}, { 'foo' => 'bar' }.to_json)
47
+ subject.put('/domains/2', {}, { 'foo' => 'bar' }.to_json)
48
+
49
+ JSON.parse(subject.get('/domains').body)['uris'].should == ['/domains/1']
50
+ end
51
+ end
52
+
53
+ context "with permissions to only search a collection" do
54
+ before do
55
+ subject.put('/pools/1', {}, { 'foo' => 'bar' }.to_json)
56
+ subject.put('/pools/2', {}, { 'foo' => 'bar' }.to_json)
57
+ end
58
+
59
+ it "responds with a 401 when getting the collection itself" do
60
+ subject.get('/pools').status.should == 401
61
+ end
62
+
63
+ it "filters results" do
64
+ query = URI.escape({ 'foo' => 'bar' }.to_json)
65
+ JSON.parse(subject.get("/pools?search=#{query}").body)['uris'].should == ['/pools/1']
66
+ end
67
+ end
68
+
69
+ context "without permissions to get a collection" do
70
+ it "responds with a 401" do
71
+ subject.get('/instances').status.should == 401
72
+ end
73
+ end
74
+ end
75
+
76
+ end