Yii CDbHttpSession, where is it called? - php

I've been trying to locate where the CDbHttpSession is called after login, to rewrite it.
My problem is that I have 3 products in my App, and each are restricted on X simultaneous users, so I shouldn't allow any user to access these products until someone closes session or the admin manually removes the session from the DB.
Any help on how could I achieve it?
Thanks!

It's a fixed application component available from CWebApplication. So you can access the session instance through Yii::app()->session. You can configure your own session component in your main.php.
'components' => array(
'session' => array(
'class' => 'MyCustomSession',
),
),
But this is probably not the right place where you want to solve your problem. There is no "close session" event in PHP's session system. So you can not really find out, when a user has "closed" his session.
What could be helpful for you are maybe the afterLogin() and afterLogout() methods in CWebUser. Much like with the session component you can also override the user component with your own class. There you can at least get hold of every login/logout process and do something. Note though, that a log out does not necessarily always occur: The session can simply time out and you won't get hold if it.

Related

CakePHP 3 - login through non-Cake subdomain

I'm re-building a web application in CakePHP 3 and plan to change how the application is structured. At the moment the architecture is as follows - and none of it is written in Cake.
There is a login page at https://app.example.com which sets PHP session variables on successful login. All of the applications are then in sub-directories, e.g.
https://app.example.com/application-1
https://app.example.com/application-2
https://app.example.com/application-3
Each sub-directory has a script which checks the appropriate session vars are set, otherwise redirects to the login page, e.g. trying to access https://app.example.com/application-1 without being logged in sends the user to https://app.example.com/
I'm planning to rebuild one of the applications, https://app.example.com/application-2 in CakePHP 3, and do so on a separate subdomain (e.g. https://cake.example.com/).
What I want to do is allow the users to still login through https://app.example.com and then use https://cake.example.com/ if they are succesfully authenticated.
I was planning to allow my PHP sessions to work across multiple subdomains - as per Allow php sessions to carry over to subdomains
I'm not sure though how this would work within Cake 3 though. One idea I had was to set up https://cake.example.com/ without any of Cake's Auth functionality enabled. I was then going to use the AppController::beforeFilter() to check the session variables. If they were set appropriately, allow the user to use any Cake Controller method. If not, redirect them to https://app.example.com where they can login.
I was looking for some advice on whether there is a better way to do this, and if this is secure? I'm aware that doing this is essentially like developing the Cake app with no authentication, and just relying on the session vars being read in beforeFilter().
The login script at https://app.example.com also writes to a database where we have things such as the user ID, IP, user agent string and date/time. I can access this DB from my Cake application, but the idea of querying this database on every single request also seems wrong.
It's worth mentioning that https://cake.example.com cannot have it's own login page, even if it connected to the existing users database to lookup the credentials. This is because the users login through https://app.example.com which then acts as a dashboard for their applications. Essentially by the time they get to https://cake.example.com they either have to be authenticated, or sent back to the existing login page.
Checking the session manually can be just as secure as using CakePHPs auth component, as the component does exactly the same (given that you'd be using the session storage), just with data that you've set via AuthComponent::setUser(), ie it all depends on whether you implement things properly.
Checking the session value in AppController::beforeFilter(), and redirecting if necceesary should generally be fine, and as mentioned is pretty much the same as what the auth component does internally, it will check whether the configured session key is present and not empty.
You could possibly still leverage the CakePHP auth functionality if you wanted to, the flat u_id value in the session should suffice. For the auth component, just configure the login/logout options and the session storage key accordingly, ie if your login page is at https://app.example.com, and your login app writes auth data to $_SESSION['u_id'], configure the auth component like this:
$loginUrl = 'https://app.example.com';
$this->loadComponent('Auth', [
'loginAction' => $loginUrl,
'loginRedirect' => $loginUrl,
'logoutRedirect' => $loginUrl,
'storage' => [
'class' => 'Session',
'key' => 'u_id'
]
]);
That should be all that is needed (authentication wise), the component should pick up the possibly existing session key and treat you as authenticated, or otherwise redirect to https://app.example.com. Defining loginAction will prevent the component from whitelisting a controller/action, and logoutRedirect will be returned by AuthComponent::logout(), so you could easily implement a standard logout action in your CakePHP app if you want/need.
Of course this all depends on the u_id session value being accessible (ie you've configured your CakePHP app to pick up the existing session) and reliable in the first place.

When session writes

When and where the session writes in CakePHP 2.x. In my webpage there is 2 types of login Admin and user. I made the session setting as write in the database.
Configure::write('Session', array(
'defaults' => 'database',
'handler' => array(
'model' => 'cake_sessions'
)
));
When I logged in and logged out as a user and logged in as a Admin, Session not stored in the database. But When I logged out as Admin, It stores data in the database
{
"id" : "14f3190cee9b45fbef6d825f06845634",
"data" : "Config|a:3:{s:9:"userAgent";s:0:"";s:4:"time";i:1487143496;s:9:"countdown";i:10;}Message|a:1:{s:5:"flash";a:3:{s:7:"message";s:20:"You have logged out.";s:7:"element";s:7:"default";s:6:"params";a:0:{}}}jdebug_output_carry_over|a:4:{s:11:"development";b:1;s:9:"geo_cache";s:4:"miss";s:4:"city";s:7:"unknown";s:6:"region";s:7:"unknown";}"
"expires" : "1487143496"
}
So Can you please guide me, how it works?
Where do you change session config? In bootstrap.php? Cause you have to do it pretty early.
Second thing if you 2 login types, e.g. 2 models, not just different roles, you need a separate session config for each (using different model) and you got to know which one to use in boostrap.php already (maybe is url starting with /admin/ or something like that). Hope that helps.

How prevent destroy of specific session

I use Yii2 framework for my current project. My problem is when the user logs out all the sessions are destroyed but on the frontend I have a session registered which needs to be there after the logout process.
Is there a way in PHP to store that one session?
You probably will need to actually create 2 separate sessions. For this I would think the advanced template would be the best starting point. Frontend would be your main site, and backend would be your logged in area. You could even make a 3rd for your admin panel, if needed.
In your config you would need to specify different sessions. The way I use it, is to completely separate my frontend from the backend.
Example of config;
'components' => [
'user' => [
'identityClass' => 'common\models\User',
'enableAutoLogin' => true,
'identityCookie' => [
'name' => '_frontendUser', // unique for frontend
]
],
'session' => [
'name' => 'PHPFRONTSESSID',
'savePath' => sys_get_temp_dir(),
],
....
You would do the same for backend, only using different names.
If they can still go to the main site while they are logged in, you would need to do some addition checks, like checking if the other session exists. You could make a special rule to redirect them off the main site to the logged in area if it exists. If they still need to access the main site but know if they are logged in (like to show logout instead of login link, or show their username) then you would have to reference the other session.
I am not sure if you can actually use a session from another section... A way around it would be to store data in the first session about the 2nd session. In your login routine, you would need to inject the user data into the first session. And on logout, remove it.
Not sure what our going for, and there are still some things to look into (like if you can access another session without hacky options).
However, I think your hangup right now is that you need to define separate session values in your config.
I should also add, I wrote a wiki about how to have 2 separate sessions here: http://www.yiiframework.com/wiki/814/guide-how-to-actually-separate-frontend-user-and-backend-admin-on-yii2-advanced/
Problem with yiii2 advanced, is by default if you login to the frontend you are also logged into the backend. Well if you use frontend as members and backend as admin, you dont want it like that! A member shouldn't be logged into the admin area. So you have to make them 2 separate sessions.
While my wiki is for a slightly different use, I think it stems from the same problem and may help you figure this out.
If you need different sessions for frontend / backend, separate it as pointed in other responses but, if you need to save data between user sessions, save it to the database.

Yii always starts a session when I touch CWebUser

I'm developing a RESTful API server which require on some of its API methods a valid session, indicated in the form of a cookie with a session ID.
I'm using Yii v1.1.15 with stock PHP session handler (probably 'files').
Thing is that on every call to CWebUser it creates a session and I don't want this. A session should exists only when I explicitly create it, meaning on login (or register which auto-logins the users). For example, if in a certain API method I check if the user is guest using a construct which involves:
Yii::app()->user->isGuest
it automatically creates a session since this code is given in CWebUser.init().
Now, I'm not in a hurry to change CWebUser (in fact, to change this in the already extending class which altered it slightly, in other aspects) since I'm afraid this will have un-anticipated impact on the system.
Can anyone enlight me on this?
What would you do?
Thanks!
Environment:
// Yii v1.1.15
// session component configuration: (but believe me, I've tried every
// combination - its not really related. Check CWebUser.init()...)
'session' => array(
'class' => 'CHttpSession',
'autoStart' => false,
'sessionName' => 'MY_COOKIE_NAME',
'cookieMode' => 'allow',
'cookieParams' => ['lifetime' => 1000],
'gcProbability' => 33,
'timeout' => 1000,
'savePath' => '/tmp/',
),
// Web User's _allowAutoLogin_ is set on 'false'
So you need to check if a user is logged in (This is why you use isGuest) but you don't want to use a session?
The method isGuest uses a session variable to check if an user is logged in. The session is opened when the CWebUser is created. (in the init method like you said.) The isGuest is part of the CWebUser class. If you want to call this method it will always create a session. Unless you overwrite it.
I think you can go 2 ways at this:
Open a session, check if a user is logged in (isGuest) and then close it only if the user is not logged in. You will need to overwrite the isGuest method. Overwrite any other methods to open a session when you need it. (login/register)
Let the client send its login data on every request so you dont have to check the session and thus don't have to open it.
In both cases you will need to overwrite the CWebUser.init() so it won't open a session whenever the CWebUser is created.
So basically this was all a need that came from the following requirement set:
Yii will be used (also) as a RESTful API server.
The RESTful server will establish session only after successful login.
The above last point implies that there is no session cookie for guest users but rather it exists only for an authenticated user session.
The advantages of the above? mostly the 'free' management of login sessions by the stock PHP session including timeouts, garbage collection etc.
Despite the initial appealing of this design, the drawback overcame the advantages:
Indeed, isGuest is a property of CWebUser that when tested, already implied a session generated for the request.
Trying to change the above behavior introduced lots of issues and bugs, and god knows what lurked ahead. In essence, trying to change this behavior on Yii v1.1.x was too problematic as lots of built in features and behaviors (in the abstract meaning...) of Yii based app are implicitly using an established session.
So, I reverted to the following design:
Yii's session management was reverted to stock - yes please! open a session for everything going on! (just do it well as you normally do).
The RESTful server sends an explicit session token on successful login calls.
The client needs to save this token and send it explicitly with every API method that requires an authenticated session.
Server side saves the session token in the "freely managed" (PHP) session and thus is able to verify on each distinct request that the token for the user with this PHP session is indeed his, and is valid.

Avoid session matching with two different domains in cakephp?

I have two different domains both are developed in cakephp, My problem is, When I have logged into anyone of domain, Its working fine and when I'm open another one in new tab, It will take same session data. Suppose, If I logged out anyone, both are logout. So I need separate sessions. And one project have ACL component and another one doesn't have.
I have tried with different security.salt values, Its not working. Please sugges me what is the best way to maintain the different sessions.
Thanks in Advance.
In your core.php, you could set the session-configuration to one of CakePHP's default-configurations which will then store your sessions in the respective app's tmp-directory.
Configure::write('Session', array(
'defaults' => 'cake', // instead of 'php'
'cookie' => 'app_cookie1', // select a different one for each app
[...]
));
Moreover, you should select a different cookie-name for each app so they are not both unset upon logout.
This should resolve the conflict. If you are interested in some more advanced settings, take a look here: http://book.cakephp.org/2.0/en/development/sessions.html

Categories