apill 4.0.3 → 4.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.
- checksums.yaml +4 -4
- data/lib/apill/matchers/subdomain.rb +2 -2
- data/lib/apill/requests/base.rb +19 -19
- data/lib/apill/requests/rack.rb +21 -6
- data/lib/apill/requests/rails.rb +15 -4
- data/lib/apill/tokens/base64.rb +44 -0
- data/lib/apill/tokens/base64s/invalid.rb +13 -0
- data/lib/apill/tokens/base64s/null.rb +13 -0
- data/lib/apill/tokens/{invalid_request_authorization.rb → invalid.rb} +6 -2
- data/lib/apill/tokens/{request_authorization.rb → json_web_token.rb} +5 -5
- data/lib/apill/tokens/json_web_tokens/invalid.rb +13 -0
- data/lib/apill/tokens/json_web_tokens/null.rb +13 -0
- data/lib/apill/tokens/{null_request_authorization.rb → null.rb} +5 -1
- data/lib/apill/version.rb +1 -1
- data/spec/apill/middleware/api_request_spec.rb +2 -2
- data/spec/apill/requests/rack_spec.rb +97 -10
- data/spec/apill/requests/rails_spec.rb +97 -10
- data/spec/apill/tokens/base64_spec.rb +43 -0
- data/spec/apill/tokens/json_web_token_spec.rb +49 -0
- data/spec/support/private_keys.rb +12 -3
- metadata +14 -7
- data/spec/apill/tokens/request_authorization_spec.rb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 905997a468c58168a9f87fbae4df382ced3cc1fd
|
4
|
+
data.tar.gz: d354947d9ca949dadaad2d25969c5f7865b0652c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a8576261ae11512401546d1b2e22b6e435921ab67ec2efce00e0ddeabcfff846522d1a2b918dbeff6c7175166004aee450db10eb6fed6cd136487c6c568b867e
|
7
|
+
data.tar.gz: fdd74cbe6f6245d3b6caa3b730487cbbf04bb0c80c08deecc5a5dab7b84f216fe403732142191d57892a0313d2a65515b30c18474e6a41d5b388b9b1a249192a
|
@@ -9,13 +9,13 @@ class Subdomain
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def matches?(request)
|
12
|
-
self.request = request
|
12
|
+
self.request = Requests::Base.resolve(request)
|
13
13
|
|
14
14
|
allowed_subdomains.include? request.subdomain
|
15
15
|
end
|
16
16
|
|
17
17
|
def matches_api_subdomain?(request)
|
18
|
-
self.request = request
|
18
|
+
self.request = Requests::Base.resolve(request)
|
19
19
|
|
20
20
|
allowed_api_subdomains.include? request.subdomain
|
21
21
|
end
|
data/lib/apill/requests/base.rb
CHANGED
@@ -1,10 +1,15 @@
|
|
1
|
-
require 'apill/tokens/
|
2
|
-
require 'apill/tokens/
|
1
|
+
require 'apill/tokens/json_web_tokens/invalid'
|
2
|
+
require 'apill/tokens/json_web_token'
|
3
3
|
|
4
4
|
module Apill
|
5
5
|
module Requests
|
6
6
|
class Base
|
7
|
-
|
7
|
+
BASE64_PATTERN = %r{[A-Za-z0-9_/\+\=\-\.]}
|
8
|
+
BASE64_TOKEN_PARAM_NAME = 'token_b64'.freeze
|
9
|
+
JSON_WEB_TOKEN_PARAM_NAME = 'token_jwt'.freeze
|
10
|
+
JSON_WEB_TOKEN_PATTERN = /(#{BASE64_PATTERN}+?\.){4}#{BASE64_PATTERN}+?/
|
11
|
+
BASE64_TOKEN_HEADER_PATTERN = /\A(?:Basic|Bearer)\s+(.*)\z/
|
12
|
+
JSON_WEB_TOKEN_HEADER_PATTERN = /\AToken\s+(.*)\z/
|
8
13
|
|
9
14
|
attr_accessor :token_private_key,
|
10
15
|
:request
|
@@ -85,18 +90,17 @@ class Base
|
|
85
90
|
end
|
86
91
|
|
87
92
|
def authorization_token_from_header
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
raw_token: raw_authorization_token_from_params || '')
|
93
|
+
case raw_authorization_header
|
94
|
+
when JSON_WEB_TOKEN_HEADER_PATTERN
|
95
|
+
Tokens::JsonWebToken.convert(
|
96
|
+
token_private_key: token_private_key,
|
97
|
+
raw_token: raw_authorization_header[JSON_WEB_TOKEN_HEADER_PATTERN, 1])
|
98
|
+
when BASE64_TOKEN_HEADER_PATTERN
|
99
|
+
Tokens::Base64.convert(
|
100
|
+
raw_token: raw_authorization_header[BASE64_TOKEN_HEADER_PATTERN, 1])
|
101
|
+
else
|
102
|
+
Tokens::Null.instance
|
103
|
+
end
|
100
104
|
end
|
101
105
|
|
102
106
|
private
|
@@ -104,10 +108,6 @@ class Base
|
|
104
108
|
def raw_host
|
105
109
|
request.fetch('HTTP_HOST', '')
|
106
110
|
end
|
107
|
-
|
108
|
-
def raw_authorization_token_from_header
|
109
|
-
raw_authorization_header[TOKEN_PATTERN, 1] || ''
|
110
|
-
end
|
111
111
|
end
|
112
112
|
end
|
113
113
|
end
|
data/lib/apill/requests/rack.rb
CHANGED
@@ -1,12 +1,31 @@
|
|
1
1
|
require 'apill/configuration'
|
2
2
|
require 'apill/requests/base'
|
3
3
|
require 'apill/accept_header'
|
4
|
+
require 'apill/tokens/json_web_token'
|
5
|
+
require 'apill/tokens/base64'
|
4
6
|
|
5
7
|
module Apill
|
6
8
|
module Requests
|
7
9
|
class Rack < Base
|
8
|
-
ACCEPT_PARAM_PATTERN
|
9
|
-
|
10
|
+
ACCEPT_PARAM_PATTERN = /(?:\A|&)accept=(.+?)(?=\z|&)/
|
11
|
+
BASE64_TOKEN_PARAM_PATTERN = /(?:\A|&)#{BASE64_TOKEN_PARAM_NAME}=(.*)(?=\z|&)/
|
12
|
+
JSON_WEB_TOKEN_PARAM_PATTERN = /(?:\A|&)#{JSON_WEB_TOKEN_PARAM_NAME}=(.*)(?=\z|&)/
|
13
|
+
|
14
|
+
def authorization_token_from_params
|
15
|
+
case request['QUERY_STRING']
|
16
|
+
when JSON_WEB_TOKEN_PARAM_PATTERN
|
17
|
+
Tokens::JsonWebToken.convert(
|
18
|
+
token_private_key: token_private_key,
|
19
|
+
raw_token: request['QUERY_STRING'][JSON_WEB_TOKEN_PARAM_PATTERN, 1] || '',
|
20
|
+
)
|
21
|
+
when BASE64_TOKEN_PARAM_PATTERN
|
22
|
+
base64_token = request['QUERY_STRING'][BASE64_TOKEN_PARAM_PATTERN, 1]
|
23
|
+
|
24
|
+
Tokens::Base64.convert(raw_token: base64_token)
|
25
|
+
else
|
26
|
+
Tokens::Null.instance
|
27
|
+
end
|
28
|
+
end
|
10
29
|
|
11
30
|
private
|
12
31
|
|
@@ -22,10 +41,6 @@ class Rack < Base
|
|
22
41
|
request['HTTP_AUTHORIZATION'] || ''
|
23
42
|
end
|
24
43
|
|
25
|
-
def raw_authorization_token_from_params
|
26
|
-
URI.unescape(request['QUERY_STRING'][AUTH_TOKEN_PARAM_PATTERN, 1] || '')
|
27
|
-
end
|
28
|
-
|
29
44
|
def raw_request_application_name
|
30
45
|
request['HTTP_X_APPLICATION_NAME']
|
31
46
|
end
|
data/lib/apill/requests/rails.rb
CHANGED
@@ -1,10 +1,25 @@
|
|
1
1
|
require 'apill/configuration'
|
2
2
|
require 'apill/requests/base'
|
3
3
|
require 'apill/accept_header'
|
4
|
+
require 'apill/tokens/json_web_token'
|
5
|
+
require 'apill/tokens/base64'
|
4
6
|
|
5
7
|
module Apill
|
6
8
|
module Requests
|
7
9
|
class Rails < Base
|
10
|
+
def authorization_token_from_params
|
11
|
+
case
|
12
|
+
when request.params.key?(JSON_WEB_TOKEN_PARAM_NAME)
|
13
|
+
Tokens::JsonWebToken.convert(
|
14
|
+
token_private_key: token_private_key,
|
15
|
+
raw_token: request.params[JSON_WEB_TOKEN_PARAM_NAME] || '')
|
16
|
+
when request.params.key?(BASE64_TOKEN_PARAM_NAME)
|
17
|
+
Tokens::Base64.convert(raw_token: request.params[BASE64_TOKEN_PARAM_NAME] || '')
|
18
|
+
else
|
19
|
+
Tokens::Null.instance
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
8
23
|
private
|
9
24
|
|
10
25
|
def raw_accept_header_from_header
|
@@ -19,10 +34,6 @@ class Rails < Base
|
|
19
34
|
request.headers['HTTP_AUTHORIZATION'] || ''
|
20
35
|
end
|
21
36
|
|
22
|
-
def raw_authorization_token_from_params
|
23
|
-
request.params['auth_token'] || ''
|
24
|
-
end
|
25
|
-
|
26
37
|
def raw_request_application_name
|
27
38
|
request.headers['X-Application-Name']
|
28
39
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'apill/tokens/base64s/null'
|
3
|
+
require 'apill/tokens/base64s/invalid'
|
4
|
+
|
5
|
+
module Apill
|
6
|
+
module Tokens
|
7
|
+
class Base64
|
8
|
+
attr_accessor :token
|
9
|
+
|
10
|
+
def initialize(token:)
|
11
|
+
self.token = token
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid?
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
def blank?
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_h
|
23
|
+
[
|
24
|
+
{
|
25
|
+
'token' => token,
|
26
|
+
},
|
27
|
+
{
|
28
|
+
'typ' => 'base64',
|
29
|
+
},
|
30
|
+
]
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.convert(raw_token:)
|
34
|
+
return Base64s::Null.instance if raw_token.to_s == ''
|
35
|
+
|
36
|
+
::Base64.strict_decode64(raw_token)
|
37
|
+
|
38
|
+
new(token: raw_token)
|
39
|
+
rescue ArgumentError
|
40
|
+
Base64s::Invalid.instance
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -2,7 +2,7 @@ require 'singleton'
|
|
2
2
|
|
3
3
|
module Apill
|
4
4
|
module Tokens
|
5
|
-
class
|
5
|
+
class Invalid
|
6
6
|
include Singleton
|
7
7
|
|
8
8
|
def valid?
|
@@ -14,7 +14,11 @@ class InvalidRequestAuthorization
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def to_h
|
17
|
-
|
17
|
+
{}
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
''
|
18
22
|
end
|
19
23
|
end
|
20
24
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'jwt'
|
2
2
|
require 'json/jwt'
|
3
|
-
require 'apill/tokens/
|
4
|
-
require 'apill/tokens/
|
3
|
+
require 'apill/tokens/json_web_tokens/invalid'
|
4
|
+
require 'apill/tokens/json_web_tokens/null'
|
5
5
|
|
6
6
|
module Apill
|
7
7
|
module Tokens
|
8
|
-
class
|
8
|
+
class JsonWebToken
|
9
9
|
attr_accessor :token
|
10
10
|
|
11
11
|
def initialize(token:)
|
@@ -25,7 +25,7 @@ class RequestAuthorization
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def self.convert(raw_token:, token_private_key: Apill.configuration.token_private_key)
|
28
|
-
return
|
28
|
+
return JsonWebTokens::Null.instance if raw_token.to_s == ''
|
29
29
|
|
30
30
|
decrypted_token = JSON::JWT.decode(raw_token, token_private_key).plain_text
|
31
31
|
decoded_token = JWT.decode(decrypted_token,
|
@@ -55,7 +55,7 @@ class RequestAuthorization
|
|
55
55
|
JWT::InvalidJtiError,
|
56
56
|
OpenSSL::PKey::RSAError
|
57
57
|
|
58
|
-
|
58
|
+
JsonWebTokens::Invalid.instance
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
@@ -2,7 +2,7 @@ require 'singleton'
|
|
2
2
|
|
3
3
|
module Apill
|
4
4
|
module Tokens
|
5
|
-
class
|
5
|
+
class Null
|
6
6
|
include Singleton
|
7
7
|
|
8
8
|
def valid?
|
@@ -16,6 +16,10 @@ class NullRequestAuthorization
|
|
16
16
|
def to_h
|
17
17
|
[{}, {}]
|
18
18
|
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
''
|
22
|
+
end
|
19
23
|
end
|
20
24
|
end
|
21
25
|
end
|
data/lib/apill/version.rb
CHANGED
@@ -132,7 +132,7 @@ describe ApiRequest, singletons: HumanError::Configuration do
|
|
132
132
|
request = {
|
133
133
|
'HTTP_HOST' => 'api.example.com',
|
134
134
|
'HTTP_ACCEPT' => 'application/vnd.matrix+zion;version=1.0.0',
|
135
|
-
'HTTP_AUTHORIZATION' => "Token #{
|
135
|
+
'HTTP_AUTHORIZATION' => "Token #{valid_jwt_token}",
|
136
136
|
'QUERY_STRING' => 'accept=application/vnd.matrix+zion;version=1.0.0',
|
137
137
|
}
|
138
138
|
|
@@ -150,7 +150,7 @@ describe ApiRequest, singletons: HumanError::Configuration do
|
|
150
150
|
request = {
|
151
151
|
'HTTP_HOST' => 'api.example.com',
|
152
152
|
'HTTP_ACCEPT' => 'application/vnd.matrix+zion;version=1.0.0',
|
153
|
-
'HTTP_AUTHORIZATION' => "Token #{
|
153
|
+
'HTTP_AUTHORIZATION' => "Token #{invalid_jwt_token}",
|
154
154
|
'QUERY_STRING' => 'accept=application/vnd.matrix+zion;version=1.0.0',
|
155
155
|
}
|
156
156
|
|
@@ -54,7 +54,7 @@ describe Rack do
|
|
54
54
|
|
55
55
|
it 'finds the authorization token from the header' do
|
56
56
|
raw_request = {
|
57
|
-
'HTTP_AUTHORIZATION' => "Token #{
|
57
|
+
'HTTP_AUTHORIZATION' => "Token #{valid_jwt_token}",
|
58
58
|
'QUERY_STRING' => '',
|
59
59
|
}
|
60
60
|
request = Rack.new(token_private_key: test_private_key,
|
@@ -68,24 +68,52 @@ describe Rack do
|
|
68
68
|
])
|
69
69
|
end
|
70
70
|
|
71
|
-
it '
|
71
|
+
it 'finds the Base64 token from the header' do
|
72
72
|
raw_request = {
|
73
|
-
'HTTP_AUTHORIZATION' => "#{
|
73
|
+
'HTTP_AUTHORIZATION' => "Basic #{valid_b64_token}",
|
74
74
|
'QUERY_STRING' => '',
|
75
75
|
}
|
76
76
|
request = Rack.new(token_private_key: test_private_key,
|
77
77
|
request: raw_request)
|
78
78
|
|
79
|
-
expect(request.authorization_token).
|
80
|
-
expect(request.authorization_token.to_h).to eql(
|
79
|
+
expect(request.authorization_token).to be_valid
|
80
|
+
expect(request.authorization_token.to_h).to eql(
|
81
|
+
[
|
82
|
+
{ 'token' => valid_b64_token },
|
83
|
+
{ 'typ' => 'base64' },
|
84
|
+
])
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'finds a null token from the header if there is no header' do
|
88
|
+
raw_request = {
|
89
|
+
'HTTP_AUTHORIZATION' => '',
|
90
|
+
'QUERY_STRING' => '',
|
91
|
+
}
|
92
|
+
request = Rack.new(token_private_key: test_private_key,
|
93
|
+
request: raw_request)
|
94
|
+
|
95
|
+
expect(request.authorization_token).to be_valid
|
96
|
+
expect(request.authorization_token).to be_blank
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'ignores incorrectly passed in tokens since we do not know what to do' do
|
100
|
+
raw_request = {
|
101
|
+
'HTTP_AUTHORIZATION' => "#{valid_jwt_token}",
|
102
|
+
'QUERY_STRING' => '',
|
103
|
+
}
|
104
|
+
request = Rack.new(token_private_key: test_private_key,
|
105
|
+
request: raw_request)
|
106
|
+
|
107
|
+
expect(request.authorization_token).to be_valid
|
108
|
+
expect(request.authorization_token).to be_blank
|
81
109
|
end
|
82
110
|
|
83
111
|
it 'finds the authorization token from the params if the authorization token from ' \
|
84
112
|
'the header is invalid and the authorization token from the params is valid' do
|
85
113
|
|
86
114
|
raw_request = {
|
87
|
-
'HTTP_AUTHORIZATION' => "Token #{
|
88
|
-
'QUERY_STRING' => "
|
115
|
+
'HTTP_AUTHORIZATION' => "Token #{invalid_jwt_token}",
|
116
|
+
'QUERY_STRING' => "token_jwt=#{valid_jwt_token}",
|
89
117
|
}
|
90
118
|
request = Rack.new(token_private_key: test_private_key,
|
91
119
|
request: raw_request)
|
@@ -102,7 +130,7 @@ describe Rack do
|
|
102
130
|
'the header is not present and the authorization token from the params is valid' do
|
103
131
|
|
104
132
|
raw_request = {
|
105
|
-
'QUERY_STRING' => "
|
133
|
+
'QUERY_STRING' => "token_jwt=#{valid_jwt_token}",
|
106
134
|
}
|
107
135
|
request = Rack.new(token_private_key: test_private_key,
|
108
136
|
request: raw_request)
|
@@ -126,9 +154,9 @@ describe Rack do
|
|
126
154
|
expect(request.authorization_token.to_h).to eql([{}, {}])
|
127
155
|
end
|
128
156
|
|
129
|
-
it 'finds the
|
157
|
+
it 'finds the JSON web token from the params' do
|
130
158
|
raw_request = {
|
131
|
-
'QUERY_STRING' => "
|
159
|
+
'QUERY_STRING' => "token_jwt=#{valid_jwt_token}",
|
132
160
|
}
|
133
161
|
request = Rack.new(token_private_key: test_private_key,
|
134
162
|
request: raw_request)
|
@@ -141,6 +169,65 @@ describe Rack do
|
|
141
169
|
])
|
142
170
|
end
|
143
171
|
|
172
|
+
it 'finds the generic Base64 web token from the params' do
|
173
|
+
raw_request = {
|
174
|
+
'QUERY_STRING' => "token_b64=#{valid_b64_token}",
|
175
|
+
}
|
176
|
+
request = Rack.new(request: raw_request)
|
177
|
+
|
178
|
+
expect(request.authorization_token).to be_valid
|
179
|
+
expect(request.authorization_token.to_h).to eql(
|
180
|
+
[
|
181
|
+
{ 'token' => valid_b64_token },
|
182
|
+
{ 'typ' => 'base64' },
|
183
|
+
])
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'finds invalid tokens from the params' do
|
187
|
+
raw_request = {
|
188
|
+
'QUERY_STRING' => 'token_b64=bla.h',
|
189
|
+
}
|
190
|
+
request = Rack.new(request: raw_request)
|
191
|
+
|
192
|
+
expect(request.authorization_token_from_params).not_to be_valid
|
193
|
+
expect(request.authorization_token_from_params).not_to be_blank
|
194
|
+
|
195
|
+
raw_request = {
|
196
|
+
'QUERY_STRING' => "token_jwt=#{invalid_jwt_token}",
|
197
|
+
}
|
198
|
+
request = Rack.new(token_private_key: test_private_key,
|
199
|
+
request: raw_request)
|
200
|
+
|
201
|
+
expect(request.authorization_token_from_params).not_to be_valid
|
202
|
+
expect(request.authorization_token_from_params).not_to be_blank
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'finds the null token from the params if nothing is passed in' do
|
206
|
+
raw_request = {
|
207
|
+
'QUERY_STRING' => 'token_b64=',
|
208
|
+
}
|
209
|
+
request = Rack.new(request: raw_request)
|
210
|
+
|
211
|
+
expect(request.authorization_token_from_params).to be_valid
|
212
|
+
expect(request.authorization_token_from_params).to be_blank
|
213
|
+
|
214
|
+
raw_request = {
|
215
|
+
'QUERY_STRING' => 'token_jwt=',
|
216
|
+
}
|
217
|
+
request = Rack.new(request: raw_request)
|
218
|
+
|
219
|
+
expect(request.authorization_token_from_params).to be_valid
|
220
|
+
expect(request.authorization_token_from_params).to be_blank
|
221
|
+
|
222
|
+
raw_request = {
|
223
|
+
'QUERY_STRING' => '',
|
224
|
+
}
|
225
|
+
request = Rack.new(request: raw_request)
|
226
|
+
|
227
|
+
expect(request.authorization_token_from_params).to be_valid
|
228
|
+
expect(request.authorization_token_from_params).to be_blank
|
229
|
+
end
|
230
|
+
|
144
231
|
it 'defaults to the application name in the configuration if none is found in ' \
|
145
232
|
'the header' do
|
146
233
|
|
@@ -45,7 +45,7 @@ describe Rails do
|
|
45
45
|
it 'finds the authorization token from the header' do
|
46
46
|
raw_request = OpenStruct.new(
|
47
47
|
headers: {
|
48
|
-
'HTTP_AUTHORIZATION' => "Token #{
|
48
|
+
'HTTP_AUTHORIZATION' => "Token #{valid_jwt_token}",
|
49
49
|
},
|
50
50
|
params: {})
|
51
51
|
request = Rails.new(token_private_key: test_private_key,
|
@@ -59,17 +59,45 @@ describe Rails do
|
|
59
59
|
])
|
60
60
|
end
|
61
61
|
|
62
|
-
it '
|
62
|
+
it 'finds the Base64 token from the header' do
|
63
63
|
raw_request = OpenStruct.new(
|
64
64
|
headers: {
|
65
|
-
'HTTP_AUTHORIZATION' => "#{
|
65
|
+
'HTTP_AUTHORIZATION' => "Basic #{valid_b64_token}",
|
66
66
|
},
|
67
67
|
params: {})
|
68
68
|
request = Rails.new(token_private_key: test_private_key,
|
69
69
|
request: raw_request)
|
70
70
|
|
71
|
-
expect(request.authorization_token).
|
72
|
-
expect(request.authorization_token.to_h).to eql(
|
71
|
+
expect(request.authorization_token).to be_valid
|
72
|
+
expect(request.authorization_token.to_h).to eql(
|
73
|
+
[
|
74
|
+
{ 'token' => valid_b64_token },
|
75
|
+
{ 'typ' => 'base64' },
|
76
|
+
])
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'finds a null token from the header if there is no header' do
|
80
|
+
raw_request = OpenStruct.new(
|
81
|
+
headers: {},
|
82
|
+
params: {})
|
83
|
+
request = Rails.new(token_private_key: test_private_key,
|
84
|
+
request: raw_request)
|
85
|
+
|
86
|
+
expect(request.authorization_token).to be_valid
|
87
|
+
expect(request.authorization_token).to be_blank
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'ignores incorrectly passed in tokens since we do not know what to do' do
|
91
|
+
raw_request = OpenStruct.new(
|
92
|
+
headers: {
|
93
|
+
'HTTP_AUTHORIZATION' => "#{valid_jwt_token}",
|
94
|
+
},
|
95
|
+
params: {})
|
96
|
+
request = Rails.new(token_private_key: test_private_key,
|
97
|
+
request: raw_request)
|
98
|
+
|
99
|
+
expect(request.authorization_token).to be_valid
|
100
|
+
expect(request.authorization_token).to be_blank
|
73
101
|
end
|
74
102
|
|
75
103
|
it 'finds the authorization token from the params if the authorization token from ' \
|
@@ -77,9 +105,9 @@ describe Rails do
|
|
77
105
|
|
78
106
|
raw_request = OpenStruct.new(
|
79
107
|
headers: {
|
80
|
-
'HTTP_AUTHORIZATION' => "Token #{
|
108
|
+
'HTTP_AUTHORIZATION' => "Token #{invalid_jwt_token}",
|
81
109
|
},
|
82
|
-
params: { '
|
110
|
+
params: { 'token_jwt' => valid_jwt_token })
|
83
111
|
request = Rails.new(token_private_key: test_private_key,
|
84
112
|
request: raw_request)
|
85
113
|
|
@@ -96,7 +124,7 @@ describe Rails do
|
|
96
124
|
|
97
125
|
raw_request = OpenStruct.new(
|
98
126
|
headers: {},
|
99
|
-
params: { '
|
127
|
+
params: { 'token_jwt' => valid_jwt_token })
|
100
128
|
request = Rails.new(token_private_key: test_private_key,
|
101
129
|
request: raw_request)
|
102
130
|
|
@@ -119,10 +147,10 @@ describe Rails do
|
|
119
147
|
expect(request.authorization_token.to_h).to eql([{}, {}])
|
120
148
|
end
|
121
149
|
|
122
|
-
it 'finds the
|
150
|
+
it 'finds the JSON web token from the params' do
|
123
151
|
raw_request = OpenStruct.new(
|
124
152
|
headers: {},
|
125
|
-
params: { '
|
153
|
+
params: { 'token_jwt' => valid_jwt_token })
|
126
154
|
request = Rails.new(token_private_key: test_private_key,
|
127
155
|
request: raw_request)
|
128
156
|
|
@@ -134,6 +162,65 @@ describe Rails do
|
|
134
162
|
])
|
135
163
|
end
|
136
164
|
|
165
|
+
it 'finds the generic Base64 web token from the params' do
|
166
|
+
raw_request = OpenStruct.new(
|
167
|
+
headers: {},
|
168
|
+
params: { 'token_b64' => valid_b64_token })
|
169
|
+
request = Rails.new(request: raw_request)
|
170
|
+
|
171
|
+
expect(request.authorization_token).to be_valid
|
172
|
+
expect(request.authorization_token.to_h).to eql(
|
173
|
+
[
|
174
|
+
{ 'token' => valid_b64_token },
|
175
|
+
{ 'typ' => 'base64' },
|
176
|
+
])
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'finds invalid tokens from the params' do
|
180
|
+
raw_request = OpenStruct.new(
|
181
|
+
headers: {},
|
182
|
+
params: { 'token_b64' => 'bla.h' })
|
183
|
+
request = Rails.new(request: raw_request)
|
184
|
+
|
185
|
+
expect(request.authorization_token_from_params).not_to be_valid
|
186
|
+
expect(request.authorization_token_from_params).not_to be_blank
|
187
|
+
|
188
|
+
raw_request = OpenStruct.new(
|
189
|
+
headers: {},
|
190
|
+
params: { 'token_jwt' => invalid_jwt_token })
|
191
|
+
request = Rails.new(token_private_key: test_private_key,
|
192
|
+
request: raw_request)
|
193
|
+
|
194
|
+
expect(request.authorization_token_from_params).not_to be_valid
|
195
|
+
expect(request.authorization_token_from_params).not_to be_blank
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'finds the null token from the params if nothing is passed in' do
|
199
|
+
raw_request = OpenStruct.new(
|
200
|
+
headers: {},
|
201
|
+
params: { 'token_b64' => '' })
|
202
|
+
request = Rails.new(request: raw_request)
|
203
|
+
|
204
|
+
expect(request.authorization_token_from_params).to be_valid
|
205
|
+
expect(request.authorization_token_from_params).to be_blank
|
206
|
+
|
207
|
+
raw_request = OpenStruct.new(
|
208
|
+
headers: {},
|
209
|
+
params: { 'token_jwt' => '' })
|
210
|
+
request = Rails.new(request: raw_request)
|
211
|
+
|
212
|
+
expect(request.authorization_token_from_params).to be_valid
|
213
|
+
expect(request.authorization_token_from_params).to be_blank
|
214
|
+
|
215
|
+
raw_request = OpenStruct.new(
|
216
|
+
headers: {},
|
217
|
+
params: {})
|
218
|
+
request = Rails.new(request: raw_request)
|
219
|
+
|
220
|
+
expect(request.authorization_token_from_params).to be_valid
|
221
|
+
expect(request.authorization_token_from_params).to be_blank
|
222
|
+
end
|
223
|
+
|
137
224
|
it 'defaults to the application name in the configuration if none is found in ' \
|
138
225
|
'the header' do
|
139
226
|
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'apill/tokens/base64'
|
3
|
+
|
4
|
+
module Apill
|
5
|
+
module Tokens
|
6
|
+
describe Base64 do
|
7
|
+
it 'is valid' do
|
8
|
+
expect(Base64.new(token: 'foo')).to be_valid
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'is not blank' do
|
12
|
+
expect(Base64.new(token: 'foo')).not_to be_blank
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'can convert itself into a hash' do
|
16
|
+
token = Base64.new(token: 'foo')
|
17
|
+
|
18
|
+
expect(token.to_h).to eql([
|
19
|
+
{
|
20
|
+
'token' => 'foo',
|
21
|
+
},
|
22
|
+
{
|
23
|
+
'typ' => 'base64',
|
24
|
+
},
|
25
|
+
])
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'can convert itself into a null token' do
|
29
|
+
token = Base64.convert(raw_token: nil)
|
30
|
+
|
31
|
+
expect(token).to be_valid
|
32
|
+
expect(token).to be_blank
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'can convert itself into an invalid token' do
|
36
|
+
token = Base64.convert(raw_token: 'bla.h')
|
37
|
+
|
38
|
+
expect(token).not_to be_valid
|
39
|
+
expect(token).not_to be_blank
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'apill/tokens/json_web_token'
|
3
|
+
|
4
|
+
module Apill
|
5
|
+
module Tokens
|
6
|
+
describe JsonWebToken do
|
7
|
+
it 'can convert an empty token' do
|
8
|
+
token = JsonWebToken.convert(token_private_key: test_private_key,
|
9
|
+
raw_token: nil)
|
10
|
+
|
11
|
+
expect(token).to be_a JsonWebTokens::Null
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'can convert an invalid token' do
|
15
|
+
token = JsonWebToken.convert(token_private_key: test_private_key,
|
16
|
+
raw_token: invalid_jwt_token)
|
17
|
+
|
18
|
+
expect(token).to be_a JsonWebTokens::Invalid
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'can verify an expired token' do
|
22
|
+
expired_jwe = valid_jwt_token('exp' => 1.day.ago.to_i,
|
23
|
+
'baz' => 'bar')
|
24
|
+
token = JsonWebToken.convert(
|
25
|
+
token_private_key: test_private_key,
|
26
|
+
raw_token: expired_jwe)
|
27
|
+
|
28
|
+
expect(token).to be_a JsonWebTokens::Invalid
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'can convert an invalidly signed token' do
|
32
|
+
other_private_key = OpenSSL::PKey::RSA.new(2048)
|
33
|
+
token = JsonWebToken.convert(
|
34
|
+
token_private_key: other_private_key,
|
35
|
+
raw_token: valid_jwt_token)
|
36
|
+
|
37
|
+
expect(token).to be_a JsonWebTokens::Invalid
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'can convert a valid token' do
|
41
|
+
token = JsonWebToken.convert(token_private_key: test_private_key,
|
42
|
+
raw_token: valid_jwt_token)
|
43
|
+
|
44
|
+
expect(token).to be_a JsonWebToken
|
45
|
+
expect(token.to_h).to eql([{ 'bar' => 'baz' }, { 'typ' => 'JWT', 'alg' => 'RS256' }])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
require 'json/jwt'
|
2
|
+
require 'base64'
|
2
3
|
|
3
4
|
def test_private_key
|
4
5
|
OpenSSL::PKey::RSA.new File.read(File.expand_path('../fixtures/test_rsa_key', __dir__))
|
5
6
|
end
|
6
7
|
|
7
|
-
def
|
8
|
+
def valid_jwt_token(payload = { 'bar' => 'baz' })
|
8
9
|
@valid_token ||= begin
|
9
10
|
jwt = JSON::JWT.new(payload)
|
10
11
|
jws = jwt.sign(test_private_key, :RS256)
|
@@ -14,6 +15,14 @@ def valid_token(payload = { 'bar' => 'baz' })
|
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
17
|
-
def
|
18
|
-
@invalid_token ||=
|
18
|
+
def invalid_jwt_token
|
19
|
+
@invalid_token ||= valid_jwt_token.tr('a', 'f')
|
20
|
+
end
|
21
|
+
|
22
|
+
def valid_b64_token(payload = 'hereisacoollittlestring')
|
23
|
+
@valid_b64_token ||= Base64.encode64(payload).chomp
|
24
|
+
end
|
25
|
+
|
26
|
+
def invalid_b64_token
|
27
|
+
@invalid_b64_token ||= valid_b64_token.tr('abcdefghijklmnop', '$o#m$k#i$g#e$c#a')
|
19
28
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apill
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0
|
4
|
+
version: 4.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jfelchner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-10-
|
11
|
+
date: 2015-10-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: human_error
|
@@ -119,9 +119,14 @@ files:
|
|
119
119
|
- lib/apill/responses/invalid_subdomain.rb
|
120
120
|
- lib/apill/responses/invalid_token.rb
|
121
121
|
- lib/apill/serializers/json_api.rb
|
122
|
-
- lib/apill/tokens/
|
123
|
-
- lib/apill/tokens/
|
124
|
-
- lib/apill/tokens/
|
122
|
+
- lib/apill/tokens/base64.rb
|
123
|
+
- lib/apill/tokens/base64s/invalid.rb
|
124
|
+
- lib/apill/tokens/base64s/null.rb
|
125
|
+
- lib/apill/tokens/invalid.rb
|
126
|
+
- lib/apill/tokens/json_web_token.rb
|
127
|
+
- lib/apill/tokens/json_web_tokens/invalid.rb
|
128
|
+
- lib/apill/tokens/json_web_tokens/null.rb
|
129
|
+
- lib/apill/tokens/null.rb
|
125
130
|
- lib/apill/version.rb
|
126
131
|
- spec/apill/accept_header_spec.rb
|
127
132
|
- spec/apill/errors/invalid_api_request_spec.rb
|
@@ -142,7 +147,8 @@ files:
|
|
142
147
|
- spec/apill/resource/processors/indexing_spec.rb
|
143
148
|
- spec/apill/resource/processors/paging_spec.rb
|
144
149
|
- spec/apill/resource/processors/sorting_spec.rb
|
145
|
-
- spec/apill/tokens/
|
150
|
+
- spec/apill/tokens/base64_spec.rb
|
151
|
+
- spec/apill/tokens/json_web_token_spec.rb
|
146
152
|
- spec/fixtures/test_rsa_key
|
147
153
|
- spec/fixtures/test_rsa_key.pub
|
148
154
|
- spec/spec_helper.rb
|
@@ -191,7 +197,8 @@ test_files:
|
|
191
197
|
- spec/apill/resource/processors/indexing_spec.rb
|
192
198
|
- spec/apill/resource/processors/paging_spec.rb
|
193
199
|
- spec/apill/resource/processors/sorting_spec.rb
|
194
|
-
- spec/apill/tokens/
|
200
|
+
- spec/apill/tokens/base64_spec.rb
|
201
|
+
- spec/apill/tokens/json_web_token_spec.rb
|
195
202
|
- spec/fixtures/test_rsa_key
|
196
203
|
- spec/fixtures/test_rsa_key.pub
|
197
204
|
- spec/spec_helper.rb
|
@@ -1,49 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'apill/tokens/request_authorization'
|
3
|
-
|
4
|
-
module Apill
|
5
|
-
module Tokens
|
6
|
-
describe RequestAuthorization do
|
7
|
-
it 'can convert an empty token' do
|
8
|
-
token = RequestAuthorization.convert(token_private_key: test_private_key,
|
9
|
-
raw_token: nil)
|
10
|
-
|
11
|
-
expect(token).to be_a NullRequestAuthorization
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'can convert an invalid token' do
|
15
|
-
token = RequestAuthorization.convert(token_private_key: test_private_key,
|
16
|
-
raw_token: invalid_token)
|
17
|
-
|
18
|
-
expect(token).to be_a InvalidRequestAuthorization
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'can verify an expired token' do
|
22
|
-
expired_jwe = valid_token('exp' => 1.day.ago.to_i,
|
23
|
-
'baz' => 'bar')
|
24
|
-
token = RequestAuthorization.convert(
|
25
|
-
token_private_key: test_private_key,
|
26
|
-
raw_token: expired_jwe)
|
27
|
-
|
28
|
-
expect(token).to be_a InvalidRequestAuthorization
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'can convert an invalidly signed token' do
|
32
|
-
other_private_key = OpenSSL::PKey::RSA.new(2048)
|
33
|
-
token = RequestAuthorization.convert(
|
34
|
-
token_private_key: other_private_key,
|
35
|
-
raw_token: valid_token)
|
36
|
-
|
37
|
-
expect(token).to be_a InvalidRequestAuthorization
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'can convert a valid token' do
|
41
|
-
token = RequestAuthorization.convert(token_private_key: test_private_key,
|
42
|
-
raw_token: valid_token)
|
43
|
-
|
44
|
-
expect(token).to be_a RequestAuthorization
|
45
|
-
expect(token.to_h).to eql([{ 'bar' => 'baz' }, { 'typ' => 'JWT', 'alg' => 'RS256' }])
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|