Kong / kong

🦍 The Cloud-Native API Gateway and AI Gateway.
https://konghq.com/install/#kong-community
Apache License 2.0
39.06k stars 4.79k forks source link

Hybrid or "consumer-less" authentication and integration with other plugins #1195

Closed jmdacruz closed 8 years ago

jmdacruz commented 8 years ago

I'm not sure if this is really an issue, but more of a general question and may be it's related to missing documentation.

I have a plugin that validates JWT tokens against an external service (an RFC 7662 token introspection endpoint), and passes certain parameters to the upstream service, such as attributes on the JWT. Because of the nature of our application, we can't have consumers pre-provisioned, and these type of tokens play nicely with that model since you basically get a "Consumer Custom ID" out of the token itself that the upstream service can use.

The plugin is smart enough to check whether a Consumer exists for the token (it looks up the database matching "Custom ID" to the value coming on the token), and if one exists then the "X-Consumer-ID" header is set. Else, only the "X-Consumer-Custom-ID" header is set with the value from the token.

I started to wonder about integration with other plugins, such as Rate Limiting. I see that many of these plugins rely on ngx.ctx.authenticated_credential being set, in most cases more specifically ngx.ctx.authenticated_credential.id. From what I can gather from the code itself (looking at this: https://github.com/Mashape/kong/blob/0.8.1/kong/plugins/rate-limiting/handler.lua), I could in theory just set ngx.ctx.authenticated_credential.id to whatever I want and the plugin may just work (to avoid the plugin relying on ngx.var.remote_addr and being more accurate)

Now, I understand that ngx.ctx.authenticated_credential may have some other properties, such as ngx.ctx.authenticated_credential.consumer_id. As I explained below, in most cases I won't have that value available in my plugin and I won't be able to set it in the context.

So, I think the general requests/issues here are:

I think the first bullet on the list above is they key, so that developers building authentication plugins clearly understand the rules of engagement. Maybe having a core function for the plugins to populate the context uniformly would help, so that the semantics are encoded there instead of every plugin relying on looking at other plugins' code.

subnetmarco commented 8 years ago

Is there documentation on the semantics of ngx.ctx.authenticated_credential.* and how the upstream plugins rely on the values there? What are the general rules on what to store there?

Unfortunately this is not documented. ngx.ctx.authenticated_credential is usually a table that has the following properties:

ngx.ctx.authenticated_credential = {
  id = "something",
  consumer_id = "something"
}

How do ngx.ctx.authenticated_credential.consumer_id and ngx.ctx.authenticated_credential.id relate to each other?

ngx.ctx.authenticated_credential.id is the ID of the actual credential entity on the database, while ngx.ctx.authenticated_credential.consumer_id is the consumer whose the credential belongs to.

Can plugins that rely on some sort of customer ID survive with ngx.ctx.authenticated_credential.id or ngx.ctx.authenticated_credential.consumer_id not being an actual "Consumer ID" on the database?

I believe so.

The internal API is subject to change and we hope to freeze and document it in a 1.0 release, this is mainly the reason why things are a little bit vague right now. We are basically waiting for 1.0.

jmdacruz commented 8 years ago

Thanks for the clarification, @thefosk. I think that leaving it open for these type of applications where consumers do not necessarily have an entity on the database makes a lot of sense. In some cases, certain plugins will work with this model (rate limiting being a clear example), but some other plugins might not (plugins that need to attach information to consumers beforehand). Plugins such as mine should be smart enough to try and look up a consumer on the database, and fall back to a entity-less consumer if none exists.

This means that the documentation for this situation it's just a set of "best practices" for plugin developers (which you inadvertently, or not, applied when developing the rate limiting plugin), e.g., treat IDs as opaque identifiers when possible, do not loop up an identifier on the database if not needed, etc.

thibaultcha commented 8 years ago

Closing this question, we keep those things in mind in our roadmap.

mecampbellsoup commented 3 years ago

The plugin is smart enough to check whether a Consumer exists for the token (it looks up the database matching "Custom ID" to the value coming on the token)

Hi @jmdacruz , how did you do this part? I can't see how to connect to my Postgres DB and e.g. lookup a user or a session/permissions. Did you write a custom Kong plugin?

jmdacruz commented 3 years ago

@mecampbellsoup At the time (this was version 0.8.3 of Kong, if my memory serves me well), this was a custom plugin that would check against the Kong DB to try and get any available information for the consumer. The code for looking up the consumer data was something like this: https://github.com/Kong/kong/blob/0.8.3/kong/plugins/basic-auth/access.lua#L108. This was an optional step meant to provide extra info for the consumer (if present). Also note this was pre-PDK days, so you'll need to check the latest and greatest PDK.