public function testDeleteActionRemoveRelation()
 {
     $this->logInWithPermission('ADMIN');
     $config = GridFieldConfig::create()->addComponent(new GridFieldDeleteAction(true));
     $gridField = new GridField('testfield', 'testfield', $this->list, $config);
     $form = new Form(new Controller(), 'mockform', new FieldList(array($this->gridField)), new FieldList());
     $stateID = 'testGridStateActionField';
     Session::set($stateID, array('grid' => '', 'actionName' => 'deleterecord', 'args' => array('RecordID' => $this->idFromFixture('GridFieldAction_Delete_Team', 'team1'))));
     $token = SecurityToken::inst();
     $request = new SS_HTTPRequest('POST', 'url', array(), array('action_gridFieldAlterAction?StateID=' . $stateID => true, $token->getName() => $token->getValue()));
     $this->gridField->gridFieldAlterAction(array('StateID' => $stateID), $this->form, $request);
     $this->assertEquals(2, $this->list->count(), 'User should be able to delete records with ADMIN permission.');
 }
 /**
  * Invoke a batch action
  *
  * @param SS_HTTPRequest $request
  * @return SS_HTTPResponse
  */
 public function handleBatchAction($request)
 {
     // This method can't be called without ajax.
     if (!$request->isAjax()) {
         return $this->parentController->redirectBack();
     }
     // Protect against CSRF on destructive action
     if (!SecurityToken::inst()->checkRequest($request)) {
         return $this->httpError(400);
     }
     // Find the action handler
     $action = $request->param('BatchAction');
     $actionHandler = $this->actionByName($action);
     // Sanitise ID list and query the database for apges
     $csvIDs = $request->requestVar('csvIDs');
     $ids = $this->cleanIDs($csvIDs);
     // Filter ids by those which are applicable to this action
     // Enforces front end filter in LeftAndMain.BatchActions.js:refreshSelected
     $ids = $actionHandler->applicablePages($ids);
     // Query ids and pass to action to process
     $pages = $this->getPages($ids);
     return $actionHandler->run($pages);
 }
 public function testFormActionsCanBypassAllowedActions()
 {
     SecurityToken::enable();
     $response = $this->get('RequestHandlingTest_FormActionController');
     $this->assertEquals(200, $response->getStatusCode());
     $tokenEls = $this->cssParser()->getBySelector('#Form_Form_SecurityID');
     $securityId = (string) $tokenEls[0]['value'];
     $data = array('action_formaction' => 1);
     $response = $this->post('RequestHandlingTest_FormActionController/Form', $data);
     $this->assertEquals(400, $response->getStatusCode(), 'Should fail: Invocation through POST form handler, not contained in $allowed_actions, without CSRF token');
     $data = array('action_disallowedcontrollermethod' => 1, 'SecurityID' => $securityId);
     $response = $this->post('RequestHandlingTest_FormActionController/Form', $data);
     $this->assertEquals(403, $response->getStatusCode(), 'Should fail: Invocation through POST form handler, controller action instead of form action,' . ' not contained in $allowed_actions, with CSRF token');
     $data = array('action_formaction' => 1, 'SecurityID' => $securityId);
     $response = $this->post('RequestHandlingTest_FormActionController/Form', $data);
     $this->assertEquals(200, $response->getStatusCode());
     $this->assertEquals('formaction', $response->getBody(), 'Should pass: Invocation through POST form handler, not contained in $allowed_actions, with CSRF token');
     $data = array('action_controlleraction' => 1, 'SecurityID' => $securityId);
     $response = $this->post('RequestHandlingTest_FormActionController/Form', $data);
     $this->assertEquals(200, $response->getStatusCode(), 'Should pass: Invocation through POST form handler, controller action instead of form action, contained in' . ' $allowed_actions, with CSRF token');
     $data = array('action_formactionInAllowedActions' => 1);
     $response = $this->post('RequestHandlingTest_FormActionController/Form', $data);
     $this->assertEquals(400, $response->getStatusCode(), 'Should fail: Invocation through POST form handler, contained in $allowed_actions, without CSRF token');
     $data = array('action_formactionInAllowedActions' => 1, 'SecurityID' => $securityId);
     $response = $this->post('RequestHandlingTest_FormActionController/Form', $data);
     $this->assertEquals(200, $response->getStatusCode(), 'Should pass: Invocation through POST form handler, contained in $allowed_actions, with CSRF token');
     $data = array();
     $response = $this->post('RequestHandlingTest_FormActionController/formaction', $data);
     $this->assertEquals(404, $response->getStatusCode(), 'Should fail: Invocation through POST URL, not contained in $allowed_actions, without CSRF token');
     $data = array();
     $response = $this->post('RequestHandlingTest_FormActionController/formactionInAllowedActions', $data);
     $this->assertEquals(200, $response->getStatusCode(), 'Should pass: Invocation of form action through POST URL, contained in $allowed_actions, without CSRF token');
     $data = array('SecurityID' => $securityId);
     $response = $this->post('RequestHandlingTest_FormActionController/formactionInAllowedActions', $data);
     $this->assertEquals(200, $response->getStatusCode(), 'Should pass: Invocation of form action through POST URL, contained in $allowed_actions, with CSRF token');
     $data = array();
     // CSRF protection doesnt kick in for direct requests
     $response = $this->post('RequestHandlingTest_FormActionController/formactionInAllowedActions', $data);
     $this->assertEquals(200, $response->getStatusCode(), 'Should pass: Invocation of form action through POST URL, contained in $allowed_actions, without CSRF token');
     SecurityToken::disable();
 }
 /**
  * Create a new form, with the given fields an action buttons.
  *
  * @param Controller $controller The parent controller, necessary to create the appropriate form action tag.
  * @param string $name The method on the controller that will return this form object.
  * @param FieldList $fields All of the fields in the form - a {@link FieldList} of {@link FormField} objects.
  * @param FieldList $actions All of the action buttons in the form - a {@link FieldLis} of
  *                           {@link FormAction} objects
  * @param Validator|null $validator Override the default validator instance (Default: {@link RequiredFields})
  */
 public function __construct($controller, $name, FieldList $fields, FieldList $actions, Validator $validator = null)
 {
     parent::__construct();
     $fields->setForm($this);
     $actions->setForm($this);
     $this->fields = $fields;
     $this->actions = $actions;
     $this->controller = $controller;
     $this->setName($name);
     if (!$this->controller) {
         user_error("{$this->class} form created without a controller", E_USER_ERROR);
     }
     // Form validation
     $this->validator = $validator ? $validator : new RequiredFields();
     $this->validator->setForm($this);
     // Form error controls
     $this->setupFormErrors();
     // Check if CSRF protection is enabled, either on the parent controller or from the default setting. Note that
     // method_exists() is used as some controllers (e.g. GroupTest) do not always extend from Object.
     if (method_exists($controller, 'securityTokenEnabled') || method_exists($controller, 'hasMethod') && $controller->hasMethod('securityTokenEnabled')) {
         $securityEnabled = $controller->securityTokenEnabled();
     } else {
         $securityEnabled = SecurityToken::is_enabled();
     }
     $this->securityToken = $securityEnabled ? new SecurityToken() : new NullSecurityToken();
     $this->setupDefaultClasses();
 }
 /**
  * Update the position and parent of a tree node.
  * Only saves the node if changes were made.
  *
  * Required data:
  * - 'ID': The moved node
  * - 'ParentID': New parent relation of the moved node (0 for root)
  * - 'SiblingIDs': Array of all sibling nodes to the moved node (incl. the node itself).
  *   In case of a 'ParentID' change, relates to the new siblings under the new parent.
  *
  * @param HTTPRequest $request
  * @return HTTPResponse JSON string with a
  * @throws HTTPResponse_Exception
  */
 public function savetreenode($request)
 {
     if (!SecurityToken::inst()->checkRequest($request)) {
         return $this->httpError(400);
     }
     if (!Permission::check('SITETREE_REORGANISE') && !Permission::check('ADMIN')) {
         $this->getResponse()->setStatusCode(403, _t('LeftAndMain.CANT_REORGANISE', "You do not have permission to rearange the site tree. Your change was not saved."));
         return;
     }
     $className = $this->stat('tree_class');
     $statusUpdates = array('modified' => array());
     $id = $request->requestVar('ID');
     $parentID = $request->requestVar('ParentID');
     if ($className == 'SilverStripe\\CMS\\Model\\SiteTree' && ($page = DataObject::get_by_id('Page', $id))) {
         $root = $page->getParentType();
         if (($parentID == '0' || $root == 'root') && !SiteConfig::current_site_config()->canCreateTopLevel()) {
             $this->getResponse()->setStatusCode(403, _t('LeftAndMain.CANT_REORGANISE', "You do not have permission to alter Top level pages. Your change was not saved."));
             return;
         }
     }
     $siblingIDs = $request->requestVar('SiblingIDs');
     $statusUpdates = array('modified' => array());
     if (!is_numeric($id) || !is_numeric($parentID)) {
         throw new InvalidArgumentException();
     }
     $node = DataObject::get_by_id($className, $id);
     if ($node && !$node->canEdit()) {
         return Security::permissionFailure($this);
     }
     if (!$node) {
         $this->getResponse()->setStatusCode(500, _t('LeftAndMain.PLEASESAVE', "Please Save Page: This page could not be updated because it hasn't been saved yet."));
         return;
     }
     // Update hierarchy (only if ParentID changed)
     if ($node->ParentID != $parentID) {
         $node->ParentID = (int) $parentID;
         $node->write();
         $statusUpdates['modified'][$node->ID] = array('TreeTitle' => $node->TreeTitle);
         // Update all dependent pages
         if (class_exists('SilverStripe\\CMS\\Model\\VirtualPage')) {
             $virtualPages = VirtualPage::get()->filter("CopyContentFromID", $node->ID);
             foreach ($virtualPages as $virtualPage) {
                 $statusUpdates['modified'][$virtualPage->ID] = array('TreeTitle' => $virtualPage->TreeTitle());
             }
         }
         $this->getResponse()->addHeader('X-Status', rawurlencode(_t('LeftAndMain.REORGANISATIONSUCCESSFUL', 'Reorganised the site tree successfully.')));
     }
     // Update sorting
     if (is_array($siblingIDs)) {
         $counter = 0;
         foreach ($siblingIDs as $id) {
             if ($id == $node->ID) {
                 $node->Sort = ++$counter;
                 $node->write();
                 $statusUpdates['modified'][$node->ID] = array('TreeTitle' => $node->TreeTitle);
             } else {
                 if (is_numeric($id)) {
                     // Nodes that weren't "actually moved" shouldn't be registered as
                     // having been edited; do a direct SQL update instead
                     ++$counter;
                     DB::prepared_query("UPDATE \"{$className}\" SET \"Sort\" = ? WHERE \"ID\" = ?", array($counter, $id));
                 }
             }
         }
         $this->getResponse()->addHeader('X-Status', rawurlencode(_t('LeftAndMain.REORGANISATIONSUCCESSFUL', 'Reorganised the site tree successfully.')));
     }
     return Convert::raw2json($statusUpdates);
 }
 public function tearDown()
 {
     SecurityToken::enable();
     parent::tearDown();
     unset($this->mainSession);
 }
 public function testNamedTokensCarryDifferentValues()
 {
     $t1 = new SecurityToken('one');
     $t2 = new SecurityToken('two');
     $this->assertNotEquals($t1->getName(), $t2->getName());
     $this->assertNotEquals($t1->getValue(), $t2->getValue());
 }
 /**
  * Returns the value of an the global SecurityToken in the current session
  * @return int
  */
 public static function getSecurityID()
 {
     $token = SecurityToken::inst();
     return $token->getValue();
 }
 /**
  * REST endpoint to publish a {@link ChangeSet} and all of its items.
  *
  * @param HTTPRequest $request
  *
  * @return HTTPResponse
  */
 public function publishCampaign(HTTPRequest $request)
 {
     // Protect against CSRF on destructive action
     if (!SecurityToken::inst()->checkRequest($request)) {
         return new HTTPResponse(null, 400);
     }
     $id = $request->param('ID');
     if (!$id || !is_numeric($id)) {
         return new HTTPResponse(null, 400);
     }
     /** @var ChangeSet $record */
     $record = ChangeSet::get()->byID($id);
     if (!$record) {
         return new HTTPResponse(null, 404);
     }
     if (!$record->canPublish()) {
         return new HTTPResponse(null, 403);
     }
     try {
         $record->publish();
     } catch (LogicException $e) {
         return (new HTTPResponse(json_encode(['status' => 'error', 'message' => $e->getMessage()]), 401))->addHeader('Content-Type', 'application/json');
     }
     return (new HTTPResponse(Convert::raw2json($this->getChangeSetResource($record)), 200))->addHeader('Content-Type', 'application/json');
 }
 public function testCoreGlobalVariableCalls()
 {
     $this->assertEquals(Director::absoluteBaseURL(), $this->render('{$absoluteBaseURL}'), 'Director::absoluteBaseURL can be called from within template');
     $this->assertEquals(Director::absoluteBaseURL(), $this->render('{$AbsoluteBaseURL}'), 'Upper-case %AbsoluteBaseURL can be called from within template');
     $this->assertEquals(Director::is_ajax(), $this->render('{$isAjax}'), 'All variations of is_ajax result in the correct call');
     $this->assertEquals(Director::is_ajax(), $this->render('{$IsAjax}'), 'All variations of is_ajax result in the correct call');
     $this->assertEquals(Director::is_ajax(), $this->render('{$is_ajax}'), 'All variations of is_ajax result in the correct call');
     $this->assertEquals(Director::is_ajax(), $this->render('{$Is_ajax}'), 'All variations of is_ajax result in the correct call');
     $this->assertEquals(i18n::get_locale(), $this->render('{$i18nLocale}'), 'i18n template functions result correct result');
     $this->assertEquals(i18n::get_locale(), $this->render('{$get_locale}'), 'i18n template functions result correct result');
     $this->assertEquals((string) Member::currentUser(), $this->render('{$CurrentMember}'), 'Member template functions result correct result');
     $this->assertEquals((string) Member::currentUser(), $this->render('{$CurrentUser}'), 'Member template functions result correct result');
     $this->assertEquals((string) Member::currentUser(), $this->render('{$currentMember}'), 'Member template functions result correct result');
     $this->assertEquals((string) Member::currentUser(), $this->render('{$currentUser}'), 'Member template functions result correct result');
     $this->assertEquals(SecurityToken::getSecurityID(), $this->render('{$getSecurityID}'), 'SecurityToken template functions result correct result');
     $this->assertEquals(SecurityToken::getSecurityID(), $this->render('{$SecurityID}'), 'SecurityToken template functions result correct result');
     $this->assertEquals(Permission::check("ADMIN"), (bool) $this->render('{$HasPerm(\'ADMIN\')}'), 'Permissions template functions result correct result');
     $this->assertEquals(Permission::check("ADMIN"), (bool) $this->render('{$hasPerm(\'ADMIN\')}'), 'Permissions template functions result correct result');
 }
 public function testDisableSecurityToken()
 {
     SecurityToken::enable();
     $form = $this->getStubForm();
     $this->assertTrue($form->getSecurityToken()->isEnabled());
     $form->disableSecurityToken();
     $this->assertFalse($form->getSecurityToken()->isEnabled());
     SecurityToken::disable();
     // restore original
 }
 public function tearDown()
 {
     SecurityToken::enable();
     parent::tearDown();
     unset($this->mainSession);
     if (static::get_disable_themes()) {
         Config::inst()->update('SSViewer', 'theme', $this->originalTheme);
     }
 }
 /**
  * Creates a single folder, within an optional parent folder.
  *
  * @param HTTPRequest $request
  * @return HTTPRequest|HTTPResponse
  */
 public function apiCreateFolder(HTTPRequest $request)
 {
     $data = $request->postVars();
     $class = 'SilverStripe\\Assets\\Folder';
     // CSRF check
     $token = SecurityToken::inst();
     if (empty($data[$token->getName()]) || !$token->check($data[$token->getName()])) {
         return new HTTPResponse(null, 400);
     }
     // check addchildren permissions
     /** @var Folder $parentRecord */
     $parentRecord = null;
     if (!empty($data['ParentID']) && is_numeric($data['ParentID'])) {
         $parentRecord = DataObject::get_by_id($class, $data['ParentID']);
     }
     $data['Parent'] = $parentRecord;
     $data['ParentID'] = $parentRecord ? (int) $parentRecord->ID : 0;
     // Build filename
     $baseFilename = isset($data['Name']) ? basename($data['Name']) : _t('SilverStripe\\AssetAdmin\\Controller\\AssetAdmin.NEWFOLDER', "NewFolder");
     if ($parentRecord && $parentRecord->ID) {
         $baseFilename = $parentRecord->getFilename() . '/' . $baseFilename;
     }
     // Ensure name is unique
     $nameGenerator = $this->getNameGenerator($baseFilename);
     $filename = null;
     foreach ($nameGenerator as $filename) {
         if (!File::find($filename)) {
             break;
         }
     }
     $data['Name'] = basename($filename);
     // Create record
     /** @var Folder $record */
     $record = Injector::inst()->create($class);
     // check create permissions
     if (!$record->canCreate(null, $data)) {
         return (new HTTPResponse(null, 403))->addHeader('Content-Type', 'application/json');
     }
     $record->ParentID = $data['ParentID'];
     $record->Name = $record->Title = basename($data['Name']);
     $record->write();
     $result = $this->getObjectFromData($record);
     return (new HTTPResponse(json_encode($result)))->addHeader('Content-Type', 'application/json');
 }