Help for integrating the Laravel package
Forum rules: Always add your Laravel, Aimeos and PHP version as well as your environment (Linux/Mac/Win)
#2108 by swpierce
25 Nov 2015, 17:45
Trying to secure the /admin routes. Not working at all.

Here's what I've tried:

Attempt #1: Put this in App\Http\routes.php:

Code: Select allRoute::get('admin', array(
    'as' => 'aimeos_shop_admin',
    'middleware' => 'auth',
    'uses' => 'Aimeos\Shop\Controller\AdminController@indexAction',
));

Route::get('admin/do', array(
    'as' => 'aimeos_shop_admin_json',
    'middleware'=> 'auth',
    'uses' => 'Aimeos\Shop\Controller\AdminController@doAction'
));

Route::get('admin/file', array(
    'as' => 'aimeos_shop_admin_file',
    'middleware' => 'auth',
    'uses' => 'Aimeos\Shop\Controller\AdminController@fileAction'
));


Guest still allowed to /admin

Attempt #2: put this in App\Http\routes.php:

Code: Select allRoute::group(config('shop.routes.admin', ['middleware'=>'auth']), function() {

   Route::match( array( 'GET' ), 'admin/file', array(
      'as' => 'aimeos_shop_admin_file',
      'uses' => 'Aimeos\Shop\Controller\AdminController@fileAction'
   ));
   Route::match( array( 'POST' ), 'admin/do', array(
      'as' => 'aimeos_shop_admin_json',
      'uses' => 'Aimeos\Shop\Controller\AdminController@doAction'
   ));
   Route::match( array( 'GET' ), 'admin', array(
      'as' => 'aimeos_shop_admin',
      'uses' => 'Aimeos\Shop\Controller\AdminController@indexAction'
   ));

});


Guest still allowed to /admin

Attempt #3: changed vendor\aimeos-laravel\src\routes.php to read:

Code: Select allRoute::group(config('shop.routes.admin', ['middleware' => 'auth']), function() {

   Route::match( array( 'GET' ), 'admin/file', array(
      'as' => 'aimeos_shop_admin_file',
      'uses' => 'Aimeos\Shop\Controller\AdminController@fileAction'
   ));
   Route::match( array( 'POST' ), 'admin/do', array(
      'as' => 'aimeos_shop_admin_json',
      'uses' => 'Aimeos\Shop\Controller\AdminController@doAction'
   ));
   Route::match( array( 'GET' ), 'admin', array(
      'as' => 'aimeos_shop_admin',
      'uses' => 'Aimeos\Shop\Controller\AdminController@indexAction'
   ));

});


Guest still allowed access to /admin

Attempts #4/5/6: repeated all of the above but changed the controller name to MyController (which doesn't exist and should have broken something):
example:
Code: Select allRoute::group(config('shop.routes.admin', ['middleware' => 'auth']), function() {

   Route::match( array( 'GET' ), 'admin/file', array(
      'as' => 'aimeos_shop_admin_file',
      'uses' => 'MyController@fileAction'
   ));
   Route::match( array( 'POST' ), 'admin/do', array(
      'as' => 'aimeos_shop_admin_json',
      'uses' => 'MyController@doAction'
   ));
   Route::match( array( 'GET' ), 'admin', array(
      'as' => 'aimeos_shop_admin',
      'uses' => 'MyController@indexAction'
   ));

});


/admin still works AND Guest still allowed to /admin

Just to be sure, after each of the above changes, ran php artisan aimeos:cache and php artisan clear-compiled

I should at least be able to get the login page to display if accessing as guest?
#2111 by swpierce
27 Nov 2015, 02:02
So I got it working but not ideally. If I upgrade Aimeos, I'll lose it.

I started out trying to override the AdminController in the aimeos-laravel package but that seemed too much of a hassle.

Here's what worked (not an ideal solution but something that lets us deploy this week):

1) Created a Laravel migration for a model called Employee (table is just id and user_id with foreign key on user_id pointing to users).
2) The ORM stuff kept going into a loop if I put the methods in for a one-to-one relationship so I threw out the ORM stuff and wrote a super-simple method in App\User :
Code: Select allpublic function isAdmin() {
    return Employee::where('user_id', $this->id)->count();
}

3) In the boot method of App\Providers\AuthServiceProvider
Code: Select all$gate->define('admin', function($user) {
    return $user->isAdmin();
}

4) In aimeos-laravel package, edited Aimeos\Shop\Controller\AdminController and added the following line to the beginning of indexAction doAction and fileAction
Code: Select all$this->authorize('admin');

5) The above causes an HttpException to be thrown with a status code of 403. To handle redirecting somewhere decent, I changed App\Exception\Handler.php and added the following at the beginning of the render method:
Code: Select allif ($e->getStatusCode() == '403') {
    return redirect('unauthorized');
}

6) Lastly, I defined the 'unauthorized' route in App\Http\routes.php
Code: Select allRoute::get('unauthorized', array(
    'as' => 'aimeos_ship_unauth',
    'uses' => 'PageController@unauthorizedAction'
));

PageController is a very simple controller that handles routing to a few pages we have that we want to put Aimeos components on
7) Set up the page in config\shop.php so that it includes the basket/mini and the catalog/filter (though I couldn't tell you the reasoning behind that at this point, other than maybe consistency of appearance)

It works. I point the browser to /admin and, if I'm not logged in as as Employee, I get redirected. We're manually editing the employee table currently (our company is less than 10 people) but it seems it would be simple to add a boolean field to the users table and modify the AdminController to check a config setting to determine if people want to use the ACL stuff. Maybe something like:
Code: Select allif getConfigValue('shop.useacl') {
    $this->authorize('admin');
}
#2113 by aimeos
27 Nov 2015, 14:48
swpierce wrote:modify the AdminController to check a config setting to determine if people want to use the ACL stuff. Maybe something like:
Code: Select allif getConfigValue('shop.useacl') {
    $this->authorize('admin');
}


OK, we will add this to the admin controller :-)
#2118 by aimeos
28 Nov 2015, 10:51
We've talked a bit internally and came up with another solution that requires less changes (hopefully) :-)

How to setup a login in Laravel is already described here: http://laravel.com/docs/5.1/authentication/.
It is based on the standard user table we are extending by additional columns.

Our thought was that support for user groups is already there in Aimeos. If we create a user group "admin" during setup and developers create or register a new user, they only have to associate the "admin" group to that new user in the admin interface before they activate the authorization checks. The missing part is then only how the check must look like to see if
- users.id = users_list.parentid and
- users.list.domain = 'customer/group' and
- users_list.refid = mshop_customers_group.id and
- mshop_customers_group.code = 'admin'
for
Code: Select all$gate->define('admin', function($user) {
    return ...;
}

Do you know what's the easiest solution for this check in Laravel?
#2123 by swpierce
28 Nov 2015, 23:23
If there are Aimeos objects that can do the job, it should be easy enough to use those with the AuthServiceProvider closure?

Maybe something like:
Code: Select allUse Aimeos\whatever\group\manager;
$gate->define('admin', function($user) {
    $manager = getAimeosManager();
    return $manager->isUserInAdminGroup($user);
}


I'll dig a little deeper after I've pushed our site to production. Missed our Black Friday launch we wanted so... :?
#2125 by aimeos
29 Nov 2015, 18:10
We've pushed the Aimeos Laravel package to a new level (to be more precise: require Laravel 5.1.11 or later) by implementing the authorization stuff :-)

Steps to do to protect the admin interface:

1.) Setup login/register stuff like described in http://laravel.com/docs/5.1/authentication

2.) Create a new admin user with:
Code: Select all./artisan aimeos:account <email> --admin

3.) In the boot method of your App\Providers\AuthServiceProvider
Code: Select all$gate->define('admin', function($user) {
    return app( '\Aimeos\Shop\Base\Support' )->checkGroup( $user->id, 'admin' );
});


Basically, that's it! It works with the latest dev-master code and will be in version 2.0 of the Aimeos Laravel package.