ZF2 - init or something that is called in every module controller - authentication

I have a Module called "Backend" and in this module I want to check for valid authentication on all pages except the backend_login page. How do I do this? I tried to add it to the onBootstrap in the Backend/Module.php , but it turns out that is called in my other modules as well... which is of course not what I want.
So how do I do this?
Thanks in advance!

To get clear information about zf2 authentication you can follow:
ZF2 authentication
adapter auth
database table auth
LDAP auth
digest auth....These all are different methods here is an example of database table auth:
in every controller's action, where you need user auth something should like this:
use Zend\Authentication\Result;
use Zend\Authentication\AuthenticationService;
use Zend\Authentication\Adapter\AdapterInterface;
use Zend\Db\Adapter\Adapter as DbAdapter;
use Zend\Authentication\Adapter\DbTable as AuthAdapter;
public function login($credential)
{
$bcrypt = new Bcrypt();
$user = new User();
$auth = new AuthenticationService();
$user->exchangeArray($credential);
$password = $user->password;
$data = $this->getUserTable()->selectUser($user->username);
if (!$data){
$message = 'Username or password is not correct!';
}
elseif($auth->getIdentity() == $user->username){
$message = 'You have already logged in';
}
elseif($bcrypt->verify($password, $data->password)){
$sm = $this->getServiceLocator();
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$authAdapter = new AuthAdapter(
$dbAdapter,
'user',
'username',
'password'
);
$authAdapter -> setIdentity($user->username) -> setCredential($data->password);
$result = $auth->authenticate($authAdapter);
$message = "Login succesfull.Welcome ".$result->getIdentity();
} else {
$message = 'Username or password is not correct';
}
return new ViewModel(array("message" =>$message));
}
Like this in every action you can check whether it is authenticated or not
if($auth -> hasIdentity()){
//your stuff
}
else{
//redirected to your login route;
}

I had once a similar problem and figured it out within my Module.php in the onBootstrap() function. Try this, it worked for me:
class Module {
// white list to access with being non-authenticated
//the list may contain action names, controller names as well as route names
protected $whitelist = array('login');
//....
public function onBootstrap($e){
$app = $e->getApplication();
$em = $app->getEventManager();
$sm = $app->getServiceManager();
$list = $this->whitelist;
$auth = new AuthenticationService();
$em->attach(MvcEvent::EVENT_ROUTE, function($e) use ($list, $auth) {
$match = $e->getRouteMatch();
// No route match, this is a 404
if (!$match instanceof RouteMatch) {
return;
}
// Route is whitelisted
$action = $match->getParam('action');
if (in_array($action, $list) ) {
return;
}
// User is authenticated
if ($auth->hasIdentity()){
return;
}
// the user isn't authenticated
// redirect to the user login page, as an example
$router = $e->getRouter();
$url = $router->assemble(array(
'controller' => 'auth',
'action'=>'login'
), array(
'name' => 'route_name',
));
$response = $e->getResponse();
$response->getHeaders()->addHeaderLine('Location', $url);
$response->setStatusCode(302);
return $response;
}, -100);
}
}
Or you may see bjyauthorize.

Related

Yii2 signup without saving session data

I have registration form in my Yii2 advanced application. In my application only admin can register users. But when I register new user, admin session data are destroyed and new user's session data are set. What I am trying is not to change session data when I register new user. Admin user is still should be set to session data. How to solve this problem. This is my action in controller:
public function actionSignup()
{
$model = new SignupForm();
if(Yii::$app->user->can('admin'))
{
if (($response = self::ajaxValidate($model)) !== false)
return $response;
if (self::postValidate($model))
{
try
{
$trans = Yii::$app->db->beginTransaction();
if ($user = $model->signup()) {
Yii::$app->getUser()->login($user);
}
//tagidan tushgan odamining child_left, child_right tini o'zgartirish
$under = UserModel::findOne($user->id_parent_under);
if ($under->id_child_left == 0)
$under->id_child_left = $user->id;
else
$under->id_child_right = $user->id;
$under->update(false);
ChildrenBinaryModel::insertNewUser($user);
ChildrenClassicModel::insertNewUser($user);
$parents = ChildrenBinaryModel::find()->with('user')->where(["id_child" => $user->id])->orderBy(['depth' => SORT_ASC])->all();
$c_user = $user;
foreach($parents as $p)
{
$p_user = $p->user;
if ($p_user->id_child_left == $c_user->id)
$p_user->ball_left += 100;
else
$p_user->ball_right += 100;
$p_user->update(false);
$c_user = $p_user;
}
$trans->commit();
}
catch(\Exception $e)
{
$trans->rollBack();
return $this->renderContent($e->getMessage());
}
return $this->render('index');
}
return $this->render('signup', [
'model' => $model,
]);
}else{
throw new ForbiddenHttpException;
}
}
Checkout the documentation for \yii\web\User::login(). When this is run in your code by calling Yii::$app->getUser()->login($user), the session data is set to match your $user.
If it's always the admin user that's signing up new users, I'm not sure you even need to run the login method.
I have solved this problem. In order to make answer clearly and simple I will show you default signup action in site controller (Yii2 advanced template):
public function actionSignup()
{
$model = new SignupForm();
if ($model->load(Yii::$app->request->post())) {
if ($user = $model->signup()) {
if (Yii::$app->user->enableSession = false &&
Yii::$app->getUser()->login($user)) {
return $this->goHome();
}
}
}
return $this->render('signup', [
'model' => $model,
]);
}
Only I have done was adding this
Yii::$app->user->enableSession = false
inside the if statement

Google Plus Login API not working on production server

I have implemented the google plus api on development server and it works fine. I used the same code on production server. But after requesting the permission it takes a long time to return to my site and login.
Can anyone please let me know what might be the cause. I have used oauth2.
Below is the code I am using
<?php
session_start();
require_once 'googleplus/src/Google_Client.php';
require_once 'googleplus/src/contrib/Google_Oauth2Service.php';
class Webpage_UserGPlusLogin extends Webpage
{
public function __construct()
{
$temp_redirect = $_SESSION['RETURN_URL_AFTERLOGIN'];
$this->title = 'User Account';
$client = new Google_Client();
$client->setApplicationName(WEBSITE_NAME);
$client->setClientId(GOOGLE_PLUS_CLIENT_ID); // Client Id
$client->setClientSecret(GOOGLE_PLUS_CLIENT_SECRET); // Client Secret
$client->setRedirectUri(GOOGLE_PLUS_REDIRECT_URI); // Redirect Uri set while creating API account
$client->setDeveloperKey(GOOGLE_PLUS_DEVELOPER_KEY); // Developer Key
$oauth2 = new Google_Oauth2Service($client);
if (isset($_GET['code'])) {
$client->authenticate($_GET['code']);
$_SESSION['token'] = $client->getAccessToken();
$redirect = GOOGLE_PLUS_REDIRECT_URI;
header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL)); // Redirects to same page
return;
}
if (isset($_SESSION['token'])) {
$client->setAccessToken($_SESSION['token']);
}
if (isset($_REQUEST['logout'])) {
unset($_SESSION['token']);
$client->revokeToken();
}
if(!isset($_SESSION['email_address_user_account'])) // Check if user is already logged in or not
{
if ($client->getAccessToken()) {
$user = $oauth2->userinfo->get(); // Google API call to get current user information
$email = filter_var($user['email'], FILTER_SANITIZE_EMAIL);
$img = filter_var($user['picture'], FILTER_VALIDATE_URL);
$googleuserid = $user['id'];
$given_name = $user['given_name'];
$family_name = $user['family_name'];
// The access token may have been updated lazily.
$_SESSION['token'] = $client->getAccessToken();
// If email address is present in DB return user data else insert user info in DB
$this->result = UserAccount::gplus_sign_up($email, $googleuserid, $given_name, $family_name);
// Create new user object.
$this->user_account = new UserAccount($this->result['id'],$this->result['email_address'],$this->result['password'],$this->result['confirmation_code'],$this->result['is_confirmed'], $this->result['first_name'], $this->result['last_name']);
$_SESSION['gplus_email_address'] = $email;
$_SESSION['gplus_first_name'] = $given_name;
$_SESSION['gplus_last_name'] = $family_name;
$_SESSION['gplus_id'] = $googleuserid;
$_SESSION['gplus_profile_pic'] = $img;
$_SESSION['email_address_user_account'] = $email;
} else {
$authUrl = $client->createAuthUrl();
}
}
if(isset($temp_redirect))
header("Location:".$temp_redirect);
else
header("Location:/");
}
}
Thanks in advance
Try this
use following code
$temp = json_decode($_SESSION['token']);
$request = "https://www.googleapis.com/oauth2/v1/userinfo?alt=json";
$curl = curl_init();
curl_setopt($curl,CURLOPT_URL,$request);
curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
curl_setopt($curl,CURLOPT_TIMEOUT,30);
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($curl, CURLINFO_HEADER_OUT, true);
curl_setopt($curl,CURLOPT_HTTPHEADER,array('Authorization: OAuth '.$temp->access_token));
$response = trim(curl_exec($curl));
$info = curl_getinfo($curl);
$request_header_info = curl_getinfo($curl, CURLINFO_HEADER_OUT);
//var_dump($info);
//var_dump($request_header_info);
curl_close($curl);
echo "<pre>";
print_r(json_decode($response));
instade of
$user = $oauth2->userinfo->get(); // Google API call to get current user information`enter code here`
Hope this will help you .. :)

Joomla onUserAuthenticate

In the Joomla source, I found a method caled onUserAuthenticate, which could not be found in the API (through google), but its functionality is the similar to onLoginUser... So, after login/password check I need to run some more code via this function. As a result, I have true/false - depending on it I need to set users' authorization completely. Even if the user's login/password is correct, but my code returns false -> authorization fail...
I am trying something like:
functionon UserAuthenticate($credentials,$options,&$response){
jimport('joomla.user.helper');
$username=mysql_real_escape_string($credentials['username']);
$password=mysql_real_escape_string(md5($credentials['password']));
//my code returns $result
if($result!=NULL){
$response->status=JAUTHENTICATE_STATUS_SUCCESS;
$response->error_message='';
}
else{
$response->status=JAUTHENTICATE_STATUS_FAILURE;
$response->error_message=JText::_('JGLOBAL_AUTH_INVALID_PASS');
}
}
onUserAuthenticate is an event not a method. You use plugins to listen for Joomla events, in this case usually a user plugin would listen for this. When the event happens your code will run.
http://docs.joomla.org/Plugin
You can try this for custom login form-
$app = JFactory::getApplication();
$data = array();
$data['return'] = '';
$data['username'] = JRequest::getVar('username', '', 'method', 'username');
$data['password'] = JRequest::getString('password', '', 'post', JREQUEST_ALLOWRAW);
// Get the log in options.
$options = array();
// Get the log in credentials.
$credentials = array();
$credentials['username'] = $data['username'];
$credentials['password'] = $data['password'];
// Perform the log in.
$error = $app->login($credentials, $options);
if (!JError::isError($error)) {
$response->status=JAUTHENTICATE_STATUS_SUCCESS;
$response->error_message='';
}else{
$response->status=JAUTHENTICATE_STATUS_FAILURE;
$response->error_message=JText::_('JGLOBAL_AUTH_INVALID_PASS');
}
If you want authenticate solution on function "onUserAuthenticate" you should check it yourself if user credential is valid or not And you do it with this code :
function onUserAuthenticate($credentials, $options, &$response)
{
$response->type = 'Joomla';
// Joomla does not like blank passwords
if (empty($credentials['password'])) {
$response->status = JAuthentication::STATUS_FAILURE;
$response->error_message = JText::_('JGLOBAL_AUTH_EMPTY_PASS_NOT_ALLOWED');
return false;
}
// Initialise variables.
$conditions = '';
// Get a database object
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$query->select('id, password');
$query->from('#__users');
$query->where('username=' . $db->Quote($credentials['username']));
$db->setQuery($query);
$result = $db->loadObject();
if ($result) {
$parts = explode(':', $result->password);
$crypt = $parts[0];
$salt = #$parts[1];
$testcrypt = JUserHelper::getCryptedPassword($credentials['password'], $salt);
if ($crypt == $testcrypt) {
$user = JUser::getInstance($result->id); // Bring this in line with the rest of the system
$response->email = $user->email;
$response->fullname = $user->name;
$response->status = JAuthentication::STATUS_SUCCESS;
$response->error_message = '';
print_r("You login correct Sir");
die();
} else {
print_r("you enter wrong credential");
die();
$response->status = JAuthentication::STATUS_FAILURE;
$response->error_message = JText::_('JGLOBAL_AUTH_INVALID_PASS');
}
} else {
print_r("you enter blank credential");
die();
$response->status = JAuthentication::STATUS_FAILURE;
$response->error_message = JText::_('JGLOBAL_AUTH_NO_USER');
}
return true;
}

Yii::app()->user->isGuest always returns true even though login was successful

I started to make some differences between those users which have authenticated and those that not. For this, i am using
Yii::app()->user->id;
However, in a determined view i put the following code:
<?php
if(Yii::app()->user->isGuest) {
print("Welcome back Guest!");
print("Your id is ".Yii::app()->user->id);
} else {
print("Welcome back ".Yii::app()->user->name);
print("Your id is ".Yii::app()->user->id);
}?>
And i always get the "welcome back guest!", whether i have logged in (successfully) or not. And if i have logged in, then it displays the welcome message together with the user's id!
EDIT
#briiC.lv
Hey.. sorry for the late reply, I hope you are still following this! I am not extending the given UserIdentity class. Is this mandatory? Since i still dont get very well the whole authorization issue, i thought it would be best to give a try with the class they provide, and then extend with my own functionality.. Anyway, next i post my UserIdentity class with its small tweaks.. maybe the problem lies here??
<?php class UserIdentity extends CUserIdentity{
private $_id;
public function authenticate()
{
$user = Users::model()->findAll('username=\''.$this->username.'\' AND password=\''.$this->encryptedPassword.'\'');
if(!isset($user[0]))
{
return false;
}
else
{
$this->setState('id', $user[0]->id);
$this->username = $user[0]->username;
$this->errorCode=self::ERROR_NONE;
return true;
}
}
public function getId()
{
return $this->_id;
}
}
Here is the output i got when i started to log as you suggested; i got this output immediately after successfully logging in.
[05:23:21.833][trace][vardump] CWebUser#1 (
[allowAutoLogin] => true
[guestName] => 'Guest'
[loginUrl] => array ( '0' => '/site/login' )
[identityCookie] => null
[authTimeout] => null
[autoRenewCookie] => false
[autoUpdateFlash] => true
[CWebUser:_keyPrefix] => '0f4431ceed8f17883650835e575b504b'
[CWebUser:_access] => array()
[behaviors] => array()
[CApplicationComponent:_initialized] => true
[CComponent:_e] => null
[CComponent:_m] => null
)
Any help is much appreciated!
Maybe you can try to debug harder:
change messages to something like this:
if(Yii::app()->user->isGuest) {
print("Not logged");
} else {
print_r(Yii::app()->user);
print("Welcome ".Yii::app()->user->name);
print("Your id is ".Yii::app()->user->id);
}
And check session variable in your config/main.php file
...
'session' => array(
'autoStart'=>true,
),
...
The error is in the following line
$this->setState('id', $user[0]->id);
As seen in the official yii documentation regarding auth & auth, setState should be used for anything but the id field. In order to implement the key Yii will use to identify your user, return a unique value per user in the Identity getId() function.
In your case, this means you simply have to change the above line into the following:
$this->_id = $user[0]->id;
Regarding the actual inner working of the login procedure, I'd recommend a look at the CWebUser class, and especially at its login function, which is responsible for the actual storage of the Identity getId() return value.
when you call authenticate function login user as
$userIdentity = new UserIdentity($username, $password);
$userIdentity->authenticate();
if ($userIdentity->errorCode===UserIdentity::ERROR_NONE) {
Yii::app()->user->login($userIdentity,0);
}
and fetch id as
echo 'id='.Yii::app()->user->getId();
apply this code and check
I have faced same problem and found that only one line in UserIdentity Component will resolve this issue.
This is your code:
else
{
$this->setState('id', $user[0]->id);
$this->username = $user[0]->username;
$this->errorCode=self::ERROR_NONE;
return true;
}
Update this code by this one
else
{
$this->_id = $user[0]->id;
$this->setState('id', $user[0]->id);
$this->username = $user[0]->username;
$this->errorCode=self::ERROR_NONE;
return true;
}
First of all, you need to know condition that sets guest and logged-in user apart.
Based on Yii master's branch CWebUser::getIsGuest():
public function getIsGuest()
{
return $this->getState('__id')===null;
}
Compared to your code:
$user = Users::model()->findAll('username=\''.$this->username.'\' AND password=\''.$this->encryptedPassword.'\'');
if(!isset($user[0])) {
// false
} else {
$this->setState('id', $user[0]->id); // this is for persistent state sakes
...
}
}
In short: you did supply 'id' to Identity persistent state but Yii CWebUser expecting '__id' based on UserIdentity::getId().
Solution is pretty dead simple. You just need to set $this->_id
$user = Users::model()->findAll('username=\''.$this->username.'\' AND password=\''.$this->encryptedPassword.'\'');
if(!isset($user[0])) {
// false
} else {
$this->setState('id', $user[0]->id); // this is for persistent state sakes
$this->_id = $user[0]->id; // this is UserIdentity's ID that'll be fetch by CWebUser
...
}
}
This routine explains how CWebUser get UserIdentity's ID: https://github.com/yiisoft/yii/blob/master/framework/web/auth/CWebUser.php#L221
Please do test it out.
Please try following code. Its working well
//config/main.php
return array (
'component' => array(
'session' => array(
'savePath' => INSTANCE_ROOT.DS.'runtime'.DS.'session',
'autoStart' => true,
),
)
);
// LoginController
class LoginController extends CController {
public function actionLogin () {
if(isset($_POST['LoginForm']))
{
$form = new LoginForm;
$form->setAttributes($_POST['LoginForm']);
if ($form->validate()) {
$user = Users::model()->find('upper(username) = :username', array(
':username' => strtoupper($form->username)));
if($user)
return $this->authenticate($user, $form);
else {
Yii::log( 'som.....', 'error');
$form->addError('password', Yii::t('Username or Password is incorrect'));
}
return false;
}
}
}
protected function authenticate($user, $form) {
$identity = new UserIdentity($user->username, $form->password);
$identity->authenticate();
switch($identity->errorCode) {
case UserIdentity::ERROR_NONE:
$duration = $form->rememberMe ? 3600*24*30 : 0; // 30 days
Yii::app()->user->login($identity,$duration);
return $user;
break;
case UserIdentity::ERROR_EMAIL_INVALID:
$form->addError("password",Yii::t('Username or Password is incorrect'));
break;
case UserIdentity::ERROR_STATUS_INACTIVE:
$form->addError("status",Yii::t('This account is not activated.'));
break;
case UserIdentity::ERROR_STATUS_BANNED:
$form->addError("status",Yii::t('This account is blocked.'));
break;
case UserIdentity::ERROR_STATUS_REMOVED:
$form->addError('status', Yii::t('Your account has been deleted.'));
break;
case UserIdentity::ERROR_PASSWORD_INVALID:
Yii::log( Yii::t(
'Password invalid for user {username} (Ip-Address: {ip})', array(
'{ip}' => Yii::app()->request->getUserHostAddress(),
'{username}' => $form->username)), 'error');
if(!$form->hasErrors())
$form->addError("password",Yii::t('Username or Password is incorrect'));
break;
return false;
}
}
}
class UserIdentity extends CUserIdentity {
const ERROR_EMAIL_INVALID=3;
const ERROR_STATUS_INACTIVE=4;
const ERROR_STATUS_BANNED=5;
const ERROR_STATUS_REMOVED=6;
const ERROR_STATUS_USER_DOES_NOT_EXIST=7;
public function authenticate()
{
$user = Users::model()->find('username = :username', array(
':username' => $this->username));
if(!$user)
return self::ERROR_STATUS_USER_DOES_NOT_EXIST;
if(Users::encrypt($this->password)!==$user->password)
$this->errorCode=self::ERROR_PASSWORD_INVALID;
else if($user->status == YumUser::STATUS_INACTIVE)
$this->errorCode=self::ERROR_STATUS_INACTIVE;
else if($user->status == YumUser::STATUS_BANNED)
$this->errorCode=self::ERROR_STATUS_BANNED;
else if($user->status == YumUser::STATUS_REMOVED)
$this->errorCode=self::ERROR_STATUS_REMOVED;
return !$this->errorCode;
}
}
class Users extends CActiveModel
{
const STATUS_INACTIVE = 0;
const STATUS_ACTIVE = 1;
const STATUS_BANNED = -1;
const STATUS_REMOVED = -2;
// some ..........
public static function encrypt($string = "")
{
$salt = 'salt';
$string = sprintf("%s%s%s", $salt, $string, $salt);
return md5($string);
}
}
check your security configuration for cookies and sessions.
disable session.use_only_cookies & session.cookie_httponly in php.ini
file.
in PHP.INI => session.use_only_cookies = 0

Login with Kohana auth module - what am I doing wrong?

I'm trying to login with the following controller action, but my login attempt keeps failing (I get the 'invalid username and/or password' message). What am I doing wrong? I also tried the other method given in the examples in the auth documentation, Auth::instance()->login($user->username, $form->password);, but I get the same result. Kohana version is 2.3.4.
public function login() {
$auth = Auth::instance();
if ($auth->logged_in()) {
url::redirect('/account/summary');
}
$view = new View('login');
$view->username = '';
$view->password = '';
$post = $this->input->post();
$form = new Validation($post);
$form->pre_filter('trim', 'username')
->pre_filter('trim', 'password')
->add_rules('username', 'required');
$failed = false;
if (!empty($post) && $form->validate()) {
$login = array(
'username' => $form->username,
'password' => $form->password,
);
if (ORM::factory('user')->login($login)) {
url::redirect('/accounts/summary');
} else {
$view->username = $form->username;
$view->message = in_array('required', $form->errors()) ?
'Username and password are required.' :
'Invalid username and/or password.';
}
}
$view->render(true);
}
Figured out my problem... Something in my registration process is missing, because it's creating the user record but not the role-to-user assoc record. Login needs a specific role to log in to, or it won't work even with a valid username and password. Manually inserting the record allowed my to log in, so I'll just have to debug my registration action a bit.