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); }
/** * 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 testInstReturnsSingleton() { $inst1 = SecurityToken::inst(); $inst2 = SecurityToken::inst(); $this->assertEquals($inst1, $inst2); }
/** * 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 testDisableSecurityTokenAcceptsSubmissionWithoutToken() { SecurityToken::enable(); $expectedToken = SecurityToken::inst()->getValue(); $response = $this->get('FormTest_ControllerWithSecurityToken'); // can't use submitForm() as it'll automatically insert SecurityID into the POST data $response = $this->post('FormTest_ControllerWithSecurityToken/Form', array('Email' => '*****@*****.**', 'action_doSubmit' => 1)); $this->assertEquals(400, $response->getStatusCode(), 'Submission fails without security token'); // Generate a new token which doesn't match the current one $generator = new RandomGenerator(); $invalidToken = $generator->randomToken('sha1'); $this->assertNotEquals($invalidToken, $expectedToken); // Test token with request $response = $this->get('FormTest_ControllerWithSecurityToken'); $response = $this->post('FormTest_ControllerWithSecurityToken/Form', array('Email' => '*****@*****.**', 'action_doSubmit' => 1, 'SecurityID' => $invalidToken)); $this->assertEquals(200, $response->getStatusCode(), 'Submission reloads form if security token invalid'); $this->assertTrue(stripos($response->getBody(), 'name="SecurityID" value="' . $expectedToken . '"') !== false, 'Submission reloads with correct security token after failure'); $this->assertTrue(stripos($response->getBody(), 'name="SecurityID" value="' . $invalidToken . '"') === false, 'Submission reloads without incorrect security token after failure'); $matched = $this->cssParser()->getBySelector('#Form_Form_Email'); $attrs = $matched[0]->attributes(); $this->assertEquals('*****@*****.**', (string) $attrs['value'], 'Submitted data is preserved'); $response = $this->get('FormTest_ControllerWithSecurityToken'); $tokenEls = $this->cssParser()->getBySelector('#Form_Form_SecurityID'); $this->assertEquals(1, count($tokenEls), 'Token form field added for controller without disableSecurityToken()'); $token = (string) $tokenEls[0]; $response = $this->submitForm('Form_Form', null, array('Email' => '*****@*****.**', 'SecurityID' => $token)); $this->assertEquals(200, $response->getStatusCode(), 'Submission suceeds with security token'); }
/** * 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'); }