?
avatar nikosdion
nikosdion
2 Nov 2019

The current implementation of the API application (inside the api folder) has at least two obvious security issues.

First, the protection against user enumeration is wrong. You assume that by hashing the password provided in a request with an invalid user you are going to take as much time as authenticating a user. That's an arbitrary and wrong assumption. Among other things, the time safe hash comparison is completely missing, meaning that in case of a wrong username your response will take less time than a response against an existing user.

Also, the whole point of the user enumeration is rendered completely partially moot by using a different language key depending on whether the password of an existing user is incorrect or the user doesn't exist at all. Even if the timing differences weren't there you are essentially delegating the site's security to the translators. All user authentication errors should use the same language key, e.g. JGLOBAL_AUTH_INVALID_PASS.

At least, unlike WordPress, Joomla doesn't seem to allow direct listing all users and / or leak their information such as email addresses without any authentication at all.

In any case, the discussion to this point is moot because usernames are not to be treated as secrets. They are more or less public information. If you have, for example, a forum you will most likely be able to see everyone's usernames there. That's why we have passwords and, most importantly, two factor authentication.

Therein lies the next and most serious attack vector. The basic API authentication plugin is effectively bypassing Two Step Authentication. This means that an attacker can very easily brute force the password of a user.

Now, you'll tell me, if I have the username and password I can't log into the site if the user has Two Step Authentication enabled.
Obligatory Batman slapping Robin meme
The API lets me create, modify and delete users as long as I know the username and password of a Super User. Which I do, having brute forced the password with the ever so helpful API. Now I can very easily create a new Super User (or, if I am a sneaky s.o.b. subvert this Super User by disabling Two Step Verification and changing the password and email address). Then I can simply delete all other users on the site. The site has been pwned and none is the wiser as to how it happened.

In short, the way the API is implemented is a security nightmare. It does allow side-channel user enumeration despite assurances to the contrary, it allows brute forcing of the password and, even more scary, allows me to pwn a site with nothing but a Super User's username and password, TFA be damned!

APIs should not use usernames and passwords. They should use revokable tokens at worst. I am aware I've done the same mistake. It's one I'm in the process of fixing. Naturally, I looked into how Joomla addresses the challenge I had and found out it's even worse. Oh boy.

I would recommend scraping the api-authentication/basic plugin altogether and replacing it with a token implementation. Writing a user plugin to create / regenerate a per-user token isn't that hard. It also has the added benefit of essentially making the API inoperable unless one or more users explicitly go ahead and create tokens for themselves. This will protect the bulk of innocent users who don't need or even know about the API.

As I obliquely mentioned before, Joomla is not alone in this mess. WordPress' API shares the same design mistakes and it is being used to enumerate users and leak information. But just because someone does something wrong doesn't mean you should too. Am I right?

avatar nikosdion nikosdion - open - 2 Nov 2019
avatar joomla-cms-bot joomla-cms-bot - change - 2 Nov 2019
Labels Added: ?
avatar joomla-cms-bot joomla-cms-bot - labeled - 2 Nov 2019
avatar nikosdion nikosdion - change - 2 Nov 2019
The description was changed
avatar nikosdion nikosdion - edited - 2 Nov 2019
avatar wilsonge
wilsonge - comment - 2 Nov 2019

I don't disagree with you on any of this and am happy to see any Pull Requests that take us in the direction of token authentication.

avatar nikosdion
nikosdion - comment - 3 Nov 2019

Sounds like a fun challenge :)

I’ll make two plugins, a user plugin to manage tokens and an api-authentication plugin. Not sure if I can reuse Joomla’s tokens tables or create a new one.

Since I’m busy this week I’ll aim for a PR in 2 weeks or so.

While I am at it, would you like me to create a master switch for the API application in Global Configuration? There are plenty of sites which don’t need the API and having it enabled may result in information leak since our target audience may not know how to secure that properly (thinking about public API endpoints). Otherwise I can deal with it in my security software.

avatar wilsonge
wilsonge - comment - 3 Nov 2019

While I am at it, would you like me to create a master switch for the API application in Global Configuration? There are plenty of sites which don’t need the API and having it enabled may result in information leak since our target audience may not know how to secure that properly (thinking about public API endpoints). Otherwise I can deal with it in my security software.

So I've considered this but in some cases we are going to want to use the API internally - I'm thinking media manager especially (but also maybe the finder indexing etc over time) which kinda has an API and once we move to token auth I'd intend as an SPA to basically just use the API just as standard backend use.

So if we had such a switch it would be based around stopping users who have permissions (at the moment the API is super user only - BUT my personal intention is to maybe relax that in the future to lower admin groups once we've battle tested the security part of the API over J4 stable releases) to use the API in the global config from being able to generate tokens rather than just outright forbidding people to use the API if that makes sense?

I’ll make two plugins, a user plugin to manage tokens and an api-authentication plugin. Not sure if I can reuse Joomla’s tokens tables or create a new one.

Thankyou sounds perfect - I assume this is the same kinda thing we discussed on skype 6 months ago (or whenever it was - I'm too lazy to open skype and check for the exact date :D)

avatar nikosdion
nikosdion - comment - 3 Nov 2019

I don't think it's a good idea using the API application from the back- or front-end applications. Local actions in the back- or frontend application should be executed in the session context of the current application. Moreover, you'd also have to deal with authentication and access to the API. In the current authentication scheme you'd need to store the user's password in plaintext for an API call to work. In my scheme you'd have to decrypt the API token. And how do you make your request? Through AJAX (security credentials are unnecessarily exposed to the browser) or via PHP (most local hosts don't allow loopback connections)? Or do you implement an atrocious solution like share login sessions across all three, unrelated applications which introduce further security risks? This is an architectural and security nightmare.

A JSON API (I am not calling it RESTful because it's not) in the context of a CMS like Joomla is meant for remote access and automation, not executing local actions. If someone decides to create a Joomla fork that's a JS application built around a server-side API we can talk about it again. In this case neither username/password nor token authentication will be apt for task. We'd need a stable login session to provide context for all the actions taking place. In short, the API application is not a replacement / successor to com_ajax and various AJAX implementations in core and 3PD components.

I strongly believe that the API must be for remote access / automation only and the users must be able to turn it off, especially when it eventually evolves to include a public portion.

If that's not the case then neither the existing username/password API authentication nor my proposed token authentication make sense. If the API application is envisioned as architecturally incorrect replacement for com_ajax you need shared sessions between all applications. Since I understand the security implications of that approach I do not want to condone it or work on it.

Please advise.

avatar wilsonge
wilsonge - comment - 4 Nov 2019

If that's not the case then neither the existing username/password API authentication nor my proposed token authentication make sense. If the API application is envisioned as architecturally incorrect replacement for com_ajax

It's not a replacement for com_ajax - that thing still very much has a place as it has access to the users current browser state.

Specifically in the case of com_media the API itself is state agnostic - as it is already a javascript page app (yes I understand there's a whole argument about whether that is correct or not - but it is what it is right now) - the only thing that's tied to state is the authentication itself (and I'm sure we both know architecturally there are lots of ways that you can build things to deal with that - although of course whether such ways are suitable for Joomla is of course subject to debate).

In the current authentication scheme you'd need to store the user's password in plaintext for an API call to work. In my scheme you'd have to decrypt the API token

If someone decides to create a Joomla fork that's a JS application built around a server-side API we can talk about it again.

I agree. I'm more than aware with the current situation you are proposing it cannot work. However we know there are already Joomla shops in places that are building JS applications for the frontend, so I personally don't see this as being particularly far off. Same said companies however will not use our built in authentication but probably devise their own versions based on oAuth.

But baring this in mind I would rather not have a kill switch for the API and keep the existing system of Super User only for now. In the future if we downgrade the super user requirement we can also decide if we want a kill switch.

TL/DR: Please work on the auth feature. Please don't do the kill switch

avatar nikosdion
nikosdion - comment - 4 Nov 2019

Regarding com_media, what you have in mind is wrong on more levels than what I stated (and which is to a certain extent subjective). May I state the obvious and objective problem? You are adamant that 1. the api application is for Super Users only and 2. that com_media will go through the api application. Ergo only Super Users can use the media manager. Busted 😛

I have several more misgivings about the API application in general. For example and if I understand this correctly, the API application extends the CMS application which means that every time you authenticate you create a session. I do see a reference to a CLI session but I'm actually running late for something and can't follow it. Is this what I am missing or was I about to go down the wrong rabbit hole?

Finally, the API seems to be very much non-RESTful. We don't even seem to be doing half of what Phil Sturgeon described in his 2014 book “Build APIs you won't hate”. If we're building an extensible Joomla API why not aim for a RESTful implementation? It would really open up new horizons for Joomla in a way that the current API cannot. Yes, it can be refactored for 5.0 but it'd be great if some architectural foresight was part of the 4.0 cycle to prevent a hard b/c break if one can be avoided.

Anyway. I don't want to die of scope creep. I am here to fix the security of the API application and that's it for now. Baby steps.

I won't work on the kill switch. I will only work on a token authentication implementation which is resistant to brute force attacks and resistant to SQL injection resulting in dumping the database.

In fact, I am already working on a token implementation for FOF. I'll give you a link when it's in a working state so you can see how token authentication could work and get your input on my ideas (I would port the same concept to the core).

avatar brianteeman
brianteeman - comment - 4 Nov 2019

the api application is for Super Users only

My understanding is that this is just a default setting and only a temporary default until the API matures

avatar nikosdion
nikosdion - comment - 4 Nov 2019

@brianteeman Yes, I know it's a temporary thing. I'm saying that since it's just for Super Users right now, using it for the Media Manager is jumping the shark. I'm a "you should grow legs before you try to run" kind of guy :)

@wilsonge Here's my WIP for token implementation in FOF. Some bullet points:

  • Implemented as a user plugin, using user profile fields. A core implementation would use its own table for efficiency.
  • The data saved in the database is just a base64-encoded crypto-safe random string. By itself it's useless.
  • The token the user needs to use is the base64 encoded string of an HMAC algorithm, the user ID and the HMAC of the random string with the site's secret as the key.
  • The security of the site is largely dependent on the quality of $secret in configuration.php. This is not visible in any user-facing parts of the application and is calculated with a crypto-safe random string generator which is good news. Also, changing the secret immediately changes all tokens, making it a dependable nuclear option if one so wishes.
  • Authentication goes through all the motions of calculating a reference HMAC and doing a time-safe string comparison, even when an invalid user ID is given or the user has not created a token. This prevents timing attacks.
  • Even friggin' MD5 is relatively safe in this context -- and I use SHA-1 by default. Yo, guys. Before starting bitching about how SHA-1 is already broken please do click the link. Also, yeah, it can be upgraded all the way up to SHA-512 and soon SHA-3 (once PHP supports it).
  • Tokens can be disabled.
  • Tokens for users who are blocked, not yet activated or requested a password reset are automatically invalid. In short, if you couldn't log into the site using your username and password you ain't gonna use the token to circumvent this restriction (something that the current "basic" api authentication plugin seems to ignore?).
  • The token is sent to the server preferably as an "Authentication: Bearer " HTTP header. We can also use a GET/POST parameter for wider compatibility (think about using it with Apple's Shortcuts app in iOS / iPadOS)
  • This POC works but lacks some polish e.g. reset the token, choose which user groups are allowed to have tokens, ability to choose a preferred hash algorithm etc.

Should I pursue converting this to core code for J4 or do you have any comments?

avatar brianteeman
brianteeman - comment - 4 Nov 2019

@brianteeman Yes, I know it's a temporary thing

Good - it wasn't clear so thought it best to state it (plus for others reading this)

All sounds good to me and certainly better/moresecure than the implementation I have seen in another cms using the same api

avatar wilsonge
wilsonge - comment - 4 Nov 2019

@brianteeman Yes, I know it's a temporary thing. I'm saying that since it's just for Super Users right now, using it for the Media Manager is jumping the shark. I'm a "you should grow legs before you try to run" kind of guy :)

It is running before I can walk to an extent - but if i don't come up with any long term view people scream about that too - so I can't win :D. It's not going to be a 4.0 thing for sure. So can we agree that it's a thing to maybe disagree about another day in the future :)

Finally, the API seems to be very much non-RESTful

Can you be more specific. In the strictest definition we're RESTful in terms of we're using the restful verbs https://github.com/joomla/joomla-cms/blob/4.0-dev/libraries/src/Router/ApiRouter.php#L90 for registering all the routes and enforcing them with content negotiation and they are stateless (fully answering the session question below). I fully accept REST verbs in itself doesn't make a REST API hence why I want you to clarify on what you feel is not RESTful.

I'm well aware of Phil's book - I've owned it since May 2015 ;)

I have several more misgivings about the API application in general. For example and if I understand this correctly, the API application extends the CMS application which means that every time you authenticate you create a session. I do see a reference to a CLI session but I'm actually running late for something and can't follow it. Is this what I am missing or was I about to go down the wrong rabbit hole?

Yes the CLI session is exactly what we're doing for the API. So for bad code that crosses from the old web days it covers our asses but only lives for the duration of the request. https://github.com/joomla-framework/session/blob/2.0-dev/src/Storage/RuntimeStorage.php Code is here for that. As you can see no way that it persists between requests as no php session handlers were harmed in the making. As I guess you saw it's init'd here https://github.com/joomla/joomla-cms/blob/4.0-dev/libraries/src/Service/Provider/Session.php#L158-L187 and set to the main session handler here https://github.com/joomla/joomla-cms/blob/4.0-dev/api/includes/app.php#L41-L45

The security of the site is largely dependent on the quality of $secret in configuration.php. This is not visible in any user-facing parts of the application and is calculated with a crypto-safe random string generator which is good news. Also, changing the secret immediately changes all tokens, making it a dependable nuclear option if one so wishes.

So back in the old Joomla days this used to be just md5 - are we happy that is safe for this (I don't see any particular reason it wouldn't be) - or would we be safer having a new crypto safe secret for this? (for sites being upgraded from probably 2.5 sites)

This POC works but lacks some polish e.g. reset the token, choose which user groups are allowed to have tokens, ability to choose a preferred hash algorithm etc.

Is this something that will be in your final PR or is this stuff that will be a TODO once it's submitted? Just so I can plan around that beyond your PR

Other than that your description of the feature reads fine to me.

avatar nikosdion
nikosdion - comment - 4 Nov 2019

I'm well aware of Phil's book - I've owned it since May 2015 ;)

Awesome :) Go back to the first chapter and see the four conditions for calling an API RESTful. At the very least we are not implementing two things, the OPTIONS verb and HATEOAS. What we have is halfway RESTful. At least it does content negotiation and supports most HTTP verbs.

Yes the CLI session is exactly what we're doing for the API. So for bad code that crosses from the old web days it covers our asses but only lives for the duration of the request.

Awesome. That's what I was looking for.

So back in the old Joomla days this used to be just md5 - are we happy that is safe for this (I don't see any particular reason it wouldn't be) - or would we be safer having a new crypto safe secret for this? (for sites being upgraded from probably 2.5 sites)

The secret was an MD5 of pseudo-random data. The secret itself is used as a key so this still gives us a key of 128 bits which is pretty secure. Also, the key generation from the key usage in those cases is so far removed that I don't think we should reasonably worry about an attacker having captured the pseudo-random number generator seed within any accuracy and not having hacked that site yet... So, I'm good working with it as is.

Is this something that will be in your final PR or is this stuff that will be a TODO once it's submitted? Just so I can plan around that beyond your PR

My plan is to polish it for FOF and then convert the final code to core code. I don't want to make a half-baked PR. I'm still working on the UX of those features.

As an aside, I'd like to note that I am aware of JSON Web Tokens but they can't really be used in our CMS. The whole idea behind JWTs is that you sign claims but we already have a layered ACL system which isn't really compatible with that concept. Therefore I decided NOT to go down that rabbit hole and opt for the next best thing. The only reason I'm writing this is that I fully expect someone to do a Google search and berate me for not using the hot, leading edge stuff 😛

Now, in practical terms, should someone need to have a token that has access to a subset of the site's features they need to create a new user and assign it to suitable user groups. In other words, do it The One True Joomla Way™. I think this is acceptable.

avatar wilsonge
wilsonge - comment - 4 Nov 2019

Awesome :) Go back to the first chapter and see the four conditions for calling an API RESTful. At the very least we are not implementing two things, the OPTIONS verb and HATEOAS. What we have is halfway RESTful. At least it does content negotiation and supports most HTTP verbs.

We're definitely not doing options. I'll go away and take a look at what we need to do there. If you could create me an issue to go away and work on that I'm more than happy to own that piece of work (although can't put a definite timescale on when I'll have it finished other than "in time for 4.0 stable)

If we implement JSON API https://jsonapi.org/ fully then we will have HATEOAS implementation. However of course as you know with FOF - Joomla sucks at relations so a lot of building these data relations is formed of big bodges (for example: exhibit A of massive hacks to deal with associations: https://github.com/joomla/joomla-cms/blob/4.0-dev/libraries/src/Serializer/ContentSerializer.php#L39-L43). The flexibility is there for extensions - but it's really hard to do properly with the current MVC for core components. However for 3rd party - especially doing something like you are doing in FOF I don't see any reason why you can't implement full HATEOS.

As an aside, I'd like to note that I am aware of JSON Web Tokens but they can't really be used in our CMS. The whole idea behind JWTs is that you sign claims but we already have a layered ACL system which isn't really compatible with that concept. Therefore I decided NOT to go down that rabbit hole and opt for the next best thing. The only reason I'm writing this is that I fully expect someone to do a Google search and berate me for not using the hot, leading edge stuff 😛

As I've done some work on JWT's in my outside of Joomla jobs I'd say that our ACL system doesn't forbid JWT's in any way (you don't have to support claims for subsets of resources - of course it looses much of the value but not all - just being able add custom data into the JWT payload or having tokens that are only valid at specific times would still have nominal value) . I'd use the secret and HMAC rather than RSA'ing IF i was to do it in Joomla. But neither am I advocating for it's use - I'm quite happy with what you proposed as I don't see it providing any value for the 90% (I just don't think our ACL stops us using it).

avatar nikosdion
nikosdion - comment - 4 Nov 2019

We're definitely not doing options. I'll go away and take a look at what we need to do there.

Good. We basically need to tell the client the acceptable representations and possible HTTP verbs for each resource. This is one half of making the API self-documenting which is what RESTful is supposed to be all about :)

The flexibility is there for extensions - but it's really hard to do properly with the current MVC for core components. However for 3rd party - especially doing something like you are doing in FOF I don't see any reason why you can't implement full HATEOS.

I had a grander vision than that but I'm not sure how to best implement it. For example, let's say I have a site with Akeeba Subscriptions. Each user has subscriptions. I'd like to somehow "hook" into com_users' output and add a link to the subscriptions resource for the user. Barring a proliferation of Events (read: plugins) I have no good idea on how to do it.

And true, on my side I can do HATEOAS but it would be an uneven relation. I can point to the user from a subscription but the user cannot point back to me unless I introduce my own users resource which has now taken RESTful and drove a big, silver spike through it heart. I guess designing an API is hard, designing a RESTful API is harder, designing an extensible RESTful API is a feat and designing an extensible RESTful API in an open-source CMS with third party extensions is getting somewhat ludicrous.

As I've done some work on JWT's in my outside of Joomla jobs I'd say that our ACL system doesn't forbid JWT's in any way (you don't have to support claims for subsets of resources - of course it looses much of the value but not all - just being able add custom data into the JWT payload or having tokens that are only valid at specific times would still have nominal value)

Oh, that's a good point. My use of JWTs focuses around cloud providers, the claims being effectively ACLs.

But neither am I advocating for it's use - I'm quite happy with what you proposed as I don't see it providing any value for the 90% (I just don't think our ACL stops us using it).

Yeah, I found the engineering challenge fun (I am a masochist, I know) but I could not find a practical utility to JWTs versus HMAC-based tokens.

So, it's settled. I'll proceed with the token implementation as-is and I'll make an issue for you regarding implementing OPTIONs in the api application.

avatar wilsonge
wilsonge - comment - 4 Nov 2019

Good. We basically need to tell the client the acceptable representations and possible HTTP verbs for each resource. This is one half of making the API self-documenting which is what RESTful is supposed to be all about :)

Unfortunately with custom fields and plugin added fields a truly self-documenting API (in terms of something like a JSON API output) will never be possible (because content types can actually change in different categories - which is a major pain point) - technically speaking I break the JSON API with this as things stand - but I don't really have any real alternative.

Of course options is something I should have put in but the comment above is just for completeness more than anything else

And true, on my side I can do HATEOAS but it would be an uneven relation. I can point to the user from a subscription but the user cannot point back to me unless I introduce my own users resource which has now taken RESTful and drove a big, silver spike through it heart. I guess designing an API is hard, designing a RESTful API is harder, designing an extensible RESTful API is a feat and designing an extensible RESTful API in an open-source CMS with third party extensions is getting somewhat ludicrous.

It's a fair point. The problem I guess I have is my serializer right now is based around adding fuctions in to transcribe extra functionality (which was logical for bonus component functionality - I refer back to the associations custom data above). Hard in plugins :P. However given we have a serializer adding a singular plugin event in the right place may not be impossible (although obviously complicated!)

Oh, that's a good point. My use of JWTs focuses around cloud providers, the claims being effectively ACLs.

Just to elaborate a bit one of the fun and legit things I've seen in several APIs is JWT payloads being used to specify whether clients have signed nda's/term's and conditions in order to use the API in the first place (in order not to query the db every page load but it's the equivalent of storing said data in the session).

So, it's settled. I'll proceed with the token implementation as-is and I'll make an issue for you regarding implementing OPTIONs in the api application.

One last thing that's occurred to me. Whilst i'm fine with dropping this behaviour in with tokens we've discussed here - Can we make sure it's not borderline impossible to disable the token scheme we're adding in. For obvious reasons there is going to be a 10% of people where likely a full blown oAuth authentication is going to be practical and desired. I don't want/need all this stuff in a plugin so it can be disabled at a plugin click. I'm happy to be biased in favour of our solution in terms of it being in com_users etc BUT it shouldn't - practically speaking - forbid someone from creating an oAuth implementation in Joomla without having two token systems active

avatar nikosdion
nikosdion - comment - 6 Nov 2019

I don't want/need all this stuff in a plugin so it can be disabled at a plugin click.

Absolutely. I am a very outspoken proponent of modularity and huge fan of the interchangeability inherent in the Joomla! plugin system.

I'd like to have a single plugin (that's what I'm doing with FOF) but neither does com_users load api-authentication plugins nor are user plugins loaded at authentication time in the API application. So, we get two plugins:

  • A user plugin to manage the tokens, the random data used to calculate the HMAC sums stored in user profile fields.
  • An api-authentication plugin which implements the token authentication.

All you need to disable this token scheme is unpublish at least the api-authentication plugin, ideally both to also prevent confusion.

I could merge both in a single system plugin but it feels awkward and violates good design principles. I am doing this in FOF because I have no other choice. However, for the core code I'd rather follow more sane architecture since we're setting an example for other developers to follow.

Tell me if you want a single system plugin or two user and api-authentication plugins and you'll have a PR within the next week or so.

avatar wilsonge
wilsonge - comment - 7 Nov 2019

A user plugin to manage the tokens, the random data used to calculate the HMAC sums stored in user profile fields.

This might be a dumb idea - but I'm going to ask it anyway without having spent more than 15 minutes thinking it through - but how bad would it be to dump the 'user plugin part' in the user component. As long as the fields are in a fieldset then they can be removed using the existing JForm components.

I definitely agree about not putting everything into a single system plugin.

neither does com_users load api-authentication plugins

Given we're going to be specifically having token authentication for practically everything I'm not totally against triggering API Auth plugins in com_users. It's not exactly single responsibility but doesn't seem that impractical either.

avatar wilsonge
wilsonge - comment - 7 Nov 2019

If both of these two things seem terrible then stick with your original concept of user and api-authentication plugins

avatar nikosdion
nikosdion - comment - 7 Nov 2019

but how bad would it be to dump the 'user plugin part' in the user component

It's not so much the technical aspect of it as the wrong conclusions users and, most importantly, developers would draw from that course of action. We'd be giving them the unintentional message that Joomla API Tokens are the One True Joomla Way to interact with the API application. We've already made that mistake with password authentication and the login modules and see how incredibly complicated is to implement any non-password authentication for Joomla. Or how third party developers, yours truly included, make the assumption that username and password authentication will always be available in Joomla, no matter what.

As long as the fields are in a fieldset then they can be removed using the existing JForm components.

Removing form fields would require a plugin or yet another option.

The plugin method allows for abuse by a misguided developer who feels that their implementation of tokens should always remove Joomla's core implementation of tokens, an assumption as arbitrary as it is dangerous.

The component option method is very Joomla, in a negative sense. We already have too many options which contribute towards a sharp learning curve, making the Options pages daunting for newcomers. I also feel that disabling a plugin is simpler and more intuitive that hunting down obscure component Options, especially given the fact that we must have an api-authentication plugin to prevent an architectural obscenity with regards to the default token implementation. The latter point comes from my experience with the way FOF currently handles transparent authentication.

Given we're going to be specifically having token authentication for practically everything I'm not totally against triggering API Auth plugins in com_users. It's not exactly single responsibility but doesn't seem that impractical either.

There are two architectural contortions I am worried about with this.

First, com_users is going to call api-authentication plugins. The latter should be written under the assumption they can only run inside the API application. We now break that assumption, having them run equally in all three Joomla applications (frontend, backend and api).

Furthermore, the api-authentication plugins will suffer severe scope creep as they are not only authenticating users but also rendering a UI and handling the writing of data to the database. I already feel that user plugins have a bit of scope creep for having to assume both of the latter responsibilities but I and everyone else accepts that architectural contortion given that the alternative of having separate plugins for rendering user profile fields and for managing the data of user profile fields would be user-hostile. In the case of API authentication we have options, we don't need to shoot our feet.

Alternative

So, let's think about not just what we're doing but why and for whom.

First of all, who's our target audience? Power users. True, simple users will be exposed to the UI for tokens. How do we deal with them? Make the user plugin render the UI for Super Users only by default and make it clear this is for "remote API authentication; if you are not sure what this is you can safely ignore it".

Second, the problems we're trying to solve with these plugins are: 1. having API tokens and 2. making it easy to replace them with a different implementation.

Problem 1. The technical aspect is solved by the mere existence of the api-authentication plugin which is enabled by default. The user plugin deals with the UI aspect. Plugins are the natural, One True Joomla Way for adding functionality so nobody will be caught off guard. Moreover, the UX is fairly good because API access is meant to be per user and users are managed in the aptly named Users component. Having an API Tokens tab there is logical and discoverable.

Problem 2 -- how would our target audience approach it? "I don't want Joomla's tokens so I will disable that (api-authentication) plugin and enable my own". So, the actual problem we need to solve is that the user will think to disable the api-authentication plugin but not the user plugin. Reasonable and understandable. Here's a simple solution. The user plugin can look if the api-authentication plugin is enabled. If not, it can refrain from rendering the UI even if it's enabled.

This brings us to a next possible problem. What if someone publishes the api-authentication plugin but not the user plugin? The token authentication works i.e. the API application doesn't break which is a graceful way to deal with the problem at a technical level. At the UX level, they won't see the token UI which might lead to a bit of confusion. What I'd do is look at my plugins; did I forget to enabled something? To make more obvious the two plugins will have the same name with a different prefix e.g. "User - Joomla API Token" and "API Authentication - Joomla API token" (titles are work in progress). So if you look for "api" or "token" in the plugins you will see both and realize your mistake.

I think that's a simpler, sweeter solution which does not go into UX anti-pattern or architectural contortionist territory.

avatar joomla-cms-bot joomla-cms-bot - change - 8 Nov 2019
Status New Closed
Closed_Date 0000-00-00 00:00:00 2019-11-08 08:50:07
Closed_By joomla-cms-bot
avatar alikon alikon - change - 8 Nov 2019
Closed_By joomla-cms-bot alikon
avatar joomla-cms-bot joomla-cms-bot - close - 8 Nov 2019
avatar joomla-cms-bot
joomla-cms-bot - comment - 8 Nov 2019

Set to "closed" on behalf of @alikon by The JTracker Application at issues.joomla.org/joomla-cms/26925

avatar alikon
alikon - comment - 8 Nov 2019

please see #27021


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/26925.

avatar wilsonge
wilsonge - comment - 18 Feb 2020

I had a grander vision than that but I'm not sure how to best implement it. For example, let's say I have a site with Akeeba Subscriptions. Each user has subscriptions. I'd like to somehow "hook" into com_users' output and add a link to the subscriptions resource for the user. Barring a proliferation of Events (read: plugins) I have no good idea on how to do it.

And true, on my side I can do HATEOAS but it would be an uneven relation. I can point to the user from a subscription but the user cannot point back to me unless I introduce my own users resource which has now taken RESTful and drove a big, silver spike through it heart. I guess designing an API is hard, designing a RESTful API is harder, designing an extensible RESTful API is a feat and designing an extensible RESTful API in an open-source CMS with third party extensions is getting somewhat ludicrous.

@nikosdion https://github.com/wilsonge/joomla-cms/pull/new/4.0-dev...feature/api-custom-relations

It's a very quick POC (written on a train with no PHP install) but does these two events kinda cover the thing you're after? onGetApiFields needs to return a list of fields - this will be enumerated. Then there's a function onGetApiRelation which will then actually return the relationship (effectively it will do this: https://github.com/joomla/joomla-cms/blob/4.0-dev/api/components/com_content/src/Serializer/ContentSerializer.php#L36-L52 )

As I say needs testing and someone to pick it up - but as a PoC

avatar nikosdion
nikosdion - comment - 19 Feb 2020

@wilsonge Yup. That looks like a good solution. In FOF 3 I had each Model define its own relationships to keep everything self-contained. However, I don't see a reason why an API controller or even a model couldn't register its own events to implement the relationship management features required by your POC. It's workable and fits the core patterns. I will still roll my own view for the JSON API (probably extending from JsonApiView) since I tend to set up access control and common features in the Dispatcher but, yeah, for core MVC components your POC looks just fine!

avatar alexandreelise
alexandreelise - comment - 15 Mar 2020

This conversation is gold! Thanks for sharing so much knowledge on security and api @nikosdion @wilsonge

avatar wilsonge
wilsonge - comment - 16 Mar 2020

PR for custom properties and relations #28377

Add a Comment

Login with GitHub to post a comment