consumer-plugin.t 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. #
  2. # Licensed to the Apache Software Foundation (ASF) under one or more
  3. # contributor license agreements. See the NOTICE file distributed with
  4. # this work for additional information regarding copyright ownership.
  5. # The ASF licenses this file to You under the Apache License, Version 2.0
  6. # (the "License"); you may not use this file except in compliance with
  7. # the License. You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. #
  17. use t::APISIX 'no_plan';
  18. repeat_each(1);
  19. no_long_string();
  20. no_root_location();
  21. run_tests;
  22. __DATA__
  23. === TEST 1: add consumer with username and plugins
  24. --- config
  25. location /t {
  26. content_by_lua_block {
  27. local t = require("lib.test_admin").test
  28. local code, body = t('/apisix/admin/consumers',
  29. ngx.HTTP_PUT,
  30. [[{
  31. "username": "jack",
  32. "plugins": {
  33. "limit-count": {
  34. "count": 2,
  35. "time_window": 60,
  36. "rejected_code": 503,
  37. "key": "remote_addr"
  38. },
  39. "key-auth": {
  40. "key": "auth-one"
  41. }
  42. }
  43. }]]
  44. )
  45. if code >= 300 then
  46. ngx.status = code
  47. end
  48. ngx.say(body)
  49. }
  50. }
  51. --- request
  52. GET /t
  53. --- response_body
  54. passed
  55. === TEST 2: enable key auth plugin using admin api
  56. --- config
  57. location /t {
  58. content_by_lua_block {
  59. local t = require("lib.test_admin").test
  60. local code, body = t('/apisix/admin/routes/1',
  61. ngx.HTTP_PUT,
  62. [[{
  63. "plugins": {
  64. "key-auth": {}
  65. },
  66. "upstream": {
  67. "nodes": {
  68. "127.0.0.1:1980": 1
  69. },
  70. "type": "roundrobin"
  71. },
  72. "uri": "/hello"
  73. }]]
  74. )
  75. if code >= 300 then
  76. ngx.status = code
  77. end
  78. ngx.say(body)
  79. }
  80. }
  81. --- request
  82. GET /t
  83. --- response_body
  84. passed
  85. === TEST 3: invalid consumer
  86. --- request
  87. GET /hello
  88. --- more_headers
  89. apikey: 123
  90. --- error_code: 401
  91. --- response_body
  92. {"message":"Invalid API key in request"}
  93. === TEST 4: valid consumer
  94. --- request
  95. GET /hello
  96. --- more_headers
  97. apikey: auth-one
  98. --- response_body
  99. hello world
  100. === TEST 5: up the limit
  101. --- pipelined_requests eval
  102. ["GET /hello", "GET /hello", "GET /hello", "GET /hello"]
  103. --- more_headers
  104. apikey: auth-one
  105. --- error_code eval
  106. [200, 200, 503, 503]
  107. === TEST 6: use the new configuration after the consumer's configuration is updated
  108. --- config
  109. location /t {
  110. content_by_lua_block {
  111. local function test()
  112. local json_encode = require("toolkit.json").encode
  113. local http = require "resty.http"
  114. local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
  115. local status_count = {}
  116. for i = 1, 5 do
  117. local httpc = http.new()
  118. local res, err = httpc:request_uri(uri,
  119. {
  120. method = "GET",
  121. headers = {
  122. apikey = "auth-one",
  123. }
  124. }
  125. )
  126. if not res then
  127. ngx.say(err)
  128. return
  129. end
  130. local status = tostring(res.status)
  131. status_count[status] = (status_count[status] or 0) + 1
  132. end
  133. ngx.say(json_encode(status_count))
  134. end
  135. test()
  136. local t = require("lib.test_admin").test
  137. local code, body = t('/apisix/admin/consumers',
  138. ngx.HTTP_PUT,
  139. [[{
  140. "username": "jack",
  141. "plugins": {
  142. "limit-count": {
  143. "count": 4,
  144. "time_window": 60,
  145. "rejected_code": 503,
  146. "key": "remote_addr"
  147. },
  148. "key-auth": {
  149. "key": "auth-one"
  150. }
  151. }
  152. }]]
  153. )
  154. ngx.sleep(0.1)
  155. test()
  156. }
  157. }
  158. --- request
  159. GET /t
  160. --- response_body
  161. {"200":2,"503":3}
  162. {"200":4,"503":1}
  163. === TEST 7: consumer with multiple auth plugins
  164. --- config
  165. location /t {
  166. content_by_lua_block {
  167. local t = require("lib.test_admin").test
  168. local code, body = t('/apisix/admin/consumers',
  169. ngx.HTTP_PUT,
  170. [[{
  171. "username": "John_Doe",
  172. "desc": "new consumer",
  173. "plugins": {
  174. "key-auth": {
  175. "key": "consumer-plugin-John_Doe"
  176. },
  177. "hmac-auth": {
  178. "key_id": "my-access-key",
  179. "secret_key": "my-secret-key",
  180. "clock_skew": 1
  181. }
  182. }
  183. }]]
  184. )
  185. if code >= 300 then
  186. ngx.status = code
  187. end
  188. ngx.say(body)
  189. }
  190. }
  191. --- request
  192. GET /t
  193. --- response_body
  194. passed
  195. === TEST 8: bind to routes
  196. --- config
  197. location /t {
  198. content_by_lua_block {
  199. local t = require("lib.test_admin").test
  200. local code, body = t('/apisix/admin/routes/1',
  201. ngx.HTTP_PUT,
  202. [[{
  203. "plugins": {
  204. "key-auth": {}
  205. },
  206. "upstream": {
  207. "nodes": {
  208. "127.0.0.1:1980": 1
  209. },
  210. "type": "roundrobin"
  211. },
  212. "uri": "/hello"
  213. }]]
  214. )
  215. if code >= 300 then
  216. ngx.log(ngx.ERR, "failed to bind route 1")
  217. ngx.status = code
  218. ngx.say(body)
  219. return
  220. end
  221. local code, body = t('/apisix/admin/routes/2',
  222. ngx.HTTP_PUT,
  223. [[{
  224. "plugins": {
  225. "hmac-auth": {}
  226. },
  227. "upstream": {
  228. "nodes": {
  229. "127.0.0.1:1980": 1
  230. },
  231. "type": "roundrobin"
  232. },
  233. "uri": "/status"
  234. }]]
  235. )
  236. if code >= 300 then
  237. ngx.status = code
  238. end
  239. ngx.say(body)
  240. }
  241. }
  242. --- request
  243. GET /t
  244. --- response_body
  245. passed
  246. === TEST 9: hit consumer, key-auth
  247. --- request
  248. GET /hello
  249. --- more_headers
  250. apikey: consumer-plugin-John_Doe
  251. --- response_body
  252. hello world
  253. --- error_log
  254. find consumer John_Doe
  255. === TEST 10: hit consumer, hmac-auth
  256. --- config
  257. location /t {
  258. content_by_lua_block {
  259. local ngx_time = ngx.time
  260. local ngx_http_time = ngx.http_time
  261. local core = require("apisix.core")
  262. local t = require("lib.test_admin")
  263. local hmac = require("resty.hmac")
  264. local ngx_encode_base64 = ngx.encode_base64
  265. local secret_key = "my-secret-key"
  266. local timestamp = ngx_time()
  267. local gmt = ngx_http_time(timestamp)
  268. local key_id = "my-access-key"
  269. local custom_header_a = "asld$%dfasf"
  270. local custom_header_b = "23879fmsldfk"
  271. local signing_string = {
  272. key_id,
  273. "GET /status",
  274. "date: " .. gmt,
  275. "x-custom-header-a: " .. custom_header_a,
  276. "x-custom-header-b: " .. custom_header_b
  277. }
  278. signing_string = core.table.concat(signing_string, "\n") .. "\n"
  279. core.log.info("signing_string:", signing_string)
  280. local signature = hmac:new(secret_key, hmac.ALGOS.SHA256):final(signing_string)
  281. core.log.info("signature:", ngx_encode_base64(signature))
  282. local headers = {}
  283. headers["Date"] = gmt
  284. headers["Authorization"] = "Signature keyId=\"" .. key_id .. "\",algorithm=\"hmac-sha256\"" .. ",headers=\"@request-target date x-custom-header-a x-custom-header-b\",signature=\"" .. ngx_encode_base64(signature) .. "\""
  285. headers["x-custom-header-a"] = custom_header_a
  286. headers["x-custom-header-b"] = custom_header_b
  287. local code, body = t.test('/status',
  288. ngx.HTTP_GET,
  289. nil,
  290. nil,
  291. headers
  292. )
  293. ngx.status = code
  294. ngx.say(body)
  295. }
  296. }
  297. --- request
  298. GET /t
  299. --- response_body
  300. passed
  301. --- error_log
  302. find consumer John_Doe
  303. === TEST 11: the plugins bound on the service should use the latest configuration
  304. --- config
  305. location /t {
  306. content_by_lua_block {
  307. local t = require("lib.test_admin").test
  308. local code, body = t('/apisix/admin/consumers',
  309. ngx.HTTP_PUT,
  310. [[{
  311. "username":"jack",
  312. "plugins": {
  313. "key-auth": {
  314. "key": "auth-jack"
  315. }
  316. }
  317. }]]
  318. )
  319. if code >= 300 then
  320. ngx.status = code
  321. ngx.say(body)
  322. return
  323. end
  324. local code, body = t('/apisix/admin/services/1',
  325. ngx.HTTP_PUT,
  326. [[{
  327. "plugins": {
  328. "key-auth": {
  329. "header": "Authorization"
  330. },
  331. "proxy-rewrite": {
  332. "uri": "/hello1"
  333. }
  334. }
  335. }]]
  336. )
  337. if code >= 300 then
  338. ngx.status = code
  339. ngx.say(body)
  340. return
  341. end
  342. local code, body = t('/apisix/admin/routes/1',
  343. ngx.HTTP_PUT,
  344. [[{
  345. "methods": [
  346. "GET"
  347. ],
  348. "uri": "/hello",
  349. "service_id": "1",
  350. "upstream": {
  351. "nodes": {
  352. "127.0.0.1:1980": 1
  353. },
  354. "type": "roundrobin"
  355. }
  356. }]]
  357. )
  358. if code >= 300 then
  359. ngx.status = code
  360. ngx.say(body)
  361. return
  362. end
  363. local http = require "resty.http"
  364. local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/hello"
  365. local httpc = http.new()
  366. local headers = {
  367. ["Authorization"] = "auth-jack"
  368. }
  369. local res, err = httpc:request_uri(uri, {headers = headers})
  370. assert(res.status == 200)
  371. if not res then
  372. ngx.log(ngx.ERR, err)
  373. return
  374. end
  375. ngx.print(res.body)
  376. local code, body = t('/apisix/admin/services/1',
  377. ngx.HTTP_PUT,
  378. [[{
  379. "plugins": {
  380. "key-auth": {
  381. "header": "Authorization"
  382. },
  383. "proxy-rewrite": {
  384. "uri": "/server_port"
  385. }
  386. }
  387. }]]
  388. )
  389. if code >= 300 then
  390. ngx.status = code
  391. ngx.say(body)
  392. return
  393. end
  394. ngx.sleep(0.1)
  395. local res, err = httpc:request_uri(uri, {headers = headers})
  396. assert(res.status == 200)
  397. if not res then
  398. ngx.log(ngx.ERR, err)
  399. return
  400. end
  401. ngx.say(res.body)
  402. }
  403. }
  404. --- request
  405. GET /t
  406. --- response_body
  407. hello1 world
  408. 1980