Skip to content

Commit

Permalink
DOC Form sudo mode
Browse files Browse the repository at this point in the history
  • Loading branch information
emteknetnz committed Feb 19, 2025
1 parent c3dbf08 commit 3209462
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 23 deletions.
72 changes: 49 additions & 23 deletions en/02_Developer_Guides/09_Security/04_Sudo_Mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,67 +6,93 @@ icon: key

# Sudo mode

Sudo mode represents a heightened level of permission in that you are more certain that the current user is actually the person whose account is logged in. This is performed by re-validating that the account's password is correct, and will then last for a certain amount of time (configurable) until it will be checked again.
Sudo mode represents a heightened level of permission in that you are more certain that the current CMS user is actually the person whose account is logged in. This is performed by re-validating that the account's password is correct, and will then last for a certain amount of time (configurable) until it will be checked again.

Sudo mode will automatically be enabled for the configured lifetime when a user logs into the CMS. Note that if the PHP session lifetime expires before the sudo mode lifetime, that sudo mode will also be cleared (and re-enabled when the user logs in again). If the user leaves their CMS open, or continues to use it, for an extended period of time with automatic refreshing in the background, sudo mode will eventually deactivate once the max lifetime is reached.
Sudo mode is not active when a user logs in to the CMS. If the PHP session lifetime expires before the sudo mode lifetime, that sudo mode will also be cleared. If the user leaves their CMS open, or continues to use it, for an extended period of time with automatic refreshing in the background, sudo mode will eventually deactivate once the max lifetime is reached.

## Configuring the lifetime
## Sudo mode for models

The default [`SudoModeServiceInterface`](api:SilverStripe\Security\SudoMode\SudoModeServiceInterface) implementation is [`SudoModeService`](api:SilverStripe\Security\SudoMode\SudoModeService), and its lifetime can be configured with YAML. You should read the lifetime value using `SudoModeServiceInterface::getLifetime()`.
The data of models (usually a [`DataObject`](api:SilverStripe\ORM\DataObject) subclass) are protected by sudo mode is still viewable without entering the password, and any actions that modify data, e.g. POSTing an edit form submission, will require the user to enter their password. This is done to balance usability with security. The following `DataObject` subclasses are protected by sudo mode:

```yml
SilverStripe\Security\SudoMode\SudoModeService:
lifetime_minutes: 25
```
- [`Member`](api:SilverStripe\Security\Member)
- [`Group`](api:SilverStripe\Security\Group)
- [`PermissionRole`](api:SilverStripe\Security\PermissionRole)
- [`PermissionRoleCode`](api:SilverStripe\Security\PermissionRoleCode)

## Enabling sudo mode for controllers
### Configuring sudo mode for a `DataObject`

You can add the `SudoModeServiceInterface` singleton as a dependency to a controller that requires sudo mode for one of its actions:
To add sudo mode for a particular model, including your `DataObject` subclasses, simply set the [`require_sudo_mode`](api:SilverStripe\View\ViewableData->require_sudo_mode) configuration property to `true`, either directly on the class or via yml.

```php
namespace App\Control;
namespace App\Model;

class MyController extends Controller
use SilverStripe\ORM\DataObject;

class Product extends DataObject
{
private ?SudoModeServiceInterface $sudoModeService = null;
// ...
private static bool $require_sudo_mode = true;
}
```

private static array $dependencies = ['SudoModeService' => '%$' . SudoModeServiceInterface::class];
```yml
SomeModule\Model\Player:
require_sudo_mode: true
```
public function setSudoModeService(SudoModeServiceInterface $sudoModeService): static
{
$this->sudoModeService = $sudoModeService;
return $this;
}
}
> [!NOTE]
> This will only add sudo mode to edit forms within the CMS interface. It will have no effect on forms outside of the CMS, such as custom forms in the frontend.
> [!WARNING] If you add new fields to form that is protected by sudo mode, such as in an overridden [`LeftAndMain::getEditForm()`](api:SilverStripe\Admin\LeftAndMain::getEditForm()) method, it may mean having to call [`Form::requireSudoMode()`](api:SilverStripe\Forms\Form::requireSudoMode()) on the form to ensure the newly added fields are set to read-only while sudo mode is inactive.

## Configuring the sudo mode lifetime

The default [`SudoModeServiceInterface`](api:SilverStripe\Security\SudoMode\SudoModeServiceInterface) implementation is [`SudoModeService`](api:SilverStripe\Security\SudoMode\SudoModeService), and its lifetime can be configured with YAML. You should read the lifetime value using `SudoModeServiceInterface::getLifetime()`.

```yml
SilverStripe\Security\SudoMode\SudoModeService:
lifetime_minutes: 25
```

Performing a sudo mode verification check in a controller action is simply using the service to validate the request:
## Sudo mode for controller endpoints

Performing a sudo mode verification check in a controller endpoint by using the sudo mode service to validate the request:

```php
namespace App\Control;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Security\SudoMode\SudoModeServiceInterface;
class MyController extends Controller
{
// ...
public function myAction(HTTPRequest $request): HTTPResponse
{
if (!$this->sudoModeService->check($request->getSession())) {
$service = Injector::inst()->get(SudoModeServiceInterface::class);
if (!$service->check($request->getSession())) {
return $this->httpError(403, 'Sudo mode is required for this action');
}
// ... continue with sensitive operations
}
}
```

## Using sudo mode in a react component
## Sudo mode for react components

The `silverstripe/admin` module defines a [React Higher-Order-Component](https://reactjs.org/docs/higher-order-components.html) (aka HOC) which can
be applied to React components in your module or code to intercept component rendering and show a "sudo mode required"
information and log in screen, which will validate, activate sudo mode, and re-render the wrapped component afterwards
on success.

This sudo mode differs from sudo mode for `DataObject`s in that it is not tied to a specific model, but rather to a
specific react component.

> [!WARNING]
> Sudo mode for react components does not protect the data the component manages, or any endpoints the component uses, it simply requires the user to re-enter their password before the component is rendered.

> [!IMPORTANT]
> The `WithSudoMode` HOC is exposed via [Webpack's expose-loader plugin](https://webpack.js.org/loaders/expose-loader/). You will need to add it as a [webpack external](https://webpack.js.org/configuration/externals/) to use it. The recommended way to do this is via the [@silverstripe/webpack-config npm package](https://www.npmjs.com/package/@silverstripe/webpack-config) which handles all the external configuration for you.

You can get the injector to apply the HOC to your component automatically using [injector transformations](/developer_guides/customising_the_admin_interface/reactjs_redux_and_graphql/#transforming-services-using-middleware):
Expand Down
28 changes: 28 additions & 0 deletions en/08_Changelogs/5.4.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ title: 5.4.0 (unreleased)

- [Security considerations](#security-considerations)
- [Features and enhancements](#features-and-enhancements)
- [Sudo mode for sensitive data](#form-sudo-mode)
- [Logged warning if allowed hosts have not been configured](#allowed-hosts-warning)
- [New `XssSanitiser` class](#new-xsssanitiser-class)
- [Option to change `ClassName` column from enum to varchar](#classname-varchar)
Expand All @@ -33,6 +34,33 @@ We have provided a severity rating of the vulnerabilities below based on the CVS

## Features and enhancements

### Sudo mode for sensitive data {#form-sudo-mode}

Some data managed by the CMS is always considered sensitive from a security point of view, such as member data and permissions assigned to groups. Data of this nature is now protected by default by "sudo mode" in the CMS. When a user tries to edit sensitive data, they will be prompted to enter their password to confirm their identity.

This change was made to provide an extra layer of protection against cross site scripting (XSS) attacks, as well as people maliciously using someone elses computer left unattended in a logged-in state.

Users will still be able to view sensitive data without entering their password as they could before. Previously "sudo mode" only protected a member's MFA settings. Now the following [`DataObject`](api:SilverStripe\ORM\DataObject) subclasses are also protected by sudo mode:

- [`Member`](api:SilverStripe\Security\Member)
- [`Group`](api:SilverStripe\Security\Group)
- [`PermissionRole`](api:SilverStripe\Security\PermissionRole)
- [`PermissionRoleCode`](api:SilverStripe\Security\PermissionRoleCode)
- [`SiteConfig`](api:SilverStripe\SiteConfig\SiteConfig)

You can also add sudo mode to your own `DataObject` subclass by setting the [`DataObject.require_sudo_mode`](api:SilverStripe\ORM\DataObject->require_sudo_mode) configuration property to `true`. For example:

```yml
SomeModule\Model\Player:
require_sudo_mode: true
```
Previously sudo mode was automatically activated when a user logged in, which largely negated the value the feature provided. This has now been changed so that users will always have to enter their password to activate sudo mode the first time they reach a sensitive area of the CMS.
There is still a configurable grace period where, after entering your password to activate sudo mode, it will remain active for a short time.
[Learn more about sudo mode](/developer_guides/security/sudo_mode) in the developer docs.
### Logged warning if allowed hosts have not been configured {#allowed-hosts-warning}
If your site does not have one of the following configured, then a warning will now be logged on every request:
Expand Down

0 comments on commit 3209462

Please sign in to comment.