mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-09-24 18:37:52 +02:00
Add: qr code for new secrets
This commit is contained in:
parent
3b31e63810
commit
b6b4315337
@ -6,7 +6,6 @@ use Exception;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Authentication\Auth;
|
||||
use Icinga\Authentication\Totp;
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Forms\PreferenceForm;
|
||||
use Icinga\User\Preferences;
|
||||
use Icinga\Web\Form;
|
||||
@ -135,10 +134,12 @@ class TotpForm extends PreferenceForm
|
||||
'Please enter the verification code from your TOTP application to verify the new secret.'
|
||||
),
|
||||
'class' => 'autofocus content-centered',
|
||||
'style' => 'width: 200px;',
|
||||
'style' => 'width: 120px;',
|
||||
'autocomplete' => 'off',
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
$this->addElement(
|
||||
'submit',
|
||||
'btn_verify_totp',
|
||||
@ -159,6 +160,26 @@ class TotpForm extends PreferenceForm
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
$this->addElement(
|
||||
'hidden',
|
||||
'qr_code_image',
|
||||
[
|
||||
'required' => false,
|
||||
'ignore' => false,
|
||||
'autoInsertNotEmptyValidator' => false,
|
||||
'decorators' => [
|
||||
[
|
||||
'HtmlTag', [
|
||||
'tag' => 'img',
|
||||
'src' => $this->totp->createQRCode(),
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
);
|
||||
|
||||
$this->addDisplayGroup(
|
||||
['totp_verification_code', 'btn_verify_totp'],
|
||||
'verify_buttons',
|
||||
@ -167,7 +188,10 @@ class TotpForm extends PreferenceForm
|
||||
'FormElements',
|
||||
[
|
||||
'HtmlTag',
|
||||
['tag' => 'div', 'class' => 'control-group form-controls']
|
||||
[
|
||||
'tag' => 'div',
|
||||
'class' => 'control-group form-controls'
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
@ -2,6 +2,10 @@
|
||||
|
||||
namespace Icinga\Authentication;
|
||||
|
||||
use chillerlan\QRCode\Common\EccLevel;
|
||||
use chillerlan\QRCode\Data\QRMatrix;
|
||||
use chillerlan\QRCode\QRCode;
|
||||
use chillerlan\QRCode\QROptions;
|
||||
use Icinga\Clock\PsrClock;
|
||||
use Icinga\Common\Database;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
@ -47,7 +51,6 @@ class Totp
|
||||
*/
|
||||
const COLUMN_MODIFIED_TIME = 'mtime';
|
||||
|
||||
|
||||
/**
|
||||
* State indicating that a secret check is required
|
||||
*/
|
||||
@ -61,6 +64,14 @@ class Totp
|
||||
*/
|
||||
const STATE_APPROVED_TEMPORARY_SECRET = 'approve_temporary_secret';
|
||||
|
||||
/**
|
||||
* The label for the TOTP application
|
||||
*
|
||||
* This label is used when generating the TOTP secret and QR code.
|
||||
* It helps identify the application in the user's TOTP app.
|
||||
*/
|
||||
const TOTP_LABEL = 'IcingaWeb2';
|
||||
|
||||
/**
|
||||
* The username for which the TOTP is configured
|
||||
*
|
||||
@ -355,6 +366,44 @@ class Totp
|
||||
return $this->totpObject->now();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a QR code for the TOTP secret.
|
||||
* This method generates a QR code that can be scanned by TOTP apps to set up the user's secret.
|
||||
*
|
||||
* @return string The rendered QR code as a string
|
||||
*/
|
||||
public function createQRCode(): ?string
|
||||
{
|
||||
if ($this->temporaryTotpObject === null) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
$urlOTPAUTH = sprintf(
|
||||
'otpauth://totp/%1$s:%2$s?secret=%3$s&issuer=%1$s',
|
||||
urlencode(self::TOTP_LABEL),
|
||||
urlencode($this->username),
|
||||
urlencode($this->temporarySecret),
|
||||
);
|
||||
$options = new QROptions();
|
||||
|
||||
$options->scale = 5;
|
||||
|
||||
// $options->svgLogo = __DIR__.'/github.svg'; // logo from: https://github.com/simple-icons/simple-icons
|
||||
// $options->svgLogoScale = 0.25;
|
||||
// $options->svgLogoCssClass = 'dark';
|
||||
//
|
||||
// $options->addLogoSpace = true;
|
||||
// $options->logoSpaceWidth = 19;
|
||||
// $options->logoSpaceHeight = 19;
|
||||
// $options->logoSpaceStartX = 25;
|
||||
// $options->logoSpaceStartY = 25;
|
||||
// $options->eccLevel = EccLevel::H;
|
||||
|
||||
return (new QRCode($options))->render($urlOTPAUTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the TOTP secret for the current user.
|
||||
* This method retrieves the secret used for generating TOTP codes.
|
||||
@ -464,20 +513,40 @@ class Totp
|
||||
return $this;
|
||||
}
|
||||
$this->temporaryTotpObject = $this->temporarySecret !== null
|
||||
? extTOTP::createFromSecret($this->temporarySecret, $this->clock)
|
||||
? $this->createTotpObject($this->temporarySecret)
|
||||
: null;
|
||||
|
||||
$this->totpObject = $this->secret !== null
|
||||
? extTOTP::createFromSecret($this->secret, $this->clock)
|
||||
? $this->createTotpObject($this->secret)
|
||||
: null;
|
||||
} else {
|
||||
$this->temporaryTotpObject = extTOTP::generate($this->clock);
|
||||
$this->temporaryTotpObject = $this->createTotpObject();
|
||||
$this->temporarySecret = $this->temporaryTotpObject->getSecret();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a TOTP object with the given secret.
|
||||
* If no secret is provided, a new TOTP object is generated.
|
||||
* This method sets the label and issuer for the TOTP object.
|
||||
*
|
||||
* @param string|null $secret The TOTP secret to use, or null to generate a new one
|
||||
* @return extTOTP The created TOTP object
|
||||
*/
|
||||
private function createTotpObject(string $secret = null): extTOTP
|
||||
{
|
||||
$totpObject = ($secret === null)
|
||||
? extTOTP::generate($this->clock)
|
||||
: extTOTP::createFromSecret($secret, $this->clock);
|
||||
|
||||
$totpObject->setLabel(self::TOTP_LABEL);
|
||||
$totpObject->setIssuer($this->username);
|
||||
|
||||
return $totpObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the temporary TOTP object permanent.
|
||||
* This method updates the main TOTP object and clears the temporary state.
|
||||
|
Loading…
x
Reference in New Issue
Block a user