JSON-RPC Authentication
#1
Debate about JSON-RPC authentication as a follow up to https://github.com/xbmc/xbmc/pull/5098

Will complete here later as most current information are already in the PR.
Reply
#2
I guess I'll make the start.

First of all there are two different types and places for authentication when it comes to JSON-RPC:
  1. On the transport protocol level i.e. the authentication is transport protocol specific. This is basically an all or nothing authentication so you either can access the JSON-RPC API through the transport protocol or you can't.
  2. On JSON-RPC level i.e. the authentication is transport protocol independent and also applies to access from python. This can be an all or nothing authentication but it can also be a "permission" authentication.
Authentication on the transport protocol level
This is already supported on the HTTP transport by setting a username and password on the access to the webserver. There is however no authentication over TCP, WebSockets or Python. Doing authentication over TCP would require a special protocol and doing it over python probably doesn't make much sense at all because the script is already running on the same machine as part of the XBMC process. For the webserver based access we could also update our webserver library to get HTTPS.

Authentication on JSON-RPC level
A long time ago (almost 3 years) I have already done a lot of work on this, see https://github.com/Montellese/xbmc/commi...henticated. The basic idea is that every client has a set of permissions that he needs (depending on the methods that are being called) and the user has the possibility to grant or deny them (whether this is an all or nothing choice or a selective decision is up for discussion). So when a client starts using the JSON-RPC API it first calls JSONRPC.Authenticate and provides a list of permissions that it would like to access. XBMC then prompts the user with that list and lets him/her decide whether access is granted or denied. Read access (like VideoLibrary.GetMovies) is always allowed. The users choice can be remembered by XBMC so he doesn't have to allow/deny the same client every other day.

The advantage of this is that it happens independent of the transport protocol being used so even python addons must be authenticated (which could happen implicitly during installation and when starting the addon).

The problem is how to track a client. On TCP and WebSockets it's easy because everything coming over a specific socket is from one specific client. For python addons it's even easier because we have control over the python call and know which addon made the call. Over HTTP it's not so easy and requires the use of a cookie. Over HTTPS it would again become easier because HTTPS sessions can be tracked as well.

Another problem is client identification. XBMC needs a way to remember that the user allowed/denied access for client X but nothing stops another client from pretending to be X even though its a very bad client called Y which wants to destroy your whole library.
Always read the online manual (wiki), FAQ (wiki) and search the forum before posting.
Do not e-mail Team Kodi members directly asking for support. Read/follow the forum rules (wiki).
Please read the pages on troubleshooting (wiki) and bug reporting (wiki) before reporting issues.
Reply
#3
Sorry, did not have time to make a correct post so I preferred delay it Sad

I guess first part is to define what authentication should cover, for the general transport level, should the authentication be generic (ie one solution for all and every client) or a more refined solution.

At the moment for http you have one login / password solution, this does cover some security but since no https it's plain text so not very secure.
Second point it that you only have one combination, meaning if you have a security problem or want to revoke one client, you need to impact all clients.

If going to a new solution, a per client token solution would be the best.
Like a client generates an unique id, send an authentication request, XBMC display a dialog to accept it or not the first time, then return a token derivated from it. And until revoke no more asks on XBMC side.

One problem about client tracking, is that for me, socket to identify client is far from perfect since it needs to restart authentication scheme on every connection. And from mobile point of view this could happens a lot on most phone wifi goes off when screen off for example (and it's good for battery usage).

The per client token solution could cover this too, you can perhaps add an ip related to the currently generated token. And ask for a new challenge of the authentication, meaning the client needs to send the previously sent unique id. (But without asking on XBMC screen of course). If a client is compromised to it's source code to be able to get the generated token and the unique id then there will never be a way to secure things so this cover 99% of security.

The token thing could then be enhanced a little, with the need for the client to send a name with the first challenge so XBMC could do a proper listing , and then the use could activate / revoke some permissions on token level.
Like access to media for streaming.
Add a default set of permission and you have something not too bad I think.

As discussed in the PR, at protocol level encryption / tampering avoiding sounds more important than authentication if it's already handled at Application level.

Having dual authentication would not bring additional security (If handling the application level authentication also for file access like with a header for http)
Reply
#4
Sorry for not getting back to you for so long but I had very little time for XBMC/Kodi and I tried to spend it on hunting down bugs etc.

I've finally had the time to give this some thought again and I agree that going with a per-client token solution is the best way to go (and also the way a lot of other projects with a public API work). What I was thinking of is either letting the client generate an API token (which should always stay the same across multiple connections) or by providing functionality inside Kodi to generate API tokens for different clients that can then be used by Kodi to identify the client. Either way every client (except for python addons) will be assigned an API token which is used to uniquely identify every client.

This is how it would then work for a new client that wants to make use of the JSON-RPC API:
  1. Somehow generate/retrieve (to be defined) an API token
  2. Call JSONRPC.Authenticate providing the API token, a name and the required permissions
  3. Kodi will check if the client is already known and if not it will prompt the user asking whether the client should be allowed to use the JSON-RPC API with the specified permissions.
From this point on the client is known to Kodi with the provided API token and that's all that is needed for identification. Depending on the transport being used a known client needs to behave differently to provide the API token:

Connection-based transports (TCP sockets, WebSockets, ...):
Over these transports the JSON-RPC client needs to call JSONRPC.Authenticate once at the beginning of the connection providing its API token (with or without permissions). Because it's a connection-based transport we don't need to track every single request from the client because we know that every request on a specific socket comes from the same client.

Connection-less transports (HTTP GET/POST):
Over these transports the JSON-RPC client needs to provide the API token in every request. Over HTTP POST this can be done with a separate HTTP header field-value-pair. Over HTTP GET this can be done with an additional GET parameter in the HTTP URL.
This addition should also help against cross-site request forgery attacks.
Always read the online manual (wiki), FAQ (wiki) and search the forum before posting.
Do not e-mail Team Kodi members directly asking for support. Read/follow the forum rules (wiki).
Please read the pages on troubleshooting (wiki) and bug reporting (wiki) before reporting issues.
Reply
#5
Well this kind of implementation is more oriented for public things with random people asking for access, that needs a first manual step to generate an api key.

For Kodi with users and multiple devices to connect to a private service step 1 should not be needed and step 2 should be a little more secure as a name is not an identifier given a possible public API key.

For me should more be like

JSONRPC.requestAccessToken providing a random private key generated by the client, a display name and an set of permissions.
Depending on settings it should return a token that will then be used later to authenticate. (For settings I mean user should be able to configure somewhere to auto allow such requests, as plugging a keyboard each time a new remote is used would not be cool) + interface to revoke access and tokens off course.

For the authentication part it's way more complicated for remotes like phone or limited devices.

TCP is more efficient than HTTP due to way less overhead but having authenticate each time a connection is set up would kill that.
  1. As said by Topfs batch commands are not guaranteed an ordered running, meaning the authenticate need to be sent as a separate command, wait for result then send the actual command.
  2. Keeping a connection always up on phone or some devices is not possible for battery usage. (Simple use case : Android device, a widget with arrows on it would mean 100 % up network connection with Wifi up, not possible at all).
And 1 + 2 make the API not usable via TCP and will force users to switch to HTTP.

And if you want a little more security access token should contain a duration, and an API refreshAccessToken that gives new token if sent the correct private key and previously valid token.
And then comes the question on how to ask for more permissions Smile either add a revokeAccessToken and send a new request or add an updateAccessTokenPermission.
Reply
#6
(2014-12-17, 12:54)Tolriq Wrote: Well this kind of implementation is more oriented for public things with random people asking for access, that needs a first manual step to generate an api key.
I don't think my local installation of SickBeard or CouchPotato count as "public" and there are also no "random people asking for access".

(2014-12-17, 12:54)Tolriq Wrote: For Kodi with users and multiple devices to connect to a private service step 1 should not be needed and step 2 should be a little more secure as a name is not an identifier given a possible public API key.
The name is just there to be able to show it to the user in a dialog. It isn't used at all for authentication or anything. For that you provide the API key. Maybe I didn't make it clear but I was thinking about different API keys for different remotes/clients and not one API key for all of them.

(2014-12-17, 12:54)Tolriq Wrote: JSONRPC.requestAccessToken providing a random private key generated by the client, a display name and an set of permissions.
Depending on settings it should return a token that will then be used later to authenticate. (For settings I mean user should be able to configure somewhere to auto allow such requests, as plugging a keyboard each time a new remote is used would not be cool) + interface to revoke access and tokens off course.
How does this work for very stupid remotes that are only capable of calling HTTP GET URLs and are incapable of processing the response?

(2014-12-17, 12:54)Tolriq Wrote: TCP is more efficient than HTTP due to way less overhead but having authenticate each time a connection is set up would kill that.
  1. As said by Topfs batch commands are not guaranteed an ordered running, meaning the authenticate need to be sent as a separate command, wait for result then send the actual command.
  2. Keeping a connection always up on phone or some devices is not possible for battery usage. (Simple use case : Android device, a widget with arrows on it would mean 100 % up network connection with Wifi up, not possible at all).
And 1 + 2 make the API not usable via TCP and will force users to switch to HTTP.
How do you want to do authentication on TCP otherwise? There's no header or anything where you can send the token so you have to make a call first letting Kodi know who you are. And relying on the IP address is an absolute no-go. If we'd do that we may as well not do any authentication at all.

(2014-12-17, 12:54)Tolriq Wrote: And if you want a little more security access token should contain a duration, and an API refreshAccessToken that gives new token if sent the correct private key and previously valid token.
And then comes the question on how to ask for more permissions Smile either add a revokeAccessToken and send a new request or add an updateAccessTokenPermission.
IMO updating permissions should be done with the same call as initially authenticating. Kodi then simply determines the diff between the previous and the new permissions and reacts accordingly.
Always read the online manual (wiki), FAQ (wiki) and search the forum before posting.
Do not e-mail Team Kodi members directly asking for support. Read/follow the forum rules (wiki).
Please read the pages on troubleshooting (wiki) and bug reporting (wiki) before reporting issues.
Reply
#7
I had understood perfectly Smile

But from a user point of view to add a remote : Put a keyboard on Kodi, create an key, start the remote type in the long and complex key then start to use is all but friendly. User are not even able to type the host ip or hostname in the remote most of the time.

Sickbeard and couchpotato are not the same target users as Kodi but a very small high end user part Wink

Normal process have to be started from the remote with the user just having to press ok or refuse on Kodi.

For very stupid remotes the API is already not usable if they can't process the response : How do they get the player id for sending commands ? They should be considered as exception, or a guest mode API key could be handled eventually.

For TCP part it's to be defined but coupled with your idea of sending permissions each time you authenticate would make a lot of not necessary data transmitted Sad And yes IP is not authentication.

For permissions, well I do not agree as from remote point of view you have no way to know if this will trigger a popup on Kodi for user interaction that could need a keyboard or another remote to be plugged.
And triggering those without warning the user before is not good at all.
Reply
#8
To be the devils advocate we need to consider headless too Smile There its very hard to pop up a dialog Smile

Perhaps its as simple as headless should accept anything, but its worth consideration.
If you have problems please read this before posting

Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.

Image

"Well Im gonna download the code and look at it a bit but I'm certainly not a really good C/C++ programer but I'd help as much as I can, I mostly write in C#."
Reply
#9
(2014-12-17, 16:30)Tolriq Wrote: But from a user point of view to add a remote : Put a keyboard on Kodi, create an key, start the remote type in the long and complex key then start to use is all but friendly. User are not even able to type the host ip or hostname in the remote most of the time.

Sickbeard and couchpotato are not the same target users as Kodi but a very small high end user part Wink

Normal process have to be started from the remote with the user just having to press ok or refuse on Kodi.
I didn't say that the key had to be created manually on Kodi. It could also be generated by the client/remote and sent to Kodi during authentication. Then all the user has to do is select ok or refuse. Obviously this can't be done with the same client/remote but IMO this kind of setup is done once and you don't change the remote every other day. There is no way around this if we want to have a more secure communication and environment.

The problem is that not all clients/remote are capable of generating and remembering the token or a private key either. As an example the default webinterface can only use HTML and JavaScript so it can't reliably store the token/private key anywhere expect for in a cookie or something like that but that can be wiped by the user when he cleans up his browser.

(2014-12-17, 16:30)Tolriq Wrote: For very stupid remotes the API is already not usable if they can't process the response : How do they get the player id for sending commands ? They should be considered as exception, or a guest mode API key could be handled eventually.
They don't get the player id. They just make assumptions and write static requests. But IMO we could limit the use of JSON-RPC over HTTP GET to the case where authentication has been disabled by the user completely in Kodi's settings. They'll have to live with the fact that they have a security risk/issue.

(2014-12-17, 16:30)Tolriq Wrote: For TCP part it's to be defined but coupled with your idea of sending permissions each time you authenticate would make a lot of not necessary data transmitted Sad And yes IP is not authentication.
Isn't "to be defined" what this thread is for? I don't see how you want to do client authentication across TCP connections without breaking/reducing security. IMO for single requests like done by an android widget TCP is the wrong transport. If you use HTTP there you at least don't have to send the authentication request again as you can simply pass your existing token in the header. Obviously this doesn't work if we have expiring tokens.

(2014-12-17, 16:49)topfs2 Wrote: To be the devils advocate we need to consider headless too Smile There its very hard to pop up a dialog Smile

Perhaps its as simple as headless should accept anything, but its worth consideration.
Good point. This one is tricky. The only way I can see is that during setup the authentication is disabled and there should be a possibility to manage them through JSON-RPC as well so that e.g. the webinterface can authenticate itself before authentication is enabled and afterwards any other device.
Always read the online manual (wiki), FAQ (wiki) and search the forum before posting.
Do not e-mail Team Kodi members directly asking for support. Read/follow the forum rules (wiki).
Please read the pages on troubleshooting (wiki) and bug reporting (wiki) before reporting issues.
Reply
#10
Quote:I didn't say that the key had to be created manually on Kodi. It could also be generated by the client/remote and sent to Kodi during authentication. Then all the user has to do is select ok or refuse. Obviously this can't be done with the same client/remote but IMO this kind of setup is done once and you don't change the remote every other day. There is no way around this if we want to have a more secure communication and environment.

Well this is exactly what I'm proposing, but in logical way Smile But yes users does change devices, application and things often.

Quote:The problem is that not all clients/remote are capable of generating and remembering the token or a private key either. As an example the default webinterface can only use HTML and JavaScript so it can't reliably store the token/private key anywhere expect for in a cookie or something like that but that can be wiped by the user when he cleans up his browser.

And how would they store the api key too, the problem is the exact same with your case ?

Quote:They don't get the player id. They just make assumptions and write static requests.
Meaning they can't control external player for example, and most the things. So are de facto limited, so do not support the API but bad workaround (I do remember you that it's clearly explained everywhere that players ID can change and must not be statically used, this is the same as videodb:// fiasco before).
So either they will not work with security and if user want to use such device he will have to disable security, or implement a limited thing for such devices (but IMO should not be necessary)

Quote:Isn't "to be defined" what this thread is for? I don't see how you want to do client authentication across TCP connections without breaking/reducing security. IMO for single requests like done by an android widget TCP is the wrong transport. If you use HTTP there you at least don't have to send the authentication request again as you can simply pass your existing token in the header. Obviously this doesn't work if we have expiring tokens.

Yes the thread is here for that, and yes TCP maybe not the correct transport but apps are not limited to one function, and having widgets use a way and rest of the app use another way would not be very efficient for the dev Smile
And yes correct solution is authentication on each connection, but not with again full data as name and permissions like you suggest.
And what I'd like to see is either batch ordering support for that, or a way to include authentication in first query to avoid unnecessary slowdowns.

And expiring token are easy to handle on app side with HTTP (440/511) or directly in json answer. It's just a slowdown of a button one time in a row, not more data every requests Smile
Reply
#11
(2014-12-18, 10:40)Tolriq Wrote:
Quote:The problem is that not all clients/remote are capable of generating and remembering the token or a private key either. As an example the default webinterface can only use HTML and JavaScript so it can't reliably store the token/private key anywhere expect for in a cookie or something like that but that can be wiped by the user when he cleans up his browser.

And how would they store the api key too, the problem is the exact same with your case ?
Yes but there needs to be a way for our addon webinterfaces (which can only do HTML, CSS and JavaScript) to work with the new security measures. I don't know how right now either. Addon webinterfaces might have an advantage as we could implement some special handling for any HTML page from addon webinterfaces that we return to inject an API token to be used for JSON-RPC requests.

(2014-12-18, 10:40)Tolriq Wrote: Yes the thread is here for that, and yes TCP maybe not the correct transport but apps are not limited to one function, and having widgets use a way and rest of the app use another way would not be very efficient for the dev Smile
Yes security is always the enemy/death of convenience and efficiency. You can't have good security without doing some extra work.

(2014-12-18, 10:40)Tolriq Wrote: And yes correct solution is authentication on each connection, but not with again full data as name and permissions like you suggest.
I never said that clients have to send the name and permissions with every authentication request. Once they are authenticated and the token is valid Kodi will just allow access for the previously assigned permissions. So all you need to provide is your token.

(2014-12-18, 10:40)Tolriq Wrote: And what I'd like to see is either batch ordering support for that, or a way to include authentication in first query to avoid unnecessary slowdowns.
Including authentication in any possible request would make the API much more complicated because we would have to add the token as a possible optional parameter to every single method in the API. That's absolutely not gonna happen.
Making sure that any batch request coming after an authentication request is delayed until the authentication request has been terminated might be a possibility but makes the batch handling inconsistent.

(2014-12-18, 10:40)Tolriq Wrote: And expiring token are easy to handle on app side with HTTP (440/511) or directly in json answer. It's just a slowdown of a button one time in a row, not more data every requests Smile
We'd probably have to add a new error code to the JSON-RPC error response which would indicate an expired token. But that obviously also leads to additional requests.
Always read the online manual (wiki), FAQ (wiki) and search the forum before posting.
Do not e-mail Team Kodi members directly asking for support. Read/follow the forum rules (wiki).
Please read the pages on troubleshooting (wiki) and bug reporting (wiki) before reporting issues.
Reply
#12
ich mцchte mich in die JSON-Api einarbeiten. Seit Juli 2014 soll es eine "JSON RPC-Doku" geben.
Leider finde ich sie nicht.
Wer kann mir einen Link geben?
Danke.

GruЯ
Dirk
Reply

Logout Mark Read Team Forum Stats Members Help
JSON-RPC Authentication0