Silex Defining Access Rules - php

I follow the Silex documention section http://silex.sensiolabs.org/doc/providers/security.html#defining-access-rules
And here is my confirguration
'security.role_hierarchy' => [
'ROLE_ADMIN' => [
'ROLE_USER',
],
'ROLE_SUPER_ADMIN' => [
'ROLE_USER',
'ROLE_ADMIN',
'ROLE_ALLOWED_TO_SWITCH'
]
],
'security.access_rules' => [
[ '^.*$', 'IS_AUTHENTICATED_ANONYMOUSLY' ],
[ '^/account', 'ROLE_USER' ],
[ '^/admin', 'ROLE_ADMIN' ]
]
So what I need is quite simple, an anonymous user can access everywhere (except the /account/* and /admin/* paths), a user with "ROLE_USER" can access averywhere and /account/* paths, but not /admin/* paths, and a user with "ROLE_ADMIN" can access everywhere.
I make a very basic controller to test if a user is redirected if he's not a "ROLE_ADMIN":
$app->get('/admin', function () use ($app) {
return 1;
})->bind('admin');
But not at all. He can acces to /admin, with a printed "1" on the page...
According to the doc:
With the above configuration, users must have the ROLE_ADMIN to access the /admin section of the website [...] (if that's not the case, the user will be automatically redirected).

Definitely the order of the rules is important, only one will be matched. Silex will look at each starting at the top, and stop as soon as it finds one security.access_rules entry that matches the URL, in other words, Silex will decide which security.access_rules to use based on the URI and the first rule that matches is used. So you need move the first rule to end to resolve this:
'security.access_rules' => [
[ '^/account', 'ROLE_USER' ],
[ '^/admin', 'ROLE_ADMIN' ],
[ '^.*$', 'IS_AUTHENTICATED_ANONYMOUSLY' ],
]

Related

Why is a login via `auth guard A` redirected different than one from `auth guard B` when the same behaviour is expected?

First of all, i'm not a pro in PHP development or Laravel but will try to explain my question as well as possible for me. I also try to give enough information but when something is missing, please let me know whats missing and i will add it!
Some important context about my project:
Laravel 6.18 (will update soon if my first goal is reached)
I use Hyn/Multi-tenant to make my application mutli tenant.
I use a Vue front end, i give a bearer token to Vue via the app.js
The application should be a multi tenant application where each tenant has its own user table. I first built everything as "single tenant". When the basic functionality was implemented and worked fine, i added Hyn/MT to make it multi tenant, moved the tenant specific tables to the tenant db folder and updated the models. Now i know it was better to start with Hyn/MT before building all the functionality but so far i got everything working fine.
After i added the multi tenant support to my project and fixed the broken functionality i decided to add an admin specific area to manage the tenants. To achieve this i added a SystemU ser table to the master database which contains the admin users. After that i update my web.php so it gives the subdomain to the LoginController.guard() function. My code:
// web.php
Route::group(array('domain' => '{subdomain}.festipay.xlan'), function () {
Route::post('login', 'Auth\LoginController#login');
});
// LoginController.php
protected function guard()
{
if (Request::route("subdomain") == "admin") {
return Auth::guard('admin_web');
} else {
return Auth::guard('web');
}
}
I also updated my config/auth.php, it looks like this now:
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admin_web' => [
'driver' => 'session',
'provider' => 'admin_users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admin_users' => [
'driver' => 'eloquent',
'model' => App\SystemUser::class,
]
],
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
],
],
Except for the mentoined changes i did not implement any admin specific logic yet. So i expect that the admin users are handeled exactly the same except for the way they are authenticated.
The tenant users who log in to e.g. tenant_x.domain.com are redirected to /dashboard when they login and are redirected back to /login when they log out. The admin users who log in to admin.domain.com are not redirected to /dashboard when the login is successfull but are redirected back to /login again. Offcourse this is not the expected behaviour as it should be (currenly) the same as the tenant users (so a redirect to /dasboard when the login is succesfull)
I think that the authentication them selve works fine as the LoginController.attemptLogin() returns true when i use valid admin credentials and false (and view shows wrong credetials) when i use invalid credentials.
I found in this post that is may be a session issue and i tried to apply the solution mentoined in that post. Unfortunately did adding protected $primaryKey = 'id'; to the SystemUser class not solve the issue. I also compared the tenant User class with the SystemUser class but they are almost identical exccept for unimportant fields i removed from the SystemUser like address.
I have no idea how i can find out where the issue occurs or how to solve this. The goal is that an admin which logged in succesfully is redirect to another page as the /dashboard. Can someone help me find out what goes wrong? i'm already happy when someone can help me to get the same behaviour for the admin's as the tenants currently have.
Thanks in advance!
Update 1 #David Barker
When its about the session, i think this is important to know as well:
- I use a Vue front end, i give a bearer tokento Vue via theapp.js``
My session config:
<?php
use Illuminate\Support\Str;
return [
'driver' => env('SESSION_DRIVER', 'file'),
'lifetime' => env('SESSION_LIFETIME', 120),
'expire_on_close' => false,
'encrypt' => false,
'files' => storage_path('framework/sessions'),
'connection' => env('SESSION_CONNECTION', null),
'table' => 'sessions',
'store' => env('SESSION_STORE', null),
'lottery' => [2, 100],
'cookie' => env(
'SESSION_COOKIE',
Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
),
'path' => '/',
'domain' => env('SESSION_DOMAIN', null),
'secure' => env('SESSION_SECURE_COOKIE', false),
'http_only' => true,
'same_site' => null,
];
I did a dd($request->session();) in the LoginController->attemptLogin(); function, see the result bellow. The result is the same for both users except for the id and _token. (i cleaned the cookies before the login attempt in both cases)
Illuminate\Session\Store {#490 ▼
#id: "7WI7JUWPnS4pg3EHvaxk5TOKaM9l9UXJi1zJNKuG"
#name: "festipay_session"
#attributes: array:1 [▼
"_token" => "mtMWanYGMUxFHivOqAaEmVQnHDE0hvwKkHMgCswg"
]
#handler: Illuminate\Session\FileSessionHandler {#489 ▼
#files: Illuminate\Filesystem\Filesystem {#198}
#path: "/var/www/domain.com/storage/framework/sessions"
#minutes: "120"
}
#started: true
}
Maybe this is also interesting infomation. Left are the responses for the admin (after i clicked the login button) and right the working tenant login.
I finally found the issue. It was very easy to solve. I did not specify the auth guard for the Route::group.
It was like this:
Route::group(['middleware' => 'auth'], function () {
Route::get('/', function () { return redirect('/dashboard'); });
Route::get('/dashboard', function () { return view('dashboard'); })->name('dashboard');
Route::get('/logout', 'Auth\LoginController#logout')->name
I changed it to this to make it work:
Route::group(['middleware' => 'auth:system_user_web,web'], function () {
Route::get('/', function () { return redirect('/dashboard'); });
Route::get('/dashboard', function () { return view('dashboard'); })->name('dashboard');
Route::get('/logout', 'Auth\LoginController#logout')->name

Yii2 RBAC check permissions without each actions in controller

How i can check permissions in one place?
I don't want to check each function individually.
My RBAC controller.
I would like check permission for logged in user for all actions in the controller. Now I have to use Yii::$app->user->can('...') individually for each actions in the controller
$admin = $auth->createRole('Admin');
$moderator = $auth->createRole('Moderator');
$createPost=$auth->createPermission('createPost');
$updatePost=$auth->createPermission('updatePost');
$deletePost=$auth->createPermission('deletePost');
$createCategory=$auth->createPermission('createCategory');
$updateCategory=$auth->createPermission('updateCategory');
$deleteCategory=$auth->createPermission('deleteCategory');
$auth->add($admin);
$auth->add($moderator);
$auth->add($createPost);
$auth->add($updatePost);
$auth->add($deletePost);
$auth->add($createCategory);
$auth->add($updateCategory);
$auth->add($deleteCategory);
Here I assign role with permissions, but i never use these permissions because write manually in behavior->(like your example)
What is goal, create permissons in RBAC, if this not working? If I would like add premium user. I could only add action in controller e.g. actionPremium and set in behavior actions for premium user.
e.g
action=>['premium']
roles=>['premiumUser']
and one more question.
How in behavior customize message error?
$auth->addChild($admin,$moderator);
$auth->addChild($admin,$createCategory);
$auth->addChild($admin,$updateCategory);
$auth->addChild($admin,$deleteCategory);
$auth->addChild($moderator, $createPost);
$auth->addChild($moderator, $updatePost);
$auth->addChild($moderator, $deletePost);
$auth->assign($admin,1);
$auth->assign($moderator,2);
You can assign the permission allowed in controller for all action in behaviors
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'actions' => ['index','view'], // these action are accessible
//only the yourRole1 and yourRole2
'allow' => true,
'roles' => ['yourRole1', 'yourRole2'],
],
[ // all the action are accessible to superadmin, admin and manager
'allow' => true,
'roles' => ['superAdmin', 'admin', 'manager'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['post'],
],
],
];
}
The role you assigned in behaviors are for action .. allowd or deny .. the if a role had an allowed action in behaviors then he can execute otherwise he get permission denied 403 .. (not authorized) ..
You can also check the role in procedural code with
if ( Yii::$app->User->can('admin') ){
.....
yourdCode
....
}

How to access defined URL in Yii2

I have controller UserController and action actionAjax. I access by Chrome with below URL and it is working normally.
index.php?r=user/ajax
Now I define new action with named actionAjaxUser, still using Chrome to access URL index.php?user/ajaxUser
Then 404 returned.
What should I do to getting content of actionAjaxUser?
add for each additional uppercase Letter after "action" a "-" so in your case
index.php?r=user/ajax-user
So if you would have an action like actionTest1Test2Test3 the url would be controllername/test1-test2-test3.
Be aware that if you are using access rules you also have to use the "url" path.
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'actions' => ['test1-test2-test3'],
'allow' => true,
'roles' => ['#'],
],
],
],
];
The same Naming scheme is btw. also used for Controllers. E.g. if your Controller is named Test1Test2Controller the view folder name would be test1-test2.
Hope this clarifies this for you.

What are role providers?

How do I use zfc rbac role providers?
I understand guards prevent users from accessing routes but it seems like I need the role providers as well. Are these database permissions? In the example below is 'article' a controller and the part after the '.' the permission granted on that controller? How can I test these once in place? Many thanks.
return [
'zfc_rbac' => [
'role_provider' => [
'ZfcRbac\Role\InMemoryRoleProvider' => [
'admin' => [
'permissions' => [
'article.delete',
'article.edit',
'article.archive',
'article.read'
]
],
'member' => [
'permissions' => [
'article.edit',
'article.archive',
'article.read'
]
],
'guest' => [
'permissions' => ['article.read']
]
]
]
]
];
Here you can read about role providers
In ZF-Rbac one identity can have different roles with different permissions/privileges. To collect the roles for the authorizationService you need role providers. They will include a RoleProvicerInterface (link) with the getRoles method which is supposed to return the roles that the authorization service has to work with.
Each Identity has an IdentityInterface (link) which has also a getRoles method. This will return an array of roleNames which will be mapped to the roles from the RolesProvider to find out about permissions/privileges.
You can then find out what the current user (identity) is allowed to do.

Override Yii2 assetManager config in controller

I use yii-jui to add some UI elements in the views such as datePicker. In the frontend\config\main-local.php I set the following to change the theme used by the JqueryUI:
$config = [
'components' => [
'request' => [
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
'cookieValidationKey' => 'gjhgjhghjg87hjh8878878',
],
'assetManager' => [
'bundles' => [
'yii\jui\JuiAsset' => [
'css' =>
['themes/flick/jquery-ui.css'],
],
],
],
],
];
I tried the following to override this configuration item in the controller actions method:
public function actions() {
Yii::$app->components['assetManager'] = [
'bundles' => [
'yii\jui\JuiAsset' => [
'css' =>
['themes/dot-luv/jquery-ui.css'],
],
],
];
return parent::actions();
}
Also I tried to set the value of Yii::$app->components['assetManager'] shown above to the view itself (it is partial view of form _form.php) and to the action that calls this view (updateAction). However, all this trying doesn't be succeeded to change the theme. Is there in Yii2 a method like that found in CakePHP such as Configure::write($key, $value);?
You should modify Yii::$app->assetManager->bundles (Yii::$app->assetManager is an object, not an array), e.g.
Yii::$app->assetManager->bundles = [
'yii\jui\JuiAsset' => [
'css' => ['themes/dot-luv/jquery-ui.css'],
],
];
Or if you want to keep other bundles config :
Yii::$app->assetManager->bundles['yii\jui\JuiAsset'] = [
'css' => ['themes/dot-luv/jquery-ui.css'],
];
You are going about this all wrong, you want to change the JUI theme for 1 controller alone because of a few controls. You are applying 2 css files to different parts of the website that have the potential to change styles in the layouts too. The solution you found works but it is incredibly bad practice.
If you want to change just some controls do it the proper way by using JUI scopes.
Here are some links that will help you:
http://www.filamentgroup.com/lab/using-multiple-jquery-ui-themes-on-a-single-page.html
http://jqueryui.com/download/
In this way you are making the website easier to maintain and you do not create a bigger problem for the future than you what solve.

Categories