Hi,

I'm building a new website in Drupal and there are some administrative web services that I would like to make available to middleware together a legacy system. I did some research into Drupal's XMLRPC system and figured that token based authentication in the core would be useful.

This is what I have sketched out on a napkin:

Scenario:
Client wants to create some new data in the system. This is the process:

1. Client requests a service token, sends username/password of a Drupal user
2. Drupal loads the $user matching the crudentials
- creates a random alphanumeric token to send back to the user
- serializes, and caches the $user object, key = md5(token + ip address of client)
- sends the token back to the client
3. Client makes an RPC call to say: module.createListing($token,$arg1,$arg2,...)
4. In createListing(...)
-- Checks the token, if valid does it's thing, otherwise, returns an error message.

I think it would take a fairly small amount of code to accomplish the above. I haven't given a lot of thought about Drupal's external authentication system though. I'm not too familiar with it, but maybe somebody can fill me it. For this system I may write my own version of user_authenticate() without the variable_get('user_register',1) in it so some malicous person doesn't create an unlimited number of random users in the system.

Any thoughts or previous work on this?
I would like it to be implemented in core, but it would probably be just as easy to implement as a module. Since modules will depend on the functionality, I want to avoid the logic of checking if the module is enabled or not.

I took a look at how the blogapi module accomplishes authentication. It has $username,$password for each request, and does a user_load(...), which is alright, but I would like have a shared authentication for web services rather than rolling a custom one for every module that needs it.

Privileges and access can be combined into a xmlrpc_check_token($token,$privilege) function, e.g:

xmlrpc_check_token($token,'access content')

It wouldn't take me long to write the code for this. I wanted some feedback from the community first before I dive into design/coding.

Thanks.
Ben.

Comments

dkruglyak’s picture

To be sure, are you talking about using hardware tokens on the client for login authentication?

This would definitely be a valuable feature. I think it would require a new module, a patch to the core and a client API.

I hope we find some core developers willing to help.

phrax’s picture

Are you thinking about hardware dongles?
That's not what I'm talking about. I was thinking of a way to add authentication to the web service.

Ben.

moshe weitzman’s picture

seems that these APIs are all the rage and it would be great to expand ours.

$user changes with ever page view I think since the last access time is in there. maybe that doesn't matter.

also, i'm unclear on why we need the token. can't the server just return the session_id? Then the client will send a session_id on each request. Thats how browsers identify themselves today and i'm unclear why we need another mechanism. If the concern is security then why are we OK with using this mechanism for usual web browsers?

phrax’s picture

Sessions are authentication tokens, they're just passed via cookies by the browser to PHP which automatically creates all the session data.

I think it comes down to where the system finds that authentication token. PHP's session handling makes it easy to create a session then it auto-magically does all the cookie/browser stuff for us. Those facilities aren't automatically available with a web service client.

If we want to leverage the free energy provided by PHP's session handling, web service clients must sent the session key (auth token) as a cookie in the HTTP headers. I think this is an undesireable requirement.

Also using the PHP session system will require that the client set the name of the cookie correctly. By default that may be PHPSESSID, or whatever is set in the php.ini file. This will likely result in a lot of explaining to client developers on why they have to send a cookie named X with value Y in order for the authenticated web service to work.

The alternative is to make the server side code a little more complex. For custom RPC call back functions the token is one of the arguments. Those functions then use xmlrpc_check_token($token,'permission name') to check if the user has a particular permission.

I would prefer the a separate token system so we can make the permission checking based on the token with a single xmlrpc_check_token() function call.

An alternative could be that once the client gets the authentication token, the request URL changes to:

/xmlrpc.php?token=foobar

That way there is no need for a $token argument in each RPC callback function, and xmlrpc.php can create a new session based on $token, and the user_access('...') function will work as normal.

I like option #3, it would be very easy to implement, doesn't alter the system too much, and intuitive for client developers to simply tag on a token to the GET string.

jvandyk’s picture

This is how the publish and subscribe modules establish a subscription relationship.

phrax’s picture

Right, implementation similar but supported as official functionality in core.

boris mann’s picture

So, as John mentioned, looked at publish-subscribe as a module, and perhaps prepare a patch against core. Or, would this be an xmlrpc.inc issue? Perhaps...

It's probably looking at seeing if you can meet the use cases of both blogapi and the publish-subscribe modules.

Chris Johnson’s picture

Ben, If you are attending the DrupalCon Vancouver, there are 2 sessions which are particularly applicable to your ideas here. I would suggest you sign up for them, if you haven't already, and come discuss your interesting ideas with other session participants. Those 2 sessions are:

* http://www.oscms-summit.org/events/drupal-enterprise-wide
* http://www.oscms-summit.org/events/inter-site-functionality

kbahey’s picture

key = md5(token + ip address of client)

Please do not use the IP address. Users behind proxy pools will be excluded.

Think of all the poor souls that use AOL as an ISP, some corporate networks, and even some countries.

Think of something else. The PHPSESSID perhaps?
--
Drupal development and customization: 2bits.com
Personal: Baheyeldin.com

--
Drupal performance tuning and optimization, hosting, development, and consulting: 2bits.com, Inc. and Twitter at: @2bits
Personal blog: Ba

phrax’s picture

I added a patch, see: http://drupal.org/node/46377 that adds token based authentication to the web service.

The token is basically a PHP session id. I added code to do a (essentially) a log in over the web service (system.getToken), and if successful the php session id (token) is returned.

Subsequent web service requests will go to:

/xmlrpc.php?token={session id}

where there is some code to check if the token is valid, and if it is, loads the proper session data, which changes the global $user, thus providing escalated privileges.

In your xmlrpc_callback functions, you will be able to use user_access('') as normal to check if they have access to whatever it is they are requesting.