Joomla 2.5 onAfterInitialise event not being triggered - joomla

I'm trying to write a single-signon extension so that our MediaWiki users with the correct permissions don't need to log in to our Joomla 2.5. I can't get it to work, because the onAfterInitialise event won't trigger (neither does onAfterRoute or onAfterDispatch if I try to use those instead). I know the extension is actually running because the onUserAuthentication event is triggering and logging me in as my test user.
Below is my code with the two events, the first won't trigger and execute the die() statement, the second triggers after login and unconditionally authenticates me properly.
Is there something I'm missing here like that one extension can't use two different categories of events or something?
class plgAuthenticationMwSSO extends JPlugin {
function __construct( &$subject, $config ) {
parent::__construct( $subject, $config );
}
public function onAfterInitialise() {
die('testing');
}
public function onUserAuthenticate( $creds, $opt, &$response ) {
$response->username = 'Foo';
$response->fullname = 'Foo Bar';
$response->email = 'foo#bar.baz';
$response->status = JAuthentication::STATUS_SUCCESS;
$response->error_message = '';
}
}

You need to put the onAfterInitialise in a system plugin. As a parallel example, notice how the Remember plugin is a system plugin and then the Cookie plugin is an authentication one. System plugins are checked very early in the stack and are checked on every page load. Authentication plugins are checked when authentication starts and are specifically loaded as a group at certain times. Since you have an authentication plugin, it is not triggered at the right time to respond to the system events that you are looking for.

Related

Cookie-less Laravel sessions

We have a small quiz type functionality built in Laravel to be embedded in a site via an iframe served from a separate domain (to work around CMS limitations).
It uses sessions to keep track of the user's progress in the quiz. This doesn't work in Safari (Mac/iOS), I believe because Apple disable cookies issued from within an iframe.
Assuming that limitation is one we're stuck with, has anyone had any success making Laravel sessions cookie-less? I found this code on Github, which looks promising but is old enough (and incompatible with current Laravel) that I can't tell if it's going to be a solution.
In case it helps someone else, or anyone can see any silly errors in my code, this is what I did (an adaption of the Github code, to work in Laravel 9).
I extended StartSession and SessionServiceProvider (to use my new StartSession). I created an override for handleStatefulRequest in Start Session, and where it adds a cookie to the reponse (it calls addCookieToResponse) did this:
if ($request->cookies->get($session->getName())) {
$this->addCookieToResponse($response, $session);
}
else {
// Add session ID to header
$this->addIdentifierToResponse($response, $session);
}
That new function looks like this:
protected function addIdentifierToResponse(Response $response, Session $session)
{
if ($this->sessionIsPersistent($config = $this->manager->getSessionConfig())) {
$response->headers->set("X-Session-Token", $session->getId());
}
}
I also changed the getSession method to get the session ID from that newly set header (when no cookie found):
public function getSession(Request $request)
{
return tap($this->manager->driver(), function ($session) use ($request) {
if ($request->cookies->get($session->getName())) {
Log::debug('1. Set session ID from cookie');
$session->setId($request->cookies->get($session->getName()));
}
else if ($request->headers->get("X-Session-Token", $request->input("sess_id"))) {
$sessionToken = $request->headers->get("X-Session-Token", $request->input("sess_id"));
$session->setId($sessionToken);
}
});
}
I created a Github repo containing the whole thing.

Zend framework 2 : Add different authentication adapter for two different modules

I have two different modules. Now I need to add different authentication mechanism for both modules.
So I added event code first module's Module.php's onBootstrap method
$listener = $serviceManager->get('First\Service\AuthListener');
$listener->setAdapter($serviceManager->get('First\Service\BasicAuthAdapter'));
$eventManager->attach(MvcEvent::EVENT_ROUTE, $listener, 0);
and in second module's Module.php's onBootstrap method
$listener = $serviceManager->get('Second\Service\AuthListener');
$listener->setAdapter($serviceManager->get('Second\Service\AdvAuthAdapter'));
$eventManager->attach(MvcEvent::EVENT_ROUTE, $listener, 0);
Now if I disable one of modules, functionality working fine and request properly authenticated. While enabling both module do some kind of overlapping So even required module properly authenticated, But other module event code also got executed and system give not authenticated error.
I am thinking this due to event handler code in both module.php is executed without take care of requested module url.
I can verify with requested route pattern before authentication, But that is look like a hack instead of good solution.
If better solution exists for handling this issue ?
UPDATE :
My AuthListener Code :
namespace First\Service;
use Zend\Authentication\Adapter\AdapterInterface;
use Zend\Mvc\MvcEvent;
class AuthListener
{
protected $adapter;
public function setAdapter(AdapterInterface $adapter)
{
$this->adapter = $adapter;
}
public function __invoke(MvcEvent $event)
{
$result = $this->adapter->authenticate();
if (!$result->isValid()) {
$response = $event->getResponse();
// Set some response content
$response->setStatusCode(401);
$routeMatch = $event->getRouteMatch();
$routeMatch->setParam('controller', 'First\Controller\Error');
$routeMatch->setParam('action', 'Auth');
}
}
}
There is a good way to make module specific bootstrap - to use SharedManager:
$e->getApplication()->getEventManager()->getSharedManager()
->attach(__NAMESPACE__, 'dispatch', function(MvcEvent $e) {
// This code will be executed for all controllers in current __NAMESPACE__
}, 100);
Here is a good article to understand difference between EventManager and SharedEventManager
There is no additional info about listeners in the question, but I try to guess:
If you use as listener some callable class - it's ok, just replace function() { } by your $listener.
If you use as listener some class, that implements
ListenerAggregateInterface, you should convert listeners to
SharedListenerAggregateInterface and use method attachAggregate
instead of attach
I hope it helps!

How to get a reference to the service manager inside the Module's init method (ZF2)?

I need that some code be executed before any MvcEvent::EVENT_BOOTSTRAP listener get execute. Evidently Module::onBootstrap is no an option. I end with the following code:
class Module
{
function init(\Zend\ModuleManager\ModuleManager $moduleManager)
{
$moduleManager->getEventManager()->attach(
MvcEvent::EVENT_BOOTSTRAP, array(ClassX, 'StaticMethodOfClassX'), 20000);
}
}
I don't want have hard code the array(ClassX, 'StaticMethodOfClassX') reference but get it from the service manager. My problem is that I don't know how to get an service manager reference inside the module's init method. Any help? or this is impossible in ZF2 right now? Whatever variant to this schema or opinion will be appreciate too ;)
EDIT:
I will clarify "Evidently Module::onBootstrap is no an option", cos may be is not so trivial ;)
Modules Module::onBootstrap methods are executed when the event MvcEvent::EVENT_BOOTSTRAP is triggered, but the attachment of each module's Module::onBootstrap method to that event depend of the order in which modules were loaded. Due to, the order in which a specific Module::onBootstrap method will be executed depend on what other modules exist and how other modules affect the order in which that specific module will be loaded. Beside, whatever listener attached to the MvcEvent::EVENT_BOOTSTRAP event with priority greater than 1 will be execute before any module Module::onBootstrap method, example the ViewManager::onBootstrap listener. So, to achieve what I want
I need that some code be executed before any
MvcEvent::EVENT_BOOTSTRAP listener get execute
modules obBootstrap methods are not an option.
This is a very old post but since no answer has been accepted and I recently needed to achieve the same thing, I thought I'd share my solution.
The reason I needed to access the ServiceManager before the Bootstrap event is triggered, was so I could manipulate the merged configuration with values retrieved from the database.
Problem:
The example found in the Zend documentation shows how to manipulate the merged configuration, but at that particular time the Service manager is empty, making it impossible to retrieve things like database adapters etc.
Solution:
In your module class, implement the interface InitProviderInterface and add the appropriate method.
public function init(ModuleManagerInterface $moduleManager)
{
$eventManager = $moduleManager->getEventManager();
$eventManager->attach(ModuleEvent::EVENT_LOAD_MODULES_POST, [$this, 'onLoadModulesPost']);
}
The EVENT_LOAD_MODULES_POST event will get invoked after the EVENT_MERGE_CONFIG event but before the EVENT_BOOTSTRAP event is triggered. Also at this particular time the ServiceManager will contain all the factories, invokable classes you're wanting to access.
Your callback method may look something like.
public function onLoadModulesPost(ModuleEvent $event)
{
/* #var $serviceManager \Zend\ServiceManager\ServiceManager */
$serviceManager = $event->getParam('ServiceManager');
$configListener = $event->getConfigListener();
$configuration = $configListener->getMergedConfig(false);
$someService = $serviceManager->get('Your/Custom/Service');
$information = $someService->fetchSomeInformation();
$configuration = array_merge($configuration, $information);
$configListener->setMergedConfig($configuration);
$event->setConfigListener($configListener);
$serviceManager->setAllowOverride(true);
$serviceManager->setService('Config', $configuration);
$serviceManager->setAllowOverride(false);
}
You can get it off the MvcEvent
$locator = $event->getTarget()->getServiceLocator()->get('YourObject')
If you don't have access to the event, you can set the event as a property on the Module class on bootstrap, and then use it in your init method whenever.
public function onBootstrap($event) {
$this->setMvcEvent($event);
}
function init(\Zend\ModuleManager\ModuleManager $moduleManager)
{
$locator = $this->mvc_event->getTarget()->getServiceLocator()->get('YourClass');
$moduleManager->getEventManager()->attach(
MvcEvent::EVENT_BOOTSTRAP, array(ClassX, 'StaticMethodOfClassX'), 20000);
}
Are you using ZfcBase in your application? The AbstractModule has a boostrap method (not onBootstrap) which is executed by this event handler in the init method
$sharedManager->attach('Zend\Mvc\Application', 'bootstrap', function($e) use ($instance, $moduleManager) {
$app = $e->getParam('application');
...
$instance->bootstrap($moduleManager, $app);
});
Of course you can use this approach without ZfcBase.
Then you can implement Zend\ServiceManager\ServiceLocatorAwareInterface:
public function bootstrap(\Zend\ModuleManager\ModuleManager $moduleManager, \Zend\Mvc\ApplicationInterface $app){
$this->setServiceLocator($app->getServiceManager());
parent::bootstrap($moduleManager, $app);
}
public function setServiceLocator(\Zend\ServiceManager\ServiceLocatorInterface $serviceLocator){
$this->_serviceLocator = $serviceLocator;
return $this;
}
public function getServiceLocator(){
return $this->_serviceLocator;
}
Maybe a bit later but hope it will help somebody else. At the init point there is no much services at the Service Manager but you can access it:
public function init(ModuleManager $moduleManager)
{
$sm = $moduleManager->getEvent()->getParam('ServiceManager');
$applicationConfig = $sm->get('applicationconfig');
var_dump($applicationConfig['modules']);
}
In this case we are retrieving the module names.
This is better idea.
class module
public function onBootstrap(MvcEvent $e)
{
$sm = $app->getServiceManager();
$config = $sm->get('config');
and this is all.

Observe customer account verification event in Magento

Is there a way to catch the event when the customer verifies it's account? I need this feature to enable user's access to other integrated subsystem
Since confirmAction() doesnt seem to fire any events in
/app/code/core/Mage/Customer/controllers/AccountController.php
You could do either
Overriding Frontend Core Controllers to create you own event using Mage::dispatchEvent() or add code directly to confirmAction in AccountController.php
Use #Pavel Novitsky answer but you may need to check that you are on the confirm account controller or check for the changing of email verification flag, because this event will trigger every time a customer information is change/updated
eg
public function myObserver(Varien_Event_Observer $observer)
{
if(Mage::app()->getRequest()->getControllerName() == '....account_confirm'){
$customer = $observer->getCustomer();
....
}
}
Every model has standard load_before, load_after, save_before, save_after, etc. events. Look at the Mage_Core_Model_Abstract to get the list of all predefined events.
For customers you can use customer_save_after event. In observer check original data vs new data:
public function myObserver(Varien_Event_Observer $observer)
{
$customer = $observer->getCustomer();
$orig_active_flag = $custoner->getOrigData('is_active');
$new_active_flag = $customer->getData('is_active');
// do something here …
return $this;
}
Even you can create your own event after customer vefication using below code.
Mage::dispatchEvent('Yuor_Unique_Event_Name', array());
Now using this event you can do anything you want.

Anyway to redirect to previous URL after registration in Joomla?

I am developing a component that required login at some level, then if user is not logged in, I placed a login link, that take user to login page with following in query string.
return=<?php echo base64_encode($_SERVER['REQUEST_URI']);?>
After login, it comes back to that page, but is there some way to tackle this if user is not registered and user starts registering? Is there some way to do this without changing some thing in Joomla it self? like by just setting some thing in cookie e.t.c. Or I will need to change some thing in Joomla Registration component or module. Or is there some plugin for that?
Any response will be appreciated, please tell what ever way you know so that it may give me some better clue.
In your component you could try to store the referrer in the Joomla! session - I don't believe the session changes or is replaced during login. I haven't had time to try this but it should work.
To Save:
$session = JFactory::getSession();
$session->set('theReferrer', $_SERVER['HTTP_REFERER'], 'mycomponentname');
To Retrieve:
$session = JFactory::getSession();
$redirectTo = $session->get('theReferrer', '', 'mycomponentname');
Then you can just use a setRedirect before you return.
$this->setRedirect($redirectTo);
You can achieve this with a plugin (at least in Joomla 3.x - not sure how far back this will work off-hand). Key here is the onUserAfterSave event, which tells you whether the user is new or existing.
I wrote the code below some time ago, so can't recall the exact reason the redirect could not be done from within the onUserAfterSave event handler, but I think the redirect is subsequently overridden elsewhere in the core Joomla user management code if you try to do it from there, hence saving a flag in the session and checking it in a later event handler.
class PlgUserSignupRedirect extends JPlugin
{
public function onUserAfterSave($user, $isnew, $success, $msg)
{
$app = JFactory::getApplication();
// If the user isn't new we don't act
if (!$isnew) {
return false;
}
$session = JFactory::getSession();
$session->set('signupRedirect', 1);
return true;
}
function onAfterRender() {
$session = JFactory::getSession();
if ($session->get('signupRedirect')) {
JFactory::getApplication()->redirect($_SERVER['HTTP_REFERER']);
$session->clear('signupRedirect');
}
}
}

Resources