cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
1724
Views
0
Helpful
1
Comments
npetrele
Cisco Employee
Cisco Employee

PHP and Cisco IM&P EPASSoap

If you want to integrate Jabber/XMPP access to Cisco IM&P within a web application, the best way to do that is to use Cisco Jabber SDK, also known as CAXL, a Javascript library.

However, there are times when you want to put together simple web or command-line applications and utilities that make use of XMPP.  JAXL (an open source project, not Cisco) is a good way to do that with PHP.  With a little easy tweaking, it works fine with Cisco IM&P XMPP servers.  And, while not being as comprehensive as Jabber SDK, PHP is often easier to work with than Javascript if what you want is basic XMPP IM and Presence functionality.

You can find instructions on how to use JAXL on Windows 10 with Cisco IM&P here.  It works find on Linux, too, minus some of the adjustments we made to make it work on Windows 10.

Adding EPASSoap to PHP and JAXL

As of June 5, the date we published the JAXL blog post, JAXL lacked some features and probably still does. JAXL doesn't have the ability to add and delete contacts, for example.  You could add these features to JAXL, but that would require building various stanzas, which can by tricky. Fortunately, you can use Cisco EPASSoap and PHP to add these and other features. You can find documentation on EPASSoap here.

I've attached a complete sample PHP application to this blog post. It includes more than what you will see in this blog post.

In this blog post, we'll be using the tips documented here. These tips show you how to view the SOAP XML that your application will send, and dump the status that is returned to the web browser.

Establishing Your Client

First, you'll need a username/password for a person with the privileges necessary to access Cisco IM&P via SOAP so you can do basic authentication.

Then you'll need the username/password of an application user, and the username (no password needed) of the end user for which you want to do things like add/remove contacts.

What follows is the code that creates the modified PHP SOAP client to allow us to see the XML it sends. (Note: Lines are artificially broken to prevent having to scroll sample code and sample XML)

<?php
$host = "your-cimp-server.com";
$username = "basic auth user";
$password = "basic auth password";
$locationURL = "https://".$host."/EPASSoap/service/v105";
$wsdlURL = "https://".urlencode($username).":".
     urlencode($password)."@".$host."/EPASSoap/service/v105?wsdl";
$showresponse = true;
$appusername = "appusername";
$appuserpass = "appuserpassword";
$endusername = "endusername";

class MySoapClient extends SoapClient {
     public $sendRequest = true;
     public $printRequest = false;
     public $formatXML = false;

     public function __doRequest($request, $location, $action, 
                                        $version, $one_way = 0) {
          if ($this->printRequest) {
               if (!$this->formatXML) {
                    $out = $request;
               } else {
                    $doc = new DOMDocument;
                    $doc->preserveWhiteSpace = false;
                    $doc->loadxml($request);
                    $doc->formatOutput = true;
                    $out = $doc->savexml();
               }
               echo "<pre>";
               echo htmlspecialchars($out);
               echo "</pre>";
          }

          if ($this->sendRequest) {
               return parent::__doRequest($request, $location, 
                              $action, $version, $one_way);
          } else {
               return '';
          }
     }
}

$clientClass = 'MySoapClient';

$context = stream_context_create([
     'ssl' => [
          // set some SSL/TLS specific options
          'verify_peer' => false,
          'verify_peer_name' => false,
          'allow_self_signed' => true,
     ]
]);

$client = new $clientClass($wsdlURL,
          array(
               'soap_version' => SOAP_1_2,
               'trace' => true,
               'exceptions' => true,
               'location' => $locationURL,
               'stream_context' => $context,
               'login' => $username,
               'password' => $password));
               
$client->sendRequest = true;
$client->printRequest = true;
$client->formatXML = true;

Notice the variable $showresponse.  Set this to true, and when a SOAP request returns the response, the app will dump the entire $response object to the web browser so you can examine every detail. Here's how it works:

if ($showresponse) {
     echo "<pre>";
     var_dump($response);
     echo "</pre>";
}

Two PHP Gotchas

Before we continue, let's look at two common problems you'll have to deal with when using PHP and SOAP.

PHP and Hyphens

PHP does not allow method names or variable names with a hyphen in them. EPASSoap requires a number of methods with hyphens, so we need to work around that problem. The solution is simple enough. For example, instead of coding this, which will fail:

     $ausessionkey = $response->success->session-key;

Code it this way:

     $ausessionkey = $response->success->{'session-key'};

PHP SOAP and XML Attributes

EPASSoap requests often use XML attributes as well as values.  For example:

<persona-id domain="cisco.com">Reed</persona-id>

And...

<group old-name="Group" new-name="New Group"/>

There are at least a couple of ways of dealing with this issue, but here's what I find to be easiest. In the former case, where there's a domain attribute, you can set the attribute and the value this way:

"persona-id" => array("_" => "Reed", "domain"=>$domain)

In the latter case, when you have a tag that only includes attributes and no value, you can define it this way (set "_" to an empty string "").

$group = array("group" => array(
          "_" => "", "old-name"=>"Newer Group", "new-name"=>"New Group")
          );

Logging In and Getting Session IDs

An application user doesn't have any groups or contacts.  But in order to manipulate an end user's groups and contact, you need to get an application user's session key and use it to log in the end user. When you log in the end user, you use the end user's session key to perform operation on that end user's contacts and groups.

Let's log in the application user first, then.

$appUserLogin = array(
          "client-type" => "thirdpartyapp",
          "username" => $appusername,
          "password" => $appuserpass);

try {
     $response = $client->login($appUserLogin);
} catch (SoapFault $sf) {
     echo "SoapFault: ".$sf."<BR>";
}
catch (Exception $e) {
     echo "Exception: ".$e."<BR>";
}

if ($response->success)
     $ausessionkey = $response->success->{'session-key'};
else
     echo "No session key returned <BR>";
     exit();

Now we should have the application user session key in the variable $ausessionkey. We'll need to put the application user's session key in the soap header in order to log in the end user.

     
$objHeader = new SoapHeader('urn:cisco:epas:soap', 'session-key', $ausessionkey);
$client->__setSoapHeaders(array($objHeader));

Before we log in end user, let's get the domain set in the Cisco IM&P.  We may need this value later.  You may already know the domain, and you can just type it yourself anywhere it is needed in your app. But here's a handy way to get it into a variable via EPASSoap. This assumes there's only one domain, which is usually the case.

try {
     $response = $client->{'get-im-domains'}();
} catch (SoapFault $sf) {
     echo "SoapFault: ".$sf."<BR>";
}
catch (Exception $e) {
     echo "Exception: ".$e."<BR>";
}

$domain = $response->domain->name;

Now let's log in the end user. No need to set the SoapHeader to the application user session key again. It remains set until we clear it.

$endUserLogin = array(
          "client-type" => "thirdclient",
          "username" => $endusername,
          "app-session-id" => $ausessionkey);

try {
     $response = $client->login($endUserLogin);
} catch (SoapFault $sf) {
     echo "SoapFault: ".$sf."<BR>";
}
catch (Exception $e) {
     echo "Exception: ".$e."<BR>";
}

if ($response->success)
     $eusessionkey = $response->success->{'session-key'};
else
     exit();

Now we have the end user session key stored in the variable $eusessionkey. This is what we use to perform the rest of the end user operations.

Let's set the header to use this session key. First, however, we have to clear out the old application user session key.

// clear out the application user session key

$client->__setSoapHeaders(null);

// now set the end user session key in the header
$objHeader = new SoapHeader('urn:cisco:epas:soap', 'session-key', $eusessionkey);
$client->__setSoapHeaders(array($objHeader));

Manipulating End User Contacts

Here's how to add the Jabber user Reed (JID Reed@somedomain.com) to your roster in the group called "Contacts".

This is the XML we want to send as the request:

<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" 
                         xmlns:ns1="urn:cisco:epas:soap">
  <env:Header>
    <ns1:session-key>end-user-session-key</ns1:session-key>
  </env:Header>
  <env:Body>
    <ns1:add-contact>
      <ns1:group name="Contacts">
        <ns1:persona-id domain="somedomain.com">Reed</ns1:persona-id>
      </ns1:group>
    </ns1:add-contact>
  </env:Body>
</env:Envelope>

Here's how to construct that request using PHP SOAP:

$contact = array(
          "group" => array("name" => "Contacts",
                         "persona-id" => array("_" => "Reed", "domain"=>$domain)
                              )
                    );

try {
     $response = $client->{'add-contact'}($contact);
} catch (SoapFault $sf) {
     echo "SoapFault: ".$sf."<BR>";
} catch (Exception $e) {
     echo "Exception: ".$e."<BR>";
}

echo "Return status: ".$response->status->{'_'} . "<BR>";

It's as simple as that. Now let's tackle something like renaming a roster group.  Here's the XML request we want to create with the SOAP client:

<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" 
               xmlns:ns1="urn:cisco:epas:soap">
  <env:Header>
    <ns1:session-key>end-user-session-key</ns1:session-key>
  </env:Header>
  <env:Body>
    <ns1:modify-group>
      <ns1:group old-name="Group" new-name="New Group"/>
    </ns1:modify-group>
  </env:Body>
</env:Envelope>

Now here's how to create that with PHP soap:

$group = array("group" => array("_" => "", "old-name"=>"Group", 
          "new-name"=>"New Group"));

try {
     $response = $client->{'modify-group'}($group);
} catch (SoapFault $sf) {
     echo "SoapFault: ".$sf."<BR>";
} catch (Exception $e) {
     echo "Exception: ".$e."<BR>";
}

echo "Return status: ".$response->status->{'_'} . "<BR>";

Some final notes:

  1. If you add a user to a group that does not exist, the group is created automatically.
  2. If you delete a user from a group and that leaves the group empty, the group is automatically removed.
  3. It is the responsibility of your graphical user interface (if you create one) to update the roster when you make changes.

I hope you'll peruse and try out the sample application attached to this blog post. Just plug in the values appropriate to your installation, and it should be ready to run.

1 Comment
Getting Started

Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the community: