OAuth for Dokuwiki

Towards oAuth support for DokuWiki.

The use-case are manifold: oAuth allows to perform secure authenticated requests (eg. over HTTP) without requiring a user to disclose credentials. Dokuwiki can make use of this for instance with XML-RPC, dokupubsub, batch media-upload (client-applications) or even feed subscription, etc. Simply: any DokuWiki request.

You may still want to run a HTTPS server to authenticate users by plaintext-password against DokuWiki or require digest-auth (which still requires the user to know the password). Combined with openID, oAuth is a prerequisite for distributed client-server and server-to-server communication such as feed/media aggregation or DokuWiki-farms over insecure connections.

Authentication Patch

Patch DokuWiki's inc/auth.php to provide a trigger that allows to hook into the authentication mechanism.

--- a/inc/auth.php
+++ b/inc/auth.php
@@ -72,7 +72,13 @@
         // external trust mechanism in place
         $auth->trustExternal($_REQUEST['u'],$_REQUEST['p'],$_REQUEST['r']);
       }else{
-        auth_login($_REQUEST['u'],$_REQUEST['p'],$_REQUEST['r']);
+        $evt = new Doku_Event('ACTION_ON_AUTH',$ACT);
+        $evt->advise_before();
+        if(empty($_SERVER['REMOTE_USER'])) {
+            auth_login($_REQUEST['u'],$_REQUEST['p'],$_REQUEST['r']);
+        }
+        $evt->advise_after();
+        unset($evt);
       }
     }



Example action-plugin to provide authentication on a per HTTP-request basis:

example plugin code

if(!defined('DOKU_INC')) die();
 
class action_plugin_oauth extends DokuWiki_Action_Plugin {
 
    function register(&$contr){
        $contr->register_hook('ACTION_ON_AUTH',
                              'BEFORE',
                              $this,
                              'handle_act_authhook');
 
        $contr->register_hook('ACTION_ACT_PREPROCESS',
                              'BEFORE',
                              $this,
                              'handle_act_preprocess');
    }
 
    function handle_act_authhook(&$event, $param){
        if (is_array($_REQUEST['do']) && !empty($_REQUEST['do']['oauth'])) return; // skip requests to oauth-API itself
        if (!empty($_REQUEST['oauth_signature'])) {
 
            // verify signature
            // check consumer and access token
            // -> bail out if signature mismatch
            // -> set username for this session
 
            // dokuwiki - set user
            $user='root';
            $_SERVER['REMOTE_USER'] = $user;
            global $USERINFO;
            global $auth;
            $USERINFO = $auth->getUserData($user);
            if (!is_array($USERINFO)) {
                $_SERVER['REMOTE_USER'] = "";
                // or bail out..
            }
        }
    }
 
    function handle_act_preprocess(&$event, $param){
        $handled=false;
        if (!empty($event->data['oauth'])) {
            // ...
            // token-exchange, admin, etc.
            //
        }
 
        if ($handled) {
            $event->stopPropagation();
            $event->preventDefault();
            $event->data="show";
        }
    }
}
//Setup VIM: ex: et sw=4 ts=4 enc=utf-8 :



Discussion

Adding the ACTION_ON_AUTH event to existing events does not seem to be too far out; however it raises a some concerns:

  1. it makes it easier to write a exploiting-plugin
  2. may slow down the system - the Auth Event plugin is called for each request!
  3. it's somewhat parallel to inc/auth/*.php structure.

The first is not really true, any plugin can be used to perform malicious actions; it's just that ACTION_ON_AUTH should never be used carelessly. This ties into the second issue: pay strict attention to optimize performance of the callback handler - On a wiki with ACLs those will be called for each request! Last but not least: oAuth is not a DokuWiki authentication backend, it uses the getUserData() from the backend. Instead of adding a hook, the auth-backends could be nested: oAuth could wrap the default auth-backend overriding the checkPass() function. Adding an Event seems to be a much cleaner way to implement this.

OAuth Plugin

work in progress - see devel repository
or download a devel snapshot (don't use this link with the DokuWiki plugin manager.)

The plugin implements an oAuth-Service Provider consisting of several parts:

  • a handler for the oAuth protocol: request and exchange tokens
  • a handler for token/user-admin: authorize, admin keys & secrets
  • a handler for transparent authentication: any request with a valid oauth-signature and authorized access-token bypasses checkPass() and authenticates a DokuWiki-user on the fly.

Config

None needed. There's a few Options in Configuration Settings most of which are related to debugging or development.

After installing the Plugin, visit http://example.org/doku.php?do=oauth to administrate tokens or simply run the example script on the next page which adds a test consumer for you.

Info

The OAuthDataStore is kept in DOKU_CONF/oauth.inidb as dba.ini text data; the config-folder (or at least latter file) needs to be writable for the web-sever.

Note: Apache rewrite-rules modify the base-string! (This is to be fixed or worked-around) The query-parameters and URL must not be modified before they are passed to the PHP script (using DirectoryIndex doku.php works, redirecting from index.php does not.) - This is a minor issue since in general oAuth requests always use a full absolute URL ending with /doku.php (or /lib/lib/exe/xmlrpc.php) to access the DokuWiki API.

ToDo

  • implement Token expiry
  • add RSA-KEY admin.
  • redo/style Admin/User interface (helper.php)
  • oAuth-Disovery (both client & server)
  • oauth-Consumer (sign outgoing requests): per user eg. image-aggregate, save-edit ; per-page(or page owner) eg. feed

Test & Examples

You can access the DokuWiki OAuth API by making requests to doku.php?do[oauth]=XXX or simply by making any request adding the oauth_signature request-parameter.

Visit ?do=oauth for the oauth plugin information page. For test-requests see dokuoauth_examples.

 
wiki/dokuoauth.txt · Last modified: 23.12.2011 21:26 (external edit)