Louder Developer Zone
Articles, Tutorials and Tips from the community and Louder developers

Implementar Aspectos de Seguridad con KEF

Publish at Monday, March 29, 2010
By Core Developers - Louder

En el presente ejemplo se va a hacer uso de los componentes Acl, Auth y los plugins de los Controladores para implementar un sencillo modelo de seguridad para un "Blog".

El ejemplo se centra en los aspectos de seguridad del "Blog" y no en publicar ó visulizar los "posts" del mismo.

Crear una lista de control ACL

Usaremos un Acl para definir una lista de control de acceso basada en una tabla de MySQL. La tabla se llamará "access_list" y tiene la siguiente estructura:
CREATE TABLE `access_list` (
  `id` int(11) NOT NULL auto_increment,
  `role` varchar(24) NOT NULL,
  `resource` varchar(32) NOT NULL,
  `action` varchar(32) NOT NULL,
  `allow` char(1) default NULL,
  PRIMARY KEY  (`id`),
  KEY `role_1` (`role`,`resource`,`action`),
  KEY `role_2` (`role`,`resource`,`action`,`allow`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Recursos a Controlar

Nuestra aplicación de "blog" tiene 3 controladores que actúan como "recursos" y una serie de "acciones" relacionadas a estos:

Nombre Recurso Descripción Acciones
SesionController Permite iniciar y terminar sesión a los administradores
  • index
  • entrar
  • salir
PostsController Muestra los posts creados hasta el momento
  • index
  • detalles
AdminController Permite crear, consultar, editar y eliminar los posts del blog
  • index
  • crear
  • editar
  • buscar
  • eliminar

Roles del Blog

El "blog" tiene 2 roles, se describen a continuación:

Nombre Rol Descripción
Visitante Este Rol es usado por defecto y se usado por los lectores del blog.
Administrador Este rol es usado por los administradores del blog, quienes tienen derecho a crear, modificar, borrar, etc los posts.

Agregar los permisos a la lista de control

Insertamos los siguientes registros a la tabla "access_list" para indicar los permisos asignados a cada rol:


//El "Visitante" no tiene acceso a:
INSERT INTO `access_list` VALUES ("Visitante", "admin", "index", "N");
INSERT INTO `access_list` VALUES ("Visitante", "admin", "crear", "N");
INSERT INTO `access_list` VALUES ("Visitante", "admin", "editar", "N");
INSERT INTO `access_list` VALUES ("Visitante", "admin", "eliminar", "N");
INSERT INTO `access_list` VALUES ("Visitante", "admin", "buscar", "N");
INSERT INTO `access_list` VALUES ("Visitante", "sesion", "salir", "N");

//El "Administrador" tiene acceso a todo
INSERT INTO `access_list` VALUES ("Administrador", "*", "*", "Y");

Crear una tabla de usuarios

Los usuarios administradores se almacenan también en la siguiente tabla junto con su rol:

CREATE TABLE `users` (
  `id` int(11) NOT NULL auto_increment,
  `login` varchar(32) NOT NULL,
  `password` char(40) NOT NULL,
  `role` varchar(24) default NULL
  PRIMARY KEY  (`id`),
  KEY `users_1` (`login`, `password`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

//Crear algunos usuarios
INSERT INTO `users` VALUES ("admin", "7df2a311e10899e9fc79f6b8f6b91297", "Administrador");
INSERT INTO `users` VALUES ("carolina", "88f1798e205c841fe851b42095329f84", "Administrador");

Implementar el controlador SesionController

Este controlador permitirá iniciar sesión y mantener la identidad del usuario. La acción entrar hace uso del componente Auth para realizar esta tarea:


<php

// apps/default/controllers/sesion_controller.php
class SesionController extends ApplicationController {

	public function indexAction(){
		//Aqui muestra el formulario de inicio de sesion
	}

	public function entrarAction(){

			//Obtener datos del formulario, encriptar password con sha1
			$login = $this->getPostParam("login", "addslaches");
			$password = sha1($this->getPostParam("password"));

			//Usar Auth para comprobar identidad en el modelo "Users"
			$auth = new Auth(array(
				"model",
				"class" => "Users",
				"login" => $login,
				"password" => $password
			));

			//Si las credenciales son validas ir a admin/index
			if($auth->authenticate()==true){
				Router::routeTo(array(
					"controller" => "admin",
					"action" => "index"
				));
			} else {
				//Si el usuario/password son inválidos volver a sesion/index
				Router::routeTo(array(
					"controller" => "sesion",
					"action" => "index"
				));
			}
	}

	public function salirAction(){
		//Destruir identidad activa y volver al sesion/index
		Auth::destroyIdentity();
		Router::routeTo(array("controller" => "sesion", "action" => "index"));
	}

}

Controlar el Acceso a los Recursos de la Aplicación

Cada vez que se ingrese a una acción en un controlador debemos validar que el usuario activo tenga acceso a la misma. Esto lo podemos hacer de forma sencilla implementando un plugin de controladores que ejecute un evento antes de cada acción:


<php

// apps/default/plugins/permisos.php
class PermisosPlugin extends ControllerPlugin {

	/**
	 * Lista de permisos ACL
	 *
	 * @var Acl
	 */
	private $_acl;

	/**
	 * Obtener el ACL al inicializar el Plugin
	 *
	 */
	public function __construct(){
		$this->_acl = new Acl("Model", "className: AccessList");
	}

	public function beforeDispatch(){

		//Si hay un usuario activo se obtiene el rol
		if(Auth::isValid()==true){
			$identidad = Auth::getActiveIdentity();
			$rol = $identidad["role"];
		} else {
			$rol = "Visitante";
		}

		//Obtener recurso y acción activa
		$recurso = Router::getController();
		$accion = Router::getAction();

		//Si no tiene permiso se enruta al controlador "sesion"
		$tienePermiso = $this->_acl->isAllowed($rol, $recurso, $accion);
		if($tienePermiso==false){
			Router::routeTo(array(
				"controller" => "sesion",
				"action" => "index"
			));
		}

	}

}

Notése que con solo hacer un enrutamiento al controlador sesión se evita que se ejecute la acción solicitada sino tiene permiso para esta.

Conclusiones

  • Los plugins de controladores permiten ejecutar procedimientos en cada enrutamiento a un controlador/acción, esto los hace muy adecuados para tareas como el control de acceso y seguridad.
  • Al usar plugins de controladores se evita agregar código traversal a la aplicación haciendo cada controlador más limpio.
  • Listas de control de acceso y usuarios pueden ser administrados usando tablas y modelos de una base de datos
Tell friends about this article on social networks:



blog comments powered by Disqus

Previous: Crear un sistema de reportes de Excepciones para nuestras Aplicaciones Next: Usar Firebird/Interbase con Kumbia Enteprise

Colaborate

Colaborate

We invite you to submit articles and tutorials to the Developer Zone.

Archive

  • Mayo 2009

Maybe you are interested

Added value to your Business.

Become a Solution Partner Louder Now.

Bring to the Open-Source retroactively..

Learn more about Shared Louder Labs