Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Take referrer filters into account in the auths cache #877

Merged
merged 4 commits into from
Sep 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Set default errlog level when `APICAST_LOG_LEVEL` is empty [PR #868](https://github.com/3scale/apicast/pull/868)
- Correct JWT validation according to [RFC 7523 Section 3](https://tools.ietf.org/html/rfc7523#section-3). Like not required `nbf` claim. [THREESCALE-583](https://issues.jboss.org/browse/THREESCALE-583)
- Mismatch in OIDC issuer when loading configuration through a configuration file [PR #872](https://github.com/3scale/apicast/pull/872)
- When the 3scale referrer filters was enabled, cached requests were not handled correctly [PR #875](https://github.com/3scale/apicast/issues/875)

## [3.3.0-beta2] - 2018-09-03

Expand Down
6 changes: 6 additions & 0 deletions gateway/src/apicast/proxy.lua
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ function _M:authorize(service, usage, credentials, ttl)

-- NYI: return to lower frame
local cached_key = ngx.var.cached_key .. ":" .. encoded_usage

local encoded_extra_params = encode_args(self.extra_params_backend_authrep)
if encoded_extra_params ~= '' then
cached_key = cached_key .. ":" .. encoded_extra_params
end

local cache = self.cache
local is_known = cache:get(cached_key)

Expand Down
34 changes: 34 additions & 0 deletions spec/proxy_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,40 @@ describe('Proxy', function()
assert.spy(proxy.cache_handler).was.called_with(
proxy.cache, 'client_id=blah:usage%5Bfoo%5D=0', response, nil)
end)

it('does not use cached auth if creds are the same but extra authrep params are not', function()
proxy.extra_params_backend_authrep = { referrer = '3scale.net' }

stub(test_backend, 'send', function() return { status = 200 } end)

local usage = Usage.new()
usage:add('hits', 1)
local cache_key = "uk:usage%5Bhits%5D=1" -- Referrer not here
proxy.cache:set(cache_key, 200)
ngx.var = { cached_key = "uk" } -- authorize() expects creds to be set up

proxy:authorize(service, usage, { user_key = 'uk' })

-- Calls backend because the call is not cached
assert.stub(test_backend.send).was_called()
end)

it('uses cached auth if creds are the same and authrep params too', function()
proxy.extra_params_backend_authrep = { referrer = '3scale.net' }

stub(test_backend, 'send', function() return { status = 200 } end)

local usage = Usage.new()
usage:add('hits', 1)
local cache_key = "uk:usage%5Bhits%5D=1:referrer=3scale.net" -- Referrer here
proxy.cache:set(cache_key, 200)
ngx.var = { cached_key = "uk" } -- authorize() expects creds to be set up

proxy:authorize(service, usage, { user_key = 'uk' })

-- Does not call backend because the call is cached
assert.stub(test_backend.send).was_not_called()
end)
end)

describe('.handle_backend_response', function()
Expand Down
114 changes: 114 additions & 0 deletions t/apicast-policy-3scale-referrer.t
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,117 @@ yay, api backend
--- error_code: 200
--- no_error_log
[error]

=== TEST 5: Referrer filters are taken into account in the APIcast auths cache
In this test, we make a request with valid credentials, and a valid referrer
filter. Then, we make a second one with the same credentials, but with an
invalid referrer, and we check that we get and "Authorization denied" error.
If the referrer filters were not taken into account in the auths cache, the
second request would return OK. We need to check that referrer filters are
taken into account.
--- 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": 2 }
],
"policy_chain": [
{
"name": "apicast.policy.3scale_referrer",
"configuration": {}
},
{ "name": "apicast.policy.apicast" }
]
}
}
]
}
--- upstream
location / {
content_by_lua_block {
ngx.say('yay, api backend');
}
}
--- backend
location /transactions/authrep.xml {
content_by_lua_block {
-- Verify just the referrer. Assume the rest of params are correct
if ngx.req.get_uri_args()['referrer'] == '3scale.net' then
ngx.exit(200)
else
ngx.exit(403)
end
}
}
--- request eval
["GET /?user_key=uk", "GET /?user_key=uk", "GET /?user_key=uk"]
--- more_headers eval
["Referer: 3scale.net", "Referer: invalid", "Referer: 3scale.net"]
--- response_body eval
["yay, api backend\x{0a}", "Authentication failed", "yay, api backend\x{0a}"]
--- error_code eval
[200, 403, 200]
--- no_error_log
[error]

=== TEST 6: Referrer filters taken into account in the auths cache when after APIcast in the chain
Same test as the one above but placing the Referrer policy after the APIcast
one in the chain.
--- 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": 2 }
],
"policy_chain": [
{ "name": "apicast.policy.apicast" },
{
"name": "apicast.policy.3scale_referrer",
"configuration": {}
}
]
}
}
]
}
--- upstream
location / {
content_by_lua_block {
ngx.say('yay, api backend');
}
}
--- backend
location /transactions/authrep.xml {
content_by_lua_block {
-- Verify just the referrer. Assume the rest of params are correct
if ngx.req.get_uri_args()['referrer'] == '3scale.net' then
ngx.exit(200)
else
ngx.exit(403)
end
}
}
--- request eval
["GET /?user_key=uk", "GET /?user_key=uk", "GET /?user_key=uk"]
--- more_headers eval
["Referer: 3scale.net", "Referer: invalid", "Referer: 3scale.net"]
--- response_body eval
["yay, api backend\x{0a}", "Authentication failed", "yay, api backend\x{0a}"]
--- error_code eval
[200, 403, 200]
--- no_error_log
[error]