christiansalazar avatar christiansalazar committed 4e30558

agregando afterLoginUrl y otras. Reparando problema de script sql. mejorando la parametrizacion del filtro de autenticacion.

Comments (0)

Files changed (13)

 
 		Conocer o establecer el valor de 'debug':
 			CrugeUtil::config()->debug = true;
-		
+
 	@author: Christian Salazar H. <christiansalazarh@gmail.com> @bluyell
 	@copyright Copyright &copy; 2008-2012 Yii Software LLC
 	@license http://www.yiiframework.com/license/
 											// a Yii::app()->user->checkAccess retornara true
 											// si el superuserName coincide con este valor
 
-											
+	public $afterLoginUrl;				// por defecto son usadas por el filtro de sesion: DefaultSessionFilter
+	public $afterLogoutUrl;				//	tras el evento onLogin y onLogout
+	public $afterSessionExpiredUrl;		//
+
 	// la clase a usar para los CGridView, debido a que BootStrap ofrece clases con distinto estilo
 	// modificando este valor se causa que los CGridView se renderizen usando la clase indicada
 	//
 	//  por defecto: normal
 	public $buttonStyle = 'normal';
 	public $buttonConf = 'small';// large, small o mini
-				
+
 	// ponerla a true para que se creen de forma automatica las operaciones en el sistema de Rbac
-	// cuando se haga una llamada a Yii::app()->user->checkAccess() y esta retorne false. 
+	// cuando se haga una llamada a Yii::app()->user->checkAccess() y esta retorne false.
 	//
 	// public function actionCreatePost(){
 	//    if(Yii::app()->user->checkAccess('createpost_get')==false)
 	public $rbacSetupEnabled=false;
 	// cuando esta en true y el modo de setup de rbac tambien lo esta (rbacSetupEnabled=true)
 	// entonces permitira al usuario acecder a la funcion denegada aunque no tenga el permiso
-	// 
+	//
 	public $allowUserAlways=false;
 
-	
+
 	// el iduser del usuario invitado. por defecto es 2. (admin es 1)
 	//
 	public $guestUserId=2;
-	
+
 	// los nombres de los modulos de autenticacion habilitados para reconocer usuarios:
 	// cada nombre debe coincidir con el valor devuelto por ICrugeAuth::authName()
+	//
+	// en UiController::actionLogin se lee esta variable para saber con que filtro de autenticacion se procesara
+	// el request de login del usuario, por defecto 'default' el cual usa a models.auth.CrugeAuthDefault
+	//
+	// para leer este valor usar:
+	//	$valor = CrugeFactory::get()->getConfiguredAuthMethodName();
+	//
 	public $availableAuthMethods = array('default');
-	
+
 	// los campos por los cuales se puede buscar a un usuario cuando hace login
-	public $availableAuthModes	 = array('email','username');	
+	public $availableAuthModes	 = array('email','username');
 
 	// ruta de la clase que implementa a ICrugeSessionFilter.
 	// si es null se usa a defaultSessionFilter
 	// son usados en: CrugeFactory::getICrugeSessionFilter para determinar con que conceder la sesion
-	public $sessionfilter=null;	
+	public $sessionfilter=null;
 	public $defaultSessionFilter = 'cruge.models.filters.DefaultSessionFilter';
-	
+
 	// este filtro permite o niega la creacion o actualizacion de un usuario.
 	//
 	// aqui se espera una clase que implemente a: ICrugeUserFilter
-	// 
+	//
 	public $userFilter='cruge.models.filters.DefaultUserFilter';
-	
+
 	// indica si una clave es almacenada con MD5 o no.
 	//
 	public $useEncryptedPassword = false;
-	
-	// estos atributos llamados xxxLayout, son para indicar que layout usar 
+
+	// estos atributos llamados xxxLayout, son para indicar que layout usar
 	// para los actions:
 	//
 	// generalUserManagementLayout: todos los actions de usermanagament (admin,create,update..)
 	//		/protected/views/layouts/otrolayout.php
 	// entonces configurar asi:
 	//		"//layouts/otrolayout"
-	public $generalUserManagementLayout = 'ui'; 
+	public $generalUserManagementLayout = 'ui';
 	public $editProfileLayout = 'ui';
-	public $activateAccountLayout = '//layouts/column1'; 
+	public $activateAccountLayout = '//layouts/column1';
 	public $registrationLayout = '//layouts/column1';
 	public $loginLayout = '//layouts/column1';
-	
+
 	// sirve para que la controladora UiController pueda que nombre pasar a $_POST['??']
 	// para actualizar los atributos de una clase.  Si se llegase a cambiar una clase
 	// por otra entonces con solo cambiar aqui el nombre el formulario podr� trabajar de nuevo
 	// ejemplo: Ma�ana no nos gusta CrugeField y cambiamos la clase por CrugeMyOwnField
 	// entonces en este array se mapearia asi:  'CrugeField'=>'CrugeMyOwnField'
 	//
-	public $postNameMappings = array(	
+	public $postNameMappings = array(
 		'CrugeLogon'=>'CrugeLogon',
 		'CrugeStoredUser'=>'CrugeStoredUser',
 		'CrugeField'=>'CrugeField',
 		'CrugeSystem'=>'CrugeSystem',
 		'CrugeSession'=>'CrugeSession',
 	);
-	
+
 	// estos parametros no deben manipularse
 	public $defaultController = 'ui';
 	public $uicontroller='ui';
 	public $_lazyAuthModes = null;
 	private $_factory;
-	
+
 	// este array es usado por CrugeUi para almacenar errors que han sido reportados
 	// por CrugeUi::addError() , luego, para desplegar los errores observados
 	// puede usarse al pie de la pagina web la siguiente linea:
 	//	echo Yii::app()->user->ui->displayErrorConsole();
 	//
 	public $globalErrors = array();
-	
-	
-	
+
+
+
 	public function init()
 	{
 		$this->setImport(array(
 			'cruge.components.*',	// clases del modelo
 			'cruge.interfaces.*',	// interfaces
 			'cruge.extensions.crugemailer.*',	// extensiones consumidas por el modulo
-			
+
 		));
-		
+
 	}
-	
+
 	public function getUiControllerName(){
 		return $this->uicontroller;
 	}
 			$this->_factory = new CrugeFactory();
 		return $this->_factory;
 	}
-	
 
-	
+
+
 	public function beforeControllerAction($controller, $action)
 	{
 		if(parent::beforeControllerAction($controller, $action))
 		else
 			return false;
 	}
-	
-	
-	
+
+
+
 }
 
 ##Entorno en donde se ha probado.
 
-* PHP Version 5.2.6, 5.4.4, 5.4.5  (ya no hace falta el uso de E_STRICT)
+* PHP Version 5.2.6, 5.4.4, 5.4.5
 
-* Yii Framework 1.10,  1.11, 1.12
+* Yii Framework 1.10,  1.11, 1.12, 1.13
 
 * Apache/2.0.58
 
 	2.	dentro de 'modules' agregar:
 			'cruge'=>array(
 				'tableprefix'=>'cruge_',
+
+				// para que utilice a protected.modules.cruge.models.auth.CrugeAuthDefault.php
+				//
+				// en vez de 'default' pon 'authdemo' para que utilice el demo de autenticacion alterna
+				// para saber mas lee documentacion de la clase modules/cruge/models/auth/AlternateAuthDemo.php
+				//
 				'availableAuthMethods'=>array('default'),
+
 				'availableAuthModes'=>array('username','email'),
 				'baseUrl'=>'http://coco.com/',
 
 				//
 				'useEncryptedPassword' => false,
 
+				// a donde enviar al usuario tras iniciar sesion, cerrar sesion o al expirar la sesion.
+				//
+				// esto va a forzar a Yii::app()->user->returnUrl cambiando el comportamiento estandar de Yii
+				// en los casos en que se usa CAccessControl como controlador
+				//
+				// ejemplo:
+				//		'afterLoginUrl'=>array('/site/welcome'),  ( !!! no olvidar el slash inicial / )
+				//		'afterLogoutUrl'=>array('/site/page','view'=>'about'),
+				//
+				'afterLoginUrl'=>null,
+				'afterLogoutUrl'=>null,
+				'afterSessionExpiredUrl'=>null,
 
 				// manejo del layout con cruge.
 				//
 	)); ?>
 
 
-##Tras iniciar sesion quiero ir a una pantalla especifica. Como hacerlo ?
+##Tras iniciar sesion, cerrar sesion o cuando la sesion expire quiero ir a una pantalla especifica. Como hacerlo ?
+
+En la configuracion principal (tuproyecto/protected/config/main.php) , puedes colocar las URL en las siguientes variables
+en el modulo Cruge:
+
+	// ejemplo:
+	//		'afterLoginUrl'=>array('/site/welcome'),  ( no olvidar el slash inicial "/" sino la url no funcionara )
+	//		'afterLogoutUrl'=>array('/site/page','view'=>'about'),
+	//		'afterSessionExpiredUrl'=>null,
+	//
+
+##Tras iniciar sesion quiero ir a una pantalla especifica. Como hacerlo ? (METODO ALTERNO RESPETANDO a CAccessControl).
 
 Supongamos que quieres que tras iniciar sesion exitosamente con Cruge el usuario sea
 redirigido al actionBienvenido de siteController (index.php?r=site/bienvenido).
 
 Si ves, Cruge escribe los mensajes en espa�ol, mientras que su codigo esta en ingl�s. Todos los mensajes se dirigen a la clase CrugeTranslator::t("mensaje en espa�ol"), por tanto ese es el punto para traducir a otro idioma. En un futuro nuevo commit hare un nuevo filtro, para traducir, sin que tengas que tocar nada dentro de CrugeTranslator.
 
+pronto se implementara la internacionalizacion.
+
+
+#Dise�o interno de Cruge
+
+Es importante conocer como esta dise�ado Cruge, para esto proveer� tres diagramas importantes, no son todos, hay mas, pero estos son los indispensables para conocer que sucede cuando se click en "Login":
+
+En este primero diagrama se muestran las clases que estan involucradas (junto a su relacion con otras clases).
+
+![diagrama de clases - login][2]
+
+En el segundo diagrama puedes observar que sucede en lineas generales cuando se presiona el boton login.
+
+![diagrama de actividad login][3]
 
+Finalmente aqui hay una secuencia en el tiempo y una vista de las clases involucradas, este diagrama se lee de izquierda a derecha, arriba en los cuadros grandes al tope se listan las clases involucradas, de cada clase sale una linea vertical larga de la cual a su vez salen flechas hacia otras clases, esas flechas son acciones a realizarse, llamadas, etc.
 
+![diagrama de secuencia login][4]
 
-[1]: https://bitbucket.org/christiansalazarh/cruge/downloads/screenshots.gif
+[1]: https://bitbucket.org/christiansalazarh/cruge/downloads/screenshots.gif
+[2]: https://bitbucket.org/christiansalazarh/cruge/downloads/Diagrama-de-clases-proceso-de-autenticacion.png
+[3]: https://bitbucket.org/christiansalazarh/cruge/downloads/diagrama-de-actividad--autenticaion.png
+[4]: https://bitbucket.org/christiansalazarh/cruge/downloads/diag.secuencia-de-login.png

TODO.md

-
-en los campos personalizados, tener la capacidad de organizar los campos en grupos, 
-ademas en System, tener la capacidad para seleccionar la forma en como los grupos de campos
-se muestran.

components/CrugeFactory.php

 		2. package cruge.models
 		3. package cruge.models
 
+	como se accede al factory: (ejemplo)
+
+		$value = CrugeFactory::get()->getConfiguredAuthMethodName();
+
+	quien accede al factory:
+
+		solo ciertas clases como CrugeUserManager o similares...
+
+		EL USUARIO DE CRUGE NO DEBE ACCEDER A ESTA CLASE
+
 	@author: Christian Salazar H. <christiansalazarh@gmail.com> @bluyell
 	@copyright Copyright &copy; 2008-2012 Yii Software LLC
 	@license http://www.yiiframework.com/license/
 		}
 		return false;
 	}
+	/*
+		lee de CrugeModule el nombre del filtro de autenticacion a utilizar, por ahora
+		solo un filtro se usa a la vez,a futuro se pretenden usar varios filtros, por eso es un array.
+
+		retorna:  un string, el nombre del filtro de autenticacion, el nombre sera validado contra
+		el valor que retorne el filtro usando la interfaz ICrugeAuth.authName()
+	*/
+	public function getConfiguredAuthMethodName(){
+		foreach(CrugeUtil::config()->availableAuthMethods as $key=>$val){
+				return $val;
+		}
+		return false;
+	}
 
 
 

components/CrugeUserManager.php

-<?php 
+<?php
 /** CrugeUserManager
 
 	funciona como una interfaz para el core del sistema cruge, opera como un API.
-	
+
 	se accede exclusivamente asi:
-	
+
 		$um = Yii::app()->user->um;
-		
+
 	dependencias:
-	
+
 		CrugeFactory
 		CrugeUtil
 		CrugeTranslator
-	
+
  	@author: Christian Salazar H. <christiansalazarh@gmail.com> @bluyell
 	@copyright Copyright &copy; 2008-2012 Yii Software LLC
 	@license http://www.yiiframework.com/license/
 		}
 		return $fieldType;
 	}
-	
+
 	public function getUserActivationOptions(){
 		$stAr=array();
 		for($i=CRUGE_ACTIVATION_OPTION_INMEDIATE;$i<=CRUGE_ACTIVATION_OPTION_MANUAL;$i++)
 		}
 		return $state;
 	}
-	
-	
-	
+
+
+
 	/* se encarga de crear una nueva llave de autenticacion para el usuario.
 	   el modelo debera ser guardado tras esta llamada.
-	
+
 		@see getActivationUrl
 	*/
 	public function generateAuthenticationKey(ICrugeStoredUser $user){
 		$user->authkey = md5($user->username."-".$user->password);
 	}
 
-	
+
 	/*
 		entrega una CArrayDataProvider obtenido desde un array de userid.
-		
+
 		es una funcion helper que invoca a listUsers con los parametros adecuados.
 	*/
 	public function listUsersDataProviderFromArray($arrayUserId,$pageSize=20){
 		@pageSize, solo tiene sentido bajo un carraydataprovider
 		@buildFromThisUsersIdArray, si se especifica el dataprovider se construira en base
 		a estos iduser entregados en un array
-	
+
 		retorna un array de objetos ICrugeStoredUser o un CArrayDataProvider
 	*/
 	public function listUsers(
 		,$pageSize=20
 		,$boolUseArray=false
 		,$buildFromThisUsersIdArray=null
-	){	
+	){
 		$ar=array();
 		// si buildFromThisUsersIdArray es null, entonces se buscan los usuarios directamente
 		if($boolUseArray == false){
 				$ar[] = $user;
 			}
 		}
-		
-		
-		
+
+
+
 		if($booleanAsDataProvider == true){
 			$sortFields = CrugeFactory::get()->getICrugeStoredUserSortFieldNames();
 			return new CArrayDataProvider($ar, array(
 				'pagination'=>array(
 					'pageSize'=>$pageSize,
 				),
-			));		
+			));
 		}
 		else
 			return $ar;
 
 	/*
 		@returns instancia ICrugeStoredUser del usuario cuyo iduser sea el $id pasado por argumento.
-		
+
 		para que el user cargado tenga los campos de perfil hay que llamar a:
 		@see loadUserFields (poner el arg a true: $boolAndLoadFields)
 		@see loadUser
 	}
 	/*
 		@returns instancia ICrugeStoredUser del usuario cuyo iduser sea el $id pasado por argumento.
-		
+
 		para que el user cargado tenga los campos de perfil hay que llamar a:
 		@see loadUserFields (poner el arg a true: $boolAndLoadFields)
 		@see loadUserById
 			$this->loadUserFields($user);
 		return $user;
 	}
-	
+
 	/*
 		crea una nueva instancia de ICrugeStoredUser
 	*/
 		}else
 		return null;
 	}
-	
+
 	/*
 		activa la cuenta, estampando la fecha de activacion.
-		
+
 		solo aplica si el estado del modelo es: CRUGEUSERSTATE_NOTACTIVATED
 	*/
 	public function activateAccount(ICrugeStoredUser $user){
 		@see generateAuthenticationKey
 	*/
 	public function getActivationUrl(ICrugeStoredUser $user){
-		return 	
+		return
 			 rtrim(CrugeUtil::config()->baseUrl,"/")
 			.CrugeUtil::uiaction('activationurl',array('key'=>$user->authkey));
 	}
-	
+
 	/*
 		marca la fecha de logon del usuario, normalmente para alterar el campo logondate,
 	*/
 	public function recordLogon(ICrugeStoredUser $user){
 		$user->logondate = CrugeUtil::now();
 	}
-	
+
 	/*
 		guarda a este usuario, bajo un escenario especial llamado 'internal', para
 		poder pasar por encima de algunas reglas de validacion que puede que apliquen
 		solo para el usuario que manipula el modelo mediante formularios.
-		
+
 		si el escenario es 'insert' (caso crear usuario o registrar usuario),
 		entonces se aplica un filtro de registro instanciado por algun ICrugeRegistrationFilter
 		declarado en la configuracion del modulo Cruge.
-		
+
 	*/
 	public function save(ICrugeStoredUser $user,$scenario='internal'){
 		$user->scenario = $scenario;
 		}
 		return $user->save();
 	}
-	
-	
+
+
 	/*
 		le cambia la clave al usuario.  el modelo debera ser guardado con $model->save() tras
 		esta llamada.
 			$epwd = md5($newPassword);
 		$user->password = $epwd;
 	}
-	
+
 	/* busca la sesion abierta mas reciente del usuario
-	
+
 		returns ICrugeSession la sesion abierta mas reciente del usuario
 	*/
 	public function findSession(ICrugeStoredUser $user){
 		retorna instancia de ICrugeSessionFilter del filtro de sesion instalado
 	*/
 	public function getSessionFilter(){
-		return CrugeFactory::get()->getICrugeSessionFilter(); 
+		return CrugeFactory::get()->getICrugeSessionFilter();
 	}
-	
-	
+
+
 	/*
 		busca un ICrugeSystem por su nombre
 	*/
 	public function getDefaultSystem(){
 		return $this->loadSystemByName('default');
 	}
-	
-	
+
+
 	/* crea una nueva sesion para el usuario basado en los parametros del sistema seleccionado.
-		
+
 	   returns ICrugeSession
 	*/
 	public function createSession(ICrugeStoredUser $user,ICrugeSystem $sys){
-	
+
 		Yii::log(__CLASS__."::createSession. user=#"
 			.$user->getPrimaryKey(),"info");
-	
+
 		return CrugeFactory::get()->getICrugeSessionCreate(
 			$user->getPrimaryKey(),$sys->getn('sessionmaxdurationmins'));
 	}
-	
+
 	/*
 		retorna una instancia de ICrugeStoredUser de la sesion indicada.
 	*/
 	public function getUserFromSession(ICrugeSession $session) {
 		return CrugeFactory::get()->getSessionUser($session);
 	}
-	
+
 	/*
 		carga un filtro que implementa a ICrugeAuth hallado por su nombre
 	*/
 	{
 		return CrugeFactory::get()->getICrugeAuthByName($byName);
 	}
-	
+
 	/*
 		retorna una instancia de ICrugeField buscada por su idfield.
 	*/
 		return CrugeFactory::get()->getICrugeFieldCreate(CRUGEFIELDTYPE_TEXTBOX);
 	}
 	/*
-		recibe una instancia de ICrugeStoredUser y carga en esta todos los campos personalizados 
+		recibe una instancia de ICrugeStoredUser y carga en esta todos los campos personalizados
 		de perfil que el administrador ha definido.
-		
+
 		@returns: un array de instancias ICrugeField con el valor (fieldvalue) correspondiente.
-		
+
 		@see loadUserById
 	*/
 	public function loadUserFields(ICrugeStoredUser $user){
 		return CrugeFactory::get()->getICrugeFieldListModels();
 	}
 	/**
-		limpia los campos personalizados. 
+		limpia los campos personalizados.
 	*/
 	public function clearUserFields(ICrugeStoredUser $user){
 		$user->setFields(CrugeFactory::get()->getICrugeFieldListModels($user));
 	}
 	/*
 		obtiene el valor escalar de un campo para un usuario.
-		
+
 		@iduser: mixed.  puede ser el IDUSER o una instancia de ICrugeStoredUser
 		@idfield: mixed.  puede ser el FIELDNAME, IDFIELD o una instancia de ICrugeField
 	*/
 	public function getFieldValue($iduser,$idfield){
-	
+
 		if(is_string($iduser)){
 			$u = $this->loadUserById($iduser);
 		}else{
 			$u = $iduser;
 		}
-		
+
 		if($u != null){
-		
+
 			if(is_numeric($idfield)){
 				// busca por idfield
 				//
 					$field = $idfield;
 				}
 			}
-			
+
 			if($field != null){
 				$fv = CrugeFactory::get()->getICrugeFieldValue($u,$field);
 				if($fv != null)
 		}
 		return "";
 	}
-	
+
 	/*
 		funciona como lo haria un CActiveForm::labelEx, pero considerando que estos
 		campos aqui indicados no pertenecen al modelo como tal porque son campos definidos
 		por el admin.
-		
+
 		lo que se hara aqui es presentar una etiqueta pero con una clase "required" y un
 		asterisco para indicar que el campo es requerido si la config del campo asi lo decide.
 	*/
 	public function getLabelField(ICrugeField $field){
-		
+
 		$r = "";
 		$ast = "";
 		$text = ucfirst(CrugeTranslator::t($field->longname));
 			$r = " class='required' ";
 			$ast = "<span {$r}>*</span>";
 		}
-		
+
 		return "<label {$r}>{$text} {$ast}</label>";
 	}
-	
+
 	/*
 		retorna el elemento de UI correspondiente a la configuracion del campo personalizado.
 
 		Igualmente recibe el valor correspondiente que el usuario ha ingresado para este campo.
-		
+
 		$model:  es la clase que alojara los datos del formulario, no se usa para nada mas
 		de este modo si otro modelo quiere incorporar campos personalizados solo pone "$this" y asi
 		los items del form se pondran de acuerdo a la clase indicada.
-		
+
 		$field:  es un campo, instancia de ICrugeField cuyo atributo fieldvalue fue previamente
 		establecido. @see loadUserFields (para saber como se carga fieldvalue)
-		
+
 		este metodo es basicamente en las vista:
 			usermanagementupdate.php
 			registration.php
-		
+
 		@returns Elemento tag de CHtml de acuerdo a la configuracion de $field->fieldtype
 		@see loadUserFields (para saber como se carga fieldvalue)
 	*/
 	public function getInputField($model,ICrugeField $field){
-	
+
 		$className = get_class($model);
-	
+
 		$name = $className."[".$field->fieldname."]";
-		$htmlOpt = array(	
+		$htmlOpt = array(
 			 'id'=>$className."_".$field->fieldname
 			,'size'=>$field->fieldsize
 			,'maxlength'=>$field->maxlength
 			,'rows'=>5
 			,'cols'=>$field->fieldsize
 		);
-		
+
 		// caso listas: Listbox
 		// se espera que venga cada valor que se pasara al <option></option>
 		// venga en la forma "VALUE, TEXT"
 			$htmlOpt['size'] = null;
 			$htmlOpt['maxlength'] = null;
 		}
-	
+
 		// estos tipos definidos estan en CrugeUserManager
-	
+
 		switch($field->fieldtype){
 			case CRUGEFIELDTYPE_TEXTBOX:
 				return CHtml::textField($name,$field->getFieldValue(),$htmlOpt)."\n";
 	}
 	/*
 		crea una nueva instancia del modelo CrugeLogon bajo el escenario indicado {login o pwdrec}
-		
+
 		CrugeLogon es un modelo (CFormModel) para el formulario de Login y Password Recovery
 		que aparte de validar que los datos de ambos fomularios esten correctos tambien
 		ayuda al proceso de llamar a Yii::app()->user->login mediante un metodo llamado login().
-		
+
 		basicamente es como el modelo LoginForm que trae Yii por defecto.
-		
+
 		@see CrugeLogon
 		returns instancia de CrugeLogon
 	*/
 	{
 		return new CrugeLogon($scenario);
 	}
-	
+
 	/*
 		crea una nueva instancia del modelo de autenticacion CrugeUser el cual
 		representa a un usuario que quiere iniciar sesion (no es un usuario almacenado)
 	*/
-	public function getNewCrugeUser($username,$password){
-		return new CrugeUser($username,$password);
+	public function getNewCrugeUser($username,$password,$authMode='default'){
+		return new CrugeUser($username,$password,$authMode);
 	}
-	
+
 	public function getSortFieldNamesForICrugeStoredUser(){
 		return CrugeFactory::get()->getICrugeStoredUserSortFieldNames();
 	}
 	public function getSortFieldNamesForICrugeField(){
 		return CrugeFactory::get()->getICrugeFieldSortFieldNames();
 	}
-	
-	
+
+
 	public function loadSessionById($id){
 		return CrugeFactory::get()->getICrugeSession($id);
 	}
-	
+
 }

components/CrugeWebUser.php

-<?php /**
+	<?php /**
 	CrugeWebUser
-	
+
 	es un gestor que permite manejar al usuario que ha iniciado sesion o que pretende iniciarla.
 	consume a : CrugeUser
-	
+
 	esta clase necesita ser instalada en config, mediante:
-	
+
 	'components'=>array(
 		'user'=>array(
 			'allowAutoLogin'=>true,
 			'class' => 'application.modules.cruge.components.CrugeWebUser',
 		),
-		
+
 	una vez instalada puede ser accedida mediante:
-	
+
 	Yii::app()->user
 	Yii::app()->user->isGuest()
-	
+
 	Todos los dem�s miembros de CWebUser se proveen, a excepcion de algunos que
 	son sobreescritos.
-	
+
 	IMPORTANTE:
-	
+
 	No usar CHttpSession porque interfiere con el uso interno que se le da a $_SESSION dentro de CWebUser en los metodos getState setState.
-	
+
 	para almacenar valores usar $this->setState('nombreVariable','valor') y
 	$this->getState('nombreVariable','defaultValue');
-	
-	
+
+
 	@author: Christian Salazar H. <christiansalazarh@gmail.com> @bluyell
 	@copyright Copyright &copy; 2008-2012 Yii Software LLC
 	@license http://www.yiiframework.com/license/
 	}
 	/**
 		da acceso directo al valor (solo lectura) de un campo personalizado.
-		
+
 		si el nombre del campo no existe o el usuario no ha inciado sesion se retorna ""
-		
+
 		ejemplo
-		
+
 			echo Yii::app()->user->getField('email');
 			echo Yii::app()->user->getField('firstname');
 	*/
 	/*
 		extension que permite consultar si este usuario (aun siendo invitado) tiene
 		acceso o no a un determinado token de autenticacion identificado por su itemName.
-		
+
 		ejemplo:
-		
+
 		if(Yii::app()->user->checkAccess('createPostOperation')){
 			..create post..
 		}else{
 			echo "access denied";
 		}
-		
+
 		@itemName: nombre del item a ser comprobado para el usuario autenticado
 		@params: los argumentos pasados al businessRule
 		@descripcion: opcional, si rbacSetupEnabled es true, entonces se usara esta descripcion para crear el CAuthItem requerido cuando este no exista en la lista de operaciones.
-		
+
 		@returns true o false.  (si usuario activo es superadmin retorna true incondicionalmente)
 	*/
 	public function checkAccess($itemName,$descripcion="",$params=array()){
-	
+
 		// si esta habilitada la bandera de configuracion creara el CAuthItem si es requerido
 		// y este no existe.
 		//
 				$this->getrbac()->createAuthItem($itemName,CAuthItem::TYPE_OPERATION
 					,$descripcion);
 		}
-	
+
 		if($this->isSuperAdmin){
 			return true;
 		}
 			return $ok;
 		}
 	}
-	
+
 	/*
 		redirige al usuario a la pagina indicada por loginUrl en caso de que
 		se detecte que es un invitado, luego del login es redirigido a la pagina a donde queria
 		ir originalmente.
-		
+
 		este metodo es mejor usado en ambientes en donde no se esta usando a CAccessControlFilter, quien internamente invoca a Yii::app()->user->loginRequired cuando detecta que una regla ha fallado.
 	*/
 	public function checkLoginRequired(){
 	/*
 		entrega un componente (CrugeUi) listo para ser usado, que se encarga de dar
 		datos para la interfaz de usuario
-		
+
 		ejemplo:
-		
+
 		Yii::app()->user->ui
 	*/
 	public function getui(){
 	/*
 		permite llamar al authManager directamente usando:
 		Yii::app()->user->rbac
-		
+
 		previamente se debio declarar a CrugeAuthManager como la clase que administra a
 		authmanager, eso se hace en components.
 	*/
 	*/
 	/*
 		TODO:
-		
-	
+
+
 	*/
-	
+
 	/*  retorna el numero de usuario, tomado de la sesion iniciada
 		si se quiere obtener acceso al usuario completo:
 			Yii::app()->user->getUser()->getPrimaryKey()
 	*/
 	public function getId(){
-	
+
 		$_crugesesion = $this->getICrugeSession();
 		if($_crugesesion == null)
 			return CrugeUtil::config()->guestUserId;
 			return $u->email;
 		return "";
 	}
-	
-	
+
+
 	/**
 		se SUPONE que este metodo fue llamado tras un $identity->authenticate exitoso,
 		por tanto estamos garantizando que identity->getId() tiene un identificador valido de
 		un ICrugeStoredUser o un 0 si no se autentico.
-		
+
 		***el argumento $duration es pedido solo por compatibilidad, no se usa aqui.***
-		
-		la duracion del identificador en memoria de sesion dependera de la duracion de 
+
+		la duracion del identificador en memoria de sesion dependera de la duracion de
 		configuracion de PHP CONFIG, pero no asi la duracion del objeto de sesion (CrugeSession)
 		el cual durara y sera reutilizado hasta que caduque o sea cerrado.
 	*/
 				"Por favor cambie las referencias a '".get_class($identity)."' por 'CrugeUser'"
 			);
 
-	
+
 		Yii::log(__CLASS__."\nlogin\n","info");
-	
+
 		$this->_lastError = "";
 		$this->clearSessionId();
-	
+
 		// carga el filtro de sesion habilitado para este modulo:
 		$filtro = $this->getum()->getSessionFilter();
-		
+
 		// toma al usuario autenticado
 		$user = $identity->getUser();
 		if($user == null) {
 			$this->_lastError = CrugeTranslator::t("debe autenticarse");
 			return false;
 		}
-		
+
 		$system = $this->getum()->getDefaultSystem();
 		if($system == null)
 		{
 			Yii::log(__CLASS__."::login. systemName:".$_sname." no hallado.","error");
 			throw new CrugeException("debe crear un registro en la tabla cruge_system");
 		}
-			
+
 		// aplica credenciales sobre el sistema para obtener una sesion
 		Yii::log(__CLASS__."\nfiltro->startSession\n","info");
 		if(($usersession = $filtro->startSession($user,$system)) != null)
 		{
 			Yii::log(__CLASS__."\nfiltro->startSession OK\n","info");
-		
+
 			if($filtro->onStore($usersession)){
 				// ahora si...guarda el identificador de sesion que getId devolvera
 				$this->setSessionId($usersession->getPrimaryKey());
 		else
 		{
 			Yii::log(__CLASS__."\nfiltro->startSession error.\n".$filtro->getLastErrorDescr(),"info");
-		
+
 			$this->_lastError = $filtro->getLastErrorDescr();
 			return false;
-		}	
+		}
 	}
 	public function logout($destroySession=true){
 		$result=false;
 	/**HASTA AQUI llegan los metodos de la interfaz IWebUser*/
 
 	/**
-		
+
 		estas funciones de aqui para abajo no pertenecen a la interfaz: IWebUser
-		
+
 	*/
 	private function getSessionId(){
 		return $this->getState('_sessionid_','0');

controllers/UiController.php

 <?php
 /**
 	UiController
-	
+
 	Controladora comun para todas las vistas predefinidas en views/ui
-	
+
 	dependencias:
-	
+
 		La controladora no accede de ninguna manera a la capa de CrugeFactory,
 		todo lo hace mediante los componentes:
-		
+
 			Yii::app()->user->um
 			Yii::app()->user->rbac
 			Yii::app()->user->ui
-			
+
 		igualmente, no hay instancias directas a modelos de datos, esto es para ayudar
 		a la insercion de diferentes ORDBM.
 
 	@author: Christian Salazar H. <christiansalazarh@gmail.com> @bluyell
-	
+
 */
 class UiController extends Controller
 {
 		$this->registerScripts();
 		$this->layout = CrugeUtil::config()->generalUserManagementLayout;
 	}
-	
+
 	public function registerScripts(){
-		$this->basePath = Yii::app()->getAssetManager()->publish(	
+		$this->basePath = Yii::app()->getAssetManager()->publish(
 			dirname(__FILE__)."/../resources")."/";
-		
+
 		$cs = Yii::app()->getClientScript();
-		
+
 		$cs->registerCoreScript('jquery');
-		
+
 		$cs->registerCssFile($this->basePath."estilos.css");
 	}
-	
+
 	private function _publicActionsList(){
 		return array('captcha','registration','login','logout','pwdrec'
 			,'activationurl','ajaxgeneratenewpassword','welcome');
 	}
-	
+
 	public function filters()
 	{
-		return array(	
+		return array(
 				// con accessControl se garantiza que un usuario NO autenticado NO tenga acceso
 				// a las funciones NO publicas.
-				'accessControl', 					
-				
-				// con CrugeUiAccessControlFilter se garantiza que a los actions no publicos 
-				// solo accedan aquellos usuarios que tengan la operacion asignada 
+				'accessControl',
+
+				// con CrugeUiAccessControlFilter se garantiza que a los actions no publicos
+				// solo accedan aquellos usuarios que tengan la operacion asignada
 				// directamente o mediante una tarea o un rol.
-				// 
+				//
 				// al usar este filtro Y si la configuracion del modulo indica que:
 				//
 				//	SI rbacSetupEnabled es TRUE entonces:
-				//			
-				//		1. 	el filtro "crear�" si es necesario la operacion en base 
+				//
+				//		1. 	el filtro "crear�" si es necesario la operacion en base
 				//			al controller/action
 				//
 				//		2.	el filtro concede paso si la operacion controller/action esta
 				//		  	asignada al usuario.
 				//
 				array('CrugeUiAccessControlFilter','publicActions'=>self::_publicActionsList()),
-				
+
 			);
-	}	
-	
+	}
+
 	public function accessRules()
 	{
 		return array(
 			),
 		);
 	}
-	
+
 	public function actions()
 	{
 		return array(
 		);
 	}
 	public function actionLogin() {
-	
+
 		$this->layout = CrugeUtil::config()->loginLayout;
-	
+
 		$model = Yii::app()->user->um->getNewCrugeLogon('login');
+
+		// por ahora solo un metodo de autenticacion por vez es usado, aunque sea un array en config/main
+		//
+		$model->authMode = CrugeFactory::get()->getConfiguredAuthMethodName();
+
 		Yii::app()->user->setFlash('loginflash',null);
-		
+
 		Yii::log(__CLASS__."\nactionLogin\n","info");
-		
+
 		if(isset($_POST[CrugeUtil::config()->postNameMappings['CrugeLogon']]))
 		{
 			$model->attributes=$_POST[CrugeUtil::config()->postNameMappings['CrugeLogon']];
 			if($model->validate()){
 				if($model->login(false)==true){
-					
+
 					Yii::log(__CLASS__."\nCrugeLogon->login() returns true\n","info");
-				
+
 					// a modo de conocimiento, Yii::app()->user->returnUrl es
-					// establecida automaticamente por CAccessControlFilter cuando 
+					// establecida automaticamente por CAccessControlFilter cuando
 					// preFilter llama a accessDenied quien a su vez llama a
 					// CWebUser::loginRequired que es donde finalmente se llama a setReturnUrl
 					$this->redirect(Yii::app()->user->returnUrl);
 		$this->render('login',array('model'=>$model));
 	}
 	public function actionPwdRec() {
-	
+
 		$this->layout = CrugeUtil::config()->loginLayout;
-		
+
 		$model = Yii::app()->user->um->getNewCrugeLogon('pwdrec');
-		
+
 		Yii::app()->user->setFlash('pwdrecflash',null);
-		
+
 		if(isset($_POST[CrugeUtil::config()->postNameMappings['CrugeLogon']]))
 		{
 			$model->attributes=$_POST[CrugeUtil::config()->postNameMappings['CrugeLogon']];
 				Yii::app()->user->um->changePassword($model->getModel(),$newPwd);
 				Yii::app()->crugemailer->sendPasswordTo($model->getModel(),$newPwd);
 				Yii::app()->user->um->save($model->getModel());
-				
+
 				Yii::app()->user->setFlash('pwdrecflash'
 					,CrugeTranslator::t('Una nueva clave ha sido enviada a su correo')
 					);
 		}
 		$this->render('pwdrec',array('model'=>$model));
 	}
-	
+
 	public function actionLogout(){
 		Yii::app()->user->logout();
 		$this->redirect(Yii::app()->user->ui->loginurl);
 		$this->render("usermanagementadmin",array('model'=>$model,'dataProvider'=>$dataProvider));
 	}
 	public function actionEditProfile(){
-	
+
 		$this->layout = CrugeUtil::config()->editProfileLayout;
-	
+
 		if(!Yii::app()->user->isGuest){
 			$this->_editUserProfile(Yii::app()->user->user,false);
 		}else{
 			$model->attributes=$_POST[CrugeUtil::config()->postNameMappings['CrugeStoredUser']];
 			if($model->validate()){
 				// el modelo ICrugeStoredUser ha validado bien, incluso cada uno de sus campos extra
-				
+
 				/*
 					si se ha especificado algun valor en $model->newPassword se asume
 					que se quiere cambiar la clave:
 					Yii::app()->user->um->changePassword($model,$newPwd);
 					Yii::app()->crugemailer->sendPasswordTo($model,$newPwd);
 				}
-				
+
 				if(Yii::app()->user->um->save($model,'update')){
 					if($boolIsUserManagement == true){
 						$this->redirect(array('usermanagementadmin'));
 					}
 				}
 			}
-		}		
+		}
 		$this->render("usermanagementupdate",array('model'=>$model
 			,'boolIsUserManagement'=>$boolIsUserManagement));
 	}
 	*/
 	public function actionUserManagementCreate(){
 		$model = Yii::app()->user->um->createBlankUser();
-		
+
 		if(isset($_POST[CrugeUtil::config()->postNameMappings['CrugeStoredUser']]))
 		{
 			$model->attributes=$_POST[CrugeUtil::config()->postNameMappings['CrugeStoredUser']];
-			
+
 			$model->terminosYCondiciones = true;
-				
+
 			$model->scenario = 'manualcreate';
-			
+
 			if($model->validate()){
-			
+
 				$newPwd = trim($model->newPassword);
 				Yii::app()->user->um->changePassword($model,$newPwd);
-				
+
 				Yii::app()->user->um->generateAuthenticationKey($model);
-			
-				if(Yii::app()->user->um->save($model,'insert')){	
-				
+
+				if(Yii::app()->user->um->save($model,'insert')){
+
 					$this->onNewUser($model,$newPwd);
-					
+
 					$this->redirect(array('usermanagementadmin'));
 				}
 			}
-		}		
+		}
 		$this->render("usermanagementcreate",array('model'=>$model));
 	}
 	public function actionRegistration(){
-	
+
 		$this->layout = CrugeUtil::config()->registrationLayout;
-	
-	
+
+
 		$model = Yii::app()->user->um->createBlankUser();
 		$model->terminosYCondiciones = false;
 		if(Yii::app()->user->um->getDefaultSystem()->getn('registerusingterms') == 0)
 			$model->terminosYCondiciones = true;
-		
+
 		// para que cargue los campos del usuario
 		Yii::app()->user->um->loadUserFields($model);
 		if(isset($_POST[CrugeUtil::config()->postNameMappings['CrugeStoredUser']]))
 		{
 			$model->attributes=$_POST[CrugeUtil::config()->postNameMappings['CrugeStoredUser']];
 			if($model->validate()){
-			
+
 				$newPwd = trim($model->newPassword);
 				Yii::app()->user->um->changePassword($model,$newPwd);
-				
+
 				Yii::app()->user->um->generateAuthenticationKey($model);
-				
-				if(Yii::app()->user->um->save($model,'insert')){	
+
+				if(Yii::app()->user->um->save($model,'insert')){
 
 					$this->onNewUser($model,$newPwd);
-					
+
 					$this->redirect(array('welcome'));
 				}
 			}
-		}		
+		}
 		$this->render("registration",array('model'=>$model));
-	}	
-	
+	}
+
 	/* este es un evento emitido por actionRegistration y actionUserManagementCreate
 		el cual informa que un nuevo usuario ha sido creado.
-		
+
 		segun la configuracion general del sistema este usuario
 		sera activado de inmediato, o por email, o manualmente.
 	*/
 	private function onNewUser(ICrugeStoredUser $model,$newPwd=""){
 		Yii::log(__METHOD__."\n","info");
-		
+
 		$opt = Yii::app()->user->um->getDefaultSystem()->getn("registerusingactivation");
-		
+
 		$role = Yii::app()->user->um->getDefaultSystem()->get("defaultroleforregistration");
 		Yii::log(__METHOD__."\n role: ".$role,"info");
 		if(Yii::app()->user->rbac->getAuthItem($role) != null){
 				.$model->getPrimaryKey(),"info");
 			Yii::app()->user->rbac->assign($role,$model->getPrimaryKey());
 		}
-		
+
 		if($opt == CRUGE_ACTIVATION_OPTION_INMEDIATE){
 			// lo activa inmediatamente y le manda la clave al usuario
 			$model->state = CRUGEUSERSTATE_ACTIVATED;
 			Yii::app()->crugemailer->sendPasswordTo($model,$newPwd);
 		}
 		if($opt == CRUGE_ACTIVATION_OPTION_EMAIL){
-			// queda en estado no activado, pero envia un email para que 
+			// queda en estado no activado, pero envia un email para que
 			// el usuario lo active
 			Yii::app()->crugemailer->sendRegistrationEmail($model,$newPwd);
 		}
 			Yii::app()->crugemailer->sendWaitForActivation($model,$newPwd);
 		}
 	}
-	
-	
+
+
 	public function actionWelcome(){
 		$this->layout = CrugeUtil::config()->registrationLayout;
 		$this->render("welcome");
 	}
-	
+
 	public function actionUserSaved($layout=null){
 		if($layout != null)
 			$this->layout = $layout;
 		$this->render("usersaved");
 	}
-	
-	
-	
-	
-	
+
+
+
+
+
 	public function actionUserManagementDelete($id){
 		$model = Yii::app()->user->um->loadUserById($id);
 		$model->scenario = 'delete';
 		$model->deleteConfirmation=0;
-		
+
 		if(isset($_POST[CrugeUtil::config()->postNameMappings['CrugeStoredUser']]))
 		{
 			if(isset($_POST['cancelar']))
 				$this->redirect(array('usermanagementadmin'));
-		
+
 			$model->attributes=$_POST[CrugeUtil::config()->postNameMappings['CrugeStoredUser']];
 			if($model->validate()){
 				if($model->deleteConfirmation == 1)
 			}else{
 				//error, no ha confirmado con la casilla
 			}
-		}		
-		
+		}
+
 		$this->render("usermanagementdelete",array('model'=>$model));
 	}
-	
-	
-	
-	
+
+
+
+
 	public function actionFieldsAdminList(){
 		$model = Yii::app()->user->um->getSearchModelICrugeField();
 		$model->unsetAttributes();
 		if($model != null){
 			if(isset($_POST[CrugeUtil::config()->postNameMappings['CrugeField']])){
 				$model->attributes = $_POST[CrugeUtil::config()->postNameMappings['CrugeField']];
-				if($model->save())	
+				if($model->save())
 					$this->redirect(array('fieldsadminlist'));
 			}
 			$this->render("fieldsadminupdate",array('model'=>$model));
 		$model = Yii::app()->user->um->createEmptyField();
 		if(isset($_POST[CrugeUtil::config()->postNameMappings['CrugeField']])){
 			$model->attributes = $_POST[CrugeUtil::config()->postNameMappings['CrugeField']];
-			if($model->insert())	
+			if($model->insert())
 				$this->redirect(array('fieldsadminlist'));
 		}
 		$this->render("fieldsadminupdate",array('model'=>$model));
 			}
 		}
 	}
-	
+
 
 
 
 		$dataProvider = Yii::app()->user->rbac->getDataProviderOperations();
 		$this->render('rbaclistops',array('dataProvider'=>$dataProvider));
 	}
-	
-	// aqui type es uno de los valores de 
+
+	// aqui type es uno de los valores de
 	// CAuthItem::TYPE_ROLE,CAuthItem::TYPE_TASK,CAuthItem::TYPE_OPERATION
 	public function actionRbacAuthItemCreate($type){
-		
+
 		$editor = new CrugeAuthItemEditor('insert');
 		$editor->name = "";
 		$editor->description = "";
 		$editor->businessRule = "";
 		$editor->categoria = Yii::app()->user->rbac->getAuthItemTypeName($type);
 		$editor->isNewRecord = true;
-		
-		
+
+
 		if(isset($_POST['CrugeAuthItemEditor']))
 		{
 			if(isset($_POST['volver'])){
 				if($type == CAuthItem::TYPE_OPERATION)
 					$this->redirect(array('rbaclistops'));
 			}
-		
+
 			$editor->attributes=$_POST['CrugeAuthItemEditor'];
 			if($editor->validate()){
-			
-			
+
+
 				$newAi = Yii::app()->user->rbac->createAuthItem(
 						$editor->name,
 						$type,
 						$editor->description,
 						$editor->businessRule
 					);
-					
-					
+
+
 				// se va de vuelta a la lista de donde vino
 				if($type == CAuthItem::TYPE_ROLE)
 					$this->redirect(array('rbaclistroles'));
 				if($type == CAuthItem::TYPE_OPERATION)
 					$this->redirect(array('rbaclistops'));
 			}
-		}		
+		}
 		$this->render('rbacauthitemcreate',array('model'=>$editor));
 	}
 
 
 
 	public function actionRbacAuthItemUpdate($id){
-		
+
 		$aiModel = Yii::app()->user->rbac->getAuthItem($id);
 		if($aiModel == null)
 			throw new CrugeException("el item de autenticacion senalado no existe");
-		
+
 		$editor = new CrugeAuthItemEditor('update');
 		$editor->isNewRecord = false;
 		$editor->name = $aiModel->name;
 		$editor->description = $aiModel->description;
 		$editor->businessRule = $aiModel->bizRule;
 		$editor->categoria = Yii::app()->user->rbac->getAuthItemTypeName($aiModel->type);
-		
+
 		if(isset($_POST['CrugeAuthItemEditor']))
 		{
 			if(isset($_POST['volver'])){
 				if($aiModel->type == CAuthItem::TYPE_OPERATION)
 					$this->redirect(array('rbaclistops'));
 			}
-		
+
 			$editor->attributes=$_POST['CrugeAuthItemEditor'];
 			if($editor->validate()){
 				// la guarda de regreso al aiModel
 				$aiModel->description = $editor->description;
 				$aiModel->bizRule = $editor->businessRule;
 				Yii::app()->user->rbac->saveAuthItem($aiModel,$oldName);
-				
+
 				// se va de vuelta a la lista de donde vino
 				if($aiModel->type == CAuthItem::TYPE_ROLE)
 					$this->redirect(array('rbaclistroles'));
 				if($aiModel->type == CAuthItem::TYPE_OPERATION)
 					$this->redirect(array('rbaclistops'));
 			}
-		}		
-		
+		}
+
 		$this->render('rbacauthitemupdate',array('model'=>$editor));
 	}
 
 		$aiModel = Yii::app()->user->rbac->getAuthItem($id);
 		if($aiModel == null)
 			throw new CrugeException("el item de autenticacion senalado no existe");
-		
+
 		$editor = new CrugeAuthItemEditor('delete');
 		$editor->deleteConfirmation = false;
 		$editor->isNewRecord = false;
 				$this->redirect(array('rbaclisttasks'));
 			if($aiModel->type == CAuthItem::TYPE_OPERATION)
 				$this->redirect(array('rbaclistops'));
-		}		
+		}
 
 		$this->render('rbacauthitemdelete',array('model'=>$editor));
 	}
 		$aiModel = Yii::app()->user->rbac->getAuthItem($id);
 		if($aiModel == null)
 			throw new CrugeException("el item de autenticacion senalado no existe");
-			
+
 		$this->render('rbacauthitemchilditems',array('model'=>$aiModel));
 	}
 
 	/**
 		este action debe ser invocado bajo request POST, y su postdata debe contener
 		un objeto JSON de esta forma:
-		
+
 		ejemplo:
-		
+
 		{ parent: 'updateOwnPost' , child: 'updatePost' , setflag: true }
-		
+
 		esto indica que al 'parent' se le agregara o removera (setflag), el item 'child'
-		
+
 		cualquier error debe ser reportado bajo una excepcion.
 	*/
 	public function actionRbacAjaxSetChildItem(){
 		if(Yii::app()->request->isAjaxRequest){
 			if(Yii::app()->request->isPostRequest){
-				
+
 				$rbac = Yii::app()->user->rbac;
-			
+
 				$jsondata = trim(file_get_contents('php://input'));
-				
+
 				Yii::log(__CLASS__."\nactionRbacAjaxSetChildItem\njsondata:\n".$jsondata,"info");
-				
+
 				$obj = CJSON::decode($jsondata);
 				$parent = $obj['parent'];
 				$child = $obj['child'];
 				$setflag = ($obj['setflag']==1 ? "true" : "false");
-				
+
 				Yii::log(__CLASS__."\nactionRbacAjaxSetChildItem\natributos leidos:\n"
 					."parent=".$parent."\n"
 					."child=".$child."\n"
 					."setflag='".$setflag."'\n"
 					,"info");
-				
+
 				// parent y child deben existir
 				$_parent = $rbac->getAuthItem($parent);
 				$_child = $rbac->getAuthItem($child);
 					throw new CrugeException("parent: no existe.[".$parent."]");
 				if($_child == null)
 					throw new CrugeException("child: no existe.[".$child."]");
-				
+
 				$accion='...';
 				if($setflag == "true"){
 					$accion='[try add..]';
 						$accion .='removeItemChild';
 					}
 				}
-					
+
 				// OK
 				Yii::log(__CLASS__."\nactionRbacAjaxSetChildItem\nRESULTADO OK {$accion}\n","info");
-				
+
 				$result = array();
 				$result['result'] = $rbac->hasItemChild($parent,$child);
 				$result['parent'] = $parent;
 		else
 		throw new CrugeException("por favor no invoque este action manualmente");
 	}
-	
-	
+
+
 	/* asigna o revoca un authitem a un usuario en particular. puede ser un rol, una tarea o una operacion, pero por razones de orden en la vista que llama a este action solo se habilitan roles para ser agregados.
-	
+
 	la contraparte de este action es:
 	actionRbacUsersAssignments()  la cual maneja la vista que asigna/revoca un rol de forma masiva
 	a varios usuarios.
-	
+
 		funciona via ajax y post, espera que el cuerpo del post traiga lo siguiente:
 		{ authitem: 'nombrerol' , userid: 123 , setflag: true }
-		
+
 		lo que hara con ese objeto json es:
-		
+
 		asignar (<setflag> es true=asignar) el <authitem>, al usuario con primaryKey <userid>,
 		si no puede emite una excepcion
 	*/
 				$rbac = Yii::app()->user->rbac;
 				$jsondata = trim(file_get_contents('php://input'));
 				Yii::log(__CLASS__."\nactionRbacAjaxAssignment\njsondata:\n".$jsondata,"info");
-				
+
 				$obj = CJSON::decode($jsondata);
 				$authitemName = $obj['authitem'];
 				$userId = $obj['userid'];
 				$setflag = ($obj['setflag']==1 ? "true" : "false");
-				
+
 				Yii::log(__CLASS__."\nactionRbacAjaxAssignment\natributos leidos:\n"
 					."authitemName=".$authitemName."\n"
 					."userId=".$userId."\n"
 					."setflag='".$setflag."'\n"
 					,"info");
-				
+
 				// comprueba que el authitem exista
 				$_ai = $rbac->getAuthItem($authitemName);
 				if($_ai == null)
 					throw new CrugeException("authitem: no existe.[".$authitemName."]");
-				
+
 				// verifica al usuario
 				$user = Yii::app()->user->um->loadUserById($userId);
 				if($user == null)
 					throw new CrugeException("userId: no existe.[".$userId."]");
-					
+
 				Yii::log(__CLASS__."\nactionRbacAjaxAssignment\nprocede a asignar o a revocar\n","info");
-				
+
 				$accion = "";
-				
+
 				if($setflag == 'true'){
 					// quiere asignar
 					if($rbac->isAssigned($authitemName,$userId)){
 						}
 					}
 				}
-				else{	
+				else{
 					// quiere revocar
 					if(!$rbac->isAssigned($authitemName,$userId)){
 						$accion .= "[no estaba previamente asignado]";
 		else
 		throw new CrugeException("por favor no invoque este action manualmente");
 	}
-	
-	
+
+
 	public function actionRbacAjaxGetAssignmentBizRule(){
 		if(Yii::app()->request->isAjaxRequest){
 			if(Yii::app()->request->isPostRequest){
 				$rbac = Yii::app()->user->rbac;
 				$jsondata = trim(file_get_contents('php://input'));
-				
+
 				$obj = CJSON::decode($jsondata);
 				$authitemName = $obj['authitem'];
 				$userId = $obj['userid'];
-				
+
 				// comprueba que el authitem exista
 				$_ai = $rbac->getAuthItem($authitemName);
 				if($_ai == null)
 					throw new CrugeException("authitem: no existe.[".$authitemName."]");
-				
+
 				// verifica al usuario
 				$user = Yii::app()->user->um->loadUserById($userId);
 				if($user == null)
 				$aa = $rbac->getAuthAssignment($authitemName,$userId);
 				if($aa == null)
 					throw new CrugeException("asignacion no hallada");
-					
+
 				$result = array();
 				$result['bz'] = $aa->bizRule;
 				$result['obj'] = $aa;
 			if(Yii::app()->request->isPostRequest){
 				$rbac = Yii::app()->user->rbac;
 				$jsondata = trim(file_get_contents('php://input'));
-				
+
 				$obj = CJSON::decode($jsondata);
 				$authitemName = $obj['authitem'];
 				$userId = $obj['userid'];
 				$nuevoBz = $obj['bz']; // el business rule modificado
-				
+
 				// comprueba que el authitem exista
 				$_ai = $rbac->getAuthItem($authitemName);
 				if($_ai == null)
 					throw new CrugeException("authitem: no existe.[".$authitemName."]");
-				
+
 				// verifica al usuario
 				$user = Yii::app()->user->um->loadUserById($userId);
 				if($user == null)
 				$aa = $rbac->getAuthAssignment($authitemName,$userId);
 				if($aa == null)
 					throw new CrugeException("asignacion no hallada");
-					
+
 				$aa->bizRule = $nuevoBz;
 				$rbac->saveAuthAssignment($aa);
-					
+
 				$result = array();
 				$result['bz'] = $aa->bizRule;
 				$result['obj'] = $aa;
 		else
 		throw new CrugeException("por favor no invoque este action manualmente");
 	}
-	
+
 	/**
-		maneja la asignacion masiva de usuarios a roles.  su contraparte es el action: 
+		maneja la asignacion masiva de usuarios a roles.  su contraparte es el action:
 		actionRbacAjaxAssignment.
-		
+
 		como funciona este action:
-		
+
 		La vista 'rbacusersassignments.php' tiene dos CGridView, cada uno llenado
 		con los DataProviders que aqui se emiten. El primer es la lista de usuarios
 		asignados a un rol, el segundo es la lista completa de usuarios.
-		
+
 		por eso en la llamada cruda a la vista se entregan dos data providers,
 			,array(
 				'roleUsersDataProvider'=>$roleUsersDataProvider,
 				'allUsersDataProvider'=>$allUsersDataProvider,
 			)
-		
+
 		una vez en la vista se muestra una -lista de roles- a la cual al hacerle click en un
 		rol se actualizara al CGridView que presenta al dataprovider: roleUsersDataProvider,
 		mientras que el segundo CGridView permanece inalterado.
-		
+
 		el CGridView que aloja a roleUsersDataProvider sera actualizado cada vez que se haga
 		click en un rol, eso generara una llamada con modalidad ajaxRequest a este action,
 		y aqui se recibira entonces un argumento extra llamado: itemName
-		
+
 		// invocado cuando se hace click en un ROL (itemName)
 		$.fn.yiiGridView.update('_lista1',{ data : "itemName="+itemName });
-		
+
 		cuando un usuario hace click en el link "#asignarSeleccion", lo que se hace
 		basicamente es volver a invocar a $.fn.yiiGridView.update('_lista1',{ data : "itemName="+itemName });,  pero con mas argumentos:
-		
+
 		mode	: puede ser 'assign' : 'revoke'
 		userid	: lista de userid
-		
+
 		por esta razon se ve que se hace:
 		if(Yii::app()->request->isAjaxRequest && isset($_GET['mode']))
-		
+
 		para poder reconocer el ajaxRequest de:
 			$.fn.yiiGridView.update('_lista1',{ data : "itemName="+itemName });
 		del otro que trae los argumentos extra.
-		
+
 		cuando se detecta que el argumento MODE viene en la URL entonces se sabe
 		que se quiere asignar o revocar un permiso (itemName) a una lista de usuarios (userid).
-		
+
 	*/
 	public function actionRbacUsersAssignments(){
-		
+
 		$pageSize=20;
 		$rbac = Yii::app()->user->rbac;
 		$um = Yii::app()->user->um;
-		
+
 		$debug="";
 		if(Yii::app()->request->isAjaxRequest && isset($_GET['mode'])){
-		
+
 			$debug .= "AJAX REQUEST EN CURSO CON INDICACION DE ASIGNAR O REVOCAR\n";
 			$mode = $_GET['mode'];
 			$itemName = $_GET['itemName'];
 			$userid = isset($_GET['userid']) ? $_GET['userid'] :  '0';
 			$ids = explode(",",$userid);
-			
+
 			$debug .= "-itemName es: {$itemName}\n";
 			$debug .= "-modalidad es: {$mode}\n";
 			$debug .= "-userid es: {$userid}\n";
-			
+
 			foreach($ids as $uid){
 				$debug .= "OPERANDO '{$mode}' {$uid} AL AUTHITEM: {$itemName}\n";
 				if($mode == 'assign'){
 				}
 			}
 		}
-		
-		
-		
+
+
+
 		// entrega los usuarios asignados a este CAuthItem
 		//
 		$authItemName="";
 		if(isset($_GET['itemName']))
 			$authItemName = $_GET['itemName'];
-			
-		$debug .= "arg: itemName={$authItemName}\n";	
-			
-		Yii::log(__CLASS__."\nactionRbacUsersAssignments\ndebug:\n".$debug,"info");	
-			
+
+		$debug .= "arg: itemName={$authItemName}\n";
+
+		Yii::log(__CLASS__."\nactionRbacUsersAssignments\ndebug:\n".$debug,"info");
+
 		$roleUsersDataProvider = $um->listUsersDataProviderFromArray(
 			$rbac->getUsersAssigned($authItemName),$pageSize);
 		$allUsersDataProvider = $um->listAllUsersDataProvider(array(),$pageSize);
-		
-		
+
+
 		$this->render('rbacusersassignments'
 			,array(
 				'roleUsersDataProvider'=>$roleUsersDataProvider,
 			)
 		);
 	}
-	
+
 	public function actionSessionAdmin(){
 		$model = Yii::app()->user->um->getSearchModelICrugeSession();
 		$model->unsetAttributes();
 				$model->delete();
 		}
 	}
-	
+
 	public function actionSystemUpdate() {
 		$model = Yii::app()->user->um->getDefaultSystem();
-		
+
 		Yii::app()->user->setFlash('systemFormFlash',null);
-		
+
 		if(isset($_POST[CrugeUtil::config()->postNameMappings['CrugeSystem']])){
 			$model->attributes = $_POST[CrugeUtil::config()->postNameMappings['CrugeSystem']];
 			if($model->validate()){
 				}
 			}
 		}
-		
+
 		$this->render('systemupdate',array('model'=>$model));
 	}
-	
+
 	/*
 		este action debera tener acceso directo desde la calle para activar una cuenta.
-		
-		en el caso de este action, quiza no se quiera presentar el mismo layout que 
+
+		en el caso de este action, quiza no se quiera presentar el mismo layout que
 		los demas actions, en este caso se puede tomar un valor de config del modulo
 		para indicar que layout se quiere usar.
 	*/
 	public function actionActivationUrl($key){
-		
+
 		$this->layout = CrugeUtil::config()->activateAccountLayout;
-		
+
 		$model = Yii::app()->user->um->loadUserByKey($key);
 		if($model != null)
 			if($model->state == CRUGEUSERSTATE_NOTACTIVATED){
-			
+
 				$resp = CrugeTranslator::t("disculpe, no se pudo activar su cuenta");
-			
+
 				Yii::app()->user->um->activateAccount($model);
-			
+
 				if(Yii::app()->user->um->save($model))
 					$resp = CrugeTranslator::t(
 						"su cuenta ha sido activada, ahora debe iniciar sesion con las credenciales otorgadas");
-				
+
 				$this->renderText($resp);
 			}
 	}
-	
+
 	public function actionAjaxResendRegistrationEmail($id){
 		$newPassword = CrugeUtil::passwordGenerator();
 		$model = Yii::app()->user->um->loadUserById($id);
 	public function actionAjaxGenerateNewPassword(){
 		echo CrugeUtil::passwordGenerator();
 	}
-	
+
 	protected function performAjaxValidation($formid,$model)
 	{
 		if(isset($_POST['ajax']) && $_POST['ajax']===$formid)
 			echo CActiveForm::validate($model);
 			Yii::app()->end();
 		}
-	}	
+	}
 }

data/cruge-data-model-postgres.sql

   registerusingactivation integer NULL DEFAULT 1 ,
   defaultroleforregistration VARCHAR(64) NULL ,
   registerusingtermslabel VARCHAR(100) NULL ,
+  registrationonlogin integer NULL DEFAULT 1 ,
   PRIMARY KEY (idsystem) )
 ;
 delete from cruge_system;

data/cruge-data-model.sql

   `registerusingactivation` INT(11) NULL DEFAULT 1 ,
   `defaultroleforregistration` VARCHAR(64) NULL ,
   `registerusingtermslabel` VARCHAR(100) NULL ,
+  `registrationonlogin` INT(11) NULL DEFAULT 1 ,
   PRIMARY KEY (`idsystem`) )
 ENGINE = InnoDB;
 

models/auth/AlternateAuthDemo.php

+<?php
+/*
+	Esta es una clase de demostracion para que se conozca como crear metodos alternos de inicio de sesion.
+
+	en esta clase se autenticara al usuario contra la lista de user y password definida en config/main asi:
+
+
+	// EN CONFIG/MAIN LE INDICAS A CRUGE QUE USE ESTA CLASE 'authdemo':
+
+		'cruge'=>array(
+			'tableprefix'=>'cruge_',
+			// 'availableAuthMethods'=>array('default'),
+			'availableAuthMethods'=>array('authdemo'),
+			...
+			...
+			(el string "authdemo" debe esta definido en la clase de autenticacion,
+			este string es devuelto en la clase: AlternateAuthDemo.php )
+
+
+ 	@author: Christian Salazar H. <christiansalazarh@gmail.com> @bluyell
+	@copyright Copyright &copy; 2008-2012 Yii Software LLC
+	@license http://www.yiiframework.com/license/
+*/
+class AlternateAuthDemo extends CBaseUserIdentity implements ICrugeAuth {
+
+	private $username;
+	private $password;
+	private $options;
+
+	private $_user;
+
+	/**
+		este nombre sera referenciado en config/main para hacerle saber a Cruge que use esta clase
+		para autenticar:
+
+			'availableAuthMethods'=>array('authdemo'),
+	*/
+	public function authName(){
+		return "authdemo";
+	}
+
+	/*	no confundir con un getUserName, esto es un getUser a nivel de instancia,
+		debe retornar algun objeto que implemente a ICrugeStoredUser, por defecto se puede usar un
+		objeto de clase CrugeStoredUser.
+
+		@returns instancia de ICrugeStoredUser hallado tras la autenticacion exitosa
+	*/
+	public function getUser(){
+		return $this->_user;
+	}
+
+	/*
+		recibe desde cruge parametros considerados como user y password, pueden no ser user y password a nivel
+		conceptual..sino por ejemplo, cedula y clave, numerotarjeta y clave, etc.
+	*/
+	public function setParameters($username,$password,$options = array()){
+		$this->username = $username;
+		$this->password = $password;
+		$this->options = $options;
+	}
+
+	public function authenticate() {
+
+		// en errorcode reporta el error generado
+		//
+		$this->errorCode=self::ERROR_USERNAME_INVALID;
+
+
+		// retorna boolean, true si la autenticacion es exitosa
+		//
+		return $this->errorCode==self::ERROR_NONE;
+	}
+}
+

models/auth/CrugeAuthDefault.php

-<?php 
+<?php
 /**
 	CrugeAuthDefault
-	
+
 	Implementa un modo de autenticacion basado en la lista de usuarios registrados reales
 	almacenados con CrugeStoredUser.
-	
+
 	aqui se hara uso de CrugeModule::availableAuthModes
 	y de CrugeModule::useEncryptedPassword
-	
+
 	esta clase es consumida por: CrugeUser::authenticate()
 	quien a su vez es invocada por CrugeLogon
 
 	public $username;
 	public $password;
 	public $options;
-	
+
 	private $_userinstance = null;
-	
+
 	private function _getPwd(){
 		if(CrugeUtil::config()->useEncryptedPassword == true)
 			return md5($this->password);
 		return $this->password;
 	}
-	
+
+	/**
+		este nombre sera referenciado en config/main para hacerle saber a Cruge que use esta clase
+		para autenticar:
+
+			'availableAuthMethods'=>array('authdemo'),
+	*/
 	public function authName(){
 		return "default";
 	}
-	
+
 	/*	no confundir con un getUserName, esto es un getUser a nivel de instancia
-	
+
 		@returns instancia de ICrugeStoredUser hallado tras la autenticacion exitosa
 	*/
 	public function getUser(){
 		return $this->_userinstance;
 	}
-	
+
 	public function setParameters($username,$password,$options = array()){
 		$this->username = $username;
 		$this->password = $password;
 		$this->options = $options;
 	}
-	
+