In order to implement cross application authentication (getting logged in in my Symfony2 app if the user already logged in in an other application), I made a Symfony2 listener class that checks if specific data concerning the user is in the session. This data comes from a non-Symfony2 (but PHP) app.
The problem is that the session data from the other app is not present in the session object I use in my class.
Here is the listener (simplified) class:
<?php
class OldAppAuthenticationListener
{
/** #var \Symfony\Component\Security\Core\SecurityContext */
private $context;
public function __construct(SecurityContext $context)
{
$this->context = $context;
}
public function onKernelRequest(GetResponseEvent $event)
{
if (HttpKernel::MASTER_REQUEST != $event->getRequestType()) {
// don't do anything if it's not the master request
return;
}
if (!$this->context->isGranted('IS_AUTHENTICATED_FULLY')) {
$request = $event->getRequest();
$session = $request->getSession();
$userName = $session->get('nomUtilisateur');
$token = new PreAuthenticatedToken($userName, null, 'secured_area', array('ROLE_USER'));
$session->set('_security_secured_area', serialize($token));
}
}
}
It is registered in services.yml like this:
services:
my_app.listener.old_app_authentication:
class: Acme\MyAppBundle\Listener\MyAppAuthenticationListener
arguments: ["#security.context"]
tags:
- { name: kernel.event_listener, event: kernel.request }
But the $session->get('nomUtilisateur') always returns NULL (and $session->all() and $_SESSION only return some Symfony2 specific vars) although the other app stores all this data in the session.
Of course, I use the same cookie session domain for both apps (as configured in config.yml) and I can easily check that the PHPSESSID is the same.
So here is my question: why are the old app session variables not available and how can I get them from my listener class?
As stated here, Symfony2 uses session bags to store session stuff. This means that you have to directly access the $_SESSION superglobal for such a functionality.
For me the solution was to use directly the php session fonctions.
also I had to check if session name, domain and save path are the same on both applications.
In my symfony I had to add:
session_save_path('c:/wamp/tmp');
session_name(_SESSION_ID_);
session_start();
and then use $_SESSION
an other way that was given to me, but I didn't use is to use the sessions files directly like this:
"The trick was using the session cookie sent by the browser.
For example, an old web application, written in PHP, sent a cookie
called IntranetSession to the browser. As I knew where does PHP store
the session files, I simply opened that file, and decoded its contents
with session_decode(). The drawbacks of this is that session_decode()
puts its output directly into $_SESSION, overwriting you current
session data (even the stuff put there by Symfony). Basically the rule
is as follows:
$sessionData = file_get_contents($sessionFile);<br>
$tmpSess = $_SESSION;<br>
session_decode($sessionData);<br>
$otherAppSession = $_SESSION;<br>
$_SESSION = $tmpSess;<br>
"
hope this helps!
Related
I'm creating 2 projects in 2 diferent domains domain1.tld and domain2.tld.
The domain1.tld is the main event producer page and the domain2.tld is one of its events. I want to share the same sessions (they actually share the same database and the same apache server). I tried to change the session driver to "database" and create a session table, but nothing happens, if i'm log in domain1.tld nothing happens in domain2.tld.
I really have searched in the net but i have found nothing
you can't do this in your way...
when you set session, a cookie set in browser for track stored session in server side.
if you want to share session between two domain you should share cookie between to site bot you can not do it (you can do it just in sub domains of ONE domain)
but there is a little hack :
The easiest work-around is to pass login/credential information from website A to website B and have website B set a seperate cookie. For example, after logging into website A you could have them quickly redirected to website B with an encrypted querystring. Website B could then read the information, set its own cookie, and redirect the user back to site A.
It's messy but possible.
Step 1: Set Session Driver for Shared Session Data
First, set your session driver to a database or cache that is shared across both domains. Your session driver cannot be file
Step 2: Implement Cross-Domain Session IDs
Session ids are passed around by cookies in Laravel. Since your websites are on different domains the session cookie does not transfer over. One way to solve this is to append them to the query string of all your requests like so: domain2.tld/?session_token=abcds2342
Within your code there must be some login that detects a session and then query the database/cache (your session driver) for a result. If a result is found, you set the session ID manually and start the session:
session_id('abcds2342');
session_start();
Be careful to check both the IP address and the session ID
to prevent people from guessing someone elses SessionID and thus
logging in as another person
Step 2A: To do this you can implement a custom middleware that overrides StartSession. This middleware should override getSession and before it checks for session_id in cookie, check if we have a token present in the Request. Sample code below:
<?php
namespace App\Http\Middleware;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\Http\Request;
use App\SessionShare;
use Closure;
class StartSessionWithSharer extends StartSession
{
/**
* Get the session implementation from the manager.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Session\SessionInterface
*/
public function getSession(Request $request)
{
$session = $this->manager->driver();
/**
* Check if we can find a valid session token from saved records
*/
if($request->get('session_token') && !empty($request->get('session_token'))) {
$sessionShare = SessionShare::valid()->whereToken($request->get('session_token'))->first();
if($sessionShare)
$session_id = $sessionShare->session_id;
}
/**
* Fallback to session in browser
*/
if(!isset($session_id) || !$session_id)
$session_id = $request->cookies->get($session->getName());
$session->setId($session_id);
return $session;
}
}
Step 2B: Then create a custom service provider to override SessionServiceProvider like so:
<?php namespace App\Providers;
class CustomSessionServiceProvider extends \Illuminate\Session\SessionServiceProvider
{
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
$this->registerSessionManager();
$this->registerSessionDriver();
$this->app->singleton('App\Http\Middleware\StartSessionWithSharer');
}
}
And then remove the old SessionServiceProvider from config/app.php and instead use above.
Step 2C: Then create your App\SessionShare model for the table to store session IDs. Also, the above code doesn't take care of checking IP address so you would have to add that in to make it secure and prevent brute force attacks
Step 2D: Oh and finally don't forget to append the get parameter for session_token for all your requests
Note that the above implementation is for a database session driver. Of course, you can do this for a cache driver too. The only thing that would change is the model implementation (step 2C) to validate the session
I'm using Symfony 2.3 LTS.
I can fully use the remember_me feature in Symfony, including setting it and logging back in after session expiry. However my issue is that once the user is logged back in with the remember_me feature then the expiry isn't refreshed.
In other words, if you set the "lifetime" of the remember_me cookie to 14 days then regardless of how many time the user visits the site they will always need to re-authenticate with a full username/password (after 14 days.) I don't want to set a longer cookie as 14 days without visiting seems right.
I know how to manually set the remember_me cookie. I just need to know where to put that code.
I've tried these:
This SO question doesn't do what I want and is very different.
There doesn't appear to be any settings in the security.yml configuration (to refresh expiry.)
Hooking in on the processAutoLoginCookie method in Symfony\Component\Security\Http\RememberMe\TokenBasedRememberMeServices, but that can't work as there's no access to a Response (to set the cookie manually.)
Listening on the SecurityEvents::INTERACTIVE_LOGIN event looks a good idea, but InteractiveLoginEvent doesn't have access to the Response either. Here's an example.
I could get messy by setting a request attribute using one of the above and then setting a response listener to detect for that, but I think that's too messy. There must be a better way to do it.
I could use one of the above to listen on the request, generate a response (e.g. redirect), set the cookie, perform the redirect, but again that's not good enough.
My proposed approach:
Set up a kernel.response listener
Pass the SecurityContext to the listener constructor
Detect a logged in user
Manually set your remember_me cookie
Set a session var to prevent future cookie sets
Your new cookie will piggyback on the next page a user loads when logged in using the remember_me cookie.
services.yml
services:
acme.response_listener:
class: AcmeBundle\EventListener\ResponseListener
arguments: ['#security.context']
tags:
- { name: kernel.event_listener, event: kernel.response, method: onKernelResponse }
ResponseListener
namespace AcmeBundle\EventListener;
use Symfony\Component\Security\Http\Event\FilterResponseEvent;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\HttpFoundation\Cookie;
class ResponseListener
{
/** #var \Symfony\Component\Security\Core\SecurityContext */
private $securityContext;
/**
* Constructor
*
* #param SecurityContext $securityContext
*/
public function __construct(SecurityContext $securityContext)
{
$this->securityContext = $securityContext;
}
public function onKernelResponse(FilterResponseEvent $event)
{
$session = $event->getRequest()->getSession();
if (
$this->securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED') // remember_me cookie used
&& !$session->get('cookie_extended') // cookie hasn't been extended
) {
$response = $event->getResponse(); // get the Response object
$cookie = new Cookie(...); // your cookie
$response->headers->setCookie($cookie); // set that cookie!
$session->set('cookie_extended', true); // prevent future cookie sets for the current session
}
}
}
I haven't tested this code but it should be enough theory to get you started in this direction.
The expiry timestamp and the password are both part of the hash of the cookie value, so it seems that the rememberme cookie can only be set at login since the password must be available to extend the timestamp.
From https://stackoverflow.com/a/9069098:
If you are setting the rememberme cookie directly, you have to use the following format:
base64_encode(<classname>:base64_encode(<username>):<expiry-timestamp>:<hash>)
where the hash will be:
sha256(<classname> . <username> . <expiry-timestamp> . <password> . <key>)
I'm having application in codeigniter already, now i'm developing the android from this application. Using this application as a server side and doing client console in android. In server i'm maintained the session. But in android request i can't maintain the session. Instead of that i'm creating GUID in server at the first request of login request and storing at client side and also storing at customer table, afterwards for each request client will send the GUID for authentication.
Now what is my problem is each request getting from android codeigniter create session with different session id(each request generating new session id). How to avoid creating session and storing into database.(Only for android request, but browser request it have to store)
I managed to extend CI_Session in Codeigniter 3.1.3.
Here is what I did:
Create a file application/libraries/Session/MY_Session.php
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class MY_Session extends CI_Session {
public function __construct(array $params = array())
{
if ( $this->ignore_sessions() )
return;
parent::__construct();
}
function ignore_sessions()
{
$uri = str_replace ("//", "/", $_SERVER['REQUEST_URI']);
if ( strpos($uri, '/ignore_this_controller/') === 0 )
return true;
return false;
}
}
You might also want to add 'session' to your config/autoload.php:
$autoload['libraries'] = array('session',....)
Your question is rather old now, but for anyone who has this problem you should extend the CI_Session library and override the sess_create method. Within your method, test to see what user agent is making the request.
Then you only allow a session to be created if the user agent is NOT an android platform.
public function sess_create
{
//load user agent library
$this->CI->load->library('user_agent');
/**test request to see if its from android
* you can update the user_agents collection to suit more specific needs
*/
if($this->agent->platform() !== 'android'):
//create session for all non-android platforms
parent::sess_create();
endif;
}
I just want to know if I am able to hand over session variables from Laravel to my custom code. What I mean is: I want to handle log-in through Laravel and pass it to my profile section which is not in Laravel. Most of the routes are handled by a .htaccess file. The goal is to just login with Laravel auth and save that to $_SESSION['user'] var and redirect to /profile. Somehow I don't get that. The session name is the same in both, in Laravel's session.php's cookie name and my custom code's constant. Is there any other factor I should consider ?
Okay here's the code:
namespace Services\Session;
class OldSessionAuth
{
protected $auth;
function __construct()
{
$this->auth = \Auth::user();
}
public function setSession()
{
$_SESSION['user'] = $this->auth->toArray();
$_SESSION['auth'] = 'TRUE';
return true;
}
public function destroy()
{
session_destroy();
session_unset();
}
}
So, this is sort of my Session services, which is initialized only if it passes the Auth from the controller, Now I think I don't need to do that. so I skiped it, Basic Stuffs (Auth::Check()) really. So, I'd just do this in my login method.
$old = new Services\Session\OldSessionAuth();
$old->setSession();
return Redirect::to('/');
The home page is controlled by my custom made MVC and I want to grab the session, which in this case I can't. It shows Array(). There is no session manipulation when retrieving the session.
Laravel already has a pretty good session abstraction so I don't think you needed to use session_start(), $_SESSION etc directly. Sharing an session across two applications is a bit tricky. If you are tied to using the cookie approach, then you have to make sure that the session driver in use is the cookie one. You would also need to ensure that the restrictions on the cookie aren't such that your other application isn't being sent them by the user's browser.
By default, PHP will use a file cookie driver. In this case, what you would have to do in your other application is to read the "PHPSESSID" cookie, set the session ID using session_id() to this and only then would you have access to the session data using the $_SESSION variable in the other application.
This is all pretty hacky though. I would recommend that if you need to share sessions that you make use of a database session driver instead. This way, you are able to share arbitrary session data across applications using a standard interface. In this case, you would just read the "laravel_session" cookie instead to be able to look up the session in the database. There would be many hidden pitfalls if you then wanted to also modify this data from the other application as well though.
Could you tell me how to properly use sessions in ZF2? So far I have this code:
"session" =>
[
"remember_me_seconds" => 2419200,
"use_cookies" => true,
"cookie_httponly" => true
]
That's the session config I copied from some post here on stackoverflow. Now should I put this code into module.config.php in each module that uses sessions or in the Application module?
public function onBootstrap(EventInterface $Event)
{
$Config = $Event->getApplication()->getServiceManager()->get('Configuration');
$SessionConfig = new SessionConfig();
$SessionConfig->setOptions($Config['session']);
$SessionManager = new SessionManager($SessionConfig);
$SessionManager->start();
Container::setDefaultManager($SessionManager);
}
Same problem with the onBootstrap() method of the Module class. Should this code go into each module's Module class or just once into the Application's Module class?
In both cases I have tried both approaches and I even tried putting this code into both modules at once, but the only thing I was able to accomplish was to set session variables in controller's constructor and then read them in actions/methods. I wasn't able to set a session variable in one action/method and then read it in another. If I remove the lines in which I set the variables in controller's constructor, I can no longer see these variables in the session. The session just behaves like it was created and deleted each time a page is requested.
Am I missing something? Please don't link me to any resources on the internet, I have read them all and they're not really helpful.
You don't need to do any configuration to use sessions in Zend Framework 2. Sure, you can change settings, but if you just want to get up and running with sessions, then don't worry about it for now.
My apologies, but I am going to disregard your last sentence; about a month ago, I wrote an article about this subject with the purpose of showing how to quickly get started with using sessions in ZF2. It doesn't rank well in search engines, so chances are you haven't read it.
Here is a code snippet showing how it can be done. If you are interested in how it works behind the scenes, then please refer to the link above.
namespace MyApplication\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\Session\Container; // We need this when using sessions
class UserController extends AbstractActionController {
public function loginAction() {
// Store username in session
$userSession = new Container('user');
$userSession->username = 'Andy0708';
return $this->redirect()->toRoute('welcome');
}
public function welcomeAction() {
// Retrieve username from session
$userSession = new Container('user');
$username = $userSession->username; // $username now contains 'Andy0708'
}
}
about session
Where do you want to store session (in mysql-db, in mongo-db,or in ram,..)?
How to classify session into "namespace" like
$_SESSION["namespace"]["user"],
$_SESSION["namespace_1"]["user"]?
SessionManager
in Zend, Zend\Session\SessionManger help you to do many as what listed above
simple config for SessionManger
$sessionManager = new SessionManager();
$sessionStorage = new SessionArrayStorage();
$sessionManager->setStorage($sessionStorage);
//you can add more config, read document from Zend
$sessionContainer = new Container("ABC", $sessionManager);
$sessionContainer->offsetSet("user", "lehoanganh25991");
when you call new Container without any SessionManager config
$sessionContainer = new Container("abc");
behind the scence, Zend create a default SessionManager, then pass it into Container
SessionArrayStorage, $_SESSION
SessionArrayStorage in Zend can work with $_SESSION, we can access to user above through
$_SESSION["ABC"]["user"]
if you set other storages like mysql-db, mongo-db, in ram,..
access through $_SESSION may not work
access session
in Module A, set session
How can we access it in Moudle B? where $sessionContainer variable ##?
it quite weird, but when you want to access to the this container, create a new one with SAME CONFIG
$sessionManager = new SessionManager();
$sessionStorage = new SessionArrayStorage();
$sessionManager->setStorage($sessionStorage);
$sessionContainer = new Container("ABC", $sessionManager);
//access
var_dump("get user from \$sessionContainer", $sessionContainer->offsetGet("user"));
review demo on github: https://github.com/hoanganh25991/zend-auth-acl/tree/d0a501e73ac763d6ef503bbde325723ea1868351
(through commits, the project changed, access it at this tree)
in FronEnd\Controller\IndexController
in AuthAcl\Module.php
in AuthAcl\Service\SimpleAuth
i acces same session at different places
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Session\Container;
class IndexController extends AbstractActionController
{
// set session values
public function indexAction()
{
$session = new Container('User'); // name your session here by replacing User
$user_session->offsetSet('user_name', "your user name"); // set your session user name
$user_session->offsetSet('user_id', "1232"); //set your session user id
}
// function to get values from session
public function getdataAction(){
$session = new Container('User');
$user_name= $user_session->offsetGet('user_name'); // get user name from the session
$user_id= $user_session->offsetGet('user_id'); // get user id from the session
}
// function to unset session values
public function unsetdataAction(){
$session = new Container('User');
$user_session->offsetUnset('user_name'); // unset user name
$user_session->offsetUnset('user_id');
}
}