From 2395adf6b05ae36667cb0cd2d061329e06337b1e Mon Sep 17 00:00:00 2001 From: Daria Mayorova Date: Thu, 16 Mar 2017 18:56:01 +0100 Subject: [PATCH 1/6] [keycloak] load configuration via external command in init_worker --- apicast/src/configuration_loader.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apicast/src/configuration_loader.lua b/apicast/src/configuration_loader.lua index 53af7a6cf..30966ba83 100644 --- a/apicast/src/configuration_loader.lua +++ b/apicast/src/configuration_loader.lua @@ -128,7 +128,11 @@ end function boot.init_worker(configuration) local interval = ttl() or 0 - configuration.keycloak = keycloak.load_configuration() + local keycloak_config = _M.run_external_command("keycloak") + + if keycloak_config then + configuration.keycloak = cjson.decode(keycloak_config) + end local function schedule(...) local ok, err = ngx.timer.at(...) From 2ed804e15c4d34856387c49c123ae3ecebc66fd5 Mon Sep 17 00:00:00 2001 From: Daria Mayorova Date: Thu, 16 Mar 2017 19:12:33 +0100 Subject: [PATCH 2/6] [proxy] simplifies handling credentials for oauth / not-oauth --- apicast/src/proxy.lua | 45 +++++++++++++++---------------------------- 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/apicast/src/proxy.lua b/apicast/src/proxy.lua index e5ab6c899..d87d699fc 100644 --- a/apicast/src/proxy.lua +++ b/apicast/src/proxy.lua @@ -266,38 +266,15 @@ function _M:set_backend_upstream(service) ngx.var.backend_host = backend.host or server or ngx.var.backend_host end - -local function auth_oauth(proxy, service, usage, auth) - local credentials, err = proxy.oauth:transform_credentials(auth) - - if err then - return error_authorization_failed(service) - end - - credentials = encode_args(credentials) - - return proxy:authorize(service, usage, credentials) -end - -local function auth_key(proxy, service, usage, auth) - local credentials = encode_args(auth) - - return proxy:authorize(service, usage, credentials) -end - function _M:call(host) host = host or ngx.var.host local service = ngx.ctx.service or self:set_service(host) self:set_backend_upstream(service) - local authorize = auth_key - if service.backend_version == 'oauth' then local o = oauth.new(self.configuration) local f, params = oauth.call(o, service) - - authorize = auth_oauth self.oauth = o if f then @@ -308,11 +285,11 @@ function _M:call(host) return function() -- call access phase - return self:access(service, authorize) + return self:access(service) end end -function _M:access(service, authorize) +function _M:access(service) local request = ngx.var.request -- NYI: return to lower frame ngx.var.secret_token = service.secret_token @@ -328,8 +305,7 @@ function _M:access(service, authorize) insert(credentials, 1, service.id) - local _, matched_patterns, params = service:extract_usage(request) - local usage = encode_args(params) + local _, matched_patterns, usage_params = service:extract_usage(request) ngx.var.cached_key = concat(credentials, ':') @@ -342,11 +318,22 @@ function _M:access(service, authorize) local ctx = ngx.ctx -- save those tables in context so they can be used in the backend client - ctx.usage = params + ctx.usage = usage_params ctx.credentials = credentials ctx.matched_patterns = matched_patterns - return authorize(self, service, usage, credentials) + if self.oauth then + credentials, err = self.oauth:transform_credentials(credentials) + + if err then + return error_authorization_failed(service) + end + end + + credentials = encode_args(credentials) + local usage = encode_args(usage_params) + + return self:authorize(service, usage, credentials) end From 621d8caa549d078dfc5961938a54ebd11fe463bc Mon Sep 17 00:00:00 2001 From: Daria Mayorova Date: Fri, 17 Mar 2017 15:13:56 +0100 Subject: [PATCH 3/6] [configuration_loader] don't load keycloak conf on init_worker --- apicast/src/configuration_loader.lua | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apicast/src/configuration_loader.lua b/apicast/src/configuration_loader.lua index 30966ba83..a0544dcc7 100644 --- a/apicast/src/configuration_loader.lua +++ b/apicast/src/configuration_loader.lua @@ -128,12 +128,6 @@ end function boot.init_worker(configuration) local interval = ttl() or 0 - local keycloak_config = _M.run_external_command("keycloak") - - if keycloak_config then - configuration.keycloak = cjson.decode(keycloak_config) - end - local function schedule(...) local ok, err = ngx.timer.at(...) From 61bbcb85c24400aa56719b81b6bf551715bccc2b Mon Sep 17 00:00:00 2001 From: Daria Mayorova Date: Fri, 17 Mar 2017 15:14:45 +0100 Subject: [PATCH 4/6] [keycloak] only try to load keycloak configuration if the RHSSO_ENDPOINT environment variable is set --- apicast/src/configuration_loader.lua | 14 ++++++++++---- apicast/src/oauth/keycloak.lua | 4 ++++ spec/keycloak_spec.lua | 10 ++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/apicast/src/configuration_loader.lua b/apicast/src/configuration_loader.lua index a0544dcc7..65907b4cc 100644 --- a/apicast/src/configuration_loader.lua +++ b/apicast/src/configuration_loader.lua @@ -107,10 +107,16 @@ function boot.init(configuration) os.exit(0) end - local keycloak_config = _M.run_external_command("keycloak") - - if keycloak_config then - configuration.keycloak = cjson.decode(keycloak_config) + if keycloak.enabled() then + local keycloak_config + keycloak_config, err, code = _M.run_external_command("keycloak") + if keycloak_config then + ngx.log(ngx.DEBUG, 'downloaded keycloak configuration: ', keycloak_config) + configuration.keycloak = cjson.decode(keycloak_config) + else + -- TODO: consider exiting if there is problem with keycloak configuration + ngx.log(ngx.WARN, 'failed to load keycloak configuration, exiting (code ', code, ')\n', err) + end end end diff --git a/apicast/src/oauth/keycloak.lua b/apicast/src/oauth/keycloak.lua index bdd59162e..e06ec6d86 100644 --- a/apicast/src/oauth/keycloak.lua +++ b/apicast/src/oauth/keycloak.lua @@ -57,6 +57,10 @@ local function get_public_key(http_client, endpoint) return format_public_key(key) end +function _M.enabled() + return env.get('RHSSO_ENDPOINT') +end + function _M.load_configuration(client) local endpoint = env.get('RHSSO_ENDPOINT') diff --git a/spec/keycloak_spec.lua b/spec/keycloak_spec.lua index 93b344293..803e33318 100644 --- a/spec/keycloak_spec.lua +++ b/spec/keycloak_spec.lua @@ -154,4 +154,14 @@ describe('Keycloak', function() assert.spy(_M.respond_with_error).was.called_with(401, 'invalid_client') end) end) + + describe('.enabled', function() + it('is falsy if there is no RHSSO_ENDPOINT enviroment varialbe set', function() + assert.is.falsy(_M.enabled()) + end) + it('if truty a non-nil value if RHSSO_ENDPOINT enviroment varialbe set', function() + env.set('RHSSO_ENDPOINT', 'http://www.example.com:80/auth/realms/test') + assert.is.truthy(_M.enabled()) + end) + end) end) \ No newline at end of file From 10870e7138cee2e439e41bd295a9ee90e0b53f5d Mon Sep 17 00:00:00 2001 From: Daria Mayorova Date: Fri, 17 Mar 2017 15:34:06 +0100 Subject: [PATCH 5/6] [http_ng] unify request options for methods with and without body (fixes the issue with initial client options for ssl verification) --- apicast/src/resty/http_ng.lua | 46 ++++++++++++++++++++--------------- spec/resty/http_ng_spec.lua | 8 ++++++ 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/apicast/src/resty/http_ng.lua b/apicast/src/resty/http_ng.lua index cdf11d4d4..84b259692 100644 --- a/apicast/src/resty/http_ng.lua +++ b/apicast/src/resty/http_ng.lua @@ -52,6 +52,26 @@ local function merge(...) return res end +local function get_request_params(method, client, url, options) + local opts = {} + local scheme, user, pass, host, port, path = unpack(assert(resty_url.split(url))) + if port then host = concat({host, port}, ':') end + + opts.headers = { ['Host'] = host } + + if user or pass then + opts.headers.Authorization = "Basic " .. ngx.encode_base64(concat({ user or '', pass or '' }, ':')) + end + + return { + url = concat({ scheme, '://', host, path or DEFAULT_PATH }, ''), + method = method, + options = merge(opts, rawget(client, 'options'), options), + client = client, + serializer = client.serializer or http.serializers.default + } +end + http.method = function(method, client) assert(method) assert(client) @@ -64,23 +84,8 @@ http.method = function(method, client) assert(url, 'url as first parameter is required') - local opts = {} - local scheme, user, pass, host, port, path = unpack(assert(resty_url.split(url))) - if port then host = concat({host, port}, ':') end - - opts.headers = { ['Host'] = host } - - if user or pass then - opts.headers.Authorization = "Basic " .. ngx.encode_base64(concat({ user or '', pass or '' }, ':')) - end - - local req = http.request.new({ - url = concat({ scheme, '://', host, path or DEFAULT_PATH }, ''), - method = method, - options = merge(opts, rawget(client, 'options'), options), - client = client, - serializer = client.serializer or http.serializers.default - }) + local req_params = get_request_params(method, client, url, options) + local req = http.request.new(req_params) return client.backend.send(req) end @@ -99,9 +104,10 @@ http.method_with_body = function(method, client) assert(url, 'url as first parameter is required') assert(body, 'body as second parameter is required') - local req = http.request.new{ url = url, method = method, body = body, - options = options, client = client, - serializer = client.serializer or http.serializers.default } + local req_params = get_request_params(method, client, url, options) + req_params.body = body + local req = http.request.new(req_params) + return client.backend.send(req) end end diff --git a/spec/resty/http_ng_spec.lua b/spec/resty/http_ng_spec.lua index 5af7ad5df..09af6e864 100755 --- a/spec/resty/http_ng_spec.lua +++ b/spec/resty/http_ng_spec.lua @@ -88,6 +88,14 @@ describe('http_ng', function() http.get('http://example.com') local last_request = assert(backend.last_request) + assert.equal(false, last_request.options.ssl.verify) + end) + it('can turn off ssl validation for methods with body', function() + http = http_ng.new{backend = backend, options = { ssl = { verify = false } } } + + http.post('http://example.com', {}) + local last_request = assert(backend.last_request) + assert.equal(false, last_request.options.ssl.verify) end) end) From 20d2a4cdccd637dfac985a1fc9482441058b074e Mon Sep 17 00:00:00 2001 From: Daria Mayorova Date: Fri, 17 Mar 2017 15:51:44 +0100 Subject: [PATCH 6/6] Changelog update --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f71860468..446ac8db8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Ability to use Redis DB and password via `REDIS_URL` [PR #303](https://github.com/3scale/apicast/pull/303) - Ability to Authenticate against API using RHSSO and OpenID Connect [PR #283](https://github.com/3scale/apicast/pull/283) +### Fixed +- `http_ng` client supports auth passsed in the url, and default client options if the request options are missing for methods with body (POST, PUT, etc.) [PR #310](https://github.com/3scale/apicast/pull/310) + ### Removed - Removed support for sending Request logs [PR #296](https://github.com/3scale/apicast/pull/296)