kong/spec/03-plugins/18-acl/01-api_spec.lua (466 lines of code) (raw):

local utils = require "kong.tools.utils" local cjson = require "cjson" local helpers = require "spec.helpers" for _, strategy in helpers.each_strategy() do describe("Plugin: acl (API) [#" .. strategy .. "]", function() local consumer local admin_client local bp local db lazy_setup(function() bp, db = helpers.get_db_utils(strategy, { "routes", "services", "plugins", "consumers", "acls", }) assert(helpers.start_kong({ database = strategy, })) admin_client = helpers.admin_client() end) lazy_teardown(function() if admin_client then admin_client:close() end helpers.stop_kong() end) describe("/consumers/:consumer/acls/", function() lazy_setup(function() consumer = assert(bp.consumers:insert({ username = "bob" }, { nulls = true })) end) before_each(function() db:truncate("acls") end) describe("POST", function() it("creates an ACL association", function() local res = admin_client:post("/consumers/bob/acls", { body = { group = "admin" }, headers = { ["Content-Type"] = "application/json" } }) local body = assert.res_status(201, res) local json = cjson.decode(body) assert.equal(consumer.id, json.consumer.id) assert.equal("admin", json.group) end) it("creates an ACL association with tags", function() local res = admin_client:send { method = "POST", path = "/consumers/bob/acls/", body = { group = "yoloers", tags = { "tag1", "tag2" }, }, headers = { ["Content-Type"] = "application/json" } } local body = assert.res_status(201, res) local json = cjson.decode(body) assert.equal(consumer.id, json.consumer.id) assert.equal("tag1", json.tags[1]) assert.equal("tag2", json.tags[2]) end) describe("errors", function() it("returns bad request", function() local res = admin_client:post("/consumers/bob/acls", { body = {}, headers = { ["Content-Type"] = "application/json" } }) local body = assert.res_status(400, res) local json = cjson.decode(body) assert.same({ group = "required field missing" }, json.fields) end) end) end) describe("GET", function() lazy_teardown(function() db:truncate("acls") end) it("retrieves the first page", function() bp.acls:insert_n(3, { consumer = { id = consumer.id } }) local res = admin_client:get("/consumers/bob/acls") local body = assert.res_status(200, res) local json = cjson.decode(body) assert.is_table(json.data) assert.equal(3, #json.data) end) end) end) describe("/consumers/:consumer/acls/:id", function() local acl, acl2 before_each(function() db:truncate("acls") acl = bp.acls:insert { group = "hello", consumer = { id = consumer.id }, } acl2 = bp.acls:insert { group = "hello2", consumer = { id = consumer.id }, } end) describe("GET", function() it("retrieves by id", function() local res = admin_client:get("/consumers/bob/acls/" .. acl.id) local body = assert.res_status(200, res) local json = cjson.decode(body) assert.equal(acl.id, json.id) end) it("retrieves by group", function() local res = admin_client:get("/consumers/bob/acls/" .. acl.group) local body = assert.res_status(200, res) local json = cjson.decode(body) assert.equal(acl.id, json.id) end) it("retrieves ACL by id only if the ACL belongs to the specified consumer", function() bp.consumers:insert { username = "alice" } local res = admin_client:get("/consumers/bob/acls/" .. acl.id) assert.res_status(200, res) res = admin_client:get("/consumers/alice/acls/" .. acl.id) assert.res_status(404, res) end) it("retrieves ACL by group only if the ACL belongs to the specified consumer", function() local res = admin_client:get("/consumers/bob/acls/" .. acl.group) assert.res_status(200, res) res = admin_client:get("/consumers/alice/acls/" .. acl.group) assert.res_status(404, res) end) it("retrieves right ACL by group when multiple consumers share the same group name created with POST", function() local res = admin_client:post("/consumers", { body = { username = "anna", }, headers = { ["Content-Type"] = "application/json", }, }) assert.res_status(201, res) assert.response(res).has.jsonbody() local res = admin_client:post("/consumers", { body = { username = "jack", }, headers = { ["Content-Type"] = "application/json", }, }) assert.res_status(201, res) assert.response(res).has.jsonbody() local res = admin_client:post("/consumers/anna/acls", { body = { group = "foo" }, headers = { ["Content-Type"] = "application/json" }, }) local body = assert.res_status(201, res) local ag = cjson.decode(body) local res = admin_client:post("/consumers/jack/acls", { body = { group = "foo" }, headers = { ["Content-Type"] = "application/json" }, }) local body = assert.res_status(201, res) local jg = cjson.decode(body) local res = admin_client:get("/consumers/anna/acls/foo") local body = assert.res_status(200, res) local ag2 = cjson.decode(body) local res = admin_client:get("/consumers/jack/acls/foo") local body = assert.res_status(200, res) local jg2 = cjson.decode(body) assert.same(ag, ag2) assert.same(jg, jg2) assert.not_same(jg, ag) assert.not_same(jg2, ag2) assert.not_same(jg, ag2) assert.not_same(jg2, ag) local res = admin_client:delete("/consumers/anna") local _ = assert.res_status(204, res) local res = admin_client:delete("/consumers/jack") local _ = assert.res_status(204, res) end) it("retrieves right ACL by group when multiple consumers share the same group name created with PUT", function() local res = admin_client:put("/consumers/anna") assert.res_status(200, res) assert.response(res).has.jsonbody() local res = admin_client:put("/consumers/jack") assert.res_status(200, res) assert.response(res).has.jsonbody() local res = admin_client:put("/consumers/anna/acls/foo") local body = assert.res_status(200, res) local ag = cjson.decode(body) local res = admin_client:put("/consumers/jack/acls/foo") local body = assert.res_status(200, res) local jg = cjson.decode(body) local res = admin_client:get("/consumers/anna/acls/foo") local body = assert.res_status(200, res) local ag2 = cjson.decode(body) local res = admin_client:get("/consumers/jack/acls/foo") local body = assert.res_status(200, res) local jg2 = cjson.decode(body) assert.same(ag, ag2) assert.same(jg, jg2) assert.not_same(jg, ag) assert.not_same(jg2, ag2) assert.not_same(jg, ag2) assert.not_same(jg2, ag) local res = admin_client:delete("/consumers/anna") assert.res_status(204, res) local res = admin_client:delete("/consumers/jack") assert.res_status(204, res) end) end) describe("PUT", function() it("upserts an ACL's groupname", function() local res = admin_client:put("/consumers/bob/acls/pro", { body = {}, headers = { ["Content-Type"] = "application/json" } }) local body = assert.res_status(200, res) local json = cjson.decode(body) assert.equal(consumer.id, json.consumer.id) assert.equal("pro", json.group) end) describe("errors", function() it("returns bad request", function() local res = admin_client:put("/consumers/bob/acls/f7852533-9160-4f5a-ae12-1ab99219ea95", { body = { group = 123, }, headers = { ["Content-Type"] = "application/json" } }) local body = assert.res_status(400, res) local json = cjson.decode(body) assert.same({ group = "expected a string" }, json.fields) end) end) end) describe("PATCH", function() it("updates an ACL group by id", function() local previous_group = acl.group local res = admin_client:patch("/consumers/bob/acls/" .. acl.id, { body = { group = "updatedGroup" }, headers = { ["Content-Type"] = "application/json" } }) local body = assert.res_status(200, res) local json = cjson.decode(body) assert.not_equal(previous_group, json.group) end) it("updates an ACL group by group", function() local previous_group = acl.group local res = admin_client:patch("/consumers/bob/acls/" .. acl.group, { body = { group = "updatedGroup2" }, headers = { ["Content-Type"] = "application/json" } }) local body = assert.res_status(200, res) local json = cjson.decode(body) assert.not_equal(previous_group, json.group) end) describe("errors", function() it("handles invalid input", function() local res = admin_client:patch("/consumers/bob/acls/" .. acl.id, { body = { group = 123, }, headers = { ["Content-Type"] = "application/json" } }) local body = assert.res_status(400, res) local json = cjson.decode(body) assert.same({ group = "expected a string" }, json.fields) end) end) end) describe("DELETE", function() it("deletes an ACL group by id", function() local res = admin_client:delete("/consumers/bob/acls/" .. acl.id) assert.res_status(204, res) end) it("deletes an ACL group by group", function() local res = admin_client:delete("/consumers/bob/acls/" .. acl2.group) assert.res_status(204, res) end) describe("errors", function() it("returns 404 on missing group", function() local res = admin_client:delete("/consumers/bob/acls/blah") assert.res_status(404, res) end) it("returns 404 if not found", function() local res = admin_client:delete("/consumers/bob/acls/00000000-0000-0000-0000-000000000000") assert.res_status(404, res) end) end) end) end) describe("/acls", function() local consumer2 describe("GET", function() lazy_setup(function() db:truncate("acls") for i = 1, 3 do bp.acls:insert { group = "group" .. i, consumer = { id = consumer.id }, } end consumer2 = bp.consumers:insert { username = "bob-the-buidler" } for i = 1, 3 do bp.acls:insert { group = "group" .. i, consumer = { id = consumer2.id }, } end end) it("retrieves all the acls with trailing slash", function() local res = admin_client:get("/acls/") local body = assert.res_status(200, res) local json = cjson.decode(body) assert.is_table(json.data) assert.equal(6, #json.data) end) it("retrieves all the acls without trailing slash", function() local res = admin_client:get("/acls") local body = assert.res_status(200, res) local json = cjson.decode(body) assert.is_table(json.data) assert.equal(6, #json.data) end) it("paginates through the acls", function() local res = admin_client:get("/acls?size=3") local body = assert.res_status(200, res) local json_1 = cjson.decode(body) assert.is_table(json_1.data) assert.equal(3, #json_1.data) res = admin_client:get("/acls", { query = { size = 3, offset = json_1.offset, } }) body = assert.res_status(200, res) local json_2 = cjson.decode(body) assert.is_table(json_2.data) assert.equal(3, #json_2.data) assert.not_same(json_1.data, json_2.data) -- Disabled: on Cassandra, the last page still returns a -- next_page token, and thus, an offset proprty in the -- response of the Admin API. --assert.is_nil(json_2.offset) -- last page end) end) describe("POST", function() lazy_setup(function() db:truncate("acls") end) it("does not create acl when missing consumer", function() local res = admin_client:post("/acls", { body = { group = "test-group", }, headers = { ["Content-Type"] = "application/json" } }) local body = assert.res_status(400, res) local json = cjson.decode(body) assert.same("schema violation (consumer: required field missing)", json.message) end) it("creates acl", function() local res = admin_client:post("/acls", { body = { group = "test-group", consumer = { id = consumer.id } }, headers = { ["Content-Type"] = "application/json" } }) local body = assert.res_status(201, res) local json = cjson.decode(body) assert.equal("test-group", json.group) end) end) end) describe("/acls/:group_or_id", function() describe("PUT", function() lazy_setup(function() db:truncate("acls") end) it("does not create acl when missing consumer", function() local res = admin_client:put("/acls/" .. utils.uuid(), { body = { group = "test-group" }, headers = { ["Content-Type"] = "application/json" } }) local body = assert.res_status(400, res) local json = cjson.decode(body) assert.same("schema violation (consumer: required field missing)", json.message) end) it("creates acl", function() local res = admin_client:put("/acls/" .. utils.uuid(), { body = { group = "test-group", consumer = { id = consumer.id } }, headers = { ["Content-Type"] = "application/json" } }) local body = assert.res_status(200, res) local json = cjson.decode(body) assert.equal("test-group", json.group) end) end) end) describe("/acls/:acl_id/consumer", function() describe("GET", function() local credential lazy_setup(function() db:truncate("acls") credential = db.acls:insert { group = "foo-group", consumer = { id = consumer.id }, } end) it("retrieves a Consumer from an acl's id", function() local res = admin_client:get("/acls/" .. credential.id .. "/consumer") local body = assert.res_status(200, res) local json = cjson.decode(body) assert.same(consumer, json) end) end) end) end) end