Skip to content

Commit

Permalink
symfony cache doc, conf, and improvements (#954)
Browse files Browse the repository at this point in the history
- add upgrade notes,
- add cache parameters in config,
- remove expired cache entries,
- remove some warning messages,
- security: always display the same message: invalid token even if the user is not found in ldap,
- add more logs,
- set an expiration time for each cache entry
  • Loading branch information
David Coutadeur committed Sep 6, 2024
1 parent 0074476 commit a6963df
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 29 deletions.
12 changes: 12 additions & 0 deletions conf/config.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,18 @@
# Token lifetime in seconds
$token_lifetime = "3600";

## Cache
# $cache_token_expiration: integer, duration in seconds of cached objects
# each time a token is involved
# (for example when sending a token by sms or by mail)
# it is recommended to set a value >= $token_lifetime
$cache_token_expiration = 3600;
# $cache_form_expiration: integer, duration in seconds of cached objects
# at some steps when a user has to validate a form
# (for example when validating the email address before we send the mail)
# it is recommended to set a value high enough for a user to fill a form
$cache_form_expiration = 120;

# Reset URL (mandatory)
$reset_url = "http://ssp.example.com/";
# If inside a virtual host
Expand Down
28 changes: 28 additions & 0 deletions docs/config_general.rst
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,34 @@ See `FriendlyCaptcha documentation <https://docs.friendlycaptcha.com/>`_ for mor

You can also integrate any other Captcha module by developping the corresponding plugin. (see :doc:`developpers` )

.. _config_cache:

Cache
-----

self-service-password rely on Symfony cache libraries.

You can define the cache expiration for some objects:

.. code-block:: php
$cache_token_expiration = 3600;
``$cache_token_expiration`` (integer) is the duration in seconds of cached objects each time a token is involved.

For example when sending a token by sms or by mail, it is the time granted to the user for entering the sms code or for clicking on the link in the mail.

it is recommended to set a value >= ``$token_lifetime``

.. code-block:: php
$cache_form_expiration = 120;
``$cache_form_expiration`` (integer) is the duration in seconds of cached objects at some steps when a user has to validate a form.

For example it is the time granted to a user for validating the email address before sending the mail. It is used mainly for avoiding form replay (by user mistake or by a hacker).

it is recommended to set a value high enough for a user to fill a form.

.. |image0| image:: images/br.png
.. |image1| image:: images/catalonia.png
Expand Down
9 changes: 9 additions & 0 deletions docs/config_sms.rst
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,12 @@ You can also configure the allowed attempts:
$sms_max_attempts_token = 3;
After these attempts, the sent token is no more valid.

You should also set a token lifetime, so they are invalid after some time. The
value is in seconds:

.. code-block:: php
$token_lifetime = "3600";
If you use tokens, you should also set :ref:`config_cache` parameters accordingly.
5 changes: 2 additions & 3 deletions docs/config_tokens.rst
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,14 @@ You can crypt tokens, to protect the session identifier:
.. warning:: If you enable this option, you must change the default
value of the security keyphrase.

You should set a token lifetime, so they are deleted if unused. The
You should set a token lifetime, so they are invalid after some time. The
value is in seconds:

.. code-block:: php
$token_lifetime = "3600";
.. warning:: Token deletion is managed by PHP session garbage
collector.
If you use tokens, you should also set :ref:`config_cache` parameters accordingly.

Log
---
Expand Down
20 changes: 20 additions & 0 deletions docs/upgrade.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
Upgrade
=======

From 1.6 to 1.7
---------------

If you have configured ``$token_lifetime`` parameter, for example for reset by sms or reset by mail features, you should verify that the duration is coherent with the new cache parameters, and adapt these parameters in your local configuration file if needed:

.. code-block:: php
# $cache_token_expiration: integer, duration in seconds of cached objects
# each time a token is involved
# (for example when sending a token by sms or by mail)
# it is recommended to set a value >= $token_lifetime
$cache_token_expiration = 3600;
# $cache_form_expiration: integer, duration in seconds of cached objects
# at some steps when a user has to validate a form
# (for example when validating the email address before we send the mail)
# it is recommended to set a value high enough for a user to fill a form
$cache_form_expiration = 120;
From 1.5 to 1.6
---------------

Expand Down
1 change: 1 addition & 0 deletions htdocs/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
$defaultLifetime = 0,
$directory = null
);
$sspCache->prune();

#==============================================================================
# Captcha Config
Expand Down
5 changes: 4 additions & 1 deletion htdocs/resetbytoken.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@
# will gather login,time and smstoken values from session.
$cached_token = $sspCache->getItem($tokenid);
$cached_token_content = $cached_token->get();
$login = $cached_token_content['login'];
if($cached_token->isHit())
{
$login = $cached_token_content['login'];
}
$smstoken = isset($cached_token_content['smstoken']) ? $cached_token_content['smstoken'] : false;
$posttoken = isset($_REQUEST['smstoken']) ? $_REQUEST['smstoken'] : 'undefined';

Expand Down
15 changes: 11 additions & 4 deletions htdocs/sendsms.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,20 @@
$cached_token = $sspCache->getItem($tokenid);
$cached_token_content = $cached_token->get();

$login = $cached_token_content['login'];
$sessiontoken = $cached_token_content['smstoken'];
$attempts = $cached_token_content['attempts'];
if($cached_token->isHit())
{
$login = $cached_token_content['login'];
$sessiontoken = $cached_token_content['smstoken'];
$attempts = $cached_token_content['attempts'];
}

if (!$login or !$sessiontoken) {
list($result, $token) = obscure_info_sendsms("tokenattempts",
"tokennotvalid",
$token,
$obscure_notfound_sendsms,
$keyphrase);
error_log("Unable to open session $smstokenid");
error_log("Unable to open session $tokenid");
} elseif ($sessiontoken != $smstoken) {
# To have only x tries and not x+1 tries
if ($attempts < ($sms_max_attempts_token - 1)) {
Expand Down Expand Up @@ -211,7 +214,9 @@
'time' => time(),
'attempts' => 0
]);
$smscached_token->expiresAfter($cache_token_expiration);
$sspCache->save($smscached_token);
error_log("generated cache entry with id: " . $smstoken_session_id. " for storing step 'send sms' of password reset by sms workflow, valid for $cache_token_expiration s");

$data = array( "sms_attribute" => $sms, "smsresetmessage" => $messages['smsresetmessage'], "smstoken" => $smstoken) ;

Expand Down Expand Up @@ -271,7 +276,9 @@
'time' => time(),
'smstoken' => $smstoken
]);
$smscached_token->expiresAfter($cache_form_expiration);
$sspCache->save($smscached_token);
error_log("generated cache entry with id: " . $smstoken_session_id. " for storing step 'password change' of password reset by sms workflow, valid for $cache_form_expiration s");

$token = encrypt($smstoken_session_id, $keyphrase);

Expand Down
45 changes: 24 additions & 21 deletions htdocs/sendtoken.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,35 @@
$formtoken = hash('sha256', bin2hex(random_bytes(16)));
$cachedToken = $sspCache->getItem($formtoken);
$cachedToken->set($formtoken);
$cachedToken->expiresAfter($cache_form_expiration);
$sspCache->save($cachedToken);
error_log("generated form token: " . $formtoken);
error_log("generated form token: " . $formtoken . " valid for $cache_form_expiration s");
}

# Check the entered username for characters that our installation doesn't support
if ( $result === "" ) {
$result = check_username_validity($login,$login_forbidden_chars);
}

#==============================================================================
# Check tokenform
#==============================================================================

if ( !$result ) {
$formtoken = strval($_REQUEST["formtoken"]);
$cachedToken = $sspCache->getItem($formtoken);
if( $cachedToken->get() == $formtoken )
{
# Remove session
$sspCache->deleteItem($formtoken);
}
else
{
error_log("Invalid form token: sent: $formtoken, stored: " . $cachedToken->get());
$result = "invalidformtoken";
}
}

#==============================================================================
# Check captcha
#==============================================================================
Expand Down Expand Up @@ -162,7 +182,7 @@
#==============================================================================
if ( !$result ) {

# Use cache to register token
# Use cache to register token sent by mail
$token_session_id = hash('sha256', bin2hex(random_bytes(16)));
if ( $crypt_tokens ) {
$token = encrypt($token_session_id, $keyphrase);
Expand All @@ -174,29 +194,12 @@
'login' => $login,
'time' => time()
]);
$cached_token->expiresAfter($cache_token_expiration);
$sspCache->save($cached_token);
error_log("generated cache entry with id: " . $token_session_id. " for storing password reset by mail workflow, valid for $cache_token_expiration s");
}


#==============================================================================
# Check tokenform
#==============================================================================

if ( !$result ) {
$formtoken = strval($_REQUEST["formtoken"]);
$cachedToken = $sspCache->getItem($formtoken);
if( $cachedToken->get() == $formtoken )
{
# Remove session
$sspCache->deleteItem($formtoken);
}
else
{
error_log("Invalid form token: sent: $formtoken, stored: " . $cachedToken->get());
$result = "invalidformtoken";
}
}

#==============================================================================
# Send token by mail
#==============================================================================
Expand Down

0 comments on commit a6963df

Please sign in to comment.