3

I'm trying to integrate mediawiki into my website, but I'm having trouble. I think the problem has something to do with the cookies because I get a success from the mediawiki API.

Here's my code:

function mw_session_manager($Action = "")
{
    $Root = $_SERVER['SERVER_ADDR'];
    $API_Location = "${Root}/w/api.php";
    $expire = 60*60*24*14 + time();
    $CookieFilePath = tempnam("/tmp/thedirectory", "CURLCOOKIE");
    $CookiePrefix = 'theprefix';
            $Domain = 'thedomain';


    if($Action == 'login')
    {
        // Retrieves email address and password from sign-in form
        $Email = $_POST['LogInEmail'];
        $LgPassword = $_POST['LogInPassword'];
        // Query to retrieve username from database based on email. It is implied that authentication has already succeeded.
        $Query = "SELECT Username FROM Accounts WHERE Email = '$Email'";
        $ResultSet = mysql_query($Query);
        $ResultArray = mysql_fetch_array($ResultSet);
        $LgName = $ResultArray[0]; // Username

        // set variables to use in curl_setopts
        $PostFields = "action=login&lgname=$LgName&lgpassword=$LgPassword&format=php";
        // first http post to sign in to MediaWiki
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, "$API_Location");
        curl_setopt($ch, CURLOPT_POSTFIELDS, "$PostFields");
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_COOKIEJAR, $CookieFilePath);
        curl_setopt($ch, CURLOPT_COOKIEFILE, $CookieFilePath);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $ResultSerialized = curl_exec($ch);
        curl_close($ch); // curl closed
        $ResultUnserialized = unserialize($ResultSerialized);
        $Token = $ResultUnserialized[login][token];
        // cookie must be set using session id from first response
        $WikiSessionID = $ResultUnserialized[login][sessionid];
        setcookie("${CookiePrefix}_session", $WikiSessionID, $expire, '/', $Domain);

        // second http post to finish sign in
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, "$API_Location");
        curl_setopt($ch, CURLOPT_POSTFIELDS, "action=login&lgname=${LgName}&lgpassword=${LgPassword}&lgtoken=${Token}&format=php");
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_COOKIEJAR, $CookieFilePath);
        curl_setopt($ch, CURLOPT_COOKIEFILE, $CookieFilePath);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

        $ResultSerialized = curl_exec($ch);
        curl_close($ch); // curl closed
        $ResultUnserialized = unserialize($ResultSerialized);

        // set persistent cookies
        $LgToken = $ResultUnserialized["login"]["lgtoken"];
        $LgUserID = $ResultUnserialized["login"]["lguserid"];
        $LgUserName = $ResultUnserialized["login"]["lgusername"];

        setcookie("${CookiePrefix}UserName", $LgUserName, $expire, '/', $Domain);
        setcookie("${CookiePrefix}UserID", $LgUserID, $expire, '/', $Domain);
        setcookie("${CookiePrefix}Token", $LgToken, $expire, '/', $Domain);

        // Delete cURL cookie
        unlink($CookieFilePath);

        return $somedebuggingvariable;
    }
    if($Action = "logout")
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, "$API_Location");
        curl_setopt($ch, CURLOPT_POSTFIELDS, "action=logout");
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_COOKIEJAR, $CookieFilePath);
        curl_setopt($ch, CURLOPT_COOKIEFILE, $CookieFilePath);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $ResultSerialized = curl_exec($ch);
        $LogoutReturn = unserialize($ResultSerialized);
        $_SESSION['APIReturn'] = $LogoutReturn;
        curl_close($ch); // curl closed

        // destroys persistent cookies and ends session
        $expire = time() - 60*60*24*90;
        setcookie('Session', '', $expire, '/', $Domain);
        setcookie("${CookiePrefix}_session", '', $expire, '/', $Domain);
        setcookie("${CookiePrefix}UserName", '', $expire, '/', $Domain);
        setcookie("${CookiePrefix}UserID", '', $expire, '/', $Domain);
        setcookie("${CookiePrefix}Token", '', $expire, '/', $Domain);

        // delete cURL cookie
        unlink($CookieFilePath);
    }
}

I've also noticed that if I supply a bad token, the API still returns a success, so I can't outrule that, either.

Edit: I've gotten it working perfectly now and updated the code to the current, working code.

Adam11
  • 493
  • 3
  • 12
  • 3
    Have you taken a look at http://www.mediawiki.org/wiki/User:Krinkle/API_PHP_cURL_example ? – Ilmari Karonen Jan 01 '13 at 04:08
  • Yes, that was one of the guides I was using. I've updated the code to more closely follow that particular example since it's the best one... – Adam11 Jan 01 '13 at 08:30
  • So, exactly what do you do with the return values once you have them? Presumably you have to pass the cookies on to the client somehow -- maybe the problem is there? (Ps. I tested your code, and it indeed works for me as far as it goes.) – Ilmari Karonen Jan 01 '13 at 16:31
  • Awesome! Nothing, I'm not sure how to do that. I'm just now learning about http headers and cookies, so it's all completely new to me. If you would, explain how you do it? Or paste some code. – Adam11 Jan 01 '13 at 17:40
  • 1
    I notice that your code has a number of mistakes that PHP should warn you about. (For example, shouldn't `'login_userid'` be `'login_lguserid'`?) You really should enable error logging (preferably with the reporting level set to `E_ALL`) and fix any warnings you see. Also, the `lgtoken` value returned after a successful login is _not_ the same as the `token` returned after the first attempt. You really should also check what the first API query returns before blindly attempting the second one. – Ilmari Karonen Jan 02 '13 at 03:05

1 Answers1

2

It looks like you're trying to implement a single sign-on mechanism for your website and MediaWiki by having a PHP script on your website log the user into MediaWiki using the API.

The problem is that, while your script is indeed successfully logging into MediaWiki using the user's credentials, it's not passing the MediaWiki authentication cookies back to the user.

There are a couple of ways to solve this issue:

  • Perhaps the simplest solution would be to handle the MediaWiki login process entirely on the client side using JavaScript / AJAX. That way, the cookies will be sent directly to the users's browser. The down side, of course, is that this won't work for users who cannot or don't want to run JavaScript (but you could always let them just log in to MediaWiki the usual way).

  • You could also do only the first step of the login process (retrieving the token) on the server side, and then have the client request the second step URL directly e.g. by using it as the source of an invisible iframe on the returned HTML page. This doesn't require JavaScript, but does involve sending the user's password and login token back and forth between the server and the client, which could open up security issues. At least, you should make sure you disable caching for the page containing the iframe so that the password will not be saved in the browser cache.

  • Since your website and MediaWiki installation presumably live on the same domain, you could also just use your current code and then set the necessary cookies manually, something like this:

    setcookie( $cookieprefix . '_session', $sessionid );
    setcookie( $cookieprefix . 'UserName', $lgusername );
    setcookie( $cookieprefix . 'UserID',   $lguserid );
    setcookie( $cookieprefix . 'Token',    $lgtoken );
    
  • Finally, you could also turn the problem around, and write a MediaWiki auth plugin to delegate MediaWiki's user authentication to your website's user authentication system instead. This would have the advantage of allowing you to tie the two systems fully together, so that they'd user the same user database and the same authentication cookies. (MediaWiki does still insist on creating its own user records to store its own metadata, but writing an AuthPlugin let you completely override the authentication parts of the system if you want.)

Community
  • 1
  • 1
Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
  • Thanks, it works now! I set the cookies manually now. I tried that before, and I think I had a few successes, but they were so few I thought I had just forgotten to log out -- I forgot about the 5 second requirement between login attempts. There's still one problem though -- if I try to login and fail because I didn't wait long enough, it won't let me log in through the API again until I log in and log back out through the actual mediawiki form. – Adam11 Jan 01 '13 at 22:13
  • 1
    I think you'll just have to wait until the 5 minute timeout expires. If you want, you can lower it in LocalSettings.php by setting, say, `$wgPasswordAttemptThrottle['seconds'] = 60;`. Or you could even exempt requests from the same server from the throttling with something like `if ($_SERVER['REMOTE_ADDR'] == '127.0.0.1') $wgPasswordAttemptThrottle = false;`. (Of course, if you do that, it's a good idea to implement your own login attempt throttling. Actually, that's a good idea _in any case_.) – Ilmari Karonen Jan 01 '13 at 22:34
  • I don't think it's a throttling problem. I just turned throttling off and I still have the same problem. One failed logon prevents future logons. And even when it succeeds, it only registers as logged in on the main page, and only when that's the first page I visit after logging in. It won't register me as logged in at all unless I wait a good 15 seconds before visiting a mediawiki page; if I do, I get locked out completely until I log in using the mediawiki sign-in form. – Adam11 Jan 02 '13 at 01:53
  • That sounds very strange; I have no idea what could cause that. What result does the API report on the failed login attempt (and on the subsequent ones)? – Ilmari Karonen Jan 02 '13 at 02:19
  • It's just giving a regular success every time. I've just updated the code to what I'm using now. – Adam11 Jan 02 '13 at 03:06
  • I'm assuming that the wiki maintains its own session and I don't have to worry about syncing the session ids... – Adam11 Jan 02 '13 at 06:32
  • After playing around with cookie domains now, I've gotten it to work on *most* pages. There's still one page it doesn't work on: Recent Changes. I've set the cookie domains to the IP address I'm using. I don't understand, however, why it was setting them different from that in the first place. I haven't had this problem with any other cookies I've ever created. – Adam11 Jan 05 '13 at 05:24
  • 1
    Well, I solved the problem for good now. Turns out the browser cache was making it appear I was still logged in on some of the pages; it had nothing to do with MediaWiki. It's completely fixed now. I'll update the code in case someone in the future has a similar problem. It now has a logout routine built into it. Thanks for all the help! – Adam11 Jan 05 '13 at 22:18