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

Enable the 'no_body' option when authorizing against 3scale backend #483

Merged
merged 4 commits into from
Nov 15, 2017
Merged
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
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

- New policy chains system. This allows users to write custom policies to configure what Apicast can do on each of the Nginx phases [PR #450](https://github.com/3scale/apicast/pull/450)
- Resolver can resolve nginx upstreams [PR #478](https://github.com/3scale/apicast/pull/478)
- Calls 3scale backend with the 'no_body' option enabled. This reduces network traffic in cases where APIcast does not need to parse the response body [PR #483](https://github.com/3scale/apicast/pull/483)

## [3.2.0-alpha1]

32 changes: 23 additions & 9 deletions apicast/src/backend_client.lua
Original file line number Diff line number Diff line change
@@ -124,11 +124,23 @@ local function create_token_path(service_id)
return format('/services/%s/oauth_access_tokens.xml', service_id)
end

local authorize_options = {
headers = {
['3scale-options'] = 'rejection_reason_header=1'
}
}
-- Returns the authorize options that 3scale backend accepts. Those options
-- are specified via headers. Right now there are 2:
-- - rejection_reason_header: asks backend to return why a call is denied
-- (limits exceeded, application key invalid, etc.)
-- - no_nody: when enabled, backend will not return a response body. The
-- body has many information like metrics, limits, etc. This information is
-- parsed only when using oauth. By enabling this option will save some work
-- to the 3scale backend and reduce network traffic.
local function authorize_options(using_oauth)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't be nicer to pass self instead of using_oauth ?

Because if the condition changes we would have to change only one place - this method.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that it would also require changing the authrep_path method to expect self instead of just boolean.

Tough choice. Not so sure now. I guess it is fine as it is then!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this option because it makes explicit that the only thing the method needs to know about is if we are running the oauth flow or not. Although as you said, we might need to change the params this method receives and the callers in the future.

local headers = { ['3scale-options'] = 'rejection_reason_header=1' }

if not using_oauth then
headers['3scale-options'] = headers['3scale-options'] .. '&no_body=1'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@davidor why don't you first construct the string and then create the headers table... just look at the amount of accesses you are performing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is all going to be JITed ! :trollface:

end

return { headers = headers }
end

--- Call authrep (oauth_authrep) on backend.
-- @tparam ?{table,...} query list of query parameters
@@ -138,8 +150,9 @@ function _M:authrep(...)
return nil, 'not initialized'
end

local auth_uri = authrep_path(self.version == 'oauth')
return call_backend_transaction(self, auth_uri, authorize_options, ...)
local using_oauth = self.version == 'oauth'
local auth_uri = authrep_path(using_oauth)
return call_backend_transaction(self, auth_uri, authorize_options(using_oauth), ...)
end

--- Call authorize (oauth_authorize) on backend.
@@ -150,8 +163,9 @@ function _M:authorize(...)
return nil, 'not initialized'
end

local auth_uri = auth_path(self.version == 'oauth')
return call_backend_transaction(self, auth_uri, authorize_options, ...)
local using_oauth = self.version == 'oauth'
local auth_uri = auth_path(using_oauth)
return call_backend_transaction(self, auth_uri, authorize_options(using_oauth), ...)
end

--- Calls backend to create an oauth token.
19 changes: 10 additions & 9 deletions spec/backend_client_spec.lua
Original file line number Diff line number Diff line change
@@ -5,7 +5,8 @@ local test_backend_client = require 'resty.http_ng.backend.test'
describe('backend client', function()

local test_backend
local options_header_val = 'rejection_reason_header=1'
local options_header_oauth = 'rejection_reason_header=1'
local options_header_no_oauth = 'rejection_reason_header=1&no_body=1'

before_each(function() test_backend = test_backend_client.new() end)

@@ -22,7 +23,7 @@ describe('backend client', function()
url = 'http://example.com/transactions/authrep.xml?' ..
ngx.encode_args({ auth = service.backend_authentication.value, service_id = service.id }),
headers = { host = 'example.com',
['3scale-options'] = options_header_val }
['3scale-options'] = options_header_no_oauth }
}.respond_with{ status = 200 }
local backend_client = assert(_M:new(service, test_backend))

@@ -43,7 +44,7 @@ describe('backend client', function()
url = 'http://example.com/transactions/authrep.xml?' ..
ngx.encode_args({ auth = service.backend_authentication.value, service_id = service.id }) ..
'&usage%5Bhits%5D=1&user_key=foobar',
headers = { ['3scale-options'] = options_header_val }
headers = { ['3scale-options'] = options_header_no_oauth }
}.respond_with{ status = 200 }
local backend_client = assert(_M:new(service, test_backend))

@@ -62,7 +63,7 @@ describe('backend client', function()
test_backend.expect{
url = 'http://example.com/transactions/authrep.xml?service_id=42',
headers = { host = 'foo.example.com',
['3scale-options'] = options_header_val }
['3scale-options'] = options_header_no_oauth }
}.respond_with{ status = 200 }
local backend_client = assert(_M:new(service, test_backend))

@@ -80,7 +81,7 @@ describe('backend client', function()
})
test_backend.expect{
url = 'http://example.com/transactions/oauth_authrep.xml?service_id=42',
headers = { ['3scale-options'] = options_header_val }
headers = { ['3scale-options'] = options_header_oauth }
}.respond_with{ status = 200 }
local backend_client = assert(_M:new(service, test_backend))

@@ -103,7 +104,7 @@ describe('backend client', function()
url = 'http://example.com/transactions/authorize.xml?' ..
ngx.encode_args({ auth = service.backend_authentication.value, service_id = service.id }),
headers = { host = 'example.com',
['3scale-options'] = options_header_val }
['3scale-options'] = options_header_no_oauth }
}.respond_with{ status = 200 }
local backend_client = assert(_M:new(service, test_backend))

@@ -124,7 +125,7 @@ describe('backend client', function()
url = 'http://example.com/transactions/authorize.xml?' ..
ngx.encode_args({ auth = service.backend_authentication.value, service_id = service.id }) ..
'&usage%5Bhits%5D=1&user_key=foobar',
headers = { ['3scale-options'] = options_header_val }
headers = { ['3scale-options'] = options_header_no_oauth }
}.respond_with{ status = 200 }
local backend_client = assert(_M:new(service, test_backend))

@@ -143,7 +144,7 @@ describe('backend client', function()
test_backend.expect{
url = 'http://example.com/transactions/authorize.xml?service_id=42',
headers = { host = 'foo.example.com',
['3scale-options'] = options_header_val }
['3scale-options'] = options_header_no_oauth }
}.respond_with{ status = 200 }
local backend_client = assert(_M:new(service, test_backend))

@@ -161,7 +162,7 @@ describe('backend client', function()
})
test_backend.expect{
url = 'http://example.com/transactions/oauth_authorize.xml?service_id=42',
headers = { ['3scale-options'] = options_header_val }
headers = { ['3scale-options'] = options_header_oauth }
}.respond_with{ status = 200 }
local backend_client = assert(_M:new(service, test_backend))

51 changes: 51 additions & 0 deletions t/apicast-oauth.t
Original file line number Diff line number Diff line change
@@ -948,3 +948,54 @@ Content-Type: application/json
{"token_type":"bearer","expires_in":604800,"access_token":"token"}
--- no_error_log
[error]

=== TEST 21: correct 3scale backend options
When authorizing against 3scale's backend, the call includes the correct
options in the headers. That is, it includes the 'rejection_reason' option,
but not the 'no_body' one, as in the oauth flow, parsing the response body is
necessary.
--- http_config
lua_package_path "$TEST_NGINX_LUA_PATH";
include $TEST_NGINX_UPSTREAM_CONFIG;

init_by_lua_block {
require('configuration_loader').mock({
services = {
{
backend_version = 'oauth',
proxy = {
credentials_location = "query",
api_backend = "http://127.0.0.1:$TEST_NGINX_SERVER_PORT/api-backend/",
proxy_rules = {
{ pattern = '/', http_method = 'GET', metric_system_name = 'hits' }
}
}
}
}
})

ngx.shared.api_keys:set('default:foobar:usage%5Bhits%5D=0', 200)
}
lua_shared_dict api_keys 1m;
--- config
include $TEST_NGINX_APICAST_CONFIG;
include $TEST_NGINX_BACKEND_CONFIG;

location /api-backend/ {
echo "yay, upstream";
}

location = /backend/transactions/oauth_authrep.xml {
content_by_lua_block {
if ngx.var['http_3scale_options'] == 'rejection_reason_header=1' then
ngx.header['3scale-rejection-reason'] = 'limits_exceeded';
end
}
}
--- request
GET /?access_token=foobar
--- error_code: 200
--- response_body
yay, upstream
--- no_error_log
[error]
4 changes: 2 additions & 2 deletions t/apicast.t
Original file line number Diff line number Diff line change
@@ -649,7 +649,7 @@ status code (429).

location /transactions/authrep.xml {
content_by_lua_block {
if ngx.var['http_3scale_options'] == 'rejection_reason_header=1' then
if ngx.var['http_3scale_options'] == 'rejection_reason_header=1&no_body=1' then
ngx.header['3scale-rejection-reason'] = 'limits_exceeded';
end
ngx.status = 409;
@@ -696,7 +696,7 @@ Limits exceeded

location /transactions/authrep.xml {
content_by_lua_block {
if ngx.var['http_3scale_options'] == 'rejection_reason_header=1' then
if ngx.var['http_3scale_options'] == 'rejection_reason_header=1&no_body=1' then
ngx.header['3scale-rejection-reason'] = 'limits_exceeded';
end
ngx.status = 409;