Skip to content

Commit 84b3006

Browse files
committed
feat(oauth2) set generic X-Credential-Identifier (deprecating X-Credential-Username)
### Summary The PR Kong#4993 implemented `X-Credential-Identifier` for `JWT Plugin` and it was decided at time that we should add support for this less opinionated field name on other auth plugins too. This commit adds it to `OAuth2 Plugin`. This feature was originally implemented by @lucasmoreno on PR Kong#5201. Thank you, Lucas, grab your T-shirt: https://github.com/Kong/kong/blob/master/CONTRIBUTING.md#contributor-t-shirt! I just refactored @lucasmoreno's code to use our generic `X-Credential-Identifier` header instead of the proposed `X-Credential-Client-Id`. ### Issues Resolved Closes Kong#5201
1 parent bb2c8cc commit 84b3006

File tree

3 files changed

+82
-31
lines changed

3 files changed

+82
-31
lines changed

kong/plugins/oauth2/access.lua

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ local function generate_token(conf, service, credential, authenticated_userid,
9797
}
9898
end
9999

100+
100101
local function load_oauth2_credential_by_client_id(client_id)
101102
local credential, err = kong.db.oauth2_credentials:select_by_client_id(client_id)
102103
if err then
@@ -106,6 +107,7 @@ local function load_oauth2_credential_by_client_id(client_id)
106107
return credential
107108
end
108109

110+
109111
local function get_redirect_uris(client_id)
110112
local client, err
111113
if client_id and client_id ~= "" then
@@ -121,6 +123,7 @@ local function get_redirect_uris(client_id)
121123
return client and client.redirect_uris or nil, client
122124
end
123125

126+
124127
local function retrieve_parameters()
125128
-- OAuth2 parameters could be in both the querystring or body
126129
local uri_args = kong.request.get_query()
@@ -135,6 +138,7 @@ local function retrieve_parameters()
135138
return uri_args
136139
end
137140

141+
138142
local function retrieve_scope(parameters, conf)
139143
local scope = parameters[SCOPE]
140144
local scopes = {}
@@ -161,6 +165,7 @@ local function retrieve_scope(parameters, conf)
161165
end -- else return nil
162166
end
163167

168+
164169
local function authorize(conf)
165170
local response_params = {}
166171
local parameters = retrieve_parameters()
@@ -309,6 +314,7 @@ local function authorize(conf)
309314
})
310315
end
311316

317+
312318
local function retrieve_client_credentials(parameters, conf)
313319
local client_id, client_secret, from_authorization_header
314320
local authorization_header = kong.request.get_header(conf.auth_header_name)
@@ -346,6 +352,7 @@ local function retrieve_client_credentials(parameters, conf)
346352
return client_id, client_secret, from_authorization_header
347353
end
348354

355+
349356
local function issue_token(conf)
350357
local response_params = {}
351358
local invalid_client_properties = {}
@@ -561,17 +568,18 @@ local function issue_token(conf)
561568

562569
-- Sending response in JSON format
563570
return kong.response.exit(response_params[ERROR] and
564-
(invalid_client_properties and
565-
invalid_client_properties.status or 400) or 200,
566-
response_params, {
567-
["cache-control"] = "no-store",
568-
["pragma"] = "no-cache",
569-
["www-authenticate"] = invalid_client_properties and
570-
invalid_client_properties.www_authenticate
571-
}
572-
)
571+
(invalid_client_properties and
572+
invalid_client_properties.status or 400) or 200,
573+
response_params, {
574+
["cache-control"] = "no-store",
575+
["pragma"] = "no-cache",
576+
["www-authenticate"] = invalid_client_properties and
577+
invalid_client_properties.www_authenticate
578+
}
579+
)
573580
end
574581

582+
575583
local function load_token(conf, service, access_token)
576584
local credentials, err =
577585
kong.db.oauth2_tokens:select_by_access_token(access_token)
@@ -601,6 +609,7 @@ local function load_token(conf, service, access_token)
601609
return credentials
602610
end
603611

612+
604613
local function retrieve_token(conf, access_token)
605614
local token, err
606615

@@ -618,6 +627,7 @@ local function retrieve_token(conf, access_token)
618627
return token
619628
end
620629

630+
621631
local function parse_access_token(conf)
622632
local found_in = {}
623633

@@ -667,6 +677,7 @@ local function parse_access_token(conf)
667677
return access_token
668678
end
669679

680+
670681
local function load_oauth2_credential_into_memory(credential_id)
671682
local result, err = kong.db.oauth2_credentials:select { id = credential_id }
672683
if err then
@@ -676,7 +687,10 @@ local function load_oauth2_credential_into_memory(credential_id)
676687
return result
677688
end
678689

690+
679691
local function set_consumer(consumer, credential, token)
692+
kong.client.authenticate(consumer, credential)
693+
680694
local set_header = kong.service.request.set_header
681695
local clear_header = kong.service.request.clear_header
682696

@@ -698,31 +712,34 @@ local function set_consumer(consumer, credential, token)
698712
clear_header(constants.HEADERS.CONSUMER_USERNAME)
699713
end
700714

701-
kong.client.authenticate(consumer, credential)
702-
703-
if credential then
704-
if token.scope then
705-
set_header("x-authenticated-scope", token.scope)
706-
else
707-
clear_header("x-authenticated-scope")
708-
end
709-
710-
if token.authenticated_userid then
711-
set_header("x-authenticated-userid", token.authenticated_userid)
712-
else
713-
clear_header("x-authenticated-userid")
714-
end
715+
if credential and credential.client_id then
716+
set_header(constants.HEADERS.CREDENTIAL_IDENTIFIER, credential.client_id)
717+
else
718+
clear_header(constants.HEADERS.CREDENTIAL_IDENTIFIER)
719+
end
715720

716-
clear_header(constants.HEADERS.ANONYMOUS) -- in case of auth plugins concatenation
721+
clear_header(constants.HEADERS.CREDENTIAL_USERNAME)
717722

723+
if credential then
724+
clear_header(constants.HEADERS.ANONYMOUS)
718725
else
719726
set_header(constants.HEADERS.ANONYMOUS, true)
720-
clear_header("x-authenticated-scope")
721-
clear_header("x-authenticated-userid")
722727
end
723728

729+
if token and token.scope then
730+
set_header("X-Authenticated-Scope", token.scope)
731+
else
732+
clear_header("X-Authenticated-Scope")
733+
end
734+
735+
if token and token.authenticated_userid then
736+
set_header("X-Authenticated-UserId", token.authenticated_userid)
737+
else
738+
clear_header("X-Authenticated-UserId")
739+
end
724740
end
725741

742+
726743
local function do_authentication(conf)
727744
local access_token = parse_access_token(conf);
728745
if not access_token then
@@ -852,7 +869,7 @@ function _M.execute(conf)
852869
return kong.response.exit(500, { message = "An unexpected error occurred" })
853870
end
854871

855-
set_consumer(consumer, nil, nil)
872+
set_consumer(consumer)
856873

857874
else
858875
return kong.response.exit(err.status, err.message, err.headers)

kong/plugins/oauth2/handler.lua

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
local access = require "kong.plugins.oauth2.access"
22

3-
local OAuthHandler = {}
3+
4+
local OAuthHandler = {
5+
PRIORITY = 1004,
6+
VERSION = "2.1.0",
7+
}
8+
49

510
function OAuthHandler:access(conf)
611
access.execute(conf)
712
end
813

9-
OAuthHandler.PRIORITY = 1004
10-
OAuthHandler.VERSION = "2.0.0"
1114

1215
return OAuthHandler

spec/03-plugins/25-oauth2/03-access_spec.lua

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,8 @@ describe("Plugin: oauth2 [#" .. strategy .. "]", function()
907907
assert.are.equal("bob", body.headers["x-consumer-username"])
908908
assert.are.equal("email profile", body.headers["x-authenticated-scope"])
909909
assert.are.equal("userid123", body.headers["x-authenticated-userid"])
910+
assert.are.equal("clientid123", body.headers["x-credential-identifier"])
911+
assert.are.equal(nil, body.headers["x-credential-username"])
910912
end)
911913
end)
912914

@@ -1208,6 +1210,8 @@ describe("Plugin: oauth2 [#" .. strategy .. "]", function()
12081210
assert.are.equal("bob", body.headers["x-consumer-username"])
12091211
assert.are.equal("email", body.headers["x-authenticated-scope"])
12101212
assert.are.equal("hello", body.headers["x-authenticated-userid"])
1213+
assert.are.equal("clientid123", body.headers["x-credential-identifier"])
1214+
assert.are.equal(nil, body.headers["x-credential-username"])
12111215
end)
12121216
it("works in a multipart request", function()
12131217
local res = assert(proxy_ssl_client:send {
@@ -1442,6 +1446,8 @@ describe("Plugin: oauth2 [#" .. strategy .. "]", function()
14421446
assert.are.equal("bob", body.headers["x-consumer-username"])
14431447
assert.are.equal("email", body.headers["x-authenticated-scope"])
14441448
assert.are.equal("id123", body.headers["x-authenticated-userid"])
1449+
assert.are.equal("clientid123", body.headers["x-credential-identifier"])
1450+
assert.are.equal(nil, body.headers["x-credential-username"])
14451451
end)
14461452
end)
14471453
end)
@@ -1638,6 +1644,8 @@ describe("Plugin: oauth2 [#" .. strategy .. "]", function()
16381644
assert.are.equal("bob", body.headers["x-consumer-username"])
16391645
assert.are.equal("email", body.headers["x-authenticated-scope"])
16401646
assert.are.equal("userid123", body.headers["x-authenticated-userid"])
1647+
assert.are.equal("clientid123", body.headers["x-credential-identifier"])
1648+
assert.are.equal(nil, body.headers["x-credential-username"])
16411649
end)
16421650
it("fails when an authorization code is used more than once", function()
16431651
local code = provision_code()
@@ -1883,6 +1891,8 @@ describe("Plugin: oauth2 [#" .. strategy .. "]", function()
18831891
assert.are.equal(consumer.username, body.headers["x-consumer-username"])
18841892
assert.are.equal("userid123", body.headers["x-authenticated-userid"])
18851893
assert.are.equal("email", body.headers["x-authenticated-scope"])
1894+
assert.are.equal("clientid123", body.headers["x-credential-identifier"])
1895+
assert.are.equal(nil, body.headers["x-credential-username"])
18861896
assert.is_nil(body.headers["x-anonymous-consumer"])
18871897
end)
18881898
it("returns HTTP 400 when scope is not a string", function()
@@ -1934,6 +1944,8 @@ describe("Plugin: oauth2 [#" .. strategy .. "]", function()
19341944
assert.are.equal(consumer.username, body.headers["x-consumer-username"])
19351945
assert.are.equal("userid123", body.headers["x-authenticated-userid"])
19361946
assert.are.equal("email", body.headers["x-authenticated-scope"])
1947+
assert.are.equal("clientid123", body.headers["x-credential-identifier"])
1948+
assert.are.equal(nil, body.headers["x-credential-username"])
19371949
assert.is_nil(body.headers["x-anonymous-consumer"])
19381950
end)
19391951
it("works with wrong credentials and anonymous", function()
@@ -1947,6 +1959,9 @@ describe("Plugin: oauth2 [#" .. strategy .. "]", function()
19471959
local body = cjson.decode(assert.res_status(200, res))
19481960
assert.are.equal("true", body.headers["x-anonymous-consumer"])
19491961
assert.equal('no-body', body.headers["x-consumer-username"])
1962+
assert.are.equal(nil, body.headers["x-credential-identifier"])
1963+
assert.are.equal(nil, body.headers["x-credential-username"])
1964+
19501965
end)
19511966
it("errors when anonymous user doesn't exist", function()
19521967
finally(function()
@@ -2401,6 +2416,7 @@ describe("Plugin: oauth2 [#" .. strategy .. "]", function()
24012416
local user1
24022417
local user2
24032418
local anonymous
2419+
local keyauth
24042420

24052421
lazy_setup(function()
24062422
local service1 = admin_api.services:insert({
@@ -2461,7 +2477,7 @@ describe("Plugin: oauth2 [#" .. strategy .. "]", function()
24612477
},
24622478
}
24632479

2464-
admin_api.keyauth_credentials:insert({
2480+
keyauth = admin_api.keyauth_credentials:insert({
24652481
key = "Mouse",
24662482
consumer = { id = user1.id },
24672483
})
@@ -2504,6 +2520,10 @@ describe("Plugin: oauth2 [#" .. strategy .. "]", function()
25042520
local id = assert.request(res).has.header("x-consumer-id")
25052521
assert.not_equal(id, anonymous.id)
25062522
assert(id == user1.id or id == user2.id)
2523+
2524+
local client_id = assert.request(res).has.header("x-credential-identifier")
2525+
assert.equal(keyauth.id, client_id)
2526+
assert.request(res).has.no.header("x-credential-username")
25072527
end)
25082528

25092529
it("fails 401, with only the first credential provided", function()
@@ -2566,6 +2586,9 @@ describe("Plugin: oauth2 [#" .. strategy .. "]", function()
25662586
local id = assert.request(res).has.header("x-consumer-id")
25672587
assert.not_equal(id, anonymous.id)
25682588
assert(id == user1.id or id == user2.id)
2589+
local client_id = assert.request(res).has.header("x-credential-identifier")
2590+
assert.equal("clientid4567", client_id)
2591+
assert.request(res).has.no.header("x-credential-username")
25692592
end)
25702593

25712594
it("passes with only the first credential provided", function()
@@ -2582,6 +2605,9 @@ describe("Plugin: oauth2 [#" .. strategy .. "]", function()
25822605
local id = assert.request(res).has.header("x-consumer-id")
25832606
assert.not_equal(id, anonymous.id)
25842607
assert.equal(user1.id, id)
2608+
local client_id = assert.request(res).has.header("x-credential-identifier")
2609+
assert.equal(keyauth.id, client_id)
2610+
assert.request(res).has.no.header("x-credential-username")
25852611
end)
25862612

25872613
it("passes with only the second credential provided", function()
@@ -2600,6 +2626,9 @@ describe("Plugin: oauth2 [#" .. strategy .. "]", function()
26002626
local id = assert.request(res).has.header("x-consumer-id")
26012627
assert.not_equal(id, anonymous.id)
26022628
assert.equal(user2.id, id)
2629+
local client_id = assert.request(res).has.header("x-credential-identifier")
2630+
assert.equal("clientid4567", client_id)
2631+
assert.request(res).has.no.header("x-credential-username")
26032632
end)
26042633

26052634
it("passes with no credential provided", function()
@@ -2614,6 +2643,8 @@ describe("Plugin: oauth2 [#" .. strategy .. "]", function()
26142643
assert.request(res).has.header("x-anonymous-consumer")
26152644
local id = assert.request(res).has.header("x-consumer-id")
26162645
assert.equal(id, anonymous.id)
2646+
assert.request(res).has.no.header("x-credential-identifier")
2647+
assert.request(res).has.no.header("x-credential-username")
26172648
end)
26182649
end)
26192650
end)

0 commit comments

Comments
 (0)