= sfGuard plugin - extra documentacion = (esta tratará de ser una ayuda hispana para http://trac.symfony-project.com/wiki/sfGuardPluginExtraDocumentation) Este wiki brindará información adicional para el uso de sfGuardPlugin en Symfony. Esta dirigido a novatos. Basicamente, amplia el README con información adicional. comentarios y algunas correcciones de la version 1.13 PRE. Como novato en Symfony y de sfGuardPlugin, busque información en varias partes para entender mas acerca del framework y del este plugin (concretamente , el libro de Symfony y la Guia de Askeet). Este proceso tomo bastante tiempo y fue de gran ayuda. Con este documento trato de ayudar al resto, la info es correcta pero breve, asumo un gran conocimiento general y experiencia. == Introducción a la Autorización, Seguridad y Autenticación == La documentación dice 'The sfGuardPlugin adds authentication and authorization above the standard of Symfony'. Pero que significa todo eso? Basicamente, autenticación/seguridad es limitar el acceso a (partes de) tu aplicación. Significa que los usuarios tendrán que iniciar una sesión (=autenticacion) para acceder a ciertas areas (=seguridad). Diferentes usuarios pueden tener diferentes 'privilegios' (=autorización). De esta manera aseguras tu aplicación para diferentes tipos de usuarios. También, puedes administrar los privilegios en el back-end (=autorización). Si lees el capitulo 6 del Libro -'Inside the controller layer', p.100 'Action Security' , te darás una idea del mecanismo de seguridad de Symfony. Aquí un resumen: El acceso a las 'actions' puede ser restringido en Symfony. La action-access-restriction es seteada en el archivo ''myProject''/apps/''myApplication''/modules/''myModule''/config/security.yml (''italicas'' es tu propio proyecto, aplicación y modulo). Si el usuario pide una action que esta asegurada por security.yml, el usuario tiene: 1. que ser autenticado (= login) 2. tener las credenciales correctas (=privilegios adecuados) Acceder a partes de la aplicación puede ser controlado por las 'Credentials' en ''security.yml''. Para más detalles, mira la página 103 (complex credentials) del Libro de Symfony. Nota: en esta documentacion nos referimos al usuario como la persona que usa la aplicación desde el frontend. Symfony también tiene el objeto ''sfUser'' para el manejo de las sesiones. La Administración-de-Sesiones es manejada por el objeto ''sfUser'' (o ''$sf_user'' en los templates). Este es un objeto singleton y puede ser accedido desde cualquier parte de la aplicación. Por ejemplo con ''$this->getUser()->setAuthenticated(true)'' seteamos el status a ''logged-in'' y puede ser chequeado en tu template con ''isAuthenticated()) ?>''. Puedes agregar más info al objeto ''sfUser'' para distinguir entre diferentes tipos de usuarios, agregando 'Credentials' al objeto ''sfUser'': 1. ''$this->getUser()->setCredential('member')'' setea el tipo de usuario a 'member'. El objeto ''sfUser'' es un objeto de sesión. Significa que su información esta disponible a traves de toda la aplicación. Además de Credentials, puedes añadir más información al objeto ''sfUser'' que puedas necesitar usando 'Attributes', ej. el ID del usuario: 2. ''$this->getUser()->setAttribute('member_id', 123, 'membernamespace')'' almacena 123 como el ''member_id'', el cual podrá ser usado luego en la aplicación con ''$this->getUser()->getAttribute('member_id')''. El 'namespace' es el nombre para la Colección de Atributos (Espacio de Nombres) y es empleado para facilmente poder eliminar todos los atributos relativos a ese namespace ('membernamespace') (empleando ''$this->getUser()->getAttributeHolder()->removeNamespace('member')''). Entonces, que pasa cuando un usuario pide una action que esta 'asegurada' a traves del security.yml de un module? 1. Si el usuario esta autenticado y tiene las correctas credenciales, la action es ejecutada 2. Si el usuario no esta identificado/autenticado, la accion default ''login'' action será lanzada. La default ''login'' action esta definida en el 'settings.yml' de tu aplicacion! (''myProject''/apps/''myApp''/config/settings.yml). El Libro Symfony menciona al 'security.yml', pero es un error, debería decir 'setting.yml'. 3. Si el usuario está identificado pero no tiene las credenciales correctas, la default ''secure'' action sera lanzada. Tambien esta default ''secure'' action esta definida en el 'settings.yml'. Ambas, la default ''login'' y ''secure'' action serán re-definidas para usar el sfGuardPlugin. El template para estas actions puede también ser modificado por ti. Suficiente de las funcionalidades estandar de seguridad de Symfony, volvamos al sfGuardPlugin! = sfGuard plugin = El sfGuard Plugin te brinda el modelo (usuario, grupo y objetos de permisos) y los modulos (backend y frontend) para asegurar tu aplicación en un minuto de configuración. == Instalación == * Instala el plugin {{{ symfony plugin-install http://plugins.symfony-project.com/sfGuardPlugin }}} Este comando instala el plugin dentro de symfony y dentro de tu Proyecto bajo ''myProject''/plugins/sfGuardPlugin. Revisalo, y podrás ver que el plugin tiene sus propios directorios config-, data-, lib-, y un directorio modules para sus cuatro modulos. sfGuardPlugin añade 4 modulos a tu proyecto en el directorio '/plugins/sfGuardPlugin/modules': 1. sfGuardAuth - para el frontend-application 2. sfGuardGroup - para el backend-application 3. sfGuardPermission - para el backend-application 4. sfGuardUser - para el backend-application * Habilita un o más de estos modulos en tu `settings.yml` * Para tu backend necesitas: sfGuardUser, sfGuardGroup, sfGuardPermission * Para tu frontend solo necesitas: sfGuardAuth Para tu frontend: {{{ all: .settings: enabled_modules: [default, sfGuardAuth] }}} para tu backend {{{ all: .settings: enabled_modules: [default, sfGuardGroup, sfGuardUser, sfGuardPermission] }}} Con instalar el Plugin, no significaba que estuvieran activados en Symfony, por lo que necesitabas activarlos (enabled_modules) por aplicación agregando cada uno al 'settings.yml', ej. para frontend o backend (Puedes setear los plugins por aplicacián, y podrás tener diferentes plugins por aplicacion). * Limpia el cache {{{ symfony cc }}} Cada vez que añadas clases o funciones, tiene que limpiar el cache de symfony. * Regenera el modelo {{{ symfony propel-build-all }}} Ahora, sfGuardPlugin ha añadido 7 tablas a la Base! Ellas están definidas en '/plugins/sfGuardPlugin/config/schema.xml': 1. '''sf_guard_user''' - La tabla con todos los usuarios, tiene username , password etc. 2. '''sf_guard_permission''' - La tabla con todos los permisos, incluye permissionname y description 3. '''sf_guard_user_permission''' - La tabla que relaciona n:m 'user' y 'permission', es decir un user puede tener multiples permisos y un permiso puede ser compartido con multiples users. 4. '''sf_guard_group''' - La tabla que define groups 5. '''sf_guard_user_group''' - La tabla que lista los users de un group, un user puede ser parte de multiples groups 6. '''sf_guard_group_permission''' - La tabla que relaciona n:m 'group' y 'permission' 7. '''sf_guard_remember''' - almacena la ip-address y remember-key de los users Comprueba si las tablas son añadidas a su Base, sino, hubo un error. Luego en la documentación (personaliza el sfAuthUser model) puedes enlazar tu infomación de usuarios a la tabla estandar 'sf_guard_user'. * Carga el default fixtures (=database data para ej. testeo) (opcional - crea un superadmin user) {{{ symfony propel-load-data ''myApplication'' }}} Fixtures son usados para cargar datos en tu Base. Este carga ambos, el actual schema.yml de tu aplicacion, y el schema.yml del plugin dentro de tu Base.(Nota del traductor: Lleve el .yml al /data/fixtures y lo renombre a sfGuardData.yml. Tuve que hacerlo asi. ) * Opcionalmente habilita el filtro "Remember Me" en `filters.yml` {{{ security: class: sfGuardBasicSecurityFilter }}} === Asegura tu aplicación === Para asegurar una aplicación symfony: * Habilita el modulo `sfGuardAuth` en `settings.yml` (''myProject''/apps/''myApp''/config/settings.yml) del frontend {{{ all: .settings: enabled_modules: [..., sfGuardAuth] }}} Hazlo removiendo el '#' al inicio de la linea de tu 'settings.yml'. Mejor es copiarlo a unas lineas mas abajo sin los '#', esto te dara una vista clara de lo activado (por alguna razón, solo removiendo el '#' no trabajaba). * Modifica los modulos ''login'' y ''secure'' en `settings.yml` (''myProject''/apps/''myApp''/config/settings.yml), y no en 'security.yml' como dice el libro! {{{ all: .actions: login_module: sfGuardAuth login_action: signin secure_module: sfGuardAuth secure_action: secure }}} Esto cambia el comportamiento por defecto de tu aplicación, cuando el usuario no esta logueado o no tiene las credenciales apropiadas al pedir una página, como se indicó antes en la Introduccion de este wiki. * Cambia la clase padre en `myUser.class.php` de tu aplicación (''myProject''/apps/''myApp''/lib/myUser.class.php) {{{ class myUser extends sfGuardSecurityUser { } }}} ** NOTA/OPINION DEL TRADUCTOR : Tener dos veces definida la clase myUser (en cada APP) me parece medio incorrecto. Se puede crear en el mismo proyecto otra clase (''myProject''/lib/myUserProject.class.php) Y que luego cada myUser extienda a esta ultima. {{{ class myUserProject extends sfGuardSecurityUser { } }}} En Symfony sin el sfGuardPlugin, ''myUser'' se basa en sfBasicSecurityUser. Con el anterior cambio, ''myUser'' se basa en sfGuardSecurityUser. El sfGuardSecurityUser a su vez se basa en sfBasicSecurityUser, por lo tanto no pierdes ninguna funcionalidad. El sfGuardSecurityUser extiende el sfBasicSecurityUser con métodos tales como signIn y signOut, mira ''myProject''/plugins/sfGuardPlugin/lib/user). * Opcionalmente añade estas reglas al `routing.yml` {{{ sf_guard_signin: url: /login param: { module: sfGuardAuth, action: signin } sf_guard_signout: url: /logout param: { module: sfGuardAuth, action: signout } sf_guard_password: url: /request_password param: { module: sfGuardAuth, action: password } }}} Esto apunta la url .../login a la action 'signin' del modulo 'sfGuardAuth'. Puedes personalizar el parametro `url` de cada ruta. Esto es opcional porque las anteriores reglas son de routing son automaticamente registradas por el plugin si habilitas el modulo `sfGuardAuth`. Sin embargo, si lo deseas, puedes deshabilitar las reglas definiendo `sfGuardPlugin_routes_register` en false en el archivo de configuración `app.yml`. N.B.: Si o si debes tener un `@homepage` (se usa cuando el usuario cierra sesión), por ejemplo: {{{ homepage: url: / param: { module: member, action: index } }}} * Limpia tu cache {{{ symfony cc }}} Cada vez que añadas clases o funciones, tienes que limpiar el cache de symfony. * Asegura algunos modulos o toda tu aplicación en `security.yml` {{{ default: is_secure: on }}} * Listo el Pollo :). Ahora, si tratas de acceder a una página segura, serás redireccionado a la página de login. Si has cargado el default fixture, trata de loguearte con `admin` como username y `admin` como password. == Añadiendo tu propio user-(profile)-model: Personalizando el modelo de `sfAuthUser` == El modelo `sfAuthUser` que viene con el plugin es bastante simple, este tiene: - username - algorithm - salt - password - created_at - last_login - is_active - is_super_admin no hay campos/columnas para `email` o `first_name` o `birthday`. Como no quieres cambiar la clase 'sfAuthUser' directamente (porque deseas instalar actualizaciones de este plugin sin tener que agregar tus propios campos una y otra vez), puedes añadir tu propio user-profile en otra clase, la clase user-profile. Por defecto 'sfGuardUser' busca la user-profile-class 'sfGuardUserProfile', que tiene que definir en tu propio 'schema.yml'. Aqui un ejemplo de una clase `sfGuardProfile` asociada que puedes añadir al `schema.yml` de tu proyecto: {{{ sf_guard_user_profile: _attributes: { phpName: sfGuardUserProfile } id: user_id: { type: integer, foreignTable: sf_guard_user, foreignReference: id, required: true, onDelete: cascade } first_name: varchar(20) last_name: varchar(20) birthday: date }}} ''user_id'' es la clave foranea a sf_guard_user. Puedes cambiarle el nombre y tambien la user-profile-class asociada en `app.yml`: {{{ all: sf_guard_plugin: profile_class: sfGuardUserProfile profile_field_name: user_id }}} Ahora puede acceder al perfil via el objeto user: {{{ $this->getUser()->getGuardUser()->getProfile()->getFirstName() // o via proxy method $this->getUser()->getProfile()->getFirstName() }}} El metodo `getProfile()` obtiene el user-profile-object asociado o crea uno nuevo si este no existe ya. Cuando elimina un user, tambien se elimina el user-profile asociado. == Administra tus users, permisos y groups en el backend == Para administrar users, permisos y groups, `sfGuardPlugin` viene con 3 modulos que se integran a tu backend. Estos modulos son auto-generados gracias al symfony admin-generator. * Habilita los modulos en `settings.yml` {{{ all: .settings: enabled_modules: [..., sfGuardGroup, sfGuardPermission, sfGuardUser] }}} * Accede a los modulos con la ruta tipica: {{{ http://www.example.com/backend.php/sfGuardUser }}} == Personaliza los templates del modulo sfGuardAuth == Por defecto, el modulo `sfGuardAuth` viene con 2 muy simples templates: * `signinSuccess.php` * `secureSuccess.php` Si quieres personalizar uno de estos templates: * Crea un modulo `sfGuardAuth` en tu aplicacion * Crea un template con el nombre del template que quieres personalizar en tu directorio `templates` * Symfony ahora renderiza tu template en lugar del por defecto == Personaliza las acciones del modulo `sfGuardAuth` == Si quieres personalizar o agregar metodos a sfGuardAuth: * Crea un modulo `sfGuardAuth` en tu aplicacion * Crea un archivo `actions.class.php` en el directorio `actions` que herede de `BasesfGuardAuthActions` {{{ renderText('This is a new sfGuardAuth action.'); } } }}} == Clase `sfGuardSecurityUser` == Esta clase hereda de la clase `sfBasicSecurityUser` desde symfony y es usada por el objeto `user` object en tu aplicacion (porque tu lo configuraste en el `factories.yml` anteriormente). Entonces, para accederlo, puedes usar el clasico `$this->getUser()` en tus actions o `$sf_user` en tus templates. `sfGuardSecurityUser` añade algunos metodos: * `signIn()` y `signOut()` * `getGuardUser()` que devuelve el objeto `sfGuardUser` * un grupo de metodos proxy para acceder directamente al objeto `sfGuardUser` Por ejemplo, para conseguir el username actual: {{{ $this->getUser()->getGuardUser()->getUsername() // o via proxy method $this->getUser()->getUsername() }}} == Super administrator flag == `sfGuardPlugin` tiene la nocion de super administrator. Un usuario que es super administrator salta todos los chequeos de credenciales. El super administrator flag no puede ser seteado via web, debes hacerlo directamente en la Base o usar una tarea pake: {{{ symfony promote-super-admin admin }}} == Validadores == `sfGuardPlugin` trae un validador que te permitira usarlo en tus modulos: `sfGuardUserValidator`. Este validador es usado por el modulo `sfGuardAuth` para validar un usuario y password y automaticamente loguear al usuario. == Chequear el password con un metodo externo == Si no deseas almacenar la password en la Base porque ya tiene un LDAP server, un .htaccess o si las almacenas en otra tabla, puedes hacer tu propia remota `checkPassword` (static metodo o funcion) en `app.yml`: {{{ all: sf_guard_plugin: check_password_callable: [MyLDAPClass, checkPassword] }}} Cuando symfony llame al metodo `$this->getUser()->checkPassword()`, este llamara a tu metodo o funcion. Tu funcion debe tener 2 parametros, el primero es el username y el segundo es el password. Y debe retornar true o false. Aqui una muestra para tal funcion: {{{ function checkLDAPPassword($username, $password) { $user = LDAP::getUser($username); if ($user->checkPassword($password)) { return true; } else { return false; } } }}} == Cambiando el algoritmo para almacenar passwords == Por defecto, las passwords son almacenadas como un hash `sha1()`. Sin embargo, puedes cambiar esto, en `app.yml`: {{{ all: sf_guard_plugin: algorithm_callable: [MyCryptoClass, MyCryptoMethod] }}} r {{{ all: sf_guard_plugin: algorithm_callable: md5 }}} Como el algoritmo se guarda por cada usuario, puedes pensar de otra forma luego y no tendras que regenerar todas las passwords de los usuarios existentes. == Cambiando el nombre o periodo de expiracion de la cookie "Remember Me" == Por defecto, el "Remember Me" crea una cookie llamada `sfRemember` para 15 dias. Puedes cambiar esto en `app.yml`: {{{ all: sf_guard_plugin: remember_key_expiration_age: 2592000 # 30 dias en segundos remember_cookie_name: myAppRememberMe # tu nombre para la cookie }}} == Personaliza la redireccion de `sfGuardAuth` == Si quieres puedes redirigir al usuario a su perfil, luego de loguearse o definir una salida. Puedes cambiar esto, en `app.yml`: {{{ all: sf_guard_plugin: success_signin_url: @my_route?param=value # el plugin usa la referencia como defecto success_signout_url: module/action # el plugin usa la referencia como defecto }}} == TODO == * finish the `promote_super_user` task * finish the `getPassword` method * add support for HTTP Basic authentication == Changelog == === 1.1.13 PRE === === 1.1.12 === * fabien: fixed typo in secureSuccess template (closes #2260) * fabien: fixed 'secure' action in sfGuardPlugin do not need to be secure (closes #2254) * fabien: fixed typo in sfGuardUser::getProfile() * fabien: added some check in sfGuardSecurityUser proxy methods === 1.1.11 === * fabien: fixed array_merge_recursive causes recursion warnings in sfGuardUser.php (closes #1834) * fabien: fixed groups, permissions, and profile saving when sfUser has no primary key (closes #1709) * fabien: added connection parameters to all methods that interacts with the database (closes #2237) * fabien: changed signout actions, so it doesn't require to be authenticated * fabien: added a ->isSuperAdmin() method to the User class * fabien: fixed connection should be used when saving model (closes #2152) * fabien: fixed typo in modules /sfGuardAuth/config/security.yml (closes #1930) * fabien: removed warning about foreign key and profile table * davedash: when displaying the signin form, if no referer is set for the user we default to the last page * davedash: updated documentation regarding remember me cookie settings (closes #2148) * davedash: default algorithm is now sha1 not \asha1\a (closes Ticket #2189) * davedash: made the default templates i18n compatible (closes #1662) === 1.1.10 === * davedash: reordered the if/elseif structure so no loop starves === 1.1.9 === * fabien: fixed a typo in sfGuardUser reloadGroupsAndPermissions() method (closes #1758) * fabien: fixed "Remember Me" filter documentation (closes #1705) === 1.1.8 === * gordon: add two new config params 'success_signin_url' and 'success_signin_url' * gordon: split 'checkPassword()' to 'checkPassword()' and 'checkPasswordByGuard()' so it is callable by your own 'check_password()' * gordon: better redirect * gordon: 'login_module' and 'login_action' use for 'handleErrorSignin()' and after successe login * gordon: Added extra logic to make sure remember me code is only executed if user is not authenticated. * fabien: fixed is_super_admin has not default value (closes #1410) * fabien: fixed sfGuardPlugin signin.yml validation configuration (closes #1440) * fabien: fixed missing unique indexes in sf_guard_group and sf_guard_permission (closes #1454) * fabien: fixed sfGuardAuth should clear the credentials (closes #1537) * davedash: giving unique indexes unique names so that sfGuardPlugin works with postgres (closes ticket #1720) * davedash: fixed the model so getting groupPermissions works (fixes #1729) * davedash: the signin class would keep redirecting on itself if the user is logged in === 1.1.7 === * fabien: fixed deleting sfGuardUser when no profile is defined (closes #1626) * davedash: The setPassword() function of sfGuardSecurityUser() now saves the sfGuardUser object after setting the password