Yii2 session expires after user is idle for a fixed seconds despite session timeouts being set to at least 1 day - session

I have already added these codes in my config/web file
'user' => [
'identityClass' => 'app\models\User',
'enableAutoLogin' => true,
'enableSession' => true,
'authTimeout' =>86400,
'loginUrl' => ['account/login'],
],
'session' => [
'timeout' => 86400,
],
After session expires I want to automatically logout and redirect to login action.

Make sure in your php.ini file
config
session.gc_maxlifetime
by default set as :
session.gc_maxlifetime=1440
change it, to :
session.gc_maxlifetime=86400

Very first you have to set 'enableAutoLogin' => false, .
now add these lines there in your config/web.
I have added it in frontend/config/main.php because I am using frontend only.
'components' => [
...
'user' => [
'identityClass' => 'common\models\User',
'enableAutoLogin' => false,
'enableSession' => true,
'authTimeout' => 1800, //30 minutes
'identityCookie' => ['name' => '_identity-frontend', 'httpOnly' => true],
],
'session' => [
// this is the name of the session cookie used for login on the frontend
'class' => 'yii\web\Session',
'name' => 'advanced-frontend',
'timeout' => 1800,
],
...
Now go to yii2/web/User.php and write code for destroy session in logout method before return as guest()-
public function logout($destroySession = true)
{
$identity = $this->getIdentity();
if ($identity !== null && $this->beforeLogout($identity)) {
......
if ($destroySession && $this->enableSession) {
Yii::$app->getSession()->destroy();
}
$this->afterLogout($identity);
}
$session = Yii::$app->session;
$session->remove('other.id');
$session->remove('other.name');
// (or) if is optional if above won't works
unset($_SESSION['class.id']);
unset($_SESSION['class.name']);
// (or) if is optional if above won't works
unset($session['other.id']);
unset($session['other.name']);
return $this->getIsGuest();
}
For me it worked great.

Related

yii2 pagecahe array dependecny

I am implementing page cache for one of my page. For depenedency, I have to check an array, which can be either exist or not. Possible array keys cane ,
usersearch['id'], usersearch['name'], usersearch['phone]. I have to add dependency for any change in these values as well.
Also, I have to clear cache for any update or add in user table.
Is there any possible solution for this.?
Thanks in advance
You can use variations
public function behaviors(){
$usersearch = Yii::$app->requst->get('usersearch');
return [
[
'class' => 'yii\filters\PageCache',
'only' => ['index'],
'duration' => 60,
'variations' => [
'YOUR_DYNAMIC_VALUE1','YOUR_DYNAMIC_VALUE2'
],
'dependency' => [
'class' => 'yii\caching\DbDependency',
'sql' => 'SELECT COUNT(*) FROM post',
],
],
];
}
Ref link
IN YOUR CASE ,you can use
'variations' => \Yii::$app->requst->get('usersearch')??[],
or
'variations' => [
\/Yii::$app->requst->get('usersearch')['id'] ?? '',
\Yii::$app->requst->get('usersearch')['name'] ?? '',
\Yii::$app->requst->get('usersearch')['phone'] ?? '',
]
You could use a yii\caching\FileCache component with the following configuration.
Firstly, you set the cache in the init function of your controller:
Yii::$app->setComponents([
'yourCacheName' => [
'class' => \yii\caching\FileCache::class,
'defaultDuration' => 1800, //cache duration in seconds
'keyPrefix' => Yii::$app->getSession()->getId(). '_'
]
]);
Here, the parameter keyPrefix is set so that it is linked to the session ID. Thus, the visitors do not see each other's cached page. If the content is static and equal, regardless of the user or the session, this parameter can be removed.
In the view that must be cached you can call the beginCache function and the dependency as follows:
$this->beginCache('cache-id', [
'cache' => Yii::$app->yourCacheName, // the name of the component as set before
'variations' => [
$usersearch['id'] ?? '',
$usersearch['name'] ?? '',
$usersearch['phone'] ?? '',
],
'dependency' => [
'class' => \yii\caching\DbDependency::class,
'sql' => 'SELECT count(*) FROM your_user_table'
]
]);
// your view
$this->endCache();

Laravel LDAP (Adldap2) Can't authenticate,username is null into guard->attempt

Morning,
I keep getting the message "A username must be specified." when trying to login my app.
Connection to LDAP is OK, sync also, in my database/table users i see all username with password.
But can't login with anyone username.
Trying to dd($username) into LoginController, "guard()->attempt" show me "null".
Thanks for your help !
My version
Laravel Version: ^7.0
Adldap2-Laravel Version: ^6.1
PHP Version: ^7.2.5
LDAP Type: OpenLDAP
my .env
LDAP_HOSTS=ldap.forumsys.com
LDAP_BASE_DN=dc=example,dc=com
LDAP_USERNAME=cn=read-only-admin,dc=example,dc=com
LDAP_PASSWORD=password
LDAP_PASSWORD_SYNC=true
my ldap.php
<?php
return [
'logging' => env('LDAP_LOGGING', false),
'connections' => [
'default' => [
'auto_connect' => env('LDAP_AUTO_CONNECT', true),
'connection' => Adldap\Connections\Ldap::class,
'settings' => [
'schema' => Adldap\Schemas\OpenLDAP::class,
'account_prefix' => env('LDAP_ACCOUNT_PREFIX', ''),
'account_suffix' => env('LDAP_ACCOUNT_SUFFIX', ''),
'hosts' => explode(' ', env('LDAP_HOSTS', 'corp-dc1.corp.acme.org corp-dc2.corp.acme.org')),
'port' => env('LDAP_PORT', 389),
'timeout' => env('LDAP_TIMEOUT', 5),
'base_dn' => env('LDAP_BASE_DN', 'dc=corp,dc=acme,dc=org'),
'username' => env('LDAP_USERNAME', 'username'),
'password' => env('LDAP_PASSWORD', 'secret'),
'follow_referrals' => false,
'use_ssl' => env('LDAP_USE_SSL', false),
'use_tls' => env('LDAP_USE_TLS', false),
],
],
],
];
my ldap_auth
<?php
return [
'connection' => env('LDAP_CONNECTION', 'default'),
'provider' => Adldap\Laravel\Auth\DatabaseUserProvider::class,
'model' => App\User::class,
'rules' => [
// Denys deleted users from authenticating.
Adldap\Laravel\Validation\Rules\DenyTrashed::class,
// Allows only manually imported users to authenticate.
// Adldap\Laravel\Validation\Rules\OnlyImported::class,
],
'scopes' => [
// Only allows users with a user principal name to authenticate.
// Suitable when using ActiveDirectory.
// Adldap\Laravel\Scopes\UpnScope::class,
// Only allows users with a uid to authenticate.
// Suitable when using OpenLDAP.
// Adldap\Laravel\Scopes\UidScope::class,
],
'identifiers' => [
'ldap' => [
'locate_users_by' => 'uid',
'bind_users_by' => 'distinguishedname',
],
'database' => [
'guid_column' => 'objectguid',
'username_column' => 'username', //'email',
],
'windows' => [
'locate_users_by' => 'samaccountname',
'server_key' => 'AUTH_USER',
],
],
'passwords' => [
'sync' => env('LDAP_PASSWORD_SYNC', false),
'column' => 'password',
],
'login_fallback' => env('LDAP_LOGIN_FALLBACK', false),
'sync_attributes' => [
//'email' => 'userprincipalname',
'username' => 'uid',
'name' => 'cn',
],
'logging' => [
'enabled' => env('LDAP_LOGGING', true),
'events' => [
\Adldap\Laravel\Events\Importing::class => \Adldap\Laravel\Listeners\LogImport::class,
\Adldap\Laravel\Events\Synchronized::class => \Adldap\Laravel\Listeners\LogSynchronized::class,
\Adldap\Laravel\Events\Synchronizing::class => \Adldap\Laravel\Listeners\LogSynchronizing::class,
\Adldap\Laravel\Events\Authenticated::class => \Adldap\Laravel\Listeners\LogAuthenticated::class,
\Adldap\Laravel\Events\Authenticating::class => \Adldap\Laravel\Listeners\LogAuthentication::class,
\Adldap\Laravel\Events\AuthenticationFailed::class => \Adldap\Laravel\Listeners\LogAuthenticationFailure::class,
\Adldap\Laravel\Events\AuthenticationRejected::class => \Adldap\Laravel\Listeners\LogAuthenticationRejection::class,
\Adldap\Laravel\Events\AuthenticationSuccessful::class => \Adldap\Laravel\Listeners\LogAuthenticationSuccess::class,
\Adldap\Laravel\Events\DiscoveredWithCredentials::class => \Adldap\Laravel\Listeners\LogDiscovery::class,
\Adldap\Laravel\Events\AuthenticatedWithWindows::class => \Adldap\Laravel\Listeners\LogWindowsAuth::class,
\Adldap\Laravel\Events\AuthenticatedModelTrashed::class => \Adldap\Laravel\Listeners\LogTrashedModel::class,
],
],
];
my loginController
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function username()
{
return 'username';
}
}
Been through this pain myself.
It looks like you are connecting to LDAP with your service account, but I don't see where you are logging the authenticated user into Laravel. Do your users have to supply a username and password on a screen somewhere? If not, how do you grab the user and log them in to Laravel?
The way I did this in the businesses that had to go through LDAP was to have the normal Laravel login page, but a middle method within the login controller which sent a message to LDAP through the service account with the PW. If this succeeded, then login with Laravel's standard method. Basically just check the PW against LDAP and then log in rather than checking against the Laravel DB.
Example code - this will vary wildly but can give you an idea of what might work:
if(env('LOGIN', false) === 'LDAP'){
$ldap = new \App\Http\Controllers\ClientSpecific\BaseLDAPController();
$username = $request->input('username');
if($ldap->authenticate($username, $request->input('password'))){
return $this->sendLoginResponse($request);
}
}else {
if ($this->guard()->attempt($credentials, $request->has('remember'))) {
return $this->sendLoginResponse($request);
}
}
I know this is an old question, but I was still facing this issue even in 2020 and it took a lot of my time. Actually the problem is very silly if you are also trying to bind an OpenLDAP server with your Laravel application using Adldap2-Laravel package.
Adldap2-Laravel is by default configured for Microsoft's Active Directory. But for OpenLDAP, we need to properly change the Identifiers array as follows..
<?php
return [
// configurations settings...
'identifiers' => [
'ldap' => [
'locate_users_by' => 'uid', // changed from userprincipalname
'bind_users_by' => 'dn', // changed from distinguishedname
],
'database' => [
'guid_column' => 'objectguid',
'username_column' => 'username', //'email',
],
'windows' => [
'locate_users_by' => 'samaccountname',
'server_key' => 'AUTH_USER',
],
],
// rest of the configurations...
];
Do tell me if my answer is not clear for new comers since I'm also a newbie. I'll try to explain the solution further better :)

how to stop execution of ctp file in cakephp 2.x after validating the url

In my CakePHP application, I have applied Url validations so that admin can access only those actions which are defined for admin and same as with users.
In my application, "surveylist" is the action of admin and when any user directly access that action(surveylist), URL validations work(Unauthorized access msg is displayed).
But below that message ctp file of surveylist executes forcefully and show errors because I have validated URL through the try-catch block and it cannot get the set variables of action.
I want that ctp file should not execute if unauthorize error comes.
My code for surveylist is:-
public function surveylist($pg=null){
try{
if($this->checkPageAccess($this->params['controller'] . '/' . $this->params['action'])){
$this->Paginator->settings = array(
'Survey' => array(
'limit' => 5,
'order' => 'created desc',
'conditions'=>array('is_deleted'=> 0),
'page' => $pg
)
);
$numbers = $this->Paginator->paginate('Survey');
$this->set(compact('numbers'));
}else{
$this->Flash->set(__('Unauthorised access'));
}
}catch(Exception $e){
$this->Flash->set(__($e->getMessage()));
}
}
I don't want the ctp file of surveylist to execute if control comes to else.
Plz, help me out......
Thanx in advance...
I suppose you are using prefix to separate admin and users, if not please do that it is great way to handle and restrict methods.
After doing that you have to make condition to check which prefix(admin, user) is currently active and according that load Auth component and allow action in allow() method of Auth.
Example:
$this->loadComponent('Auth',[
/*'authorize' => [
'Acl.Actions' => ['actionPath' => 'controllers/']
],*/
'loginRedirect' => [
'controller' => 'Users',
'action' => 'index'
],
'authenticate' => [
'Form' => [
'fields' => [
'username' => 'email',
'password' => 'password'
]
]
],
'loginAction' => [
'controller' => 'Users',
'action' => 'login'
],
'unauthorizedRedirect' => [
'controller' => 'Users',
'action' => 'login',
'prefix' => false
],
'authError' => 'You are not authorized to access that location.',
]);
if ($this->request->params['prefix']=='admin') {
// Put actions you want to access to admin in allow method's array
$this->Auth->allow(array('add', 'edit', etc...));
} else if ($this->request->params['prefix']=='user') {
// Put actions you want to access to user in allow method's array
$this->Auth->allow(array('login', 'view', etc...));
}
This way you can restrict actions for particular role.
Hope this helps!

Installing user-management for Yii2.0

I've been trying to install user-management for Yii2.0, but getting ReflectionException while loading the page. I have attached the error page and directory structure below.
and the file path is as shown below.
I've searched a lot to find out the reason for this, but nothing worked out. can someone tell me what am I missing here to get it work. looks like the user-management installation documentation has some flaws. It is not clear enough to understand. Hope to get the steps to install. Thanks
Here is my console/web.php
<?php
$params = require(__DIR__ . '/params.php');
$config = [
'id' => 'basic',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log'],
'components' => [
'request' => [
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
'cookieValidationKey' => 'gAry7SfUr0oOjNQDqItsobmGBcJajQoW',
],
'cache' => [
'class' => 'yii\caching\FileCache',
],
'user' => [
//'identityClass' => 'app\models\User',
'enableAutoLogin' => true,
'class' => 'app\webvimark\modules\user-management\components\UserConfig',
// Comment this if you don't want to record user logins
'on afterLogin' => function($event) {
\webvimark\modules\user-management\models\UserVisitLog::newVisitor($event->identity->id);
}
],
'errorHandler' => [
'errorAction' => 'site/error',
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
// send all mails to a file by default. You have to set
// 'useFileTransport' to false and configure a transport
// for the mailer to send real emails.
'useFileTransport' => true,
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
'db' => require(__DIR__ . '/db.php'),
],
'modules'=>[
'user-management' => [
'class' => 'webvimark\modules\user-management\UserManagementModule',
// 'enableRegistration' => true,
// Here you can set your handler to change layout for any controller or action
// Tip: you can use this event in any module
'on beforeAction'=>function(yii\base\ActionEvent $event) {
if ( $event->action->uniqueId == 'user-management/auth/login' )
{
$event->action->controller->layout = 'loginLayout.php';
};
},
],
],
'params' => $params,
];
if (YII_ENV_DEV) {
// configuration adjustments for 'dev' environment
$config['bootstrap'][] = 'debug';
$config['modules']['debug'] = [
'class' => 'yii\debug\Module',
];
$config['bootstrap'][] = 'gii';
$config['modules']['gii'] = [
'class' => 'yii\gii\Module',
];
}
return $config;
It seems to have a slight difference with the expected configuration for this extension.
Use this
'class' => 'webvimark\modules\UserManagement\components\UserConfig',
ie UserManagement instead of user-management is a configuration path and not a route

yii2 Unable to verify your data submission

I use nginx, PHP 5.5.14, php-fpm, yii2, mac os.
I changed yii config to store session in database (postgress, user is superuser).
This is in my config:
'session' => [
'class' => 'yii\web\DbSession',
'sessionTable' => 'session',
],
And now when I try to register new user I've got this error:
Bad Request (#400)
Unable to verify your data submission
Here is a part of log:
10 17:25:57.434 info yii\db\Command::query SELECT "data" FROM "session" WHERE "expire">1425993957 AND "id"='cfg9sutufqchr1tdose4cack15'
/Users/pupadupa/Dev/www/mint-office-web/components/Controller.php (41)
11 17:25:57.442 info yii\web\Session::open Session started
/Users/pupadupa/Dev/www/mint-office-web/components/Controller.php (41)
12 17:25:57.450 error yii\web\HttpException:400 exception 'yii\web\BadRequestHttpException' with message 'Не удалось проверить переданные данные.' in /Users/pupadupa/Dev/www/mint-office-web/vendor/yiisoft/yii2/web/Controller.php:110
Stack trace:
#0 /Users/pupadupa/Dev/www/mint-office-web/components/Controller.php(41): yii\web\Controller->beforeAction(Object(app\controllers\user\RegistrationAction))
#1 /Users/pupadupa/Dev/www/mint-office-web/vendor/yiisoft/yii2/base/Controller.php(149): app\components\Controller->beforeAction(Object(app\controllers\user\RegistrationAction))
#2 /Users/pupadupa/Dev/www/mint-office-web/vendor/yiisoft/yii2/base/Module.php(455): yii\base\Controller->runAction('registration', Array)
#3 /Users/pupadupa/Dev/www/mint-office-web/vendor/yiisoft/yii2/web/Application.php(83): yii\base\Module->runAction('user/registrati...', Array)
#4 /Users/pupadupa/Dev/www/mint-office-web/vendor/yiisoft/yii2/base/Application.php(375): yii\web\Application->handleRequest(Object(yii\web\Request))
#5 /Users/pupadupa/Dev/www/mint-office-web/web/index.php(20): yii\base\Application->run()
#6 {main}
13 17:25:57.454 trace yii\base\Controller::runAction Route to run: index/error
BTW,
I've got <?= Html::csrfMetaTags() ?> in head section and I have csrf input in my form. So it seems not the problem
I don't want to do public $enableCsrfValidation = false; because I think it's not solution but workaround.
How could I understand what cause this error?
As I mentioned earlier problem only appears when I store session in database.
Some additional information:
I could set and get variable from session. For example, I put it in beoreAction of Controller.php
Yii::$app->session->set('test', 'qwe');
$t = Yii::$app->session->get('test') ;
var_dump($t);
But after that If I comment first line like this
//Yii::$app->session->set('test', 'qwe');
$t = Yii::$app->session->get('test') ;
var_dump($t);
and refresh the page - I recieve NULL (BTW I could see Cookie:PHPSESSID=cfg9sutufqchr1tdose4cack15 in cookies after refresh).
So it seems there are some problems with session (DbSession) or maybe my php/php-fpm/nginx settings.
My UserController.php:
<?php
namespace app\controllers;
use app\components\Controller;
use app\models\Client;
use app\models\User;
use yii\filters\AccessControl;
use yii\web\BadRequestHttpException;
use yii\web\NotFoundHttpException;
class UserController extends Controller
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['logout', 'employee'],
'rules' => [
[
'actions' => ['logout',],
'allow' => true,
'roles' => ['#'],
],
[
'actions' => ['employee', 'employee_add'],
'allow' => true,
'roles' => [ROLE_CLIENT_ADMIN],
],
],
],
];
}
public function actions()
{
return [
'login' => 'app\controllers\user\LoginAction',
'logout' => 'app\controllers\user\LogoutAction',
'restore' => 'app\controllers\user\RestoreAction',
'registration' => 'app\controllers\user\RegistrationAction',
'employee' => 'app\controllers\user\EmployeeAction',
'employee_add' => 'app\controllers\user\EmployeeAddAction',
//'passwd' => 'app\controllers\user\PasswdAction',
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV === 'dev' ? 'testme' : null,
],
];
}
/**
* #param int $clientId
* #return Client
* #throws BadRequestHttpException
* #throws NotFoundHttpException
*/
public function getClient($clientId)
{
if (!\Yii::$app->user->can(ROLE_ADMIN)) {
/* #var User $user */
$user = \Yii::$app->user->identity;
$clientId = $user->client_id;
}
if (!$clientId) {
throw new BadRequestHttpException('Bad request');
}
$client = Client::find()->where(['id' => $clientId])->one();
if (!$client) {
throw new NotFoundHttpException('Компания не найдена');
}
return $client;
}
}
My RegistrationAction.php:
<?php
namespace app\controllers\user;
use app\models\UserConfirm;
use Yii;
use app\components\Action;
use app\forms\RegistrationForm;
use yii\web\NotFoundHttpException;
class RegistrationAction extends Action
{
public function run($key = null)
{
if ($key !== null) {
/* #var UserConfirm $confirm */
$confirm = UserConfirm::find()->andWhere('expire > NOW()')->andWhere([
'key' => $key,
'action' => 'reg'
])->one();
if (!$confirm) {
throw new NotFoundHttpException('Key not found');
}
$user = $confirm->user;
$user->enabled = true;
$user->last_login = date('Y-m-d H:i:s');
$user->save();
$confirm->delete();
Yii::$app->user->login($user, 0);
return $this->controller->goHome();
}
$model = new RegistrationForm();
if ($model->load($_POST) && $model->validate() && $model->register()) {
$subject = Yii::$app->name . ' - Success';
$message = $this->controller->renderPartial(
'//email/registration',
[
'username' => $model->email,
'password' => $model->password,
'key' => $model->key,
'keyExpire' => $model->keyExpire
]
);
$res = Yii::$app->mailer->compose()
->setTo($model->email)
->setFrom([Yii::$app->params['from'] => Yii::$app->params['fromName']])
->setSubject($subject)
->setHtmlBody($message)
->send();
Yii::$app->session->setFlash('registrationFormSubmitted');
return $this->controller->refresh();
}
return $this->controller->render('registration', ['model' => $model]);
}
}
Looks like your session id changes. Check if the value of the session cookie changes after a second request. This happens when you misconfigure the domain that is set for the session cookie, make sure it matches the hostname in your URL.
I think this happens atimes when the server is messed up, all I needed to do was to restart my apache server.
For apache on MacOSx
sudo apachectl restart
For apache on Linux
sudo service apache2 restart
or
sudo service httpd restart
i hv used this while calling logout
$menuItems[] = [
'label' => 'Logout (' . Yii::$app->user->identity->username . ')',
'url' => ['/site/logout'],
// 'linkOptions' => ['data-method' => 'get']
'data-method' => 'get'
];
in main .php change post to get
---------------------------------------------------
and have changes this also
$url = Html::a('Logout',
['/site/logout'],
['class' => 'btn btn-success', 'data-method' => 'get']);
this is also in main.php
--------------------------------------------------------------------
in behaviour of site controller also
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['logout', 'signup','index'],
'rules' => [
[
'actions' => ['signup'],
'allow' => true,
'roles' => ['?'],
],
[
'actions' => ['logout','index'],
'allow' => true,
'roles' => ['#'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['get'],
],
],
];
}
change post to get...and it will work....
What I did is, I just make the "csrfParam" different for both backend and frontend and after "php init" command everything is now working fine.
Not sure whether its a bug or we must have to set different "csrfParam" in case if we use DBsession.
Not sure if it's late, but I found this solution which worked for me in a similar case of Yii2 framework spitting 400 Bad Request at POST form requests.
Simply add this code in your form to manually include a CSRF input field for the key and Yii2 will accept the data submission:
<?php
use Yii;
echo Html::tag('input', '', ['type' => 'hidden', 'name' => '_csrf-backend', 'value' => Yii::$app->request->getCsrfToken()]);
?>
Note: this is for the advanced template. In the long run I suggest not to use a framework that bases on short tags as PHPers would know its a curse.

Resources