Page 1 of 1

Adapting existing routes

Posted: 25 Nov 2015, 17:45
by swpierce
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 all

Route::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 all

Route::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 all

Route::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 all

Route::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?

Re: Adapting existing routes

Posted: 25 Nov 2015, 18:05
by aimeos
That'a a bit more complicated in Laravel ;-)

Since Laravel 5.1.11, there's an authorization service available: http://laravel.com/docs/5.1/authorization
If you get it to work, we would be happy if you could post a small tutorial :-)

Re: Adapting existing routes

Posted: 27 Nov 2015, 02:02
by swpierce
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 all

public 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 all

if ($e->getStatusCode() == '403') {
    return redirect('unauthorized');
}
6) Lastly, I defined the 'unauthorized' route in App\Http\routes.php

Code: Select all

Route::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 all

if getConfigValue('shop.useacl') {
    $this->authorize('admin');
}

Re: Adapting existing routes

Posted: 27 Nov 2015, 14:48
by aimeos
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 all

if getConfigValue('shop.useacl') {
    $this->authorize('admin');
}
OK, we will add this to the admin controller :-)

Re: Adapting existing routes

Posted: 28 Nov 2015, 10:51
by aimeos
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?

Re: Adapting existing routes

Posted: 28 Nov 2015, 23:23
by swpierce
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 all

Use 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... :?

Re: Adapting existing routes

Posted: 29 Nov 2015, 18:10
by aimeos
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.

Re: Adapting existing routes

Posted: 30 Nov 2015, 04:34
by swpierce
That's awesome. Thanks! :D