Cyberpks
Cyberpks

Reputation: 1421

Securing a PHP Web service (SOAP)

I have a PHP web service that actually helps the CMS to carry out some updations to the database. I've been trying to search for a solution on Internet but haven't got my answer yet.

Is there any way to check if the user making request to the webservice is authorized to do so i.e. check the user session?

Here is my dummy service (services.php)

<?php
    function GetMyUserName($i)
    {
        return "admin101";
    }
     $server = new SoapServer(null,array('uri' => ROOT."includes/services.php"));
     $server->addFunction('GetMyUserName');
     $server->handle();
?>

Here is the JavaScript (jQuery) for consuming the service [uses a SOAP envelop]

function GetMyUName() {
    var req1 = "";
    req1 += '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">\n';
    req1 += '<soap:Body xmlns:m="includes/services.php">\n';
    req1 += "<m:GetMyUserName>\n";
    req1 += "</m:GetMyUserName>\n";
    req1 += "</soap:Body>\n";
    req1 += "</soap:Envelope>";

    $.ajax({
        url: "includes/services.php",
        type: "POST",
        data: req1,
        cache: false
    }).done(function (data) {
        $("#UsernameTb").html($(data).find("return").text());
    });
}

Is there any thing like the one we have in ASP's WCF to allow Sessions in the webservice.

I am using UserCake for authentication if this info is somewhat helpful.

Upvotes: 1

Views: 297

Answers (1)

quickshiftin
quickshiftin

Reputation: 69621

Overview

Frankly UserCake looks like it was written almost a decade ago. Just look at login.php from UserCake, it calls die() uses header("Location: account.php") to redirect the client and echos HTML.

None of these things lend themselves to a service paradigm. Most importantly UserCake's reliance on redirects will make it practically impossible to leverage behind a SOAP or REST interface without substantial modifications. Just look at the securePage function...

//Check if a user has access to a page
function securePage($uri){
    // earlier code omitted for readability here...

    elseif(!isUserLoggedIn()) 
    {
        header("Location: login.php");
        return false;
    }

    // ...
}

Services typically don't redirect. They return formatted response payloads (eg JSON or XML) and may use HTTP codes to indicate what the result of the service inquiry was. There are exceptions like OAuth, but that's entirely unrelated to the problem at hand.

I'd recommend selecting a proper framework, Code Igniter if you want something simple, Symfony if you want something robust. Both are fully capable of supporting pure HTML pages, API requests and authentication / authorization. But if it must be UserCake...

Beating UserCake into submission

A quick search tells us Javascript must follow the redirect. The client would need to determine if the response is HTML or JSON, then handle accordingly. Code lifted from this answer and this one illustrates how this might be done with jQuery.

$.ajax({
  type: "POST",
  url: "services.php", 
  data: {action: 'someSecuredAction', data: 'some data for the command'}, 
  success: function(response, status, xhr){ 
    var ct = xhr.getResponseHeader("content-type") || "";
    if (ct.indexOf('html') > -1) {
     // If data looks like HTML, this is some page from UserCake
     // likely served by a redirect, just display it
     var newDoc = document.open("text/html", "replace");
     newDoc.write(response);
     newDoc.close();
    }
    if (ct.indexOf('json') > -1) {
     // If data looks like JSON we have a
     // successful 'service' response from the server
    } 
  }
});

In theory the browser will pass along any relevant cookies with the request, so the session should be available on the server. Feel free to correct me on this, but from reading around it sounds like the session cookie will be passed over the AJAX request.

Then your example 'service' (services.php) file could become something like this (the switch is just some contrived thing to give you an idea how to access the data from the request)

// If this ends up redirecting,
// the client should just pass it on through
securePage($_SERVER['PHP_SELF']);

switch($_POST['action']) {
   case 'someSecuredAction':
       // Again, if this redirects the client should be able to cope...
       $loggedInUser->checkPermission(['someSecuredAction']);

       // Do secured stuff here
       $aResponse = someSecureAction($_POST['data']);

   break;
}

// Now be nice enough to return the response as JSON
// like we might expect from an actual service
header('Content-Type: application/json;');
echo json_encode($aResponse);

Upvotes: 3

Related Questions