Single User OAuth using Zend Framework’s Twitter Service Class

3 Comments

Michelangelo van Dam wrote a neat little article to help with single user Twitter access.  What that means is that you can set up a Twitter application and then start tweeting without having to use a username and password.  Michelangelo did it in the context of a Zend Framework MVC application and so this blog post is only about doing what he did using the Twitter service as a library instead of the whole kit ‘n kiboodle.  Basically, here’s your code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$config = array(
  'username' => 'kpschrade',
  'consumerKey' => 'CONSUMER_KEY',
  'consumerSecret' => 'CONSUMER_SECRET',
  Zend_Oauth_Token_Access::TOKEN_PARAM_KEY => 'TOKEN',
  Zend_Oauth_Token_Access::TOKEN_SECRET_PARAM_KEY => 'SECRET'
);
$accessToken = new Zend_Oauth_Token_Access();
$accessToken->setToken($config[Zend_Oauth_Token_Access::TOKEN_PARAM_KEY]);
$accessToken->setTokenSecret($config[Zend_Oauth_Token_Access::TOKEN_SECRET_PARAM_KEY]);
$twitter = new Zend_Service_Twitter();
$twitter->setLocalHttpClient($accessToken->getHttpClient($config));
 
$result = $twitter->account->verifyCredentials();
 
if (isset($result->screen_name)) {
echo 'verified';
} else {
echo 'not verified';
}

Would you want to participate in a project to build a ZF2-based WordPress-compatible blogging platform?

24 Comments

Don’t know if it’d happen.  Just curious at this point.

The reason why I even asked the question was because WordPress, love it or hate it (I actually love it), is antiquated and, quite honestly, difficult to build for.  But if you were to build something that replaced it you would be facing a massive uphill battle due to its market size.  Ecosystem REALLY matters and it would matter doubly here.  So if you were to build a blogging platform it would need to have some kind of compatibility or mechanism for replicating functionality or people wouldn’t use it.  This poll is simply to see how many people would actually be interested in undertaking a project like that.

[UPDATE]

There is also some interest in “why” someone would want to do a project like this.  For myself, it comes down to the fact that I want to have a blogging platform that is mostly architecturally sound so I and others can build useful plugins, themes and such in a way that is easy and relatively painless.  But at the same time, there are hordes of other useful plugins and gorgeous themes that would not have a home, yet, on that platform and so you’re left with a chicken and egg problem.  That is why a compatibility layer is so important.  You could build the new stuff but still use the old stuff until something better comes along, if at all.

That is not to say that this is necessarily a good idea.  But with my own setup, I wish I could more easily build plugins on a system where theme-ing made sense, but I could still could pull in other third party tools.  That is why I’m asking the question.

And please don’t fill my comments about how it can’t or shouldn’t be done.  It can be done.  It’s not a question of if but of resources and desire.

And, for goodness sake, I’m just asking a frigging question.


Loading resources

Leave a comment

Any time I start a new ZF MVC project I am inevitably left with the unenviable task of bootstrapping a resource.  I’m not particularly a fan of them but I’m still trying to drink the Kool-Aid.  The problem is that getting  a resource autoloader going seems to be a mind-numbing experience that leads to a line of code or two.  So, rather than search for a project where I did it once before and then copy and paste the code into the project I figured I’d just blog about it so I can go here the next time I do it.

So, future idiot me,

When you have a project structure that looks like this

And you have an application config like this

resources.twitter.callbackUrl = "http://kschroeder/user/oauth"
resources.twitter.siteUrl = "http://api.twitter.com/oauth"
resources.twitter.consumerKey = "asdg425yasdfhjw46ujsfd"
resources.twitter.consumerSecret = "g246REhnfdgnDFVGNdfJ6345683SDfSGHd"

Add this to your application.ini

pluginPaths.Application_Resource = APPLICATION_PATH "/resources"

Now, future Kevin, you will never need to go project searching again.


Zend Framework 2 Event Manager

14 Comments

Yes, I know I work for Zend and that means that I should automatically be familiar with everything the company does.  Especially when it comes to Zend Framework 2.  But I have to confess that while I’m most definitely watching it, I have not been able to work with it in any meaningful sense.

Until today.  I got to play with the Event Manager.  I did like the plugin functionality in ZF1, but it required some pretty static coding.  In some cases, like the front controller plugins, it makes more sense (though this way seems more desirable).  Of course there are frameworks out there that are more event based as a whole, but what if you’re more familiar with Zend Framework?  I am, and so it makes sense that I would use the event manager in ZF2.  It’s a ZF1 application, but since (it seems) the event manager is self-contained (and the autoloader works with both ZF1 and ZF2) you can simply paste it into your include_path and BOOM, you have an event manager.

So, I had a model (the software kind) layer where all of the models were based off of an abstract class.  The abstract class had a save() method that I wanted to provide various hooks for pre and post save and, more importantly, pre and post validation.  Why validation?  Because I want to stored a hashed password in the database, but I want to validate on the plaintext.  I could have created a bunch of hooks, but that really is annoying.  I could have also overridden the save() method, but that meant adding a fair amount of logic to that method and I’m becoming less and less a fan of overriding logic because it’s insufficient at higher levels of abstraction.  So, instead, I implemented the ZF2 event manager in a ZF1 application.

The model looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
abstract class ModelAbstract
{
 
	const EVENT_PRESAVE = 'modelabstract-pre-save';
	const EVENT_PREVALIDATE = 'modelabstract-pre-validate';
	const EVENT_POSTVALIDATE = 'modelabstract-post-validate';
	const EVENT_POSTSAVE = 'modelabstract-post-save';
 
	/**
	 * @var EventManager
	 */
	protected $eventManager;
 
	public final function __construct()
	{
		$this->eventManager = new EventManager();
		$this->init();
	}
 
	public function init() {}
 
	public function save()
	{
		if ($this->tableName === null) {
			throw new ModelException('Improperly defined model');
		}
		$this->eventManager->trigger(self::EVENT_PREVALIDATE, $this);
		if (!$this->getForm()->isValid($this->data)) {
			return false;
		}
		$this->eventManager->trigger(self::EVENT_POSTVALIDATE, $this);
		$db = \Zend_Controller_Front::getInstance()->getParam('bootstrap')->getResource('db');
		$this->eventManager->trigger(self::EVENT_PRESAVE, $this);
 
// save the data (redacted due to boredom)
 
		$this->eventManager->trigger(self::EVENT_POSTSAVE, $this);
		return $ret;
	}
}

Then in my Account model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Application_Model_Account extends ModelAbstract
{
	protected $tmpPassword;
 
	public function init()
	{
		// Encrypt the password after validation if the password has changed
		$this->eventManager->attach(
			self::EVENT_POSTVALIDATE,
			function($event) {
				if ($event->getTarget()->passwordChanged()) {
					$event->getTarget()->encryptPassword();
				}
			}
		);
	}
 
	public function passwordChanged() // really annoying. Thanks PHP 5.3
	{
		return $this->tmpPassword == null;
	}
 
	public function encryptPassword()
	{
		if ($this->passwordChanged()) {
			$util = new Util();
			$this->password = $util->encryptPassword($password);
			$this->tmpPassword = null;
		}
	}
}

If the password is changed it sets both $this->password and $this->tmpPassword.  The hashing only occurs if the password has been set and there’s a value in tmpPassword.  (I guess I could have just used a boolean somewhere too).  So now, every time I save the account model the post validate event will be fired and the password will be encrypted.  (The comment on PHP 5.3 is because you cannot use $this in a closure in PHP 5.3.  That functionality will be there in 5.4.)

I believe that the method I used here allows for events to be fired for specific object instances, because each model has its own event manager.  But the event manager will also check for global events as well.  So, technically, the code that I have that does validation could be registered as a global observer to make sure that all models are properly validated prior to the save as well as having instance-specific (such as password changes) events attached to the same event name.

Pretty cool.

… waiting for Matthew to email me with corrections… 🙂

[UPDATE]

For those who have complained that I didn’t use some additional kind of methodology or best practice know that the other five billion lines of code that had nothing whatsoever to do with the event manager has been removed… or read my response down below on “Methodology Jackassery”.


Authentication using Zend_Amf

12 Comments

I forget why, but a few days ago I started doing some digging around with authentication in Zend_Amf_Server.  I had figured that I would add an adapter to the Zend_Amf_Server::setAuth() method and that would be it.

But I was wrong.

AMF allows for multiple request bodies to be sent at the same time.  Of those there are several “special” types of commands.  One of those commands is logging in.  What this means is that you don’t need a method that logs someone in for you.  Zend_Amf_Server handles authentication separately from your service classes.

Authentication for Zend_Amf_Server will generally use a combination of Zend_Auth and Zend_Acl components.  Zend_Auth is used to provide the credential verification while Zend_Acl is used to validate that the current user user can access the requested service method.  It is actually a relatively trivial task to restrict access to non-logged in users using the method that I will describe here.

The first step in the process is to create an authentication adapter.  It really doesn’t matter what you’re using.  What matters is that the adapter returns an identity object with a property called “role”.  The built in ACL handle expects this to be part of the identity object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Auth extends Zend_Amf_Auth_Abstract
{
	const LOGGEDIN_ROLE = 'loggedin';
 
	public function authenticate()
	{
		$identity = new stdClass();
		$result = Zend_Auth_Result::FAILURE;
 
		// Do a proper login, y'all
		if ($this->_username == 'test' && $this->_password == 'test') {
			$identity->role = self::LOGGEDIN_ROLE;
			$result = Zend_Auth_Result::SUCCESS;
		} else {
			$identity->role = Zend_Amf_Constants::GUEST_ROLE;
		}
 
		return new Zend_Auth_Result($result, $identity);
	}
}

The Auth class extends Zend_Amf_Auth_Abstract because Flex seems to require username and passwords as being the only mechanism for passing credentials.  The abstract class defines a method that hooks in with the special commands and passes the special credentials to the special adapter.  Clearly your authentication mechanism should be better than the one that I put in here, but you’ll get the idea.  The most important part is adding the role property to the identity object and passing it to the Zend_Auth_Result object.

Then in your gateway you need to add this adapter as well as create an simple ACL.

1
2
3
4
5
6
7
8
9
10
11
12
$server = new Zend_Amf_Server();
$server->addDirectory(realpath(__DIR__.'/../services'));
 
$acl = new Zend_Acl();
$acl->addRole(Auth::LOGGEDIN_ROLE);
$acl->allow(Auth::LOGGEDIN_ROLE);
$server->setAcl($acl);
 
$auth = new Auth();
$server->setAuth($auth);
 
echo $server->handle();

This adds the new Auth role to the ACL and says that it has access to everything.  Since there is no place where I allow guest access (denoted by Zend_Amf_Constants::GUEST_ROLE in the adapter) guest requests will be denied.

With just this little bit of code you now have a mechanism that will provide restricted access to all of your service objects.


Passing typed ActionScript objects to Flex using PHP and a message queue

4 Comments

Last week I wrote up a few blog posts (here, here and here) about creating a Flex based dashboard that utilized message queues to pass data.  It was a really fun example to write but there was one thing I did not get to implement.  What I wanted to do was use the sales notification mechanism to pass PHP objects to Flex using the message queue.  But I could not get the unserialization mechanism to work and so I had to settle for passing a simple message that a sale had been made.

However, because you can pass typed objects back and forth between PHP and ActionScript over HTTP using Zend_Amf_Server I figured that there MUST be a way of doing it automatically.  The first thing I did was create a valueObject class called Boogers (I descend into adolescence while trying new things) and called it in ActionScript so I could see the bytes that were created.  The class Boogers had a property called “nutso” (again, adolescence) to which I assigned the value of “what?”.  The code looked something like this

1
2
3
4
5
6
7
8
9
10
var bgrs : Boogers = new Boogers;
bgrs.nutso = "what?";
var baobj : ByteArray = new ByteArray;
baobj.writeObject(bgrs);
var ints2 : String = new String();
baobj.position = 0;
for (var i : uint = 0; i < baobj.length; i++) {
  var b : uint = baobj.readByte();
  ints2 +=  b + " " ;
}

This resulted in the bytes

1
10 19 41 118 97 108 117 101 79 98 106 101 99 116 115 46 66 111 111 103 101 114 115 11 110 117 116 115 111 6 11 119 104 97 116 63

Then I wrote some PHP code that created a PHP object called valueObjects\Boogers, serialize it and then output the bytes so I could compare it with the ActionScript output.  Note  that the class name follows the same namespace definition as the ActionScript class.  I wanted to have direct 1:1 relationships between PHP and ActionScript.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace valueObjects;
$b = new Boogers();
$b->nutso = "what?";
 
$stream = new \Zend_Amf_Parse_OutputStream();
$ser = new \Zend_Amf_Parse_Amf3_Serializer($stream);
$ser->writeObject($b);
$output = (string)$stream->getStream();
 
$a = '';
for ($i = 0; $i < strlen($output); $i++) {
  $a .= ord($output[$i]) . ' ';
}
echo $a;

 

The end result were the bytes

1
19 41 118 97 108 117 101 79 98 106 101 99 116 115 92 66 111 111 103 101 114 115 11 110 117 116 115 111 6 11 119 104 97 116 63

It was missing char 10.  But I found out that you needed to do a newline character for AMF to work properly, so I just prepended it to my output

1
$output = "\n" . (string)$stream->getStream();

So the next thing I wanted to do was send it to a message queue where ActionScript could read it using Stomp.

1
2
3
$stomp = new \Zend_Queue_Adapter_Activemq(array());
$stomp->setQueue(new \Zend_Queue(array('name' => '/queue/data')));
$stomp->send($output);

I ran the code and it sent the message to the message queue.  On the ActionScript side I set up a Stomp handler like I did in my webinar demo and was able to receive the message.  Reading the message is done by creating a method that responds to a message event generated by the Stomp library.

1
2
3
public function processMessage(msg : MessageEvent) : void {
  var obj : * = msg.message.body.readObject();
}

But the problem I ran into was that the typing of obj was always a generic Object.  So I proceeded to try and figure out how to get a properly typed object passed into ActionScript.  I tried several different methods but the craziest was that I tried was trying to implement a sort of null RPC call that would call com.adobe.serializers.utility.TypeUtility.convertResultHandler to do the unserializing.  But no matter what, none of the methods I tried would yield a properly type ActionScript object.  So I looked at the text output of the PHP output.

1
)valueObjects\Boogersnutsowhat?

Oh.

Notice anything?

Yep.  PHP namespace separator.  What did ActionScript use?  Yep, a period.

To solve it I added one line to the ActionScript processMessage() method.

1
2
3
4
public function processMessage(msg : MessageEvent) : void {
  flash.net.registerClassAlias("valueObjects\\Boogers", valueObjects.Boogers);
  var obj : * = msg.message.body.readObject();
}

Now when it is run I get a properly typed ActionScript object that I can work on in my Flex application.


Connecting PHP to ActionScript and Flex using Stomp

Leave a comment

In yesterday’s post I talked a little bit about some of the details on how I used messaging to connect a front end on demand request to a back end scheduled data processing mechanism.  In this post we’re going to talk about how to send data from a web page to a running Flex application without using HTTP.  It is really quite easy.

First up you need a message queue that supports Stomp.  Stomp is a text-based message queue protocol that a good number of message queue applications support.  I chose ActiveMQ, mostly because of authentication issues I was running into with RabbitMQ that I didn’t have time to solve.  Stomp isn’t turned on automatically so you need to change some config settings.  I have details at my first post on how to do that.

In my demo I wanted to have real time notifications of when a sale came in from a Magento application.  So the first thing to do would be to create a queue endpoint in ActiveMQ that you can send the data to.  That’s the easy part.  Next I needed to create an observer that would be triggered when a sale is made.  Magento uses an event based system and so hooking in to that was relatively easy.  The observer looked like this:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
use vo\SaleItem;
use vo\Sale;
use log\Logger;
 
class Zend_Dashboard_Model_Observer
{
 
  public function logSale(Varien_Event_Observer $observer)
  {
 
    $session = Mage::getSingleton('checkout/session');
    $orderId = $session->getLastOrderId();
    $order = Mage::getModel('sales/order')->load($orderId);
    $items = $order->getAllItems();
 
    $sale = new Sale();
    $sale->date = time();
    $sale->total = $order->getTotalDue();
    foreach ($items as $item) {
      $sItem = new SaleItem();
      $sItem->name = $item->getData('name');
      $sItem->price = $item->getData('price');
      $sItem->qty	 = $item->getData('qty_ordered');
      $sale->items[] = $sItem;
    }
    $logger = new Logger();
    $logger->registerSale($sale);
  }
}

 

The Logger class that it calls is where the messaging occurs.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
namespace log;
 
use vo\Sale;
 
class Logger
{
 
  private static $queues = array();
 
  /**
  *
  * Retrieves a queue object based on the name
  * @param string $queue
  * @return \Zend_Queue_Adapter_Activemq
  * @throws Exception
  */
 
  public function getQueue($queue)
  {
    if (!isset(self::$queues[$queue])) {
      $config = new \Zend_Config_Ini(__DIR__ . '/../../etc/config.ini');
      if (!isset($config->mq->$queue)) {
        throw new Exception('Undefined queue configuration');
      }
 
      $stomp = new \Zend_Queue_Adapter_Activemq(array());
      $stomp->setQueue(
        new \Zend_Queue(
          array(
            'name'=> $config->mq->$queue->endpoint
          )
        )
      );
 
      self::$queues[$queue] = $stomp;
 
    }
    return self::$queues[$queue];
  }
 
  public function registerSale(Sale $sale)
  {
    $queue = $this->getQueue('sales');
 
    $date = new \Zend_Date();
    $date->setTimestamp($sale->date);
 
    $output = sprintf(
      "%s Total: \$%s Items: %d",
      $date->toString(\Zend_Date::DATETIME_MEDIUM),
      $sale->total,
      count($sale->items)
    );
    // Send notification
    $queue->send($output);
  }
}

 

The workings of the logger and the configuration are described in yesterday’s post.  For this notification all I needed was a simple text message stating that a purchase was made and how much.  I want to figure out how to send an AMF serialized object to a Flash front end but I haven’t had time to do that yet.  So a simple text message will do.

Once the message is in the queue we now need to retrieve it in our Flex application.  I used AS3Stomp for the connection.  What I did was create a VGroup which could pretty much be inserted on any visual component. In there I created a list element that would be populated with the individual messages that were received from the queue.  The data provider for the list is a simple array of the individual messages which had been received.

<?xml version="1.0" encoding="utf-8"?>
<s:VGroup xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark"
    width="100%" height="100%" horizontalAlign="center"
    creationComplete="vgroup1_creationCompleteHandler(event)"
    xmlns:stomp="org.codehaus.stomp.*">
    <fx:Script>
    <![CDATA[
    import flashx.textLayout.elements.ListElement;
    import mx.events.FlexEvent;
    import org.codehaus.stomp.Stomp;
    import org.codehaus.stomp.event.MessageEvent;
    import valueObjects.Sale;
 
    protected function vgroup1_creationCompleteHandler( event : FlexEvent ) : void {
      stomp.connect();
      stomp.subscribe("/queue/sales");
    }
 
    protected function stomp_messageHandler( event : MessageEvent ) : void {
      var str : String = event.message.body.readUTFBytes(event.message.body.length);
      var data : Object = new Object;
      data.label = str;
      salesMessages.addItem(data);
    }
  ]]>
 
  </fx:Script>
  <fx:Declarations>
    <stomp:Stomp id="stomp" message="stomp_messageHandler(event)" />
    <s:ArrayCollection id="salesMessages" />
  </fx:Declarations>
 
  <s:Label text="Sales"/>
  <s:List id="saleList" width="100%" height="100%" color="#000000" dataProvider="{salesMessages}" fontSize="13"></s:List>
 
</s:VGroup>

The stomp object was provided as a declaration with a method associated with it’s “message” event which is thrown every time a new message comes in.  When a new message comes in the event is fired and the messageHandler() method is called where we read the message data into a string and attach it to an object with a label property.  Then we add it to the data provider at which point the list will update itself with the new value.

Easy.


Building a Flex-based dashboard with a PHP backend

Leave a comment

Today (June 1st) I got to give an online talk with Adobe on how to create a stunning analytics dashboard with Flex and PHP (recording here).  I’m a horrible graphic designer and so I don’t know how stunning it was, but from the technical perspective we covered a lot and it was a lot of fun to write.  Several of the attendees asked for code and so here is what I’ve written.  Like the webinar, it will take a little bit of time to get it working.  But the end result is that you’ll get a whole lot of stuff to think through.

What I did was take a Magento installation and create an observer that would send data to a message queue where it that data could be processed for either summary information or real-time notifications.  The dashboard contained graphs for traffic and product sales summaries and a notification list that would show new purchases as they were made.

To do this I used a lot of different programs, which you will need if you want to try it out.  You will need

  1. Magento
  2. ActiveMQ
  3. Zend Server (30 day trail available)
  4. MySQL
  5. Flash Builder for PHP (60 day trial available)

AS3Stomp is also used but I have included it in the workspace download.

Additionally, you will need to have two host names available on your machine.  I named mine magento.local and charting.local.  I set them in my hosts file (/etc/hosts or c:\windows\blah\blah\blah\hosts) but you could also use DNS as well if you needed to.  If you chose to run off of different host names you will need to change the gateway URL for the Charting project by editing the .flexProperties file and changing the serverRootURL property.

The first thing you need to do is download and install Zend Server.  You will need a license key to activate the Job Queue service.  Additionally you will need to add the directory in the project ChartingAPI, /library to your PHP include_path setting so that the logging and library classes can be included in your scripts.

You will then need to download and install Magento and then create a list of products.  Two or three should be enough.  If you want to easily integrate it with my code I would suggest that you create a blank PHP project and import the downloaded contents into the new project so that the project root is the document root for magento.local.  Do this before importing any of my project code.

Next, download and install ActiveMQ.  You will need to create three queues; saledata, sales and traffic.  You will also need to turn on Stomp support which you do by editing the activemq.xml file and adding the transport connector.

<transportConnectors>
<transportConnector name=”openwire” uri=”tcp://0.0.0.0:61616″/>
<transportConnector name=”stomp” uri=”stomp://localhost:61613″/>
</transportConnectors>

You may need to specify the JAVA_HOME directory in activemq.bat in the bin directory.

From there you can import my Magento extension into the Magento project.  Make sure that you import it into the root so that the code ends up in /app/code/local/Zend.  Additionally there should be a file called /app/etc/modules/Zend_Dashboard.xml.  This is there to inform Magento that you have a new extension that you want to use.  Once you have the code in place you will need to 1) Flush the Magento cache and 2) Enable the extension in the Magento settings (hint, it’s in one of the last sections).  With Magento, if you make a change and nothing seems to happen, it’s probably because the cache was not flushed.

To test the messaging configuration go to the ActiveMQ management page at http://localhost:8161.  Browse around the Magento site a little and check back to the queues page.  If you see messages waiting then your configuration is working.

Next up is to set up the  job queue.  In the ChartingAPI project there is a directory called public.  That should be the document root for the charting.local virtual host.  In the public directory is another folder called jobs.  In there are two scripts that will need to be run at least once.  Each of them requeues itself and so if you run it once via the URL (http://charting.local/jobs/process.traffic.php and process.sales.php).  Run them once and only once.  If you want to see what they do prior to injecting them into the job queue comment out the three lines of code starting with the object ZendJobQueue.

Now you should be ready to go with the Charting project.  If it is not able to compile due to a missing Stomp class you will need to reference the src folder in the project AS3Stomp.  After that is working right click in the Charting project on the Charting.mxml file in the src/(default package) directory and select Run As -> Mobile PHP Application.  That will kick off the charting application.  If there are problems you can select Debug As -> Mobile PHP Application and debug both the Charting application’s ActionScript or the PHP application’s service calls.

The link for the workspace zip is adobe.webinar.zip.

You can also see my slides on SlideShare.

I will leave you with that for the time being.  I intend to do another blog post on some of the reasons for doing things the way I did them along with some discussions about the architecture for the different integration points.  Additionally, I found that this webinar has highlighted a couple of pieces of needed documentation both for ActionScript and asynchronous community in PHP.  So, I have my work cut out for me for the next little while.  🙂


Encrypted session handler

15 Comments

[UPDATE]  Enrico Zimuel has a better version of this[/UPDATE]

A little while ago I had come upon the problem of having to store sensitive data in a user session.  The solution that I (and several others came upon) was creating a mechanism for storing encrypted data in a session.  But what we wanted to do was build something that didn’t have a single point of failure.  We also wanted to build something portable.  What we built was a simple Zend Framework session handler for storing sensitive data.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
class EncryptedSession extends Zend_Session_Namespace {
 
    const CIPHER = MCRYPT_3DES;
    const MODE = MCRYPT_MODE_CBC;
 
    private $_iv;
 
    public function __construct($namespace = 'Default', $singleInstance = false)
    {
        parent::__construct($namespace, $singleInstance); // Must be true because of iv
 
        $storeKey = __CLASS__ . '_Data' . '_' . $namespace;
 
        if (!isset($_COOKIE[$storeKey]) || !isset($this->secretKey)) {
                $this->unsetAll();
 
                $maxKeySize = mcrypt_get_key_size(self::CIPHER, self::MODE);
 
                $secretKey = '';
                while( strlen($secretKey)<$maxKeySize) {
                    $secretKey .= dechex(uniqid(mt_rand(), true);
                }
                $this->secretKey = substr($secretKey, 0, $maxKeySize);
 
                $iv_size = mcrypt_get_iv_size(self::CIPHER, self::MODE);
 
                $this->_iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
 
            $hmac = hash_hmac('md5', $this->_iv, $this->secretKey);
            $unique = base64_encode($this->_iv);
            // The cookie has the same parameters as the session cookie
            $cookie_param = session_get_cookie_params();
            setcookie(
                $storeKey,
                $hmac.$unique,
                $cookie_param['lifetime'],
                $cookie_param['path'],
                $cookie_param['domain'],
                   $cookie_param['secure'],
                   $cookie_param['httponly']
            );
        } else {
            $hmac = substr($_COOKIE[$storeKey],0,32);
            $unique = base64_decode(substr($_COOKIE[$storeKey],32));
            $check = hash_hmac('md5',$unique,$this->secretKey);
            if($hmac !== $check) {
                 throw new Zend_Session_Exception('Invalid Session Data');
            }
            $this->_iv = $unique;
 
        }
    }
 
    public function setEncrypted($key, $value)
    {
        $this->$key = bin2hex(
            mcrypt_encrypt(
                self::CIPHER,
                $this->secretKey,
                $value,
                self::MODE,
                $this->_iv
            )
        );
    }
 
    public function getEncrypted($key)
    {
        if (isset($this->$key)) {
            $decrypt = mcrypt_decrypt(
                self::CIPHER,
                $this->secretKey,
                pack(
                    'H*',
                    $this->$key
                ),
                self::MODE,
                $this->_iv
            );
            return rtrim($decrypt, "�"); // remove null characters off of the end
        }
        return null;
    }
}

 

 

What this does is allow you to transparently store encrypted data in a session.  Because it’s encrypted, someone hacking in to the server, say via an include vulnerability, would be able to read the session data, but not decrypt it.  That’s because the initialization vector is stored in a cookie on the browser.  So in order to decrypt the session an attacker would need to do both an XSS and a remote code injection attack.


Debugging a mobile app

Leave a comment

I’m working on an example of mobile detection with the new Zend Framework 1.11 beta that was just released when I came upon an interesting problem.  That problem is; how do I debug requests coming in from the mobile phone?  The answer is actually relatively easy.  I’m doing this using a Zend Framework application, but the concepts that you’ll see here can be used quite easily across any type of framework.

The debugger in Zend Studio works by watching for certain cookies or GET parameters to be sent by the browser.  If they are detected then the Zend Debugger on the server will try to connect to the debugger in the IDE based off of the information provided in the cookie.  I typically do this using the Zend debugger toolbar, but I can’t get that on my Epic (Android).  Another option I have is to debug from the IDE but I’m not actually running from the phone so I will not have the same configuration.

The solution is similar to what I did with Debugging an RPC call in Zend Framework.  What this does is set the cookies from the remote browser to debug on the local instance of the Zend debugger.  To kick it off simply open up the URL to the debug kickoff page.  That will set the cookies in your mobile browser.  Then go to the page that you want to debug from your mobile phone and reload it.  Because you have the cookies set on the mobile browser the next request will debug in your local IDE.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class IndexController extends Zend_Controller_Action
{
 
    public function setdebugAction()
    {
        $cookies = array(
            'start_debug'            => '1',
            'debug_stop'             => '1',
            'debug_fastfile'         => '1',
            'debug_coverage'         => '1',   
            'use_remote'             => '1',
            'send_sess_end'         => '1',
            'debug_session_id'         => '2000',  
            'debug_start_session'     => '1',
            'debug_port'             => '10137',
            'debug_host'             => '127.0.0.1'
        );
        foreach ($cookies as $name => $value) {
            $this->_response->setHeader(
                'Set-Cookie',
                new Zend_Http_Cookie(
                    $name,
                    $value,
                    $this->_request->getHttpHost()
                    )
            );
        }
 
        $this->_helper->viewRenderer->setNoRender(true);
        echo "Debug set";
    }
}