Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions Documentation/ApiOverview/Authentication/BackendUsers/Index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,34 @@ stored in the global variable :php:`$GLOBALS['BE_USER']`
* `Be.security.ifAuthenticated ViewHelper <f:be.security.ifAuthenticated> <https://docs.typo3.org/permalink/t3viewhelper:typo3-fluid-be-security-ifauthenticated>`_
* `Be.security.ifHasRole ViewHelper <f:be.security.ifHasRole> <https://docs.typo3.org/permalink/t3viewhelper:typo3-fluid-be-security-ifhasrole>`_
* `TypoScript condition [backend.user.isLoggedIn] <https://docs.typo3.org/permalink/t3tsref:condition-backend-user-isloggedin>`_

.. _backend-user-api-sudo:

Sudo mode (step-up authentication) for password changes
=======================================================

.. versionadded:: 12.4.32 / 13.4.13
This functionality was introduced in response to security advisory `TYPO3-CORE-SA-2025-013 <https://typo3.org/security/advisory/typo3-core-sa-2025-013>`_
to mitigate password-change risks.

This mechanism prevents unauthorized password changes if an administrator
session is hijacked or left unattended.

When an administrator edits their own user account or changes the
password of another user via the admin interface, password confirmation
(step-up authentication) is required.

.. figure:: /Images/ManualScreenshots/AdminTools/SudoMode.png
:alt: Dialog "Verify with user password" with password prompt shown on attempting to change a password.

Step-up authentication requires the administrator to re-enter their password

.. note::
This may pose challenges when integrating remote single sign-on (SSO)
providers, as these typically do not support a dedicated step-up
authentication process.

In such cases, you can use the PSR-14 events `SudoModeRequiredEvent <https://docs.typo3.org/permalink/t3coreapi:sudomoderequiredevent>`_
(triggered before showing the sudo-mode verification dialog) and
`SudoModeVerifyEvent <https://docs.typo3.org/permalink/t3coreapi:sudomodeverifyevent>`_
(triggered before actually verifying the submitted password) to adapt the behavior.
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
.. include:: /Includes.rst.txt
.. index:: Events; SudoModeRequiredEvent
.. _SudoModeRequiredEvent:

=====================
SudoModeRequiredEvent
=====================

.. versionadded:: 12.4.32 / 13.4.13
This event was introduced by security advisory `TYPO3-CORE-SA-2025-013 <https://typo3.org/security/advisory/typo3-core-sa-2025-013>`_
to address challenges with single sign-on (SSO) providers.

The PSR-14 event
:php:`\TYPO3\CMS\Backend\Backend\Event\SudoModeRequiredEvent` is triggered before
showing the `sudo-mode verification dialog <https://docs.typo3.org/permalink/t3coreapi:backend-user-api-sudo>`_
when managing backend user accounts.

This step-up authentication, introduced as part of the fix for
`TYPO3-CORE-SA-2025-013 <https://typo3.org/security/advisory/typo3-core-sa-2025-013>`_,
helps prevent unauthorized password changes. However,
it may pose challenges when using remote single sign-on (SSO) systems, which
typically do not support a separate step-up verification process.

This event allows developers to skip / bypass the step-up
authentication process and uses custom logic, such as identifying users
authenticated through an :abbr:`SSO (single sign-on)` system.

.. seealso::

* The `SudoModeVerifyEvent <https://docs.typo3.org/permalink/t3coreapi:sudomodeverifyevent>`_
is triggered before verification of a submitted password.

.. _SudoModeRequiredEvent-example:


Example: Use an event listener to skip step-up authentication for SSO users
===========================================================================

The following example demonstrates how to use an event listener to skip step-up
authentication for `be_users` records that have an active `is_sso` flag:

.. literalinclude:: _SudoModeRequiredEvent/_Services.yaml
:caption: EXT:my_extension/Configuration/Services.yaml

.. literalinclude:: _SudoModeRequiredEvent/_SkipSudoModeDialog.php
:caption: EXT:my_extension/Classes/EventListener/SkipSudoModeDialog.php

See also: `StaticPasswordVerification example <https://docs.typo3.org/permalink/t3coreapi:sudomodeverifyevent-example>`_

.. _SudoModeRequiredEvent-api:

API
===

.. include:: /CodeSnippets/Events/Backend/SudoModeRequiredEvent.rst.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
.. include:: /Includes.rst.txt
.. index:: Events; SudoModeVerifyEvent
.. _SudoModeVerifyEvent:

===================
SudoModeVerifyEvent
===================

.. versionadded:: 12.4.32 / 13.4.13
This event was introduced by the fix for security advisory `TYPO3-CORE-SA-2025-013 <https://typo3.org/security/advisory/typo3-core-sa-2025-013>`_
to address challenges with single sign-on (SSO) providers.

The PSR-14 event
:php:`\TYPO3\CMS\Backend\Backend\Event\SudoModeVerifyEvent` is triggered before
a password submitted in `sudo-mode verification dialog
<https://docs.typo3.org/permalink/t3coreapi:backend-user-api-sudo>`_ is verified
for backend user accounts.

This step-up authentication mechanism, introduced as part of the fix for
`TYPO3-CORE-SA-2025-013 <https://typo3.org/security/advisory/typo3-core-sa-2025-013>`_,
may pose challenges when using remote single sign-on
(SSO) systems because they do not support a dedicated verification step.

This event allows developers to change the verification logic of step-up
authentication, by conditionally allowing or denying verification based
on custom logic — for example, by identifying users authenticated via an
:abbr:`SSO (single sign-on)` system.

.. seealso::

* `SudoModeRequiredEvent <https://docs.typo3.org/permalink/t3coreapi:sudomoderequiredevent>`_
is triggered before showing the sudo-mode verification dialog.

.. _SudoModeVerifyEvent-example:

Example: Use an event listener to modify the verification of password in sudo mode
==================================================================================

The following demonstrates using the event to statically check the password for
an expected hash.

.. warning::
This example has been simplified for clarity. Always use secure password
handling with salted hashing in production. **Never** hard-code a password hash as
shown below.

.. literalinclude:: _SudoModeRequiredEvent/_Services.yaml
:caption: EXT:my_extension/Configuration/Services.yaml

.. literalinclude:: _SudoModeVerifyEvent/_StaticPasswordVerification.php
:caption: EXT:my_extension/Classes/EventListener/StaticPasswordVerification.php

See also: `SkipSudoModeDialog example <https://docs.typo3.org/permalink/t3coreapi:sudomoderequiredevent-example>`_.

.. _SudoModeVerifyEvent-api:

API
===

.. include:: /CodeSnippets/Events/Backend/SudoModeVerifyEvent.rst.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
services:
_defaults:
autowire: true
autoconfigure: true
public: false

Vendor\MyExtension\EventListener\SkipSudoModeDialog:
tags:
- name: event.listener
identifier: 'ext-myextension/skip-sudo-mode-dialog'
Vendor\MyExtension\EventListener\StaticPasswordVerification:
tags:
- name: event.listener
identifier: 'ext-myextension/static-password-verification'
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

declare(strict_types=1);

namespace Vendor\MyExtension\EventListener;

use TYPO3\CMS\Backend\Hooks\DataHandlerAuthenticationContext;
use TYPO3\CMS\Backend\Security\SudoMode\Access\AccessSubjectInterface;
use TYPO3\CMS\Backend\Security\SudoMode\Access\TableAccessSubject;
use TYPO3\CMS\Backend\Security\SudoMode\Event\SudoModeRequiredEvent;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Utility\MathUtility;

final class SkipSudoModeDialog
{
public function __invoke(SudoModeRequiredEvent $event): void
{
// Ensure the event context matches DataHandler operations
if ($event->getClaim()->origin !== DataHandlerAuthenticationContext::class) {
return;
}

// Filter for TableAccessSubject types only
$tableAccessSubjects = array_filter(
$event->getClaim()->subjects,
static fn(AccessSubjectInterface $subject): bool => $subject instanceof TableAccessSubject,
);

// Abort if there are unhandled subject types
if ($event->getClaim()->subjects !== $tableAccessSubjects) {
return;
}

/** @var list<TableAccessSubject> $tableAccessSubjects */
foreach ($tableAccessSubjects as $subject) {
// Expecting format: tableName.fieldName.id
if (substr_count($subject->getSubject(), '.') !== 2) {
return;
}

[$tableName, $fieldName, $id] = explode('.', $subject->getSubject());

// Only handle be_users table
if ($tableName !== 'be_users') {
return;
}

// Skip if ID is not a valid integer (e.g., 'NEW' records)
if (!MathUtility::canBeInterpretedAsInteger($id)) {
continue;
}

$record = BackendUtility::getRecord($tableName, $id);

// Abort if any record does not use SSO
if (empty($record['is_sso'])) {
return;
}
}

// All conditions met — disable verification
$event->setVerificationRequired(false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace Example\Demo\EventListener;

use TYPO3\CMS\Backend\Security\SudoMode\Event\SudoModeVerifyEvent;

final class StaticPasswordVerification
{
public function __invoke(SudoModeVerifyEvent $event): void
{
$calculatedHash = hash('sha256', $event->getPassword());
// static hash of `dontdothis` - just used as proof-of-concept
// side-note: in production, make use of strong salted password
$expectedHash = '3382f2e21a5471b52a85bc32ab59ab2c467f6e3cb112aef295323874f423994c';

if (hash_equals($expectedHash, $calculatedHash)) {
$event->setVerified(true);
}
}
}
12 changes: 12 additions & 0 deletions Documentation/CodeSnippets/Config/Api/Events/EventsBackend.php
Original file line number Diff line number Diff line change
Expand Up @@ -303,4 +303,16 @@
'targetFileName' => 'CodeSnippets/Events/Backend/AfterSectionMarkupGeneratedEvent.rst.txt',
'withCode' => false,
],
[
'action' => 'createPhpClassDocs',
'class' => TYPO3\CMS\Backend\Security\SudoMode\Event\SudoModeRequiredEvent::class,
'targetFileName' => 'CodeSnippets/Events/Backend/SudoModeRequiredEvent.rst.txt',
'withCode' => false,
],
[
'action' => 'createPhpClassDocs',
'class' => TYPO3\CMS\Backend\Security\SudoMode\Event\SudoModeVerifyEvent::class,
'targetFileName' => 'CodeSnippets/Events/Backend/SudoModeVerifyEvent.rst.txt',
'withCode' => false,
],
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.. Generated by https://github.com/TYPO3-Documentation/t3docs-codesnippets
.. php:namespace:: TYPO3\CMS\Backend\Security\SudoMode\Event

.. php:class:: SudoModeRequiredEvent

.. php:method:: getClaim()
:returns: `\TYPO3\CMS\Backend\Security\SudoMode\Access\AccessClaim`

.. php:method:: isVerificationRequired()
:returns: `bool`

.. php:method:: setVerificationRequired(bool $verificationRequired)

:param $verificationRequired: the verificationRequired
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.. Generated by https://github.com/TYPO3-Documentation/t3docs-codesnippets
.. php:namespace:: TYPO3\CMS\Backend\Security\SudoMode\Event

.. php:class:: SudoModeVerifyEvent

.. php:method:: getClaim()
:returns: `\TYPO3\CMS\Backend\Security\SudoMode\Access\AccessClaim`

.. php:method:: getPassword()
:returns: `string`

.. php:method:: isUseInstallToolPassword()
:returns: `bool`

.. php:method:: isVerified()
:returns: `bool`

.. php:method:: setVerified(bool $verified)

:param $verified: the verified
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading