Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

894 refactor captcha system #923

Merged
merged 1 commit into from
Jul 3, 2024
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
1 change: 1 addition & 0 deletions conf/config.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@

## Captcha
$use_captcha = false;
$captcha_class = "InternalCaptcha";

## Default action
# change
Expand Down
15 changes: 13 additions & 2 deletions docs/config_general.rst
Original file line number Diff line number Diff line change
Expand Up @@ -268,17 +268,28 @@ GET or POST parameter. This method does not require any configuration.

Example: ``https://ssp.example.com/?actionresetbyquestions&login_hint=spiderman``

.. _config_captcha:

Captcha
-------

To require a captcha, set ``$use_captcha``:
To enable captcha, set ``$use_captcha`` to ``true``.

You should also define the captcha module to use.
(By default, ``InternalCaptcha`` is defined in config.inc.php)

.. code-block:: php

$use_captcha = true;
$captcha_class = "InternalCaptcha";

.. tip:: The captcha is used on every form in Self Service Password
(password change, token, questions, etc.)
(password change, token, questions,...)

For ``$captcha_class``, you can select another captcha module. For now, only ``InternalCaptcha`` and ``FriendlyCaptcha`` are supported.

You can also add your own Captcha module. (see :doc:`developpers` )


.. |image0| image:: images/br.png
.. |image1| image:: images/catalonia.png
Expand Down
160 changes: 160 additions & 0 deletions docs/developpers.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
Developper's corner
===================

LDAP Tool Box Self Service Password can be extended with your own code.

Add your own Captcha system
---------------------------

As presented in :ref:`captcha configuration<config_captcha>`, you can enable a captcha on most of the pages of Self-Service-Password.

You can define a customized class for managing your own captcha class:

.. code-block:: php

$use_captcha = true;
$captcha_class = "MyCustomClass";


Then you have to create the captcha module in ``lib/captcha/MyCustomClass.php``.

Here is a template example of such a captcha module:

.. code-block:: php

<?php namespace captcha;

require_once(__DIR__."/../../vendor/autoload.php");

# use/require any dependency here

class MyCustomClass
{
#private $captcha_property;

public function __construct()
{
#$this->captcha_property = $property;
}


# Function that insert extra css
function generate_css_captcha(){
$captcha_css = '';

return $captcha_css;
}

# Function that insert extra js
function generate_js_captcha(){
$captcha_js = '<script></script>';

return $captcha_js;
}

# Function that generate the html part containing the captcha
function generate_html_captcha($messages){

$captcha_html ='
<div class="row mb-3">
<div class="col-sm-4 col-form-label text-end captcha">
<img src="'.$this->generate_captcha_challenge().'" alt="captcha" />
<i id="captcha-refresh" class="fa fa-fw fa-refresh"></i>
</div>
<div class="col-sm-8">
<div class="input-group">
<span class="input-group-text"><i class="fa fa-fw fa-check-circle"></i></span>
<input type="text" autocomplete="new-password" name="captchaphrase" id="captchaphrase" class="form-control" placeholder="'.$messages["captcha"].'" />
</div>
</div>
</div>';

return $captcha_html;
}

# Function that generate the captcha challenge
# Could be called by the backend, or by a call through a REST API to define
function generate_captcha_challenge(){

# cookie for captcha session
ini_set("session.use_cookies",1);
ini_set("session.use_only_cookies",1);
session_name("captcha");
session_start();

# Generate your captcha challenge here
$challenge = "";

$_SESSION['phrase'] = $challenge;

# session is stored and closed now, used only for captcha
session_write_close();

$captcha_image = $captcha->build()->inline();

return $captcha_image;
}

# Function that verify that the result sent by the user
# matches the captcha challenge
function verify_captcha_challenge(){
$result="";
if (isset($_POST["captchaphrase"]) and $_POST["captchaphrase"]) {
# captcha cookie for session
ini_set("session.use_cookies",1);
ini_set("session.use_only_cookies",1);
setcookie("captcha", '', time()-1000);
session_name("captcha");
session_start();
$captchaphrase = strval($_POST["captchaphrase"]);

# Compare captcha stored in session and user guess
if (! isset($_SESSION['phrase']) or
$_SESSION['phrase'] != $captchaphrase) {
$result = "badcaptcha";
}
unset($_SESSION['phrase']);
# write session to make sure captcha phrase is no more included in session.
session_write_close();
}
else {
$result = "captcharequired";
}
return $result;
}

}


?>


Points of attention:

* you can set any configuration parameters in ``config.inc.local.php``, they will be passed to your class if you define them as properties, and initialize them in the constructor
* you can inject extra css in ``generate_css_captcha`` function
* you can inject extra js in ``generate_js_captcha`` function. For example, js code can useful for refreshing the challenge. If so, you are expected to reach ``/newcaptcha.php`` endpoint. This endpoint would call the ``generate_captcha_challenge`` function in current MyCustomClass and returns the result in json format.
* you must fill in the ``generate_html_captcha`` function. This function must return the html code corresponding to the captcha. It should call the ``generate_captcha_challenge``.
* you must fill in the ``generate_captcha_challenge`` function. This function must generate the challenge, and ensure it is stored somewhere (in the php session). This function can also be called by the REST endpoint: ``/newcaptcha.php``
* you must fill in the ``verify_captcha_challenge`` function. This function must compare the challenge generated and stored, and the user guess. It must return a string corresponding to the status: ``badcaptcha``, ``captcharequired``, or empty string (empty string means challenge is verified)
* don't forget to declare the namespace: ``namespace captcha;``
* don't forget to write the corresponding unit tests (see tests/InternalCaptchaTest.php)


Run unit tests
--------------

Run the unit tests with this command:

```
XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-text --configuration tests/phpunit.xml
```

Take care to use the phpunit shipped with composer.

If you don't have the composer dependencies yet:

```
composer update
```

1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ LDAP Tool Box Self Service Password documentation
webservices.rst
audit.rst
set_attributes.rst
developpers.rst
42 changes: 0 additions & 42 deletions htdocs/captcha.php

This file was deleted.

2 changes: 1 addition & 1 deletion htdocs/change.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
#==============================================================================
# Check captcha
#==============================================================================
if ( ( $result === "" ) and $use_captcha) { $result = global_captcha_check();}
if ( ( $result === "" ) and $use_captcha) { $result = $captchaInstance->verify_captcha_challenge();}

#==============================================================================
# Check old password
Expand Down
2 changes: 1 addition & 1 deletion htdocs/changecustompwdfield.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ function set_default_value(&$variable, $defaultValue)
#==============================================================================
# Check captcha
#==============================================================================
if ( ( $result === "" ) and $use_captcha ) { $result = global_captcha_check();}
if ( ( $result === "" ) and $use_captcha ) { $result = $captchaInstance->verify_captcha_challenge();}

#==============================================================================
# Default configuration
Expand Down
2 changes: 1 addition & 1 deletion htdocs/changesshkey.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
#==============================================================================
# Check captcha
#==============================================================================
if ( ( $result === "" ) and $use_captcha) { $result = global_captcha_check();}
if ( ( $result === "" ) and $use_captcha) { $result = $captchaInstance->verify_captcha_challenge();}

#==============================================================================
# Check password
Expand Down
24 changes: 21 additions & 3 deletions htdocs/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@
#==============================================================================
require_once("../vendor/autoload.php");
require_once("../lib/functions.inc.php");
if ($use_captcha) {
require_once("../lib/captcha.inc.php");
}

#==============================================================================
# VARIABLES
Expand Down Expand Up @@ -122,6 +119,11 @@
isset($ldap_krb5ccname) ? $ldap_krb5ccname : null
);

#==============================================================================
# Captcha Config
#==============================================================================
require_once(__DIR__ . "/../lib/captcha.inc.php");

#==============================================================================
# Other default values
#==============================================================================
Expand Down Expand Up @@ -209,6 +211,19 @@
auditlog($audit_log_file, $userdn, $login, $action, $result);
}

#==============================================================================
# Generate captcha
#==============================================================================
$captcha_html = '';
$captcha_js = '';
$captcha_css = '';
if(isset($use_captcha) && $use_captcha == true)
{
$captcha_html = $captchaInstance->generate_html_captcha($messages);
$captcha_js = $captchaInstance->generate_js_captcha();
$captcha_css = $captchaInstance->generate_css_captcha();
}

#==============================================================================
# Smarty
#==============================================================================
Expand Down Expand Up @@ -266,6 +281,9 @@
$smarty->assign('mail_address_use_ldap', $mail_address_use_ldap);
$smarty->assign('sms_use_ldap', $sms_use_ldap);
$smarty->assign('default_action', $default_action);
$smarty->assign('captcha_html', $captcha_html);
$smarty->assign('captcha_js', $captcha_js);
$smarty->assign('captcha_css', $captcha_css);
//$smarty->assign('',);

if (isset($source)) { $smarty->assign('source', $source); }
Expand Down
17 changes: 17 additions & 0 deletions htdocs/newcaptcha.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

require_once("../conf/config.inc.php");
require_once("../vendor/autoload.php");

# load captcha
require_once(__DIR__ . "/../lib/captcha.inc.php");

$captcha_challenge = $captchaInstance->generate_captcha_challenge();
$result = array(
'challenge' => "$captcha_challenge",
);

header('Content-type: application/json');
echo json_encode($result);

?>
2 changes: 1 addition & 1 deletion htdocs/resetbyquestions.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
#==============================================================================
# Check captcha
#==============================================================================
if ( ( $result === "" ) and $use_captcha) { $result = global_captcha_check();}
if ( ( $result === "" ) and $use_captcha) { $result = $captchaInstance->verify_captcha_challenge();}

# Should we pre-populate the question?
# This should ensure that $login is valid and everything else is empty.
Expand Down
2 changes: 1 addition & 1 deletion htdocs/sendsms.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@
# Check captcha
#==============================================================================
if ( $result === "" and $use_captcha) {
$result = global_captcha_check();
$result = $captchaInstance->verify_captcha_challenge();
}

#==============================================================================
Expand Down
2 changes: 1 addition & 1 deletion htdocs/sendtoken.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
# Check captcha
#==============================================================================
if ( ( $result === "" ) and $use_captcha) {
$result = global_captcha_check();
$result = $captchaInstance->verify_captcha_challenge();
}

#==============================================================================
Expand Down
2 changes: 1 addition & 1 deletion htdocs/setattributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
#==============================================================================
# Check captcha
#==============================================================================
if ( ( $result === "" ) and $use_captcha) { $result = global_captcha_check();}
if ( ( $result === "" ) and $use_captcha) { $result = $captchaInstance->verify_captcha_challenge();}

#==============================================================================
# Check password
Expand Down
2 changes: 1 addition & 1 deletion htdocs/setquestions.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
#==============================================================================
# Check captcha
#==============================================================================
if ( ( $result === "" ) and $use_captcha) { $result = global_captcha_check();}
if ( ( $result === "" ) and $use_captcha) { $result = $captchaInstance->verify_captcha_challenge();}

#==============================================================================
# Check password
Expand Down
Loading
Loading