From 82f7a91d124af53dc3356f5b4612d58067fd9ca7 Mon Sep 17 00:00:00 2001 From: thefosk Date: Thu, 6 Aug 2015 19:40:02 -0700 Subject: [PATCH] Closes #448 Former-commit-id: ad9fcbd3965648156c5e03990b2ba0945c910d72 --- kong/plugins/oauth2/access.lua | 21 ++++- kong/plugins/oauth2/schema.lua | 1 + spec/integration/proxy/api_resolver_spec.lua | 2 +- spec/plugins/oauth2/access_spec.lua | 82 ++++++++++++++++++++ 4 files changed, 104 insertions(+), 2 deletions(-) diff --git a/kong/plugins/oauth2/access.lua b/kong/plugins/oauth2/access.lua index fc68311b569e..dbb7081adf78 100644 --- a/kong/plugins/oauth2/access.lua +++ b/kong/plugins/oauth2/access.lua @@ -22,6 +22,7 @@ local GRANT_TYPE = "grant_type" local GRANT_AUTHORIZATION_CODE = "authorization_code" local GRANT_CLIENT_CREDENTIALS = "client_credentials" local GRANT_REFRESH_TOKEN = "refresh_token" +local GRANT_PASSWORD = "password" local ERROR = "error" local AUTHENTICATED_USERID = "authenticated_userid" @@ -205,7 +206,10 @@ local function issue_token(conf) local state = parameters[STATE] local grant_type = parameters[GRANT_TYPE] - if not (grant_type == GRANT_AUTHORIZATION_CODE or grant_type == GRANT_REFRESH_TOKEN or (conf.enable_client_credentials and grant_type == GRANT_CLIENT_CREDENTIALS)) then + if not (grant_type == GRANT_AUTHORIZATION_CODE or + grant_type == GRANT_REFRESH_TOKEN or + (conf.enable_client_credentials and grant_type == GRANT_CLIENT_CREDENTIALS) or + (conf.enable_password_grant and grant_type == GRANT_PASSWORD)) then response_params = {[ERROR] = "invalid_request", error_description = "Invalid "..GRANT_TYPE} end @@ -240,6 +244,21 @@ local function issue_token(conf) else response_params = generate_token(conf, client, nil, table.concat(scopes, " "), state) end + elseif grant_type == GRANT_PASSWORD then + -- Check that it comes from the right client + if conf.provision_key ~= parameters.provision_key then + response_params = {[ERROR] = "invalid_provision_key", error_description = "Invalid Kong provision_key"} + elseif not parameters.authenticated_userid or stringy.strip(parameters.authenticated_userid) == "" then + response_params = {[ERROR] = "invalid_authenticated_userid", error_description = "Missing authenticated_userid parameter"} + else + -- Check scopes + local ok, scopes = retrieve_scopes(parameters, conf) + if not ok then + response_params = scopes -- If it's not ok, then this is the error message + else + response_params = generate_token(conf, client, nil, table.concat(scopes, " "), state) + end + end elseif grant_type == GRANT_REFRESH_TOKEN then local refresh_token = parameters[REFRESH_TOKEN] local token = refresh_token and dao.oauth2_tokens:find_by_keys({refresh_token = refresh_token})[1] or nil diff --git a/kong/plugins/oauth2/schema.lua b/kong/plugins/oauth2/schema.lua index a4cf607cd58b..8115c4a79fb2 100644 --- a/kong/plugins/oauth2/schema.lua +++ b/kong/plugins/oauth2/schema.lua @@ -25,6 +25,7 @@ return { enable_authorization_code = { required = true, type = "boolean", default = true }, enable_implicit_grant = { required = true, type = "boolean", default = false }, enable_client_credentials = { required = true, type = "boolean", default = false }, + enable_password_grant = { required = true, type = "boolean", default = false }, hide_credentials = { type = "boolean", default = false } } } diff --git a/spec/integration/proxy/api_resolver_spec.lua b/spec/integration/proxy/api_resolver_spec.lua index 8f3ffc8d84ef..52c28b64e310 100644 --- a/spec/integration/proxy/api_resolver_spec.lua +++ b/spec/integration/proxy/api_resolver_spec.lua @@ -183,7 +183,7 @@ describe("Resolver", function() it("should return the correct Server and Via headers when the request was proxied", function() local _, status, headers = http_client.get(STUB_GET_URL, nil, { host = "mockbin.com"}) assert.equal(200, status) - assert.equal("cloudflare-nginx", headers.server) + assert.equal("Cowboy", headers.server) assert.equal(constants.NAME.."/"..constants.VERSION, headers.via) end) diff --git a/spec/plugins/oauth2/access_spec.lua b/spec/plugins/oauth2/access_spec.lua index 0c4c906b556b..8a023ae42046 100644 --- a/spec/plugins/oauth2/access_spec.lua +++ b/spec/plugins/oauth2/access_spec.lua @@ -43,6 +43,7 @@ describe("Authentication Plugin", function() { name = "tests oauth2 with path", public_dns = "mockbin-path.com", target_url = "http://mockbin.com", path = "/somepath/" }, { name = "tests oauth2 with hide credentials", public_dns = "oauth2_3.com", target_url = "http://mockbin.com" }, { name = "tests oauth2 client credentials", public_dns = "oauth2_4.com", target_url = "http://mockbin.com" }, + { name = "tests oauth2 password grant", public_dns = "oauth2_5.com", target_url = "http://mockbin.com" } }, consumer = { { username = "auth_tests_consumer" } @@ -52,6 +53,7 @@ describe("Authentication Plugin", function() { name = "oauth2", value = { scopes = { "email", "profile" }, mandatory_scope = true, provision_key = "provision123", token_expiration = 5, enable_implicit_grant = true }, __api = 2 }, { name = "oauth2", value = { scopes = { "email", "profile" }, mandatory_scope = true, provision_key = "provision123", token_expiration = 5, enable_implicit_grant = true, hide_credentials = true }, __api = 3 }, { name = "oauth2", value = { scopes = { "email", "profile" }, mandatory_scope = true, provision_key = "provision123", token_expiration = 5, enable_client_credentials = true, enable_authorization_code = false }, __api = 4 }, + { name = "oauth2", value = { scopes = { "email", "profile" }, mandatory_scope = true, provision_key = "provision123", token_expiration = 5, enable_password_grant = true, enable_authorization_code = false }, __api = 5 } }, oauth2_credential = { { client_id = "clientid123", client_secret = "secret123", redirect_uri = "http://google.com/kong", name="testapp", __consumer = 1 } @@ -307,6 +309,86 @@ describe("Authentication Plugin", function() end) end) + + describe("Password Grant", function() + + it("should return an error when client_secret is not sent", function() + local response, status = http_client.post(PROXY_URL.."/oauth2/token", { client_id = "clientid123", scope = "email", response_type = "token" }, {host = "oauth2_5.com"}) + local body = cjson.decode(response) + assert.are.equal(400, status) + assert.are.equal(2, utils.table_size(body)) + assert.are.equal("invalid_request", body.error) + assert.are.equal("Invalid client_secret", body.error_description) + end) + + it("should return an error when client_secret is not sent", function() + local response, status = http_client.post(PROXY_URL.."/oauth2/token", { client_id = "clientid123", client_secret="secret123", scope = "email", response_type = "token" }, {host = "oauth2_5.com"}) + local body = cjson.decode(response) + assert.are.equal(400, status) + assert.are.equal(2, utils.table_size(body)) + assert.are.equal("invalid_request", body.error) + assert.are.equal("Invalid grant_type", body.error_description) + end) + + it("should fail when no provision key is being sent", function() + local response, status = http_client.post(PROXY_URL.."/oauth2/token", { client_id = "clientid123", client_secret="secret123", scope = "email", grant_type = "password" }, {host = "oauth2_5.com"}) + local body = cjson.decode(response) + assert.are.equal(400, status) + assert.are.equal(2, utils.table_size(body)) + assert.are.equal("invalid_provision_key", body.error) + assert.are.equal("Invalid Kong provision_key", body.error_description) + end) + + it("should fail when no provision key is being sent", function() + local response, status = http_client.post(PROXY_URL.."/oauth2/token", { client_id = "clientid123", client_secret="secret123", scope = "email", grant_type = "password" }, {host = "oauth2_5.com"}) + local body = cjson.decode(response) + assert.are.equal(400, status) + assert.are.equal(2, utils.table_size(body)) + assert.are.equal("invalid_provision_key", body.error) + assert.are.equal("Invalid Kong provision_key", body.error_description) + end) + + it("should fail when no authenticated user id is being sent", function() + local response, status = http_client.post(PROXY_URL.."/oauth2/token", { provision_key = "provision123", client_id = "clientid123", client_secret="secret123", scope = "email", grant_type = "password" }, {host = "oauth2_5.com"}) + local body = cjson.decode(response) + assert.are.equal(400, status) + assert.are.equal(2, utils.table_size(body)) + assert.are.equal("invalid_authenticated_userid", body.error) + assert.are.equal("Missing authenticated_userid parameter", body.error_description) + end) + + it("should return success", function() + local response, status = http_client.post(PROXY_URL.."/oauth2/token", { provision_key = "provision123", authenticated_userid = "id123", client_id = "clientid123", client_secret="secret123", scope = "email", grant_type = "password" }, {host = "oauth2_5.com"}) + local body = cjson.decode(response) + assert.are.equal(200, status) + assert.are.equals(4, utils.table_size(body)) + assert.truthy(body.refresh_token) + assert.truthy(body.access_token) + assert.are.equal("bearer", body.token_type) + assert.are.equal(5, body.expires_in) + end) + + it("should return success with authorization header", function() + local response, status = http_client.post(PROXY_URL.."/oauth2/token", { provision_key = "provision123", authenticated_userid = "id123", scope = "email", grant_type = "password" }, {host = "oauth2_5.com", authorization = "Basic Y2xpZW50aWQxMjM6c2VjcmV0MTIz"}) + local body = cjson.decode(response) + assert.are.equal(200, status) + assert.are.equals(4, utils.table_size(body)) + assert.truthy(body.refresh_token) + assert.truthy(body.access_token) + assert.are.equal("bearer", body.token_type) + assert.are.equal(5, body.expires_in) + end) + + it("should return an error with a wrong authorization header", function() + local response, status = http_client.post(PROXY_URL.."/oauth2/token", { provision_key = "provision123", authenticated_userid = "id123", scope = "email", grant_type = "password" }, {host = "oauth2_5.com", authorization = "Basic Y2xpZW50aWQxMjM6c2VjcmV0MTI0"}) + local body = cjson.decode(response) + assert.are.equal(400, status) + assert.are.equal(2, utils.table_size(body)) + assert.are.equal("invalid_request", body.error) + assert.are.equal("Invalid client_secret", body.error_description) + end) + + end) end) describe("OAuth2 Access Token", function()