Cakephp 2 security in forms - forms

I have a question about the cakephp2 forms security. Let's assume that we have the Security Component enabled and have already build users authentication, permissions, and product management system.
We need to create an Offer Request feature, which allows users to ask for an offer for a specific product.
The user is logged in and clicks on "ask" and goes to /offer_requests/add/product_id
Scenario 1:
In the /Views/OfferRequests/add.ctp:
<?php
echo $this->Form->create('OfferRequest');
echo $this->Form->input('user_id',
array('value' => $this->Session->read('Auth.User.id'),
'type' => 'hidden' ));
echo $this->Form->input('product_id');
echo $this->Form->input('quantity');
echo $this->Form->end(__('Submit'));
?>
Scenario 2:
In the /Views/OfferRequests/add.ctp:
<?php
echo $this->Form->create('OfferRequest');
echo $this->Form->input('product_id');
echo $this->Form->input('quantity');
echo $this->Form->end(__('Submit'));
?>
And in the OfferRequestsController add():
<?php
$this->request->data['OfferRequest']['user_id'] = $this->Session->read('Auth.User.id');
?>
My question is which scenario is more safe, for example against making false requests as other user. For scenario 1, does the Security Component allow manipulating input values through Firebug or some other software?

Yes, the security component adds automatic prevention of form tampering:
From the docs:
By using the Security Component you automatically get CSRF and form
tampering protection. Hidden token fields will automatically be
inserted into forms and checked by the Security component. Among other
things, a form submission will not be accepted after a certain period
of inactivity, which is controlled by the csrfExpires time.
As stated in the other answer, you can use the fieldsList option when saving your data instead. With the security component, however, you would be able to add the user_id as a hidden field (scenario 1) and not worry about its value being tampered with. This would prevent the necessity to set it in the controller (scenario 2).

Related

CakePHP 2.3.1 deactivate form validation in certain views

The Cookbook introduces for version 2.3 the possibility to deactivate the forced valiadation for forms. Or at least I understood it like that:
Quote: from http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html
" New in version 2.3.
Since 2.3 the HTML5 required attribute will also be added to the input
based on validation rules. You can explicitly set required key in
options array to override it for a field. To skip browser validation
triggering for the whole form you can set option 'formnovalidate' =>
true for the input button you generate using FormHelper::submit() or
set 'novalidate' => true in options for FormHelper::create()."
In my case I have a search from for this model and of course the user does not need to fill in all mandatory fields like for adding a dataset. So I want to deactivate the validation for my search form.
I tried all three variations and see no results: Still the mandatory fields for create are mandatory in my search form.
Those attempts I made:
first try:
echo $this->Form->create('Partner', array('action' => 'search', 'novalidate' => true));
second try:
echo $this->Form->input('name',
array('required' => false, 'value' => $this->Session->read('Searchparameter.name'))
);
third try:
$this->Form->submit('Submit', array('formnovalidate' => true));
echo $this->Form->end();
variation:
echo $this->Form->end(__('Submit'), array('formnovalidate' => true));
What did I understand wrong? btw: I did deactivate caching, so that should not be the problem.
Of course I could still use the old workaround for this validation, but when 2.3 is offering this option, I would gladly use it.
Calamity Jane
So I guess I found the problem and at least got one varation working:
What I am using now is:
echo $this->Form->create('Partner', array('action' => 'search', 'novalidate' => true));
I guess what I expected was that the fields wouldn't be marked with the fat label and the asterisk. Those are still there, but regardless you don't have to fill them in anymore. And the times I tested with really submittig the form I guess I had one of the 99 varations, which was really wrong.
If that makes me happy is mine to decide, but obviously I can switch off the HTML5 validation by that.
If I would want to have the labels not bold & asterisk, is there an option, too?
Calamity Jane
The solution is actually a lot simpler. If you would like to disable validation in specific views you actually only have to refer to a non-existing model when you create the form. You could for example do something like
echo $this->Form->create('PartnerSearch');
In your controller you can access the form fields through:
$this->request->data["PartnerSearch"]["field"]
instead of the usual way:
$this->request->data["Partner"]["field"]
For me, to skip the browser validation, yes, array('novalidate' => true) does work.
<?php echo $this->Form->create('MyModelName', array('novalidate' => true)); ?>
To have the label not bold & asterisk,
<?php echo $this->Form->input('myinput', array('required' => false));
In my case I used button for submitting the form. This allowed me more flexibility. In that case I used then property 'formnovalidate' pass in the array of options for the button. The form would look something like the following:
<?php
echo $this->Form->create('yourCtrllerName',array('action'=>'actionInYourCtrller'));
echo $this->Form->input('your_field_pass',array('label'=>'pass','type'=>'password'));
.... other Form fields .....
echo $this->Form->button('Button Caption',
array('type'=>'submit',
'name'=>'keyInsideTheDataArrayForButtonData',
'formnovalidate' => true,
'value'=>'valueOfTheAboveKeyInTheDataArray',
'style'=>'<style you want to apply to button>',
... other options if needed...
)
);
echo $this->Form->end();

Joomla Form Field User Front End

I am trying to use JFormFieldUser::getInput as an input to my Joomla forms.
In the backend (logged in with the super user), when I call this method, it produces a nice 'select user' box when clicked displays a list of all users to chose from.
I have been trying to use the User form field on a front end form (logged in with the super user). The result is some what confusing and undesirable. A 'select user' link is produced, but when clicking on it, the result is that the super users, 'User profile' is loaded up: not a list of all users.
Why is this, and how can i make 'select user' show the full list of users like it does in the backend.
Joomla 3 (from your field definitions):
<field name="field_name" type="sql" label="COM_FIELD_LABEL"
sql_select="id,name"
sql_from="#__users"
value_field="name"
key_field="id"
description=""
header="DROP_DOWN_HEADER"
required="false" />
Apparently it can't be done
The JForm (Joomla) User field is the Joomla core field that you can
see in Joomla article form to select a user (lightbox with list of
user). Becareful this field can not be used on front-end because
Joomla core don't manage it on front-end... Often we replace this
field on front end with a select dynamic field.
I didn't have much luck with this. Instead I created my own component and added in the content from com_users. Worked a treat.
Can be done fairly simply but with some significant limitations - depending on your use case.
User must be logged in to backend (even if you are trying to access the information frontend). If they are not logged in, it will prompt for log in and break out of the modal :(
User must have permissions for User Manager
Then duplicate the \libraries\cms\form\field\user.php to a fields location of your choice (in a modal subdirectory) and rename it to something like user2.php. Make the class name JFormFieldModal_Users2 and the $type='Modal_Users2'.
Don't forget to add the new path to your form .xml if required. The type will be "modal_users2".
Last step. In user2.php, change:
$link = 'index.php?option=com_users&view=users&layout=modal&tmpl=component&field=' . $this->id
. (isset($groups) ? ('&groups=' . base64_encode(json_encode($groups))) : '')
. (isset($excluded) ? ('&excluded=' . base64_encode(json_encode($excluded))) : '');
to
$link = 'administrator/index.php?option=com_users&view=users&layout=modal&tmpl=component&field=' . $this->id
. (isset($groups) ? ('&groups=' . base64_encode(json_encode($groups))) : '')
. (isset($excluded) ? ('&excluded=' . base64_encode(json_encode($excluded))) : '');
A bit hacky, but served my purposes.
Less hacky, but less glamorous solution here: The SQL formfield type

CodeIgniter repopulate form from both session data & form validation?

I have a form with a couple search options, like a checkbox array and radio button. By using the form validation library I have the form repopulating after a submit, like so:
echo form_checkbox('check_track[]', '1', set_checkbox('check_track[]', '1', TRUE));
echo form_dropdown('select_year', $options, set_value('select_year', '2013'), $attribs);
I also save all the form options (by storing the post) into session userdata. Is it possible to repopulate all the fields from the session data if $_SERVER['REQUEST_METHOD'] !== 'POST' but keep repopulating based on form validation otherwise?
The easier would probably be to separate the form generation from the value generation. In the snippet you provide, the value is read directly from the submitted form.
I would advise you, in you controller or your model to generate a data structure, each field corresponding to one of the form field.
For each, the value would either be the default, either the one stored in the session if it matches you condition ie: valid data and not after a POST if I understood you well.
I ended up just faking that a POST had happened before the form validation stuff ran to get repopulation to work:
if(!isset($_POST['something']) && $this->session->userdata('something'))
{
$_POST = $this->session->all_userdata();
}
$this->form_validation->set_rules('something', 'stuff', 'required');
.
.
.

How do I use CakePHP to append data to database when submitting from a form?

I've been developing this application for use in my biology lab where I require the following:
User adds in data into a text field.
When the user wants to update the text field, s/he cannot update the existing text, and can only append new text to the field.
Therefore, the form must contain a blank text field that the user can input text to append to the existing entry.
Ideally, I'd also like to append the timestamp for when each entry is recorded.
As you can see, it's sort of like a lab notebook, where the integrity of previously-entered data is important.
I'm having trouble with 2nd point, in that I don't know how to create a blank text field that saves the data to the corresponding field in the model.
Here is the code I currently have for the "view":
(I've tried to hide the existing data - "results_summary" - in a "hidden" element.)
<!-- File: /app/View/Experiments/update.ctp -->
<h1>Update Experiment</h1>
<h2>Objective:</h2>
<p><?php echo $experiment['Experiment']['objective']?></p>
<p>Notebook <?php echo $experiment['Experiment']['notebook_number'] ?>, Page <?php echo $experiment['Experiment']['notebook_page'] ?> </p>
<p>Date Started: <?php echo $experiment['Experiment']['date_started']?></p>
<p>Date Ended: <?php echo $experiment['Experiment']['date_ended']?></p>
<p>Project: <?php echo $experiment['Project']['title']?>
<p>Status: <?php echo $experiment['ExperimentStatus']['title']?>
<p>Results Summary:</p>
<p><?php echo $this->Form->create('Experiment', array('action' => 'update'));
echo $this->Form->hidden('results_summary');
echo $this->Form->text('results_summary');
echo $this->Form->end('Update');
//$experiment['Experiment']['results_summary']?></p>
Does anybody have clues as to how I could go about solving this problem? I'm quite lost right now, as I haven't had the experience coding this before.
Based on requirements 3 and 4, I would model the database in a way that each summary entry is stored in a separate row. You'll need a separate table for that, something like this:
id | experiment_id | summary_entry | summary_entry_timestamp
Column experiment_id is a foreign key to the related id on experiments table. Tables/models are related so that Experiment hasMany ExperimentSummaryEntry.
Then, logging to the experiment results summary will be a matter of inserting a new row on that table.
I would have to agree with #bfavaretto
Without seeing your database structure it is hard to be sure.
I suspect that you are doing
Project hasMany Experiment
Experiment hasOne ExperimentStatus
You need an additional
Experiment hasMany ExperimentEntry
the entries table need to have
id int(11), experiment_id int (11), content TEXT, created DATETIME
if you are okay using DATETIME field for timestamp then I suggest using **created because cakephp will auto fill in for you.
instead of update experiment, you do a add experimententry.
in the afterSave method of ExperimentEntry you do a
$this->Experiment->id = $this->data['ExperimentEntry']['experiment_id'];
$latestSummary = $this->Experiment->field('result_summary');
$latestSummary .= $this->data['ExperimentEntry']['content']; // you may need to add a newline before you append. up to you
$this->Experiment->save(array(
'Experiment' => array(
'result_summary' => $latestSummary
)));
Code is not tested so use at own risk.
** no corresponding page in cakephp 2.0 docs for created and modified but definitely this works. I have tried it before.

What are some best practices for multi-step forms in Coldfusion?

I have a three step form where each step posts to its own action. The action redirects to the next step. The data is stored in the session scope. I have a filter that prevents a user from accessing the form handlers through anything other than a post request.
There's nothing to stop someone from manually typing in the address of a step, however. To deal with this problem I set a currentStep variable in the session.
<!--- Some data is processed here --->
<cfset session.currentStep = "stepTwo">
And in step two I would check for a structkey:
<cfif NOT session.currentStep = "stepTwo">
<!--- redirect to #session.currentStep# --->
This approach works, but it has a major drawback: A user can not press the back button in the browser window, or edit any data he or she has already entered.
What are some the best practices to implementing a multistep form? Can I improve my process to incorporate back-button functionality?
Instead of using the session variable to only allow them to access the current step, allow them to access the current or previous steps. Sort of a "how far you can go" flag.
Now, add links to the previous steps, like a breadcrumb trail.
Finally, use a lookup in the persistent store (db, session, xml, bag of holding, etc.) for the data already entered for that form. Create a blank set of form data, overwrite it with anything found in the persistent store, then overwrite it with anything from the form scope itself. Something like:
populate = structNew(); // this is the data to populate your form with on load
populate.someValue = "";
structappend(populate, dataFromStorage);
structappend(populate, form); // from things submitted from the form scope, in case validation fails
<input type="text" name="someValue" value="#variables.populate.someValue">
Now, if someone hits the same form step twice, they will see (in order of precedence) the values they submitted, but which didn't pass validation, values from the persistent data store, and then an empty form.
You can stay using Session approach if you want.
To solve your major drawback, you can change your logic a bit.
At the last step, make sure data of all steps are found in the session. If not, redirect the user to the first unfilled step? Shouldn't be too hard.