drillbit 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/LICENSE.txt +19 -0
- data/README.md +2 -0
- data/Rakefile +2 -0
- data/lib/drillbit.rb +19 -0
- data/lib/drillbit/accept_header.rb +50 -0
- data/lib/drillbit/authorizable_resource.rb +160 -0
- data/lib/drillbit/authorizers/parameters.rb +24 -0
- data/lib/drillbit/authorizers/parameters/filtering.rb +50 -0
- data/lib/drillbit/authorizers/parameters/resource.rb +11 -0
- data/lib/drillbit/authorizers/query.rb +40 -0
- data/lib/drillbit/authorizers/scope.rb +30 -0
- data/lib/drillbit/configuration.rb +36 -0
- data/lib/drillbit/errors/invalid_api_request.rb +29 -0
- data/lib/drillbit/errors/invalid_subdomain.rb +29 -0
- data/lib/drillbit/errors/invalid_token.rb +22 -0
- data/lib/drillbit/matchers/accept_header.rb +16 -0
- data/lib/drillbit/matchers/generic.rb +30 -0
- data/lib/drillbit/matchers/subdomain.rb +31 -0
- data/lib/drillbit/matchers/version.rb +30 -0
- data/lib/drillbit/middleware/api_request.rb +49 -0
- data/lib/drillbit/parameters.rb +22 -0
- data/lib/drillbit/parameters/filter.rb +57 -0
- data/lib/drillbit/parameters/index.rb +31 -0
- data/lib/drillbit/parameters/page.rb +28 -0
- data/lib/drillbit/parameters/sort.rb +32 -0
- data/lib/drillbit/requests/base.rb +114 -0
- data/lib/drillbit/requests/rack.rb +50 -0
- data/lib/drillbit/requests/rails.rb +44 -0
- data/lib/drillbit/resource.rb +14 -0
- data/lib/drillbit/resource/model.rb +41 -0
- data/lib/drillbit/resource/naming.rb +33 -0
- data/lib/drillbit/resource/processors/filtering.rb +66 -0
- data/lib/drillbit/resource/processors/indexing.rb +40 -0
- data/lib/drillbit/resource/processors/paging.rb +46 -0
- data/lib/drillbit/resource/processors/sorting.rb +42 -0
- data/lib/drillbit/responses/invalid_api_request.rb +18 -0
- data/lib/drillbit/responses/invalid_subdomain.rb +18 -0
- data/lib/drillbit/responses/invalid_token.rb +20 -0
- data/lib/drillbit/serializers/json_api.rb +10 -0
- data/lib/drillbit/tokens/base64.rb +45 -0
- data/lib/drillbit/tokens/base64s/invalid.rb +14 -0
- data/lib/drillbit/tokens/base64s/null.rb +14 -0
- data/lib/drillbit/tokens/invalid.rb +26 -0
- data/lib/drillbit/tokens/json_web_token.rb +112 -0
- data/lib/drillbit/tokens/json_web_tokens/invalid.rb +14 -0
- data/lib/drillbit/tokens/json_web_tokens/null.rb +14 -0
- data/lib/drillbit/tokens/null.rb +26 -0
- data/lib/drillbit/version.rb +4 -0
- data/spec/drillbit/accept_header_spec.rb +112 -0
- data/spec/drillbit/authorizers/parameters/filtering_spec.rb +71 -0
- data/spec/drillbit/authorizers/parameters/resource_spec.rb +12 -0
- data/spec/drillbit/authorizers/parameters_spec.rb +17 -0
- data/spec/drillbit/authorizers/query_spec.rb +21 -0
- data/spec/drillbit/authorizers/scope_spec.rb +20 -0
- data/spec/drillbit/errors/invalid_api_request_spec.rb +31 -0
- data/spec/drillbit/errors/invalid_subdomain_spec.rb +31 -0
- data/spec/drillbit/errors/invalid_token_spec.rb +24 -0
- data/spec/drillbit/invalid_subdomain_spec.rb +46 -0
- data/spec/drillbit/invalid_token_spec.rb +44 -0
- data/spec/drillbit/matchers/accept_header_spec.rb +114 -0
- data/spec/drillbit/matchers/subdomain_spec.rb +78 -0
- data/spec/drillbit/matchers/version_spec.rb +86 -0
- data/spec/drillbit/middleware/api_request_spec.rb +220 -0
- data/spec/drillbit/parameters_spec.rb +49 -0
- data/spec/drillbit/requests/base_spec.rb +37 -0
- data/spec/drillbit/requests/rack_spec.rb +253 -0
- data/spec/drillbit/requests/rails_spec.rb +264 -0
- data/spec/drillbit/resource/model_spec.rb +64 -0
- data/spec/drillbit/resource/processors/filtering_spec.rb +106 -0
- data/spec/drillbit/resource/processors/indexing_spec.rb +46 -0
- data/spec/drillbit/resource/processors/paging_spec.rb +74 -0
- data/spec/drillbit/resource/processors/sorting_spec.rb +66 -0
- data/spec/drillbit/tokens/base64_spec.rb +44 -0
- data/spec/drillbit/tokens/json_web_token_spec.rb +135 -0
- data/spec/fixtures/test_rsa_key +27 -0
- data/spec/fixtures/test_rsa_key.pub +9 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/support/private_keys.rb +42 -0
- metadata +244 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'drillbit/requests/base'
|
4
|
+
require 'drillbit/matchers/version'
|
5
|
+
|
6
|
+
module Drillbit
|
7
|
+
module Matchers
|
8
|
+
RSpec.describe Version do
|
9
|
+
context 'when the version is passed in the accept header' do
|
10
|
+
it 'does not match if the subdomain is API but the requested version does not ' \
|
11
|
+
'equal the version constraint' do
|
12
|
+
|
13
|
+
env = {
|
14
|
+
'HTTP_X_APPLICATION_NAME' => 'westeros',
|
15
|
+
'HTTP_ACCEPT' => 'application/vnd.westeros+redkeep;version=10.0',
|
16
|
+
}
|
17
|
+
request = Requests::Base.resolve(env)
|
18
|
+
|
19
|
+
matcher = Version.new(version_constraint: '10.1')
|
20
|
+
|
21
|
+
expect(matcher.matches?(request)).to be_a FalseClass
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'does match if the subdomain is API and the requested version equals the ' \
|
25
|
+
'version constraint' do
|
26
|
+
|
27
|
+
env = {
|
28
|
+
'HTTP_X_APPLICATION_NAME' => 'westeros',
|
29
|
+
'HTTP_ACCEPT' => 'application/vnd.westeros+redkeep;version=10.0',
|
30
|
+
}
|
31
|
+
request = Requests::Base.resolve(env)
|
32
|
+
|
33
|
+
matcher = Version.new(version_constraint: '10.0')
|
34
|
+
|
35
|
+
expect(matcher.matches?(request)).to be_a TrueClass
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when the version is not passed in the accept header' do
|
40
|
+
it 'does not match if the subdomain is API but the requested version does not ' \
|
41
|
+
'equal the version constraint' do
|
42
|
+
|
43
|
+
env = {
|
44
|
+
'HTTP_X_APPLICATION_NAME' => 'westeros',
|
45
|
+
'HTTP_ACCEPT' => 'application/vnd.westeros+redkeep',
|
46
|
+
}
|
47
|
+
request = Requests::Base.resolve(env)
|
48
|
+
|
49
|
+
matcher = Version.new(version_constraint: '10.1',
|
50
|
+
default_version: '10.0')
|
51
|
+
|
52
|
+
expect(matcher.matches?(request)).to be_a FalseClass
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'does match if the subdomain is API and the requested version equals the ' \
|
56
|
+
'version constraint' do
|
57
|
+
|
58
|
+
env = {
|
59
|
+
'HTTP_X_APPLICATION_NAME' => 'westeros',
|
60
|
+
'HTTP_ACCEPT' => 'application/vnd.westeros+redkeep',
|
61
|
+
}
|
62
|
+
request = Requests::Base.resolve(env)
|
63
|
+
|
64
|
+
matcher = Version.new(version_constraint: '10.0',
|
65
|
+
default_version: '10.0')
|
66
|
+
|
67
|
+
expect(matcher.matches?(request)).to be_a TrueClass
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'matches the default version in the configuration if none is passed in' do
|
72
|
+
Drillbit.configuration.default_api_version = '100.0'
|
73
|
+
|
74
|
+
env = {
|
75
|
+
'HTTP_X_APPLICATION_NAME' => 'westeros',
|
76
|
+
'HTTP_ACCEPT' => 'application/vnd.westeros+redkeep',
|
77
|
+
}
|
78
|
+
request = Requests::Base.resolve(env)
|
79
|
+
|
80
|
+
matcher = Version.new(version_constraint: '100.0')
|
81
|
+
|
82
|
+
expect(matcher.matches?(request)).to be_a TrueClass
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'drillbit/middleware/api_request'
|
4
|
+
|
5
|
+
# rubocop:disable Metrics/LineLength
|
6
|
+
module Drillbit
|
7
|
+
module Middleware
|
8
|
+
RSpec.describe ApiRequest, singletons: Erratum::Configuration do
|
9
|
+
let(:app) { ->(_env) { [200, {}, 'response'] } }
|
10
|
+
|
11
|
+
before(:each) do
|
12
|
+
Erratum.configuration.url_mappings = {
|
13
|
+
'external_documentation_urls' => {
|
14
|
+
'errors.responses.invalid_subdomain' => 'http://example.com/foo',
|
15
|
+
},
|
16
|
+
'developer_documentation_urls' => {
|
17
|
+
'errors.responses.invalid_subdomain' => 'http://example.com/foo',
|
18
|
+
},
|
19
|
+
}
|
20
|
+
|
21
|
+
Drillbit.configure do |config|
|
22
|
+
config.allowed_subdomains = %w{api westeros}
|
23
|
+
config.allowed_api_subdomains = %w{api}
|
24
|
+
config.application_name = 'westeros'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'allows requests for allowed subdomains without accept headers' do
|
29
|
+
api_request_middleware = ApiRequest.new(app)
|
30
|
+
|
31
|
+
request = {
|
32
|
+
'HTTP_HOST' => 'westeros.example.com',
|
33
|
+
'HTTP_ACCEPT' => '',
|
34
|
+
'QUERY_STRING' => '',
|
35
|
+
}
|
36
|
+
|
37
|
+
status, headers, response = api_request_middleware.call(request)
|
38
|
+
|
39
|
+
expect(status).to eql 200
|
40
|
+
expect(headers).to eql({})
|
41
|
+
expect(response).to eql 'response'
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'does not allow requests if they are not for an allowed subdomain' do
|
45
|
+
api_request_middleware = ApiRequest.new(app)
|
46
|
+
|
47
|
+
request = {
|
48
|
+
'HTTP_HOST' => 'notvalid.example.com',
|
49
|
+
'HTTP_ACCEPT' => '',
|
50
|
+
'QUERY_STRING' => 'first=my_param&accept=application/vnd.silent+redkeep;version=1.0.0',
|
51
|
+
}
|
52
|
+
|
53
|
+
status, headers, response = api_request_middleware.call(request)
|
54
|
+
|
55
|
+
expect(status).to eql 404
|
56
|
+
expect(headers).to eql({})
|
57
|
+
expect(JSON.load(response[0])).to include(
|
58
|
+
'errors' => [
|
59
|
+
{
|
60
|
+
'id' => match(/[a-z0-9\-]+/),
|
61
|
+
'links' => {
|
62
|
+
'about' => nil,
|
63
|
+
'documentation' => nil,
|
64
|
+
},
|
65
|
+
'status' => 404,
|
66
|
+
'code' => 'errors.invalid_subdomain',
|
67
|
+
'title' => 'Invalid Subdomain',
|
68
|
+
'detail' => 'The resource you attempted to access is either not authorized ' \
|
69
|
+
'for the authenticated user or does not exist.',
|
70
|
+
'source' => {
|
71
|
+
'http_host' => 'notvalid.example.com',
|
72
|
+
},
|
73
|
+
},
|
74
|
+
],
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'does not allow requests if they are for an allowed subdomain but does ' \
|
79
|
+
'not have a valid accept header' do
|
80
|
+
|
81
|
+
api_request_middleware = ApiRequest.new(app)
|
82
|
+
|
83
|
+
request = {
|
84
|
+
'HTTP_HOST' => 'api.example.com',
|
85
|
+
'HTTP_ACCEPT' => '',
|
86
|
+
'QUERY_STRING' => 'first=my_param&accept=application/vnd.silent+redkeep;version=1.0.0',
|
87
|
+
}
|
88
|
+
|
89
|
+
status, headers, response = api_request_middleware.call(request)
|
90
|
+
|
91
|
+
expect(status).to eql 400
|
92
|
+
expect(headers).to eql({})
|
93
|
+
expect(JSON.load(response[0])).to include(
|
94
|
+
'errors' => [
|
95
|
+
{
|
96
|
+
'id' => match(/[a-z0-9\-]+/),
|
97
|
+
'links' => {
|
98
|
+
'about' => nil,
|
99
|
+
'documentation' => nil,
|
100
|
+
},
|
101
|
+
'status' => 400,
|
102
|
+
'code' => 'errors.invalid_api_request',
|
103
|
+
'title' => 'Invalid API Request',
|
104
|
+
'detail' => 'The accept header that you passed in the request cannot be ' \
|
105
|
+
'parsed, please refer to the documentation to verify.',
|
106
|
+
'source' => {
|
107
|
+
'accept_header' => '',
|
108
|
+
},
|
109
|
+
},
|
110
|
+
],
|
111
|
+
)
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'does allow requests if both the subdomain and the accept header are valid' do
|
115
|
+
api_request_middleware = ApiRequest.new(app)
|
116
|
+
|
117
|
+
request = {
|
118
|
+
'HTTP_HOST' => 'api.example.com',
|
119
|
+
'HTTP_ACCEPT' => 'application/vnd.westeros+redkeep;version=1.0.0',
|
120
|
+
'QUERY_STRING' => 'first=my_param&accept=application/vnd.westeros+redkeep;version=1.0.0',
|
121
|
+
}
|
122
|
+
|
123
|
+
status, headers, response = api_request_middleware.call(request)
|
124
|
+
|
125
|
+
expect(status).to eql 200
|
126
|
+
expect(headers).to eql({})
|
127
|
+
expect(response).to eql 'response'
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'does allow requests if the subdomain, the accept header and the token are valid' do
|
131
|
+
Drillbit.configuration.token_private_key = test_private_key
|
132
|
+
api_request_middleware = ApiRequest.new(app)
|
133
|
+
|
134
|
+
request = {
|
135
|
+
'HTTP_HOST' => 'api.example.com',
|
136
|
+
'HTTP_ACCEPT' => 'application/vnd.westeros+redkeep;version=1.0.0',
|
137
|
+
'HTTP_AUTHORIZATION' => "Token #{valid_jwe_token}",
|
138
|
+
'QUERY_STRING' => 'accept=application/vnd.westeros+redkeep;version=1.0.0',
|
139
|
+
}
|
140
|
+
|
141
|
+
status, headers, response = api_request_middleware.call(request)
|
142
|
+
|
143
|
+
expect(status).to eql 200
|
144
|
+
expect(headers).to eql({})
|
145
|
+
expect(response).to eql 'response'
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'returns the proper response if the token is invalid' do
|
149
|
+
Drillbit.configuration.token_private_key = test_private_key
|
150
|
+
api_request_middleware = ApiRequest.new(app)
|
151
|
+
|
152
|
+
request = {
|
153
|
+
'HTTP_HOST' => 'api.example.com',
|
154
|
+
'HTTP_ACCEPT' => 'application/vnd.westeros+redkeep;version=1.0.0',
|
155
|
+
'HTTP_AUTHORIZATION' => "Token #{invalid_jwe_token}",
|
156
|
+
'QUERY_STRING' => 'accept=application/vnd.westeros+redkeep;version=1.0.0',
|
157
|
+
}
|
158
|
+
|
159
|
+
_status, _headers, response = api_request_middleware.call(request)
|
160
|
+
|
161
|
+
expect(response.first).to include 'errors.invalid_token'
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'converts JSON API compliant dasherized query params to underscored' do
|
165
|
+
app = ->(env) { [200, env, 'response'] }
|
166
|
+
api_request_middleware = ApiRequest.new(app)
|
167
|
+
|
168
|
+
request = {
|
169
|
+
'HTTP_HOST' => 'api.example.com',
|
170
|
+
'HTTP_ACCEPT' => 'application/vnd.westeros+redkeep;version=1.0.0',
|
171
|
+
'QUERY_STRING' => 'hello-there=bob-jones&' \
|
172
|
+
'nice-to-meet=you-bob&' \
|
173
|
+
'hows-the-weather=today-bob',
|
174
|
+
}
|
175
|
+
|
176
|
+
_status, headers, _response = api_request_middleware.call(request)
|
177
|
+
|
178
|
+
expect(headers['QUERY_STRING']).to eql 'hello_there=bob-jones&' \
|
179
|
+
'nice_to_meet=you-bob&' \
|
180
|
+
'hows_the_weather=today-bob'
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'properly converts the content type for Rails when it is the only one' do
|
184
|
+
api_request_middleware = ApiRequest.new(app)
|
185
|
+
|
186
|
+
request = {
|
187
|
+
'CONTENT_TYPE' => 'application/vnd.api+json',
|
188
|
+
'HTTP_HOST' => 'westeros.example.com',
|
189
|
+
'HTTP_ACCEPT' => '',
|
190
|
+
'QUERY_STRING' => '',
|
191
|
+
}
|
192
|
+
|
193
|
+
allow(app).to receive(:call)
|
194
|
+
|
195
|
+
_response = api_request_middleware.call(request)
|
196
|
+
|
197
|
+
expect(app).to have_received(:call).
|
198
|
+
with(a_hash_including('CONTENT_TYPE' => 'application/json'))
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'properly converts the content type for Rails when it is not the only one' do
|
202
|
+
api_request_middleware = ApiRequest.new(app)
|
203
|
+
|
204
|
+
request = {
|
205
|
+
'CONTENT_TYPE' => 'application/vnd.api+json;other',
|
206
|
+
'HTTP_HOST' => 'westeros.example.com',
|
207
|
+
'HTTP_ACCEPT' => '',
|
208
|
+
'QUERY_STRING' => '',
|
209
|
+
}
|
210
|
+
|
211
|
+
allow(app).to receive(:call)
|
212
|
+
|
213
|
+
_response = api_request_middleware.call(request)
|
214
|
+
|
215
|
+
expect(app).to have_received(:call).
|
216
|
+
with(a_hash_including('CONTENT_TYPE' => 'application/json;other'))
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'drillbit/parameters'
|
4
|
+
|
5
|
+
module Drillbit
|
6
|
+
RSpec.describe Parameters do
|
7
|
+
it 'can underscore the first parameter' do
|
8
|
+
query_params = 'hello-there=bob-jones'
|
9
|
+
|
10
|
+
expect(Parameters.process(query_params)).to eql 'hello_there=bob-jones'
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'does not touch params with no dashes' do
|
14
|
+
query_params = 'hello_there=bob-jones'
|
15
|
+
|
16
|
+
expect(Parameters.process(query_params)).to eql 'hello_there=bob-jones'
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'can underscore a middle parameter and a parameter at the end' do
|
20
|
+
query_params = 'hello-there=bob-jones&nice-to-meet=you-bob&hows-the-weather=today-bob'
|
21
|
+
|
22
|
+
expect(Parameters.process(query_params)).to eql 'hello_there=bob-jones&' \
|
23
|
+
'nice_to_meet=you-bob&' \
|
24
|
+
'hows_the_weather=today-bob'
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'can handle weirdly formatted parameters' do
|
28
|
+
query_params = 'hello-there=bob-jones&nice-to-meet=you-bob&='
|
29
|
+
|
30
|
+
expect(Parameters.process(query_params)).to eql 'hello_there=bob-jones&' \
|
31
|
+
'nice_to_meet=you-bob&='
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'can handle parameters with no values' do
|
35
|
+
query_params = 'hello-there&nice-to-meet=you-bob&='
|
36
|
+
|
37
|
+
expect(Parameters.process(query_params)).to eql 'hello_there&' \
|
38
|
+
'nice_to_meet=you-bob&='
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'can handle values with no parameter name' do
|
42
|
+
query_params = 'hello-there=bob-jones&=you-bob&nice-to-meet=you-bob&='
|
43
|
+
|
44
|
+
expect(Parameters.process(query_params)).to eql 'hello_there=bob-jones&' \
|
45
|
+
'=you-bob&' \
|
46
|
+
'nice_to_meet=you-bob&='
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'ostruct'
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'drillbit/requests/base'
|
5
|
+
|
6
|
+
module Drillbit
|
7
|
+
module Requests
|
8
|
+
RSpec.describe Base do
|
9
|
+
it 'can resolve itself by returning itself' do
|
10
|
+
raw_request = Base.new(token_private_key: '', request: {})
|
11
|
+
resolved_request = Base.resolve(raw_request)
|
12
|
+
|
13
|
+
expect(resolved_request).to eql raw_request
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'can resolve a Rails request' do
|
17
|
+
raw_request = OpenStruct.new(
|
18
|
+
headers: {},
|
19
|
+
params: {},
|
20
|
+
)
|
21
|
+
resolved_request = Base.resolve(raw_request)
|
22
|
+
|
23
|
+
expect(resolved_request).to be_a Requests::Rails
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'can resolve a Rack request' do
|
27
|
+
raw_request = {
|
28
|
+
'HTTP_ACCEPT' => 'accept_string',
|
29
|
+
'QUERY_STRING' => '',
|
30
|
+
}
|
31
|
+
resolved_request = Base.resolve(raw_request)
|
32
|
+
|
33
|
+
expect(resolved_request).to be_a Requests::Rack
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,253 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'drillbit/requests/rack'
|
4
|
+
|
5
|
+
# rubocop:disable Metrics/LineLength
|
6
|
+
module Drillbit
|
7
|
+
module Requests
|
8
|
+
RSpec.describe Rack do
|
9
|
+
it 'finds the accept header from the headers if it is valid' do
|
10
|
+
raw_request = {
|
11
|
+
'HTTP_ACCEPT' => 'application/vnd.westeros+redkeep;version=10.0',
|
12
|
+
'QUERY_STRING' => '',
|
13
|
+
'HTTP_X_APPLICATION_NAME' => 'westeros',
|
14
|
+
}
|
15
|
+
request = Rack.new(request: raw_request)
|
16
|
+
|
17
|
+
expect(request.accept_header.to_s).to eql 'application/vnd.westeros+redkeep;version=10.0'
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'finds the accept header from the headers if it is invalid but there is no ' \
|
21
|
+
'accept header in the params' do
|
22
|
+
|
23
|
+
raw_request = {
|
24
|
+
'HTTP_ACCEPT' => 'invalid/vnd.westeros+redkeep;version=10.0',
|
25
|
+
'QUERY_STRING' => '',
|
26
|
+
'HTTP_X_APPLICATION_NAME' => 'westeros',
|
27
|
+
}
|
28
|
+
request = Rack.new(request: raw_request)
|
29
|
+
|
30
|
+
expect(request.accept_header.to_s).to eql 'invalid/vnd.westeros+redkeep;version=10.0'
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'finds the accept header from the params if it is valid' do
|
34
|
+
raw_request = {
|
35
|
+
'HTTP_ACCEPT' => '',
|
36
|
+
'QUERY_STRING' => 'accept=application/vnd.westeros+redkeep;version=10.0',
|
37
|
+
'HTTP_X_APPLICATION_NAME' => 'westeros',
|
38
|
+
}
|
39
|
+
request = Rack.new(request: raw_request)
|
40
|
+
|
41
|
+
expect(request.accept_header.to_s).to eql 'application/vnd.westeros+redkeep;version=10.0'
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'finds the accept header from the query string if it is encoded' do
|
45
|
+
raw_request = {
|
46
|
+
'HTTP_ACCEPT' => '',
|
47
|
+
'QUERY_STRING' => 'accept=application%2Fvnd.westeros%2Bredkeep%3Bversion%3D10.0',
|
48
|
+
'HTTP_X_APPLICATION_NAME' => 'westeros',
|
49
|
+
}
|
50
|
+
request = Rack.new(request: raw_request)
|
51
|
+
|
52
|
+
expect(request.accept_header.to_s).to eql 'application/vnd.westeros+redkeep;version=10.0'
|
53
|
+
end
|
54
|
+
# rubocop:enable Metrics/LineLength
|
55
|
+
|
56
|
+
it 'finds the authorization token from the header' do
|
57
|
+
raw_request = {
|
58
|
+
'HTTP_AUTHORIZATION' => "Token #{valid_jwe_token}",
|
59
|
+
'QUERY_STRING' => '',
|
60
|
+
}
|
61
|
+
request = Rack.new(token_private_key: test_private_key,
|
62
|
+
request: raw_request)
|
63
|
+
|
64
|
+
expect(request.authorization_token).to be_valid
|
65
|
+
expect(request.authorization_token.to_h).to eql(
|
66
|
+
[
|
67
|
+
{ 'bar' => 'baz' },
|
68
|
+
{ 'typ' => 'JWT', 'alg' => 'RS256' },
|
69
|
+
],
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'finds the Base64 token from the header' do
|
74
|
+
raw_request = {
|
75
|
+
'HTTP_AUTHORIZATION' => "Basic #{valid_b64_token}",
|
76
|
+
'QUERY_STRING' => '',
|
77
|
+
}
|
78
|
+
request = Rack.new(token_private_key: test_private_key,
|
79
|
+
request: raw_request)
|
80
|
+
|
81
|
+
expect(request.authorization_token).to be_valid
|
82
|
+
expect(request.authorization_token.to_h).to eql(
|
83
|
+
[
|
84
|
+
{ 'token' => valid_b64_token },
|
85
|
+
{ 'typ' => 'base64' },
|
86
|
+
],
|
87
|
+
)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'finds a null token from the header if there is no header' do
|
91
|
+
raw_request = {
|
92
|
+
'HTTP_AUTHORIZATION' => '',
|
93
|
+
'QUERY_STRING' => '',
|
94
|
+
}
|
95
|
+
request = Rack.new(token_private_key: test_private_key,
|
96
|
+
request: raw_request)
|
97
|
+
|
98
|
+
expect(request.authorization_token).to be_valid
|
99
|
+
expect(request.authorization_token).to be_blank
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'ignores incorrectly passed in tokens since we do not know what to do' do
|
103
|
+
raw_request = {
|
104
|
+
'HTTP_AUTHORIZATION' => valid_jwe_token.to_s,
|
105
|
+
'QUERY_STRING' => '',
|
106
|
+
}
|
107
|
+
request = Rack.new(token_private_key: test_private_key,
|
108
|
+
request: raw_request)
|
109
|
+
|
110
|
+
expect(request.authorization_token).to be_valid
|
111
|
+
expect(request.authorization_token).to be_blank
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'finds the authorization token from the params if the authorization token from ' \
|
115
|
+
'the header is invalid and the authorization token from the params is valid' do
|
116
|
+
|
117
|
+
raw_request = {
|
118
|
+
'HTTP_AUTHORIZATION' => "Token #{invalid_jwe_token}",
|
119
|
+
'QUERY_STRING' => "token_jwt=#{valid_jwe_token}",
|
120
|
+
}
|
121
|
+
request = Rack.new(token_private_key: test_private_key,
|
122
|
+
request: raw_request)
|
123
|
+
|
124
|
+
expect(request.authorization_token).to be_valid
|
125
|
+
expect(request.authorization_token.to_h).to eql(
|
126
|
+
[
|
127
|
+
{ 'bar' => 'baz' },
|
128
|
+
{ 'typ' => 'JWT', 'alg' => 'RS256' },
|
129
|
+
],
|
130
|
+
)
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'finds the authorization token from the params if the authorization token from ' \
|
134
|
+
'the header is not present and the authorization token from the params is valid' do
|
135
|
+
|
136
|
+
raw_request = {
|
137
|
+
'QUERY_STRING' => "token_jwt=#{valid_jwe_token}",
|
138
|
+
}
|
139
|
+
request = Rack.new(token_private_key: test_private_key,
|
140
|
+
request: raw_request)
|
141
|
+
|
142
|
+
expect(request.authorization_token).to be_valid
|
143
|
+
expect(request.authorization_token.to_h).to eql(
|
144
|
+
[
|
145
|
+
{ 'bar' => 'baz' },
|
146
|
+
{ 'typ' => 'JWT', 'alg' => 'RS256' },
|
147
|
+
],
|
148
|
+
)
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'is a null authorization token if neither authorization token is present' do
|
152
|
+
raw_request = {
|
153
|
+
'QUERY_STRING' => '',
|
154
|
+
}
|
155
|
+
request = Rack.new(token_private_key: test_private_key,
|
156
|
+
request: raw_request)
|
157
|
+
|
158
|
+
expect(request.authorization_token).to be_valid
|
159
|
+
expect(request.authorization_token.to_h).to eql([{}, {}])
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'finds the JSON web token from the params' do
|
163
|
+
raw_request = {
|
164
|
+
'QUERY_STRING' => "token_jwt=#{valid_jwe_token}",
|
165
|
+
}
|
166
|
+
request = Rack.new(token_private_key: test_private_key,
|
167
|
+
request: raw_request)
|
168
|
+
|
169
|
+
expect(request.authorization_token).to be_valid
|
170
|
+
expect(request.authorization_token.to_h).to eql(
|
171
|
+
[
|
172
|
+
{ 'bar' => 'baz' },
|
173
|
+
{ 'typ' => 'JWT', 'alg' => 'RS256' },
|
174
|
+
],
|
175
|
+
)
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'finds the generic Base64 web token from the params' do
|
179
|
+
raw_request = {
|
180
|
+
'QUERY_STRING' => "token_b64=#{valid_b64_token}",
|
181
|
+
}
|
182
|
+
request = Rack.new(request: raw_request)
|
183
|
+
|
184
|
+
expect(request.authorization_token).to be_valid
|
185
|
+
expect(request.authorization_token.to_h).to eql(
|
186
|
+
[
|
187
|
+
{ 'token' => valid_b64_token },
|
188
|
+
{ 'typ' => 'base64' },
|
189
|
+
],
|
190
|
+
)
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'finds invalid tokens from the params' do
|
194
|
+
raw_request = {
|
195
|
+
'QUERY_STRING' => 'token_b64=bla.h',
|
196
|
+
}
|
197
|
+
request = Rack.new(request: raw_request)
|
198
|
+
|
199
|
+
expect(request.authorization_token_from_params).not_to be_valid
|
200
|
+
expect(request.authorization_token_from_params).not_to be_blank
|
201
|
+
|
202
|
+
raw_request = {
|
203
|
+
'QUERY_STRING' => "token_jwt=#{invalid_jwe_token}",
|
204
|
+
}
|
205
|
+
request = Rack.new(token_private_key: test_private_key,
|
206
|
+
request: raw_request)
|
207
|
+
|
208
|
+
expect(request.authorization_token_from_params).not_to be_valid
|
209
|
+
expect(request.authorization_token_from_params).not_to be_blank
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'finds the null token from the params if nothing is passed in' do
|
213
|
+
raw_request = {
|
214
|
+
'QUERY_STRING' => 'token_b64=',
|
215
|
+
}
|
216
|
+
request = Rack.new(request: raw_request)
|
217
|
+
|
218
|
+
expect(request.authorization_token_from_params).to be_valid
|
219
|
+
expect(request.authorization_token_from_params).to be_blank
|
220
|
+
|
221
|
+
raw_request = {
|
222
|
+
'QUERY_STRING' => 'token_jwt=',
|
223
|
+
}
|
224
|
+
request = Rack.new(request: raw_request)
|
225
|
+
|
226
|
+
expect(request.authorization_token_from_params).to be_valid
|
227
|
+
expect(request.authorization_token_from_params).to be_blank
|
228
|
+
|
229
|
+
raw_request = {
|
230
|
+
'QUERY_STRING' => '',
|
231
|
+
}
|
232
|
+
request = Rack.new(request: raw_request)
|
233
|
+
|
234
|
+
expect(request.authorization_token_from_params).to be_valid
|
235
|
+
expect(request.authorization_token_from_params).to be_blank
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'defaults to the application name in the configuration if none is found in ' \
|
239
|
+
'the header' do
|
240
|
+
|
241
|
+
Drillbit.configuration.application_name = 'redkeep'
|
242
|
+
|
243
|
+
raw_request = {
|
244
|
+
'HTTP_ACCEPT' => '',
|
245
|
+
'QUERY_STRING' => 'accept=application/vnd.redkeep+zion;version=10.0',
|
246
|
+
}
|
247
|
+
request = Rack.new(request: raw_request)
|
248
|
+
|
249
|
+
expect(request.accept_header.to_s).to eql 'application/vnd.redkeep+zion;version=10.0'
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|