-
Notifications
You must be signed in to change notification settings - Fork 170
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
318 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# FAPI Policy | ||
|
||
## Description | ||
|
||
The FAPI policy supports various features of the Financial-grade API (FAPI) standard. | ||
|
||
## Example configuration | ||
|
||
``` | ||
"policy_chain": [ | ||
{ "name": "apicast.policy.fapi", "configuration": {} }, | ||
{ | ||
"name": "apicast.policy.apicast" | ||
} | ||
] | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"$schema": "http://apicast.io/policy-v1/schema#manifest#", | ||
"name": "The Financial-grade API (FAPI)", | ||
"summary": "Support FAPI profiles", | ||
"description": ["This policy adding support for Financial-grade API (API) profiles" | ||
], | ||
"version": "builtin", | ||
"configuration": { | ||
"type": "object", | ||
"properties": {} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
--- Financial-grade API (FAPI) policy | ||
|
||
local policy = require('apicast.policy') | ||
local _M = policy.new('Financial-grade API (FAPI) Policy', 'builtin') | ||
|
||
local uuid = require 'resty.jit-uuid' | ||
|
||
local new = _M.new | ||
local X_FAPI_TRANSACTION_ID_HEADER = "x-fapi-transaction-id" | ||
|
||
function _M.new(config) | ||
local self = new(config) | ||
return self | ||
end | ||
|
||
function _M:header_filter() | ||
-- Get x-fapi-transaction-id from the request | ||
local transaction_id = ngx.req.get_headers()[X_FAPI_TRANSACTION_ID_HEADER] | ||
if not transaction_id or transaction_id == "" then | ||
-- Nothing found, generate one | ||
transaction_id = ngx.resp.get_headers()[X_FAPI_TRANSACTION_ID_HEADER] | ||
if not transaction_id or transaction_id == "" then | ||
transaction_id = uuid.generate_v4() | ||
end | ||
end | ||
ngx.header[X_FAPI_TRANSACTION_ID_HEADER] = transaction_id | ||
end | ||
|
||
return _M |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
return require('fapi') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
local FAPIPolicy = require('apicast.policy.fapi') | ||
local uuid = require('resty.jit-uuid') | ||
|
||
describe('fapi_1_baseline_profile policy', function() | ||
local ngx_req_headers = {} | ||
local ngx_resp_headers = {} | ||
local context = {} | ||
before_each(function() | ||
ngx.header = {} | ||
ngx_req_headers = {} | ||
ngx_resp_headers = {} | ||
context = {} | ||
stub(ngx.req, 'get_headers', function() return ngx_req_headers end) | ||
stub(ngx.req, 'set_header', function(name, value) ngx_req_headers[name] = value end) | ||
stub(ngx.resp, 'get_headers', function() return ngx_resp_headers end) | ||
stub(ngx.resp, 'set_header', function(name, value) ngx_resp_headers[name] = value end) | ||
end) | ||
|
||
describe('.new', function() | ||
it('works without configuration', function() | ||
assert(FAPIPolicy.new({})) | ||
end) | ||
end) | ||
|
||
describe('.header_filter', function() | ||
it('Use value from request', function() | ||
ngx_req_headers['x-fapi-transaction-id'] = 'abc' | ||
local transaction_id_policy = FAPIPolicy.new({}) | ||
transaction_id_policy:header_filter() | ||
assert.same('abc', ngx.header['x-fapi-transaction-id']) | ||
end) | ||
|
||
it('Only use x-fapi-transaction-id from request if the header also exist in response from upstream', function() | ||
ngx_req_headers['x-fapi-transaction-id'] = 'abc' | ||
ngx_resp_headers['x-fapi-transaction-id'] = 'bdf' | ||
local transaction_id_policy = FAPIPolicy.new({}) | ||
transaction_id_policy:header_filter() | ||
assert.same('abc', ngx.header['x-fapi-transaction-id']) | ||
end) | ||
|
||
it('Use x-fapi-transaction-id from upstream response', function() | ||
ngx_resp_headers['x-fapi-transaction-id'] = 'abc' | ||
local transaction_id_policy = FAPIPolicy.new({}) | ||
transaction_id_policy:header_filter() | ||
assert.same('abc', ngx.header['x-fapi-transaction-id']) | ||
end) | ||
|
||
it('generate uuid if header does not exist in both request and response', function() | ||
local transaction_id_policy = FAPIPolicy.new({}) | ||
transaction_id_policy:header_filter() | ||
assert.is_true(uuid.is_valid(ngx.header['x-fapi-transaction-id'])) | ||
end) | ||
end) | ||
end) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
use lib 't'; | ||
use Test::APIcast::Blackbox 'no_plan'; | ||
|
||
# Test::Nginx does not allow to grep access logs, so we redirect them to | ||
# stderr to be able to use "grep_error_log" by setting APICAST_ACCESS_LOG_FILE | ||
|
||
run_tests(); | ||
|
||
__DATA__ | ||
|
||
=== TEST 1: Enables fapi policy inject x-fapi-transaction-id header to the response | ||
--- configuration | ||
{ | ||
"services": [ | ||
{ | ||
"id": 42, | ||
"backend_version": 1, | ||
"backend_authentication_type": "service_token", | ||
"backend_authentication_value": "token-value", | ||
"proxy": { | ||
"api_backend": "http://test:$TEST_NGINX_SERVER_PORT/", | ||
"proxy_rules": [ | ||
{ "pattern": "/", "http_method": "GET", "metric_system_name": "hits", "delta": 1 } | ||
], | ||
"policy_chain": [ | ||
{ | ||
"name": "apicast.policy.fapi", "configuration": {} | ||
}, | ||
{ | ||
"name": "apicast.policy.apicast" | ||
} | ||
] | ||
} | ||
} | ||
] | ||
} | ||
--- backend | ||
location /transactions/authrep.xml { | ||
content_by_lua_block { | ||
ngx.exit(200) | ||
} | ||
} | ||
--- upstream | ||
location / { | ||
content_by_lua_block { | ||
ngx.exit(200) | ||
} | ||
} | ||
--- more_headers | ||
x-fapi-transaction-id: abc | ||
--- response_headers | ||
x-fapi-transaction-id: abc | ||
--- request | ||
GET /?user_key=value | ||
--- error_code: 200 | ||
--- no_error_log | ||
[error] | ||
|
||
|
||
|
||
=== TEST 2: When x-fapi-transaction-id exist in both request and response headers, always use | ||
value from request | ||
--- configuration | ||
{ | ||
"services": [ | ||
{ | ||
"id": 42, | ||
"backend_version": 1, | ||
"backend_authentication_type": "service_token", | ||
"backend_authentication_value": "token-value", | ||
"proxy": { | ||
"api_backend": "http://test:$TEST_NGINX_SERVER_PORT/", | ||
"proxy_rules": [ | ||
{ "pattern": "/", "http_method": "GET", "metric_system_name": "hits", "delta": 1 } | ||
], | ||
"policy_chain": [ | ||
{ | ||
"name": "apicast.policy.fapi" | ||
}, | ||
{ | ||
"name": "apicast.policy.apicast" | ||
} | ||
] | ||
} | ||
} | ||
] | ||
} | ||
--- backend | ||
location /transactions/authrep.xml { | ||
content_by_lua_block { | ||
ngx.exit(200) | ||
} | ||
} | ||
--- upstream | ||
location / { | ||
content_by_lua_block { | ||
ngx.header['x-fapi-transaction-id'] = "blah" | ||
ngx.exit(200) | ||
} | ||
} | ||
--- more_headers | ||
x-fapi-transaction-id: abc | ||
--- request | ||
GET /?user_key=value | ||
--- response_headers | ||
x-fapi-transaction-id: abc | ||
--- error_code: 200 | ||
--- no_error_log | ||
[error] | ||
|
||
|
||
|
||
=== TEST 3: Use x-fapi-transaction-id header from upstream response | ||
--- configuration | ||
{ | ||
"services": [ | ||
{ | ||
"id": 42, | ||
"backend_version": 1, | ||
"backend_authentication_type": "service_token", | ||
"backend_authentication_value": "token-value", | ||
"proxy": { | ||
"api_backend": "http://test:$TEST_NGINX_SERVER_PORT/", | ||
"proxy_rules": [ | ||
{ "pattern": "/", "http_method": "GET", "metric_system_name": "hits", "delta": 1 } | ||
], | ||
"policy_chain": [ | ||
{ | ||
"name": "apicast.policy.fapi" | ||
}, | ||
{ | ||
"name": "apicast.policy.apicast" | ||
} | ||
] | ||
} | ||
} | ||
] | ||
} | ||
--- backend | ||
location /transactions/authrep.xml { | ||
content_by_lua_block { | ||
ngx.exit(200) | ||
} | ||
} | ||
--- upstream | ||
location / { | ||
content_by_lua_block { | ||
ngx.header['x-fapi-transaction-id'] = "blah" | ||
ngx.exit(200) | ||
} | ||
} | ||
--- request | ||
GET /?user_key=value | ||
--- response_headers | ||
x-fapi-transaction-id: blah | ||
--- error_code: 200 | ||
--- no_error_log | ||
[error] | ||
|
||
|
||
|
||
=== TEST 4: inject uuid to the response header | ||
--- configuration | ||
{ | ||
"services": [ | ||
{ | ||
"id": 42, | ||
"backend_version": 1, | ||
"backend_authentication_type": "service_token", | ||
"backend_authentication_value": "token-value", | ||
"proxy": { | ||
"api_backend": "http://test:$TEST_NGINX_SERVER_PORT/", | ||
"proxy_rules": [ | ||
{ "pattern": "/", "http_method": "GET", "metric_system_name": "hits", "delta": 1 } | ||
], | ||
"policy_chain": [ | ||
{ | ||
"name": "apicast.policy.fapi" | ||
}, | ||
{ | ||
"name": "apicast.policy.apicast" | ||
} | ||
] | ||
} | ||
} | ||
] | ||
} | ||
--- backend | ||
location /transactions/authrep.xml { | ||
content_by_lua_block { | ||
ngx.exit(200) | ||
} | ||
} | ||
--- upstream | ||
location / { | ||
content_by_lua_block { | ||
ngx.exit(200) | ||
} | ||
} | ||
--- request | ||
GET /?user_key=value | ||
--- response_headers_like | ||
x-fapi-transaction-id: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$ | ||
--- error_code: 200 | ||
--- no_error_log | ||
[error] |