Skip to content

Commit

Permalink
NEW Form sudo mode
Browse files Browse the repository at this point in the history
  • Loading branch information
emteknetnz committed Feb 3, 2025
1 parent f48a01e commit a41f2a4
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 6 deletions.
9 changes: 9 additions & 0 deletions src/Forms/DefaultFormFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ public function getForm(RequestHandler $controller = null, $name = FormFactory::
$validator = $this->getFormValidator($controller, $name, $context);
$form = Form::create($controller, $name, $fields, $actions, $validator);

// Sudo mode
if (is_a($context['Record'], DataObject::class)) {
/** @var DataObject $record */
$record = $context['Record'];
if ($record->getRequireSudoMode()) {
$form->requireSudoMode();
}
}

// Extend form
$this->invokeWithExtensions('updateForm', $form, $controller, $name, $context);

Expand Down
35 changes: 35 additions & 0 deletions src/Forms/Form.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace SilverStripe\Forms;

use BadMethodCallException;
use SilverStripe\Admin\LeftAndMain;
use SilverStripe\Control\Controller;
use SilverStripe\Control\HasRequestHandler;
use SilverStripe\Control\HTTPRequest;
Expand All @@ -21,6 +22,8 @@
use SilverStripe\View\SSViewer;
use SilverStripe\View\ViewableData;
use SilverStripe\Dev\Deprecation;
use SilverStripe\Security\SudoMode\SudoModeServiceInterface;
use SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest;

/**
* Base class for all forms.
Expand Down Expand Up @@ -317,6 +320,38 @@ public function __construct(
$this->setupDefaultClasses();
}

public function requireSudoMode(): void
{
// sudo mode only makes sense in a CMS context i.e. not on frontend forms
$classes = [
LeftAndMain::class,
GridFieldDetailForm_ItemRequest::class,
];
$matched = false;
foreach ($classes as $class) {
if (is_a($this->getController(), $class)) {
$matched = true;
break;
}
}
if (!$matched) {
return;
}
$service = Injector::inst()->get(SudoModeServiceInterface::class);
$session = $this->getRequest()->getSession();
if ($service->check($session)) {
return;
}
$this->makeReadonly();
$name = SudoModePasswordField::FIELD_NAME;
if ($this->Fields()->fieldByName($name)) {
$this->Fields()->removeByName($name);
}
$field = new SudoModePasswordField($name);
$field->setForm($this);
$this->Fields()->insertBefore($this->Fields()->first()->getName(), $field);
}

/**
* @return bool
*/
Expand Down
16 changes: 16 additions & 0 deletions src/Forms/GridField/GridField.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use SilverStripe\ORM\SS_List;
use SilverStripe\View\HTML;
use SilverStripe\View\ViewableData;
use SilverStripe\Security\SudoMode\SudoModeServiceInterface;

/**
* Displays a {@link SS_List} in a grid format.
Expand Down Expand Up @@ -630,6 +631,21 @@ public function FieldHolder($properties = [])
}
}

// Set to read-only if sudo mode is required for the DataObject being managed
if (is_a($list, DataList::class)) {
/** @var DataObject $obj */
$obj = Injector::inst()->create($list->dataClass);
if ($obj->getRequireSudoMode()) {
$session = Controller::curr()?->getRequest()?->getSession();
if ($session) {
$service = Injector::inst()->get(SudoModeServiceInterface::class);
if (!$service->check($session)) {
$this->performReadonlyTransformation();
}
}
}
}

$total = count($list ?? []);

if ($total > 0) {
Expand Down
5 changes: 5 additions & 0 deletions src/Forms/GridField/GridFieldDetailForm_ItemRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,11 @@ public function ItemEditForm()
if ($cb) {
$cb($form, $this);
}

if (is_a($this->record, DataObject::class) && $this->record->getRequireSudoMode()) {
$form->requireSudoMode();
}

$this->extend("updateItemEditForm", $form);
return $form;
}
Expand Down
23 changes: 23 additions & 0 deletions src/Forms/SudoModePasswordField.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace SilverStripe\Forms;

use SilverStripe\Forms\PasswordField;

class SudoModePasswordField extends PasswordField
{
public const FIELD_NAME = 'SudoModePasswordField';

protected $schemaComponent = 'SudoModePasswordField';

protected $extraClasses = [
'SudoModePasswordField'
];

public function __construct($name, $title = null, $value = '')
{
// Name must be "SudoModePasswordField" as there's logic elsewhere expecting this
// $name and $value are set to null as the react component does not use these arguments
parent::__construct(SudoModePasswordField::FIELD_NAME, null, null);
}
}
7 changes: 7 additions & 0 deletions src/ORM/DataObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@
*/
class DataObject extends ViewableData implements DataObjectInterface, i18nEntityProvider, Resettable
{
private static bool $requireSudoMode = false;

public function getRequireSudoMode()
{
return $this->config()->get('requireSudoMode');
}

/**
* Human-readable singular name.
* @var string
Expand Down
2 changes: 2 additions & 0 deletions src/Security/Member.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@
*/
class Member extends DataObject
{
private static bool $requireSudoMode = true; // todo Group, Role, etc

private static $db = [
'FirstName' => 'Varchar',
'Surname' => 'Varchar',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,6 @@ public function logIn(Member $member, $persistent = false, HTTPRequest $request
if (Member::config()->get('login_marker_cookie')) {
Cookie::set(Member::config()->get('login_marker_cookie'), 1, 0);
}

// Activate sudo mode on login so the user doesn't have to reauthenticate for sudo
// actions until the sudo mode timeout expires
$service = Injector::inst()->get(SudoModeServiceInterface::class);
$service->activate($session);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Security/Member_Validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ public function php($data)
) {
$stillAdmin = true;

if (!isset($data['DirectGroups'])) {
if (!isset($data['DirectGroups']) || !is_array($data['DirectGroups'])) {
$stillAdmin = false;
} else {
$adminGroups = array_intersect(
Expand Down

0 comments on commit a41f2a4

Please sign in to comment.