PEAR QuickForm2 CSRF Protection - csrf

I was looking for a way to ensure CSRF-Protection in my Quickform2.
I found this link but it's for QuickForm1.
Any ideas how I can adapt this to QF2?

After some fiddling around I came up with this solution.
Maybe it helps someone else as well:
<?php
/**
* #uses HTML_QuickForm
* #desc Add automatic CSRF mitigation to all forms by incorporating a token that must be matched in the session and forcing the use of POST method
* Based on: http://www.zapoyok.info/2010/07/17/csrf-et-quickform-de-pear/
*/
require_once "QuickForm2.php";
class HTML_QuickForm2s extends HTML_QuickForm2
{
/**
* #property string $_sessionTokenKey The name of the session variable containing the token
*/
private $_sessionTokenKey;
/**
* #method __construct
* #desc Override the method to always use post and pass it on to the parent constructor. Create a session key for the token based on the form name.
* #param $id
* #param string $method
* #param mixed $attributes
* #param boolean $trackSubmit
*/
public function __construct($id, $method = 'post', $attributes = null, $trackSubmit = true)
{
$this->_sessionTokenKey = "QuickForm2s_" . md5($id);
parent::__construct($id, $method, $attributes, $trackSubmit);
//A token hasn't been created so do so
if (!isset($_SESSION[$this->_sessionTokenKey])) {
$_SESSION[$this->_sessionTokenKey] = md5(uniqid(rand(), true) . session_id()); //requires the session id to be known in order to add extra difficulty to compromising
}
//Hide the token at the end of the form
$this->addElement("hidden", "qfS_csrf");
$qfsCsrf= $this->getElementsByName('qfS_csrf');
$qfsCsrf[0]->setValue($_SESSION[$this->_sessionTokenKey]);
}
/**
* #method validate
* #desc Check if the passed token matches the session before allowing validation
* #return boolean
*/
public function validate()
{
$submitValues = $this->getValue();
//The token was not passed or does not match
if (!isset($submitValues['qfS_csrf']) || $submitValues['qfS_csrf'] != $_SESSION[$this->_sessionTokenKey]) {
$this->setError("Anti-CSRF token does not match");
}
return parent::validate();
}
}

Related

TYPO3 Extension - Redirect to another page in show action if no record is set or not available

How can I redirect to another page when someone access the detail page but without a record or if record is not available?
I have detail records like
domain.com/abc/ABC1234
When somone enters
domain.com/abc/
... I get:
Uncaught TYPO3 Exception
#1298012500: Required argument "record" is not set for Vendor\Extension\Controller\ActionController->show. (More information)
TYPO3\CMS\Extbase\Mvc\Controller\Exception\RequiredArgumentMissingException thrown in file
/is/htdocs/www/typo3_src-8.7.11/typo3/sysext/extbase/Classes/Mvc/Controller/AbstractController.php in line 425.
... in this case I want it to redirect to:
domain.com/other-page/
... I also need it if a specific record is not available.
... how to do so?
/**
* action show
*
* #param \Action $record
* #return void
*/
public function showAction(Action $record) {
$this->view->assign('record', $record);
}
Here are some examples TYPO3 Extbase - redirect to pid ... but not sure how to implement it
Edit: What works is ...
/**
* action show
*
* #param \Action $record
* #return void
*/
public function showAction(Action $record=null) {
if ($record === null) {
$pageUid = 75;
$uriBuilder = $this->uriBuilder;
$uri = $uriBuilder
->setTargetPageUid($pageUid)
->build();
$this->redirectToUri($uri, 0, 404);
} else {
$this->view->assign('record', $record);
}
}
The redirect method needs an action and controller parameter. So your redirect code is wrong.
$this->redirect($actionName, $controllerName = NULL, $extensionName = NULL, array $arguments = NULL, $pageUid = NULL, $delay = 0, $statusCode = 303);
To redirect to an PageUID you need to use the uriBuilder and the redirectToUri method. See here for an example.
This should do the trick:
public function showAction(Action $record=null) {
if ($record === null) {
$this->redirect(/* add parameters as needed */);
} else {
// other code
}
Alternative Solution (from Simon Oberländer)
public function intializeShowAction() {
if (!$this->request->hasArgument('record')) {
$this->redirect(/* add parameters as needed */); // stops further execution
}
}
Your question suggests that there should be an other action without arguments, probably a listAction, that is the DEFAULT action. The default action gets called when no action is specified. It is the first action enlisted in the ExtensionUtility::configurePlugin() call.
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
'Vendor.' . $_EXTKEY,
'Pluginname',
array(
'Domainobject' => 'list, show',
),
// non-cacheable actions
array(
'Domainobject' => 'list, show',
)
);
Regarding > The identity property "TTTT" is no UID
You have to distinguish between no parameter and an invalid parameter. For the latter you can add #ignorevalidation to the showAction comments and do your validation testing within the action - or you can leave it to extbase that displays the error message you have seen.
Where would you get a link like domain.com/abc/TTTT/ from anyhow? Unless the link is expired.
BTW: in a production system you would disable the display of exceptions, thus the display of the website would work.
This could be a solution:
```
/**
* Show a booking object
*
* #return void
* #throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException
*/
public function showAction()
{
$bookingObject = null;
$bookingObjectUid = 0;
if ($this->request->hasArgument('bookingObject')) {
$bookingObjectUid = (int)$this->request->getArgument('bookingObject');
}
if ($bookingObjectUid > 0) {
$bookingObject = $this->bookingObjectRepository->findByIdentifier($bookingObjectUid);
}
if (!($bookingObject instanceof BookingObject)) {
$messageBody = 'Booking object can\'t be displayed.';
$messageTitle = 'Error';
$this->addFlashMessage($messageBody, $messageTitle, AbstractMessage::ERROR);
$this->redirect('list');
}
$this->view->assign('bookingObject', $bookingObject);
}
```

How can I write a user provider for HWIOAuthBundle

I want to write a login feature via social networks.
if the user is not logged it persists it into the database, if the user exists, log the user in.
What should I write into my provider?
Docs state :
The bundle needs a service that is able to load users based on the
user response of the oauth endpoint. If you have a custom service it
should implement the interface:
HWI\Bundle\OAuthBundle\Security\Core\User\OAuthAwareUserProviderInterface.
So this is what I wrote and then got stuck
<?php
namespace ng\MyBundle\Controller\Listeners;
use HWI\Bundle\OAuthBundle\Security\Core\User\OAuthAwareUserProviderInterface;
class OAuthUserProvider implements OAuthAwareUserProviderInterface
{
}
Can you tell me what are the methods That I should use ?
Can anybody give me a provider example not using FOSuserBundle ?
Thanks
If you open the OAuthAwareUserProviderInterface you can see it has only one method :
/**
* Loads the user by a given UserResponseInterface object.
*
* #param UserResponseInterface $response
*
* #return UserInterface
*
* #throws UsernameNotFoundException if the user is not found
*/
public function loadUserByOAuthUserResponse(UserResponseInterface $response);
Below there is an example on how to implement it, ofcourse in your case, you should call your entity managers, and access users the way you have designed it.
/**
* {#inheritdoc}
*/
public function loadUserByOAuthUserResponse(UserResponseInterface $response)
{
$username = $response->getUsername();
$user = $this->userManager->findUserBy(array($this->getProperty($response) => $username));
//when the user is registrating
if (null === $user) {
$service = $response->getResourceOwner()->getName();
$setter = 'set'.ucfirst($service);
$setter_id = $setter.'Id';
$setter_token = $setter.'AccessToken';
// create new user here
$user = $this->userManager->createUser();
$user->$setter_id($username);
$user->$setter_token($response->getAccessToken());
//I have set all requested data with the user's username
//modify here with relevant data
$user->setUsername($username);
$user->setEmail($username);
$user->setPassword($username);
$user->setEnabled(true);
$this->userManager->updateUser($user);
return $user;
}
//if user exists - go with the HWIOAuth way
$user = parent::loadUserByOAuthUserResponse($response);
$serviceName = $response->getResourceOwner()->getName();
$setter = 'set' . ucfirst($serviceName) . 'AccessToken';
//update access token
$user->$setter($response->getAccessToken());
return $user;
}

Typo3 Extbase AJAX without page typenum

Is there any way to create AJAX calls in Extbase extension without using of page typeNum?
Edit:
Helmut Hummel, a member of the TYPO3 CMS team, measured that using EID with Extbase is slower than using the typeNum approach. But since the typeNum approach is cumbersome to configure, there is a third way developed by him.
The extension typoscript_rendering provides a way to call Extbase actions directly without additional configuration. It contains a ViewHelper that generates such links and can be used like this in a Fluid template:
{namespace h=Helhum\TyposcriptRendering\ViewHelpers}
<script>
var getParticipationsUri = '<h:uri.ajaxAction controller="Participation" action="listByCompetition" arguments="{competition:competition}" />';
</script>
This generates an URI that calls the action "listByCompetition" of my "ParticipationController". You can pass arguments normally.
The only downside is that for security reasons, the extension uses the cHash to validate the request arguments. The cHash is submitted by GET but you cannot pass additional arguments by GET at the same time because it would invalidate the cHash. So if you want to pass form data in such a request, you need to mix GET (for a valid AJAX call) and POST (for submitting user data):
<script>
var createAddressUri = '<h:uri.ajaxAction controller="Address" action="create" />';
$body.on('submit', '#myForm', function(e) {
e.preventDefault();
emailAddress = $('#myForm').find('#email');
if (typeof(emailAddress) === 'string') {
$.ajax({
url: createAddressUri,
type: 'POST',
data: { 'tx_myext_pluginname[address][email]' : emailAddress},
success: function() {
// things to do on success
}
})
}
});
</script>
(Of course this is only a very basic example. You might post whole models etc.)
The EID way:
Yes, you can use the EID (Extension ID) mechanism for that. There is no official statement which way (pageType or eID) should be used for Extbase AJAX calls and it seems to be just a matter of taste.
There is a nice tutorial that can be found here and I copy the source code in here:
<?php
/** *************************************************************
*
* Extbase Dispatcher for Ajax Calls TYPO3 6.1 namespaces
*
* IMPORTANT Use this script only in Extensions with namespaces
*
* Klaus Heuer <klaus.heuer#t3-developer.com>
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
* ************************************************************* */
/** ************************************************************
* Usage of this script:
*
* - Copy this script in your Extension Dir in the Folder Classes
* - Set the Vendor and Extension Name in Line 82 + 83
* - Include the next line in the ext_localconf.php, change the ext name!
* - $TYPO3_CONF_VARS['FE']['eID_include']['ajaxDispatcher'] = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('myExtension').'Classes/EidDispatcher.php';
*
* Use for Ajax Calls in your jQuery Code:
*
* $('.jqAjax').click(function(e) {
* var uid = $(this).find('.uid').html();
* var storagePid = '11';
*
* $.ajax({
* async: 'true',
* url: 'index.php',
* type: 'POST',
*
* data: {
* eID: "ajaxDispatcher",
* request: {
* pluginName: 'patsystem',
* controller: 'Todo',
* action: 'findTodoByAjax',
* arguments: {
* 'uid': uid,
* 'storagePid': storagePid
* }
* }
* },
* dataType: "json",
*
* success: function(result) {
* console.log(result);
* },
* error: function(error) {
* console.log(error);
* }
* });
*************************************************************** */
/**
* Gets the Ajax Call Parameters
*/
$ajax = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('request');
/**
* Set Vendor and Extension Name
*
* Vendor Name like your Vendor Name in namespaces
* ExtensionName in upperCamelCase
*/
$ajax['vendor'] = 'T3Developer';
$ajax['extensionName'] = 'ProjectsAndTasks';
/**
* #var $TSFE \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
*/
$TSFE = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController', $TYPO3_CONF_VARS, 0, 0);
\TYPO3\CMS\Frontend\Utility\EidUtility::initLanguage();
// Get FE User Information
$TSFE->initFEuser();
// Important: no Cache for Ajax stuff
$TSFE->set_no_cache();
//$TSFE->checkAlternativCoreMethods();
$TSFE->checkAlternativeIdMethods();
$TSFE->determineId();
$TSFE->initTemplate();
$TSFE->getConfigArray();
\TYPO3\CMS\Core\Core\Bootstrap::getInstance()->loadConfigurationAndInitialize();
$TSFE->cObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer');
$TSFE->settingLanguage();
$TSFE->settingLocale();
/**
* Initialize Database
*/
\TYPO3\CMS\Frontend\Utility\EidUtility::connectDB();
/**
* #var $objectManager \TYPO3\CMS\Extbase\Object\ObjectManager
*/
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager');
/**
* Initialize Extbase bootstap
*/
$bootstrapConf['extensionName'] = $ajax['extensionName'];
$bootstrapConf['pluginName'] = $ajax['pluginName'];
$bootstrap = new TYPO3\CMS\Extbase\Core\Bootstrap();
$bootstrap->initialize($bootstrapConf);
$bootstrap->cObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('tslib_cObj');
/**
* Build the request
*/
$request = $objectManager->get('TYPO3\CMS\Extbase\Mvc\Request');
$request->setControllerVendorName($ajax['vendor']);
$request->setcontrollerExtensionName($ajax['extensionName']);
$request->setPluginName($ajax['pluginName']);
$request->setControllerName($ajax['controller']);
$request->setControllerActionName($ajax['action']);
$request->setArguments($ajax['arguments']);
$response = $objectManager->create('TYPO3\CMS\Extbase\Mvc\ResponseInterface');
$dispatcher = $objectManager->get('TYPO3\CMS\Extbase\Mvc\Dispatcher');
$dispatcher->dispatch($request, $response);
echo $response->getContent();
//die();
?>
Have a look at the "usage of this script" section that explains how to register the eID. The script works with TYPO3 6.1 and higher.
For TYPO3 6.2 change the following line:
\TYPO3\CMS\Core\Core\Bootstrap::getInstance()->loadConfigurationAndInitialize();
to
\TYPO3\CMS\Core\Core\Bootstrap::getInstance()
For Test Extension.
Include EID in the ext_localconf.php file
## Ajax configuration
$TYPO3_CONF_VARS['FE']['eID_include']['Test'] = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('test').'Classes/Ajax/EidDispatcher.php';
Create directory in classes – Classes/Ajax/EidDispatcher.php
namespace TYPO3\Test\Ajax;
class EidDispatcher {
/**
* #var \array
*/
protected $configuration;
/**
* #var \array
*/
protected $bootstrap;
/**
* The main Method
*
* #return \string
*/
public function run() {
return $this->bootstrap->run( '', $this->configuration );
}
/**
* Initialize Extbase
*
* #param \array $TYPO3_CONF_VARS
*/
public function __construct($TYPO3_CONF_VARS) {
$ajaxRequest = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('tx_Test_addhours');
// create bootstrap
$this->bootstrap = new \TYPO3\CMS\Extbase\Core\Bootstrap();
// get User
$feUserObj = \TYPO3\CMS\Frontend\Utility\EidUtility::initFeUser();
// set PID
$pid = (\TYPO3\CMS\Core\Utility\GeneralUtility::_GET( 'id' )) ? \TYPO3\CMS\Core\Utility\GeneralUtility::_GET('id') : 1;
// Create and init Frontend
$GLOBALS['TSFE'] = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance( 'TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController', $TYPO3_CONF_VARS, $pid, 0, TRUE );
$GLOBALS['TSFE']->connectToDB();
$GLOBALS['TSFE']->fe_user = $feUserObj;
$GLOBALS['TSFE']->id = $pid;
$GLOBALS['TSFE']->determineId();
$GLOBALS['TSFE']->getCompressedTCarray(); //Comment this line when used for TYPO3 7.6.0 on wards
$GLOBALS['TSFE']->initTemplate();
$GLOBALS['TSFE']->getConfigArray();
$GLOBALS['TSFE']->includeTCA(); //Comment this line when used for TYPO3 7.6.0 on wards
// Get Plugins TypoScript
$TypoScriptService = new \TYPO3\CMS\Extbase\Service\TypoScriptService();
$pluginConfiguration = $TypoScriptService->convertTypoScriptArrayToPlainArray($GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_Test.']);
// Set configuration to call the plugin
$this->configuration = array (
'pluginName' => $ajaxRequest['pluginName'],
'vendorName' => 'TYPO3',
'extensionName' => 'Test',
'controller' => $ajaxRequest['controller'],
'action' => $ajaxRequest['action'],
'mvc' => array (
'requestHandlers' => array (
'TYPO3\CMS\Extbase\Mvc\Web\FrontendRequestHandler' => 'TYPO3\CMS\Extbase\Mvc\Web\FrontendRequestHandler'
)
),
'settings' => $pluginConfiguration['settings'],
'persistence' => array (
'storagePid' => $pluginConfiguration['persistence']['storagePid']
)
);
}
}
global $TYPO3_CONF_VARS;
// make instance of bootstrap and run
$eid = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance( 'TYPO3\Test\Ajax\EidDispatcher', $TYPO3_CONF_VARS );
echo $eid->run();
Call From Script
$.ajax({
async: 'true',
url: 'index.php',
type: 'GET',
data: {
eID: "Test",
tx_ExtName_PluginName: {
pluginName: 'Plugin_Name',
controller: 'Controller_Name',
action: 'Action_Name',
}
},
success:function(data){
// code
}
});
I had to change the first 0 of the makeInstance to the id of the page for it to work.
$id = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('id');
$TSFE = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController', $TYPO3_CONF_VARS, $id, 0);
I used a quick and probably dirty way without typeNum.
I used jQuery ajax call the common way.
My target action ended with the following.
$headers = DivUtilities::createHeader();
foreach ($headers as $header => $data) {
$this->response->setHeader($header, $data);
}
$this->response->sendHeaders();
echo $this->view->render();
exit;
The createHeader Method
/**
*
* #param string $type
* #return array
*/
public static function createHeader($type = 'html')
{
switch ($type) {
case 'txt':
$cType = 'text/plain';
break;
case 'html':
$cType = 'text/html';
break;
case 'json':
$cType = 'application/json';
break;
case 'pdf':
$cType = 'application/pdf';
break;
}
$headers = array(
'Pragma' => 'public',
'Expires' => 0,
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
'Cache-Control' => 'public',
'Content-Type' => $cType
);
return $headers;
}
The output is the template of the called action. This can be html, json or whatever u need.

Zend Framework - Router - Creating Aliases

I'm building a Zend Framework 1.11.11 application and would like to make the routes and content database driven.
I've written a FrontController Plugin that retrieves the 'paths' from the database and creates an entry in the Router for each one, with the associated controller and action.
However, I'd like to be able to use 'aliases' - a URL that behaves like a normal URL, but is an alias.
For example, if I create the following:
// Create the Zend Route
$entry = new Zend_Controller_Router_Route_Static(
$route->getUrl(), // The string/url to match
array('controller' => $route->getControllers()->getName(),
'action' => $route->getActions()->getName())
);
// Add the route to the router
$router->addRoute($route->getUrl(), $entry);
Then a route for /about/ for example can goto the staticController, indexAction.
However, what's the best way for me to create an alias of this route? So if I went to /abt/ it would render the same Controller and Action?
To me it doesn't make sense to recreate the same route as I'll be using the route as the page 'identifier' to then load content from the database for the page...
you can extend static router:
class My_Route_ArrayStatic extends Zend_Controller_Router_Route_Static
{
protected $_routes = array();
/**
* Prepares the array of routes for mapping
* first route in array will become primary, all others
* aliases
*
* #param array $routes array of routes
* #param array $defaults
*/
public function __construct(array $routes, $defaults = array())
{
$this->_routes = $routes;
$route = reset($routes);
parent::__construct($route, $defaults);
}
/**
* Matches a user submitted path with a previously specified array of routes
*
* #param string $path
* #param boolean $partial
* #return array|false
*/
public function match($path, $partial = false)
{
$return = false;
foreach ($this->_routes as $route) {
$this->setRoute($route);
$success = parent::match($path, $partial);
if (false !== $success) {
$return = $success;
break;
}
}
$this->setRoute(reset($this->_routes));
return $return;
}
public function setRoute($route)
{
$this->_route = trim($route, '/');
}
}
and add new router this way:
$r = My_Route_ArrayStatic(array('about', 'abt'), $defaults);

Zend Controller Action: _redirect() vs getHelper('Redirector')->gotoUrl()

I've read that $this->getHelper('[helper_name]') is preferable to $this->_helper->[helper_name]. What I haven't been able to find any documentation of is which of these is better/preferred: $this->_redirect($url) or $this->getHelper('Redirector')->gotoUrl($url).
Use whatever one suits you, they do exactly the same thing:
/**
* Redirect to another URL
*
* Proxies to {#link Zend_Controller_Action_Helper_Redirector::gotoUrl()}.
*
* #param string $url
* #param array $options Options to be used when redirecting
* #return void
*/
protected function _redirect($url, array $options = array())
{
$this->_helper->redirector->gotoUrl($url, $options);
}