Zend auth inside doctrine2 entity repository - zend-framework

I am trying to create a method inside a doctrine 2 entity in zend framework. It is just to keep the code DRY. I want to retrieve the user object if they are logged in, and FALSE other wise:
public function getCurrentUserId() {
//returns false if not logged in, user object otherwise
$auth = Zend_Auth::getInstance();
$id = $auth->getidentity();
$user = $this->_em->getRepository('Entities\User')
->findOneByid($id);
if (is_null($user))
return false;
else
return $user;
}
}
This works fine within a controller action, but causes the following error here:
PHP Fatal error: Doctrine\Common\ClassLoader::loadClass(): Failed opening required '/var/www/myswap/application/models/Repositories/Zend_Auth.php'
Why, and how can I avoid this?

I'm going to take a guess and assume you're using namespaces since it looks like that.
On the line where you use Zend_Auth, prefix it with a \ - eg. $auth = \Zend_Auth::getInstance();
The reason for this is that namespaces in PHP are relative. Thus, if you try to use just Zend_Auth it assumes you want an object in the current namespace. By prefixing it with a \, you're telling it you want Zend_Auth from root.
I'd suggest familiarizing yourself with the namespaces manual page

Related

How to Disallow User Access to CRUD Backend

I've got Backpack for Laravel installed and have been using it for some time as an admin back end on a project. I'm also using the spatie/permission module (might come with Backpack, can't remember) to create users for the front end.
Currently, all users are able to access both front end and back end regardless of the group they belong to. I'd like to change that so that only members in an "admin" group are able to access the back end. I've followed the instructions here for separating front end and back end sessions but that's not really what I want as all users are still able to access both sites of the project.
I'm guessing I need to add a guard to the CRUD routes but I'm finding it to be much harder than it should be. Any pointers on how to do this would be greatly appreciated. TIA.
You can create a new middleware and use it in your routes group for admin routes.
To create a new middleware use the php artisan command like so: (you can name the new middleware what ever you want:
php artisan make:middleware RequireAdminRole
Now, inside your new middleware, on the handle function you can have something like this that returns a 403 Forbidden error message:
public function handle($request, Closure $next)
{
$user = auth()->user();
if (!$user) return $next($request);
if (!$user->hasRole('Admin'))
{
// if your sessions are decoupled from the frontend
// you can even logout the user like so:
// auth()->logout();
abort(403, 'Access denied');
}
return $next($request);
}
Here we are using the hasRole method, but there are more that you can use. See the spatie/laravel-permissions documentation for more info.
Now, let's assign this middleware a 'name' so we can use it in our route groups for the admin. Inside the App\Kernel.php file, in the end, inside the $routeMiddleware array add it and give it a new, for example:
'isadmin' => \App\Http\Middleware\RequireAdminRole::class,
And finally, you can add this middleware to your admin routes group (which should be in custom.php file if you're using latest backpack 3.4 version) :
Route::group([
'prefix' => 'admin',
'middleware' => ['web', 'isadmin', config('backpack.base.middleware_key', 'admin')],
'namespace' => 'App\Http\Controllers\Admin',
], function () {
// your routes are here
});
Now all your requests to the admin routes should be protected by the user role check.
Please let us know how it went for you, and if you encountered any issues.
Best regards,
~Cristian

manually submitting symfony form results in CSRF error

I would like to be able to manually submit a symfony form with data I create but it seems I am missing the CSRF token in the submitted data and so the validation fails.
The form is simple - just one field (let's say 'name' for argument) as a text field with no constraints.
$data = [];
if ($someCondition) {
$data['name'] = 'steve';
}
$form = $this->createForm('FooType', $data);
if (!empty($data)) {
$form->submit($data);
} else {
$form->handleRequest($request);
}
if ($form->isSubmitted() && $form->isValid()) {
// do something
}
if I set $data['name'] the form submits but I get The CSRF token is invalid. Please try to resubmit the form.
so obviously, I am missing the token. I know I can disable the CSRF protection, but I don't want to do this as there is also an option to 'normally' interact with the form.
How to I submit a proper token or override this behavior?
I see you tagged this as symfony2 question. With that in mind, you can supply a valid CSRF token by injecting it into your data, thought, solution differ in <2.6 and >=2.6 version, as far as I'm aware.
Pre 2.6 version:
$provider = $this->get('form.csrf_provider');
$token = $provider->generateCsrfToken(''); // INTENTION = empty_string, by default
$data['<<YOUR_FORM_NAME']['_token'] = $token; // be sure to change the form name
Versions 2.6+
The thing is a bit different as forms now use TokenManagerInterface provided by Security component:
$tokenId = ....;
$token= (string) $this->get('security.csrf.token_manager')->getToken($tokenId);
$tokenValue = $token->getValue();
Now, the $tokenId can be many things, as described in a Form's public test:
$tokenId = $options['csrf_token_id'] ?:
($form->getName() ?:
get_class($form->getConfig()->getType()->getInnerType()));
But if you look into this, the default will be $form->getName(), up until 2.8. I think that 2.8 removed abstraction from the getName() method, thus, the 2.8 and later will user the clunky value:
get_class($form->getConfig()->getType()->getInnerType())
This all holds true, unless you injection csrf_token_id option in your form type.
UPDATE:
Ok, so it seems my bad presumption was about the token key. While you did get the valid token, that one was not used. In my example, I had separate FormType namespaced AppBundle\Form\SomeFooType and the actual token id that was used was some_foo.
I have made a pastebin of the working example (version 2.8.8, same worked in 3.1.2 as expected): http://pastebin.com/ks2jSeh7
Hope this helps a bit.

Silverstripe Login params

Im trying to style my login page. My login url is website/Security/login. Im trying to locate the 'login' piece of the url. What have i done wrong below?
public function DisplayPageType() {
$param = $this->request->param('Action');
if ($param === 'login')
{
return 'Login';
}
Thanks
I think that won't work since the controller during render is the Page_Controller and not the Security controller. So the $Action param is not equal to login. It could be index, I'm not sure.
If you just want to check if you're in the login page, you can add this to your Page_Controller:
public function getIsLoginPage()
{
return $_REQUEST['url'] == '/Security/login';
}
Then in your template:
<body class="<%if $IsLoginPage %>login-page<% end_if %>">
A bit dirty but it's the quickest way I know.
Another way is to leverage SilverStripe's legacy support. You can add a css file called tabs.css at mysite/css/tabs.css. If this file exists, SilverStripe will include this in the page.
You can also create templates that SilverStripe will automatically use if they exist:
themes/<theme_name>/Security.ss - If you want your login page to use an entirely different layout.
themes/<theme_name>/Layout/Security_login.ss - If you want to change just the content part (the $Layout section)
I hope this helps.
#gpbnz is right, the $Action param is not equal to login, it actually returns null as accessing $this->request from the Page_Controller when accessing the Security/login returns a NullHTTPRequest.
To get the action, you will want to get the current controller using Controller::curr(). It is then as simple as calling getAction on this controller.
To confirm that the action isn't from a random controller that happens to have an action called login, you can check the instanceof the controller like so: Controller::curr() instanceof Security
This check will still allow it to work for any controller that extends Security though which may/may not happen depending on the project.
I would stick away from actually reading the URL for the information manually though as that can create issues with maintainability in the future.
To bring this to a nice little function:
public function isLoginPage()
{
$controller = Controller::curr();
return $controller instanceof Security && $controller->getAction() == 'login';
}
Otherwise #gpbnz had a good suggestion of using the template system to your advantage for overriding not only the styles but the HTML around it.

Dealing with Zend Auth Data when using zend modules

I am working on zend module based structure for my project. As Zend_Auth class' default session storage is Zend_Auth. I changed according to module being called. Say for admin I use auth namespace Admin_Auth and for default module i use namespace name Default_Auth.
$auth = Zend_Auth::getInstance();
$auth->setStorage(new Zend_Auth_Storage_Session('Admin_Auth'));
I am doing this because, if I do Zend_Session::destroy() it will destroy complete session even for Default Module. and so using namespace and so at logout Zend_Session::namespaceUnset('Admin_Auth');
each time in different controller I have to use
$auth = Zend_Auth::getInstance();
$auth->setStorage(new Zend_Auth_Storage_Session('Admin_Auth'));
just to point corresponding session data.
I am considering to move it in module's Bootstrap.php like
protected function _initAuth(){
$auth = Zend_Auth::getInstance();
$auth->setStorage(new Zend_Auth_Storage_Session('Admin_Auth'));
return $auth;
}
First, is that proper way?
Second, If it is then how can I access the return value $auth of _initAuth() in each controller? Please

How to Pass data/variables/objects to Zend_Controller_Plugin

I am converting an old ZF app (its using an early ZF version where we used to do manual app loading/config in the index.php) to latest version, and in one of the plugin we are sending data directly to the plugin constructor
$front->registerPlugin(new My_Plugin_ABC($obj1, $obj2))
Now in the current version we can register a plugin by directly providing the details in the application.ini and I want to stay with this approach(registering using config file). So while testing, I noticed the the plugin constructor is called fairly early in the bootstrapping, so the only option I am left with is using Zend_Registry to store the data, and retrieve it in the hooks. So is it the right way? or are there any other better ways
EDIT
The plugin was actually managing ACL and Auth, and its receiving custom ACL and AUTH objects. Its using the preDispatch hook.
Okay so you could consider you ACL and Auth handlers as a some application resources, and be able to add configuration options for them in you application.ini
//Create a Zend Application resource plugin for each of them
class My_Application_Resource_Acl extends Zend_Application_Resource_Abstract {
//notice the fact that a resource last's classname part is uppercase ONLY on the first letter (nobody nor ZF is perfect)
public function init(){
// initialize your ACL here
// you can get configs set in application.ini with $this->getOptions()
// make sure to return the resource, even if you store it in Zend_registry for a more convenient access
return $acl;
}
}
class My_Application_Resource_Auth extends Zend_Application_Resource_Abstract {
public function init(){
// same rules as for acl resource
return $auth;
}
}
// in your application.ini, register you custom resources path
pluginpaths.My_Application_Resource = "/path/to/My/Application/Resource/"
//and initialize them
resources.acl = //this is without options, but still needed to initialze
;resources.acl.myoption = myvalue // this is how you define resource options
resources.auth = // same as before
// remove you plugin's constructor and get the objects in it's logic instead
class My_Plugin_ABC extends Zend_Controller_Plugin_Abstract {
public function preDispatch (Zend_Controller_Request_Abstract $request){
//get the objects
$bootstrap = Zend_Controller_Front::getInstance()->getParam("bootstrap");
$acl = $bootstrap->getResource('acl');
$auth = $bootstrap->getResource('auth');
// or get them in Zend_Registry if you registered them in it
// do your stuff with these objects
}
}
Acl is needed so many other places hence storing it in Zend_Registry is cool thing to do and since Zend_Auth is singleton so you can access it $auth = Zend_Auth::getInstance() ; anywhere you like so no need for auth to be stored in registry .
Lastly if you have extended Zend_Acl class for your custom acl its better to make it also singleton . Then you can access acl My_Acl::getInstance(); where My_Acl is subclass of Zend_Acl .