Zend AMF Authentication & Authorization

dkozar evolved a working method to Authenticate and Authorize a Flex based app datas service call using Zend AMF, he writes;

I’ve been struggling with it, and figured it all out – so, perhaps it could help others.

The authentication is called on the server only if credentials supplied from the client (via the remote procedure call headers). This snippet illustrates the setup of custom auth (these are the last 6 lines of gateway.php script):

// Handle request
$auth = new My_Amf_Auth(); // authentication
$server->setAuth($auth);
$acl = new Zend_Acl(); // authorization
$server->setAcl($acl);
echo $server->handle();

Now, your custom auth should extend Zend_Amf_Auth_Abstract. Since I want to authenticate users from a database, I bring the Zend_Auth_Adapter_DbTable to play. But since I cannot extend both Zend_Amf_Auth_Abstract and Zend_Auth_Adapter_DbTable, I use a composition:

< ?php require_once ('Zend/Amf/Auth/Abstract.php'); /** * AMF auth class by Danko Kozar, dankokozar.com * @author dkozar * */ class My_Amf_Auth extends Zend_Amf_Auth_Abstract { function __construct() { } public function authenticate() { $adapter = My_Db_Adapter::getInstance(); $adapter->setIdentity($this->_username);
$adapter->setCredential($this->_password);

// the adapter call
// you can wrap it into try.. catch and process DB connection errors
$result = Zend_Auth::getInstance()->authenticate($adapter);

return $result;
}
}

Here’s the adapter class:

< ?php /** * DB table adapter auth class for AMF by Danko Kozar, dankokozar.com * @author dkozar * Singleton */ class My_Db_Adapter extends Zend_Auth_Adapter_DbTable { protected static $_instance = null; /** * private! * @param My_Db_Adapter $adapter */ public function __construct(Zend_Db_Adapter_Abstract $adapter = null) { if (!$adapter) $adapter = new Zend_Db_Adapter_Mysqli( array( 'dbname' => 'test',
'username' => 'root',
'password' => '')
);

parent::__construct($adapter);

$this
->setTableName('users')
->setIdentityColumn('username')
->setCredentialColumn('password')
;

// just for testing
// $this
// ->setIdentity('username')
// ->setCredential('password')
// ;
}

/**
* @return My_Db_Adapter
*/
public static function getInstance()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}

public function authenticate() {

$_authResult = parent::authenticate();

// NOTE: The point is that $result->_identity is an OBJECT (of type stdClass), NOT string
// with Zend_Auth_Adapter_DbTable it is internally accomplished by calling its getResultRowObject() method
// It constructs the stdClass with properties named after table attributes

// $user = new stdClass();
// $user->role = "administrator";
// $user->username = $_authResult->getIdentity();

$identity = $this->getResultRowObject();

$result = new Zend_Auth_Result($_authResult->getCode(), $identity);

return $result;
}
}

MyService.php class. Here it is:


< ?php /** * PHP service class with authorization * by Danko Kozar, dankokozar.com * @author dkozar * */ class MyService { /** * from zend docs: * If the ACL object is set, and the class being called defines initAcl() method, * this method will be called with the ACL object as an argument. * This method can create additional ACL rules and return TRUE, * or return FALSE if no access control is required for this class. * * @param Zend_Acl $acl * @return boolean */ public function initAcl($acl) { $acl->addRole(new Zend_Acl_Role("administrator"));
$acl->addRole(new Zend_Acl_Role("user"));

//acl "allow" method takes 3 parameters (role, resource - class name, privileges - it's function name in this class)

// administrator
$acl->allow('administrator', 'MyService', 'helloWorld');
$acl->allow('administrator', 'MyService', 'getData');

// user
$acl->allow('user', 'MyService', 'helloWorld');
$acl->deny('user', 'MyService', 'getData');

//returning true to signal that we want to check privileges before accessing methods of this class
//in my tests if we don't return anything it will treat it like we will return false so better return true or false
//your intentions will be clear
return true;
}

/**
* Hello world method
*/
public function helloWorld(){
return "Hello world from MyService service";
}

/**
*
* Returns data
* @return [int]
*/
function getData()
{
$arr = array(1, 2, 3);
return $arr;
}
}
?>

Note that the authorization is being built dynamically inside the initAcl method.

On the Flex side I have an auto-generated class (MyService) which extends another auto-generated class (_Super_MyService).

The point is that the outer one is auto-generated only once (initially), and you can modify it, without worrying to be overwritten on service regeneration.

There’s a protected property _serviceControl (which is of type RemoteObject) which could be tweaked if needed.

I’m tweaking it by of setting the endpoint (with string read from a client side config in preInitializeService() method). Plus, I’m adding 2 more methods, which expose setCredentials and setRemoteCredentials methods of _serviceControl, so I can acces it from my code.


package services.myservice
{
public class MyService extends _Super_MyService
{
/**
* Override super.init() to provide any initialization customization if needed.
*/
protected override function preInitializeService():void
{
super.preInitializeService();

// Initialization customization goes here
_serviceControl.endpoint = "http://localhost/myapp/gateway.php";
}

public function setCredentials(username:String, password:String, charset:String=null):void
{
_serviceControl.setCredentials(username, password, charset);
}

public function setRemoteCredentials(username:String, password:String, charset:String=null):void
{
_serviceControl.setRemoteCredentials(username, password, charset);
}
}
}


So, before calling MyService methods, I’m setting the credentials with setCredentials() method and this runs the authentication on the PHP side:


private var service:MyService;
....
service = new MyService(); // ServiceLocator.getInstance().getHTTPService("presetLoader");
service.setCredentials("user1", "pass1");
var token:AsyncToken = service.getData();

The authentication via Zend_Amf_Server is, by the way, OPTIONAL! Meaning, with no credentials supplied, Zend_Amf_Server will NOT RUN IT. Thus you should rely on Zend_Acl (e.g. roles) to so your permissions and security!

Finally, here’s the MySQL DB table I’ve been using for authentication:

--
-- Table structure for table `users`
--
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(32) DEFAULT NULL,
`role` varchar(45) DEFAULT NULL,
`firstname` varchar(50) DEFAULT NULL,
`lastname` varchar(50) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`),
UNIQUE KEY `id_UNIQUE` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;

--
-- Dumping data for table `users`
--
INSERT INTO `users` (`id`, `username`, `password`, `role`, `firstname`, `lastname`, `email`) VALUES
(1, 'user1', 'pass1', 'administrator', 'Danko', 'Kozar', NULL);

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Cheers!
Danko

Adobe Forums

Authentication using Zend_Amf

Kevin Schroeder writes; 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.


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.


$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.

via Kevin Schroeder’s blog – Zend Technologies.

SkinnableTextBase focusManager runtime error popup

writes somthing that will save you quite a bit of time if you get caught with this runtime error; When you show a popup in Flex in a mobile environment, defined as the style “interactionMode” being set to InteractionMode.TOUCH in this context, that is based on a component that does not implement the mx.managers.IFocusManagerContainer interface, you will receive a runtime error when the user taps the control that is to receive focus.

via Flex 4 Examples.

Flex mobile in the browser

Flex mobile in the browserSince Flex 4.5, you have had the ability to develop and export your projects as Android, iOS and PlayBook mobile applications that behave as native ones.

You can also export your Flex mobile project as AIR desktop apps. Just open Flash builder, open your project and choose Project >  Export release build. You can then export a “Signed AIR package for installation on desktop”, which means a classic .air file. Yesterday, a customer wanted to know how to run a Flex mobile application in a desktop web browser. Of course, I answered “Why would you do this ?”, and he gave me some good reasons.

His mobile application is connected to a CMS on the backend. Administrators of the application will be able to edit the content of the mobiles apps in a web application. Wouldn’t it be nice to get a live preview in the browser ? When you think of it, a Flex mobile project exports a SWF, so we should be able to run it as a web app. Of course, all the AIR APIs such as the accelerometer, or the SQLite access would be disabled, but we could have a live preview.

And it’s always a challenge for a mobile developer to demonstrate their work. Usually, they just record and publish a video of their app.

We’ll see in this tutorial how to create a Flex mobile project with Flash Builder 4.5.1, and how to publish it as a classic web application. Just follow these steps:

via Flex mobile in the browser | RIAgora.

File uploads with Adobe Flex and Zend AMF

Leonardo França writes; Zend AMF is an implementation done in PHP to work with the communication protocol binary AMF (Action Message Format) and is part of ZendFramework. I had to implement a system to upload files that were a little different than what is typically used in Flash, with this feature had to be integrated into the Zend AMF.
Researching a little on the net, found a solution that was simpler than I thought based on that article with a few adjustments.
Begin with our gateway to be used as endpoint in Adobe Flex.

< ?php require_once 'Zend/Amf/Server.php'; require_once 'Zend/Amf/Exception.php'; require_once 'br/com/leonardofranca/vo/FileVO.php'; require_once 'br/com/leonardofranca/UploadZendAMF.php'; $server = new Zend_Amf_Server(); $server->setProduction(false);

$server->setClass('UploadZendAMF');
$server->setClassMap('FileVO',"br.com.leonardofranca.vo.FileVO");

echo($server->handle());
?>

Read more at; File uploads with Adobe Flex and Zend AMF – Workflow: Flash.

Shine MP3 Encoder on Alchemy

Shine (formely 8hz-MP3) is a simple lightweight C-based MP3 encoder made by LAME developer Gabriel Bouvigne.

Description of Shine on his website:

The goal of this encoder was not quality, but simplicity. I tryed to simplify the encoding process as much as possible. So Shine is then a good starting point when a programmer needs a very simple MP3 encoder

This Alchemy port features:

  • MP3 encoding of mono and stereo WAVs (no time limit)
  • non-blocking encoding for progress status in flash
  • errors automatically sent to flash for easy log/debug

via flash-kikko.

WAVWriter.as

Helper class to write WAV formated audio files. The class expects audio input data in a byte array with samples represented as floats.

The default compressed code is set to PCM. The class resamples and formats the audio samples according to the class properties. The resampling geared for performance and not quality, for best quality use sampling rates that divide/multiple into the desired output samplingRate.

For more information about the WAVE file format see: http://ccrma.stanford.edu/courses/422/projects/WaveFormat/

via WAVWriter.as – ghostcat – AS3 library of generic tools

Flex Builder 4.5.x Test Drive for Mobile Tutorials

Here is a very good multi-part tutorial on the ins and outs of mobile client / server development, that adds some quite useful functionality on Android, Apple IOS and Blackberry mobile devices.

In this Test Drive, you are going to create a Flex mobile application that retrieves, displays, and modifies database records (see Figure 1). A Flex application does not connect directly to a remote database. Instead, you connect it to a data service written in your favorite web language (PHP, ColdFusion, Java, or any other server-side technology). You will build the front-end Flex mobile application; the database and the server-side code to manipulate database records is provided for you as a PHP class, a ColdFusion component, or Java classes.

The Mobile Test Drive application running on a mobile device.

Figure 1. The Mobile Test Drive application running on a mobile device.

via Adobe Developer Connection.

Data paging with Flex and PHP using Flash Builder 4.5.x

Flash Builder 4.5 has a built-in data paging feature that generates ActionScript code to retrieve data from the database incrementally on demand. For example, suppose your database has thousands of records and you want to fetch only 20 rows at a time and display them in a data grid. When you enable paging for an operation and bind the operation result to a DataGrid control, the first 20 records will be retrieved initially and the next page of records is fetched only when the user requests them—that is, when he or she scrolls the vertical scroll bar of the DataGrid control.

Flash Builder 4.5 lets you enable paging for any type of data service operation including operations on a Remoting service, web service, or HTTP service. This article explains how to enable data paging for a PHP-based Remoting service. After you set up the server environment required for the sample application, you’ll use Flash Builder 4.5 to generate ActionScript service classes and build a Flex application that incrementally retrieves data sets from a database table using the PHP class on the server.

via Adobe Developer Connection.

Zend_Config_Ini and a string

Rob Allen as usual writes useful stuff; One thing that is different between Zend_Config_Xml and Zend_Config_Ini is that with Zend_Config_Xml you can pass in an XML string as the first parameter of the constructor and it will work. This doesn’t work with Zend_Config_Ini as we use parse_ini_file() under the hood.

With PHP 5.3 however there is is a new function called parse_ini_string() which will allow us to load arbitrary ini string into Zend_Config objects. This can’t go into Zend Framework 1 though due to our PHP 5.2.4 minimum version requirement.

As I needed this for a project, I extended Zend_Config_Ini to support this feature, which means simply overloading a single method


class App_Config_Ini extends Zend_Config_Ini
{
/**
* Load the INI file from disk using parse_ini_file(). Use a private error
* handler to convert any loading errors into a Zend_Config_Exception
*
* @param string $filename
* @throws Zend_Config_Exception
* @return array
*/
protected function _parseIniFile($filename)
{
set_error_handler(array($this, '_loadFileErrorHandler'));
if (substr($filename, -4) == '.ini') {
$iniArray = parse_ini_file($filename, true);
} else {
$iniArray = parse_ini_string($filename, true);
}
restore_error_handler();

// Check if there was a error while loading file
if ($this->_loadFileErrorStr !== null) {
/**
* @see Zend_Config_Exception
*/
require_once 'Zend/Config/Exception.php';
throw new Zend_Config_Exception($this->_loadFileErrorStr);
}

return $iniArray;
}
}

The actual change is to see if the last 4 characters of the filename are “.ini” and if they aren’t then use parse_ini_string() instead of parse_ini_file(). The rest of the code is just error handling.

This is one area where I really like it when a class implements methods that done just one thing.

More at Rob Allen’s Dev notes