Skip to content

Commit 54c7ac9

Browse files
committed
[WS-2909] Add hmac signing capabilities to request-validation module
1 parent 1585bd0 commit 54c7ac9

File tree

7 files changed

+156
-2
lines changed

7 files changed

+156
-2
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
target/**
2+
dump.rdb

src/lua/api-gateway/validation/factory.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ local function _validateHmacSignature()
9696
return hmacSignatureValidator:validateSignature()
9797
end
9898

99+
local function _generateHmacSignature()
100+
local hmacSignatureValidator = HmacSignatureValidator:new()
101+
return hmacSignatureValidator:generateSignature()
102+
end
103+
99104
local function _validateOAuthToken()
100105
local oauthTokenValidator = OAuthTokenValidator:new()
101106
return oauthTokenValidator:validateRequest()
@@ -110,6 +115,7 @@ end
110115
return {
111116
validateApiKey = _validateApiKey,
112117
validateHmacSignature = _validateHmacSignature,
118+
generateHmacSignature = _generateHmacSignature,
113119
validateOAuthToken = _validateOAuthToken,
114120
validateUserProfile = _validateUserProfile,
115121
validateRequest = _validateRequest,

src/lua/api-gateway/validation/signing/hmacGenericSignatureValidator.lua

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ local _M = BaseValidator:new()
4343
local RESPONSES = {
4444
MISSING_SIGNATURE = { error_code = "403030", message = "Signature is missing" },
4545
INVALID_SIGNATURE = { error_code = "403033", message = "Signature is invalid" },
46+
MISSING_SOURCE = { error_code = "400001", message = "Missing digest source" },
47+
MISSING_SECRET = { error_code = "400002", message = "Missing digest secret" },
4648
-- unknown error is not used at the moment
4749
UNKNOWN_ERROR = { error_code = "503030", message = "Could not validate Signature"}
4850
}
@@ -69,6 +71,30 @@ function _M:validateSignature()
6971
return self:exitFn(RESPONSES.INVALID_SIGNATURE.error_code, cjson.encode(RESPONSES.INVALID_SIGNATURE))
7072
end
7173

74+
function _M:generateSignature()
75+
local source = ngx.var.hmac_sign_source_string
76+
local secret = ngx.var.hmac_sign_secret or ngx.ctx.key_secret -- ngx.ctx.key_secret is set by api key validator
77+
local algorithm = ngx.var.hmac_sign_method
78+
79+
if source == nil or source == '' then
80+
ngx.log(ngx.WARN, "Invalid sign request. Missing source.")
81+
return self:exitFn(RESPONSES.MISSING_SOURCE.error_code, cjson.encode(RESPONSES.MISSING_SOURCE))
82+
end
83+
84+
if secret == nil or secret == '' then
85+
ngx.log(ngx.WARN, "Invalid sign request. Missing secret.")
86+
return self:exitFn(RESPONSES.MISSING_SECRET.error_code, cjson.encode(RESPONSES.MISSING_SECRET))
87+
end
88+
89+
local hmac = RestyHMAC:new()
90+
local digest = ngx.encode_base64(hmac:digest(algorithm, secret, self:getHmacSource(source), true))
91+
92+
self:debug(ngx.DEBUG, "Generate HMAC DIGEST WITH secret=" .. secret .. " Got digest " .. digest .. " for source " .. source)
93+
ngx.var.generated_digest = digest
94+
95+
return self:exitFn(ngx.HTTP_OK)
96+
end
97+
7298
-- method to be overriden in the super classes to return another source
7399
-- some implementations may choose to apply a lowercase or other transformations
74100
-- NOTE: the same can be achieved by using

src/lua/api-gateway/validation/validatorsHandler.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ function ValidatorsHandler:getValidatorsList()
8484
}
8585
},
8686

87+
generate_hmac_signature = {
88+
defaultProperties = {
89+
path = '/generate_hmac_signature', order=2
90+
}
91+
},
92+
8793
-- service_plan validator usually contains throttling limits
8894
validate_service_plan = {
8995
defaultProperties = {

src/lua/api-gateway/validation/validatorsHandlerErrorDecorator.lua

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,10 @@ local DEFAULT_RESPONSES = {
6565
DELAY_CLIENT_ON_REQUEST = { http_status = 503, error_code = 503071, messsage = '', headers = { ["Retry_After"] = "300s" } , headers = { ["X-Request-Id"] = "ngx.var.requestId" }},
6666
-- CC Link validation
6767
INVALID_LINK = { http_status = 403, error_code = 403040, message = '{"error_code":"403040","message":"Invalid link"}' , headers = { ["X-Request-Id"] = "ngx.var.requestId" }},
68-
LINK_NOT_FOUND = { http_status = 404, error_code = 404040, message = '{"error_code":"404040","message":"Link not found"}' , headers = { ["X-Request-Id"] = "ngx.var.requestId" }}
68+
LINK_NOT_FOUND = { http_status = 404, error_code = 404040, message = '{"error_code":"404040","message":"Link not found"}' , headers = { ["X-Request-Id"] = "ngx.var.requestId" }},
69+
-- Generate Hmac validators
70+
MISSING_SOURCE = { http_status = 400, error_code = 400001, message = '{"error_code":"400001","message"="Missing digest source"}', headers = { ["X-Request-Id"] = "ngx.var.requestId" }},
71+
MISSING_SECRET = { http_status = 400, error_code = 400002, message = '{"error_code":"400002","message"="Missing digest secret"}', headers = { ["X-Request-Id"] = "ngx.var.requestId" }}
6972
}
7073

7174
local default_responses_array

test/perl/api-gateway/validation/signing/hmacGenericSignatureValidator.t

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ log_level('warn');
3131

3232
repeat_each(2);
3333

34-
plan tests => repeat_each() * (blocks() * 8) - 4;
34+
plan tests => repeat_each() * (blocks() * 9) + 10;
3535

3636
my $pwd = cwd();
3737

@@ -271,3 +271,109 @@ __DATA__
271271
[200,200,403,403,403,403]
272272
--- no_error_log
273273
[error]
274+
275+
=== TEST 6: test HMAC signature validation and generation
276+
--- http_config eval: $::HttpConfig
277+
--- config
278+
error_log ../test-logs/hmacGenericSignatureValidator_test6_error.log debug;
279+
include ../../api-gateway/api_key_service.conf;
280+
include ../../api-gateway/default_validators.conf;
281+
# customize error response
282+
set $validator_custom_error_responses '{
283+
"MISSING_KEY" : { "http_status" : 403, "error_code" : 403000, "message" : "while (1) {}{\\"code\\":1033,\\"description\\":\\"Developer key missing or invalid\\"}" },
284+
"INVALID_KEY" : { "http_status" : 403, "error_code" : 403003, "message" : "while (1) {}{\\"code\\":1033,\\"description\\":\\"Developer key missing or invalid\\"}" },
285+
"INVALID_SIGNATURE" : { "http_status" : 403, "error_code" : 403030, "message" : "while (1) {}{\\"code\\":1033,\\"description\\":\\"Call signature missing or invalid\\"}" },
286+
"INVALID_SIGNATURE" : { "http_status" : 403, "error_code" : 403033, "message" : "while (1) {}{\\"code\\":1033,\\"description\\":\\"Call signature missing or invalid\\"}" }
287+
}';
288+
289+
location /validate-and-sign {
290+
set $service_id 123456;
291+
292+
set $api_key $arg_api_key;
293+
set_if_empty $api_key $http_x_api_key;
294+
295+
set_by_lua $hmac_source_string 'return string.lower(ngx.var.request_method .. ngx.var.uri .. ngx.var.api_key)';
296+
297+
set $hmac_target_string $arg_api_signature;
298+
set $hmac_method sha1;
299+
300+
# Generate signature
301+
set_by_lua $hmac_sign_source_string 'return string.lower(ngx.var.request_method .. ngx.var.uri)';
302+
set $hmac_sign_method sha1;
303+
304+
set $validate_api_key on;
305+
set $validate_hmac_signature on;
306+
set $generate_hmac_signature on;
307+
set $generated_digest "-";
308+
309+
access_by_lua "ngx.apiGateway.validation.validateRequest()";
310+
content_by_lua 'ngx.say(ngx.var.generated_digest)';
311+
}
312+
313+
--- pipelined_requests eval
314+
[
315+
"POST /cache/api_key?key=sZ28nvYnStSUS2dSzedgnwkJtUdLkNdR&service_id=123456&secret=mO2AIfdUQeQFiGQq",
316+
"GET /validate-and-sign?api_key=sZ28nvYnStSUS2dSzedgnwkJtUdLkNdR&api_signature=XY1Y6BPr91I2gDbYmcahwA3mWzE=",
317+
# negative scenario: missing api-key
318+
"GET /validate-and-sign",
319+
# negative scenario: api_key present but invalid
320+
"GET /validate-and-sign?api_key=WRONG_KEY_WHICH_DOES_NOT_EXIST",
321+
# negative scenario: api_key is valid but the signature is not
322+
"GET /validate-and-sign?api_key=sZ28nvYnStSUS2dSzedgnwkJtUdLkNdR&api_signature=WRONG_SIGNATURE",
323+
# negative scenario: api_key is valid , missing signature
324+
"GET /validate-and-sign?api_key=sZ28nvYnStSUS2dSzedgnwkJtUdLkNdR"
325+
]
326+
--- response_body eval
327+
[
328+
"+OK\r\n",
329+
"5XPFapKr91/nLn3F+tzfkvSuE4A=\n",
330+
'while (1) {}{"code":1033,"description":"Developer key missing or invalid"}' . "\n",
331+
'while (1) {}{"code":1033,"description":"Developer key missing or invalid"}' . "\n",
332+
'while (1) {}{"code":1033,"description":"Call signature missing or invalid"}' . "\n",
333+
'while (1) {}{"code":1033,"description":"Call signature missing or invalid"}' . "\n"
334+
]
335+
--- error_code_like eval
336+
[200,200,403,403,403,403]
337+
--- no_error_log
338+
[error]
339+
340+
=== TEST 7: test HMAC digest in isolation
341+
--- http_config eval: $::HttpConfig
342+
--- config
343+
error_log ../test-logs/hmacGenericSignatureValidator_test7_error.log debug;
344+
include ../../api-gateway/api_key_service.conf;
345+
include ../../api-gateway/default_validators.conf;
346+
347+
location /generate_digest {
348+
# Generate signature
349+
set $hmac_sign_source_string $arg_source;
350+
set $hmac_sign_secret $arg_secret;
351+
set $hmac_sign_method sha1;
352+
353+
set $generate_hmac_signature on;
354+
set $generated_digest "-";
355+
356+
access_by_lua "ngx.apiGateway.validation.validateRequest()";
357+
content_by_lua 'ngx.say(ngx.var.generated_digest)';
358+
}
359+
--- pipelined_requests eval
360+
[
361+
"GET /generate_digest?source=SignThisLikeYouOwnIt&secret=mO2AIfdUQeQFiGQq",
362+
"GET /generate_digest?source=SignThisLikeYouOwnIt",
363+
"GET /generate_digest?secret=mO2AIfdUQeQFiGQq",
364+
"GET /generate_digest"
365+
]
366+
--- response_body eval
367+
[
368+
"DYUCC7E/MCyn+aNcCb5EhM7OPDE=\n",
369+
'{"error_code":"400002","message"="Missing digest secret"}
370+
',
371+
'{"error_code":"400001","message"="Missing digest source"}
372+
',
373+
'{"error_code":"400001","message"="Missing digest source"}
374+
'
375+
]
376+
--- error_code_like eval
377+
[200, 400, 400, 400]
378+
--- no_error_log
379+
[error]

test/resources/api-gateway/default_validators.conf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ location /validate_hmac_signature {
6161
content_by_lua 'ngx.apiGateway.validation.validateHmacSignature()';
6262
}
6363

64+
location /generate_hmac_signature {
65+
internal;
66+
content_by_lua 'ngx.apiGateway.validation.generateHmacSignature()';
67+
}
68+
6469
#
6570
# default OAuth Token validator impl along with the nginx variables it sets
6671
#

0 commit comments

Comments
 (0)