Yii framework: access rules not working properly - frameworks

I have problem with access control. I have rule:
array('deny',
'actions'=>array('index'),
'expression'=>'Yii::app()->user->isRegistered()',
'deniedCallback' => array(
$this->render('//site/info',array(
'message'=>'You must activate your account.'
)
),Yii::app()->end()),
),
function:
public function isRegistered()
{
return (Yii::app()->user->isGuest) ? FALSE : $this->level == 1;
}
If I login as admin and i have level 3, isRegistered() return false, but deniedCalback runs.
How to change this to run callback only when expression is true?

You need to specify the callback as callable. The way you wrote it, it will always execute the code you have in that array. You should better write a dedicated method in the controller.
array('deny',
'actions'=>array('index'),
'expression'=>'Yii::app()->user->isRegistered()',
'deniedCallback' => array($this, 'accessDenied'),
),
// ...
public function accessDenied()
{
$this->render('//site/info', array(
'message' => 'You must activate your account.'
));
Yii::app()->end(); // not really neccessary
}

Related

Data not posted for custom operation

I've got very big trouble with custom operations in Laravel backpack.
The documentated setup is clear but lack a real exemple with a form.
In my case I wanted to use the form engine to create a form for a relationship.
First step I did this :
public function getProtocoleForm($id)
{
// Config base
$this->crud->hasAccessOrFail('update');
$this->crud->setOperation('protocole');
//
$this->crud->addFields([
[ 'name' => 'codeCim',
'type' => 'text',
'label' => 'Code CIM',
],
]);
$this->crud->addSaveAction([
'name' => 'save_action_protocole',
'visible' => function($crud) {
return true;
},
'button_text' => 'Ajouter le procotole',
'redirect' => function($crud, $request, $itemId) {
return $crud->route;
},
]);
// get the info for that entry
$this->data['entry'] = $this->crud->getEntry($id);
$this->data['crud'] = $this->crud;
$this->data['saveAction'] = $this->crud->getSaveAction();
$this->data['title'] = 'Protocole ' . $this->crud->entity_name;
return view('vendor.backpack.crud.protocoleform', $this->data);
}
This is working fine, the form appears on the screen, then I did a setup for a post route like this :
Route::post($segment . '/{id}/protocolestore', [
'as' => $routeName . '.protocolestore',
'uses' => $controller . '#storeProtocole',
'operation' => 'protocole',
]);
The route appears correctly when I execute the artisan command but the storeProtocole function is never called. I checked the generated HTML and the form action is correct and checking in the "network" panel of the browser is also targeting the correct route.
Can you help me and tell me where I missed something ?
[Quick update] I made a mistake, the form route is not good in the HTML, it takes the route of the main controller.

Codeigniter Form validation: Stop validating following rules if a rule fails

This is my controller method to process the user input
function do_something_cool()
{
if ($this->form_validation->run() === TRUE)
{
// validation passed process the input and do_somthing_cool
}
// show the view file
$this->load->view('view_file');
Validation Rules are as follow:
<?php
$config = array(
'controller/do_something_cool' => array(
array(
'field' => 'email',
'label' => 'Email',
'rules' => 'trim|required|valid_email|callback_check_email_exists',
)
)
);
My problem:
If the user input is not a valid email, the validation rule is not stopping from executing the next rule, that is callback function in this case. Therefore, even if the email is not valid, I am getting the error message for check_email_exists() callback.
Is there any option in CI to stop checking the other rules if a rule failed?
From system/libraries/Form_validation.php's _prepare_rules() method,
"Callbacks" are given the highest priority (always called), followed
by 'required' (called if callbacks didn't fail), and then every next
rule depends on the previous one passing.
That means, the input will be validated against the callbacks first. So we will have to check the input within the callback function itself.
For the above case, I have modified my callback function as follows
function check_email_exists($email)
{
if ($this->form_validation->valid_email($email) === FALSE)
{
$this->form_validation->set_message('check_email_exists', 'Enter a valid email');
return FALSE;
}
// check if email_exists in the database
// if FALSE, set validation message and return FALSE
// else return TRUE
}

Yii2 rest: checkAccess on restAction

After tackling this other question we would now like to check if the authenticated user can view, update or delete an existing record. Since checkAccess() is called by default in all restActions the following seemed the most logic thing to try:
public function checkAccess($action, $model = null, $params = []) {
if(in_array($action, ['view', 'update', 'delete'])) {
if(Yii::$app->user->identity->customer->id === null
|| $model->customer_id !== Yii::$app->user->identity->customer->id) {
throw new \yii\web\ForbiddenHttpException('You can\'t '.$action.' this item.');
}
}
}
But the API seems to ignore this function. We added this function in our controller. The actions (view, update and delete) are the default restActions.
Our BaseController sets actions like this:
...
'view' => [
'class' => 'api\common\components\actions\ViewAction',
'modelClass' => $this->modelClass,
'checkAccess' => [$this, 'checkAccess'],
'scenario' => $this->viewScenario,
],
...
Are we forgetting something?
Just add the following inside your custom action before executing any other code as it was done in the default view action (see source code here):
if ($this->checkAccess) {
call_user_func($this->checkAccess, $this->id, $model);
}
note: $this->checkAccess is defined in parent yii\rest\Action so your custom ActionView class need to either extend yii\rest\Action or redefine the variable public $checkAccess;
We obviously should have seen that the viewAction is not the default but an altered api\common\components\actions\ViewAction ... Not sure how we missed that...

How to set up Omnipay with Laravel?

I am using this packet:
https://github.com/barryvdh/laravel-omnipay
In my controller I added:
$params = [
'amount' => '10',
'issuer' => 22,
'description' => 'desc',
'returnUrl' => URL::action('PurchaseController#returnApi', [43]),
];
$response = Omnipay::purchase($params)->send();
if ($response->isSuccessful()) {
// payment was successful: update database
print_r($response);
} elseif ($response->isRedirect()) {
// redirect to offsite payment gateway
return $response->getRedirectResponse();
} else {
// payment failed: display message to customer
echo $response->getMessage();
}
Here is my omnipay.php conf file:
<?php
return array(
/** The default gateway name */
'gateway' => 'PayPal_Express',
/** The default settings, applied to all gateways */
'defaults' => array(
'testMode' => true,
),
/** Gateway specific parameters */
'gateways' => array(
'PayPal_Express' => array(
'username' => '',
'landingPage' => array('billing', 'login'),
),
),
);
But get this error:
call_user_func_array() expects parameter 1 to be a valid callback,
class 'Omnipay\Common\GatewayFactory' does not have a method
'purchase'
Anyone can help me set this?
I created app on paypal and have details about it but don't know how to set it with this API...
I recommend that you switch from PayPal Express to PayPal REST. It is newer and has better documentation.
I have looked through the laravel-omnipay package and I can't see a use case for it. I would just code to the omnipay package directly.
I recommend that you create a unique transaction ID for each transaction and provide that as part of the URLs for returnUrl and cancelUrl so that you can identify which transaction you are dealing with in the return and cancel handlers.
I think that you are taking the examples in the laravel-omnipay package too literally. You don't need or want those echo statements there. You should be capturing the response from purchase() even if it is a redirectResponse and doing a getTransactionReference() check on it, because you will need that transaction reference later, e.g. for transaction lookup. You should store it in the transaction record that you created before calling purchase().
You may use
use Omnipay\Omnipay;
in your controller, change it to
use Omnipay;

How to disable filter of a field in Zend Framework 2 in the controller?

Form to add/edit user I get from service manager with already installed filter, which is the test password. But this password is not needed when the user is edited. Can I somehow disabled password field validation in the controller?
In the getServiceConfig function of the module:
// ....
'UserCRUDFilter' => function($sm)
{
return new \Users\Form\UserCRUDFilter();
},
'UserCRUDForm' => function($sm, $param, $param1)
{
$form = new \Users\Form\UserCRUDForm();
$form->setInputFilter($sm->get('UserCRUDFilter'));
return $form;
},
// ....
In the controller I first of all getting a form object from service manager:
$form = $this->getServiceLocator()->get('UserCRUDForm');
Then disable user password validation and requirements, when user is edited and password not specified:
if ($user_id > 0 && $this->request->getPost('password') == '') {
$form->.... // Someway gained access to the filter class and change the password field validation
}
And after this i make a validation:
$form->isValid();
I found it!
// If user is editted - clear password requirement
if ($user_id > 0) {
$form->getInputFilter()->get('password')->setRequired(false);
$form->getInputFilter()->get('confirm_password')->setRequired(false);
}
This lines is disables requirement of input form fields :)
if you like to set all validators by yourself, call inside your form class
$this->setUseInputFilterDefaults(false);
to disable auto element validations/filter added from zend.
if you like to remove filter from elements call in your controller after your form object this
$form->getInputFilter()->remove('InputFilterName');
$form->get('password')->removeValidator('VALIDATOR_NAME'); should do the trick.
Note that you may have to iterate trough the Validatorchain when using Fieldsets.
$inputFilter->add(array(
'name' => 'password',
'required' => true,
'allow_empty' => true,
));
And on ModeleTable: saveModule:
public function saveAlbum(Album $album)
{
$data = array(
'name' => $album->name,
);
if (isset($album->password)){
$data['password'] = $album->password;
}