Skip to content
Open
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
2 changes: 2 additions & 0 deletions docs/en/authcore.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ signOutAction="authcore~sign:out"
; action to redirect to when displaying the login page whereas the user is
; already authenticated. Typical action: the action of the home page
signInAlreadyAuthAction=
; always/never/enabled/disabled (enabled/disabled : user can override value)
notifyAuthMode=

[sessionauth]
; action to redirect to when authentication is needed and the user is not authenticated
Expand Down
3 changes: 3 additions & 0 deletions modules/account/classes/authAccount.listener.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

use Jelix\Authentication\Account;
use Jelix\Authentication\Account\Notification\AuthenticationNotifier;
use Jelix\Authentication\Core\Workflow\Event\GetAccountEvent;
use Jelix\Authentication\Core\Workflow\Step\StepException;
use Jelix\Authentication\LoginPass\AuthLPCanResetPasswordEvent;
Expand All @@ -27,6 +28,8 @@ function onAuthWorkflowStep($event)
$account = Account\Manager::searchAccountByIdp($idpId, $user->getUserId(), true);
if ($account) {
$event->setAccount($account);
$notifier = new AuthenticationNotifier();
$notifier->successAuth($account);
}
else {
$isAccountCreationAllowed = false;
Expand Down
11 changes: 11 additions & 0 deletions modules/account/controllers/profile.classic.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Jelix\Authentication\Account\Manager;
use Jelix\Authentication\Account\Account;
use Jelix\Authentication\Account\Notification\AuthenticationNotifier;

class profileCtrl extends jController {

Expand All @@ -27,6 +28,7 @@ function index() {
}

$form->initFromDao('account~accounts', $formId);
$this->disableNotificationCtrlIfDenied($form);

$tpl = new \jTpl();
$tpl->assign('form', $form);
Expand Down Expand Up @@ -54,6 +56,7 @@ public function modify()
}

$form->initFromDao('account~accounts', $formId);
$this->disableNotificationCtrlIfDenied($form);

$tpl = new jTpl();
$tpl->assign('form', $form);
Expand Down Expand Up @@ -107,5 +110,13 @@ public function save()

return $rep;
}

protected function disableNotificationCtrlIfDenied(jFormsBase $form) {
$notifier = new AuthenticationNotifier();

if (!$notifier->canUsersOverwriteNotifConf()) {
$form->getControl('notify_auth_success')->deactivate();
}
}
}

1 change: 1 addition & 0 deletions modules/account/daos/accounts.dao.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
0 new account, invalid account
1 valid account
-->
<property name="notify_auth_success" fieldname="notify_auth_success" datatype="integer" />
<property name="create_date" fieldname="create_date" datatype="datetime"
insertpattern="now()" updatepattern=""/>

Expand Down
7 changes: 6 additions & 1 deletion modules/account/forms/profile_modify.form.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
<input type="email" ref="email">
<label locale="account~account.profile.th.email"/>
</input>
<radiobuttons ref="notify_auth_success" required='true'>
<label locale="account~account.profile.th.notify_auth_success"/>
<item value="1" locale='account~account.profile.notify_auth_success.text.on' />
<item value="0" locale='account~account.profile.notify_auth_success.text.off' />
</radiobuttons >

<output ref="create_date">
<label locale="account~account.profile.th.createdate"/>
Expand All @@ -25,4 +30,4 @@
<label locale="jelix~ui.buttons.save"/>
</submit>

</form>
</form>
1 change: 1 addition & 0 deletions modules/account/install/sql/add_notify_auth_success.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE accounts ADD COLUMN notify_auth_success integer;
19 changes: 19 additions & 0 deletions modules/account/install/upgrade_041.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php
/**
* @author Laurent Jouanneau
* @copyright 2024 Laurent Jouanneau
*
* @see https://jelix.org
* @licence MIT
*/

class accountModuleUpgrader_041 extends \Jelix\Installer\Module\Installer
{
protected $targetVersions = array('0.4.1');
protected $date = '2025-08-22';

public function install(Jelix\Installer\Module\API\InstallHelpers $helpers)
{
$helpers->database()->execSQLScript('sql/add_notify_auth_success.sql');
}
}
7 changes: 6 additions & 1 deletion modules/account/lib/Account.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,9 @@ public function getEmail()
{
return $this->data['email'];
}
}

public function getNotifyAuthSuccess()
{
return $this->data['notify_auth_success'];
}
}
70 changes: 70 additions & 0 deletions modules/account/lib/Notification/AuthenticationNotifier.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

namespace Jelix\Authentication\Account\Notification;

use DateTimeImmutable;
use DomainException;
use Jelix\Authentication\Account\Account;
use Jelix\Core\Infos\AppInfos;

class AuthenticationNotifier
{
public const NOTIFY_NEVER = 'never';
public const NOTIFY_ALWAYS = 'always';
public const NOTIFY_ON_USER_CAN_OPT_OUT = 'enabled';
public const NOTIFY_OFF_USER_CAN_OPT_IN = 'disabled';

private $notifyMode;
public function __construct()
{
$config = \jApp::config()->authentication;
if (isset($config['notifyAuthMode']) && $config['notifyAuthMode']) {
$this->notifyMode = $config['notifyAuthMode'];
if(!in_array($this->notifyMode, [self::NOTIFY_ALWAYS, self::NOTIFY_NEVER, self::NOTIFY_OFF_USER_CAN_OPT_IN, self::NOTIFY_ON_USER_CAN_OPT_OUT])) {
throw new DomainException('not a valid notifyAuthMode value');
}
} else {
// use never
$this->notifyMode = self::NOTIFY_NEVER;
trigger_error('no value defined for notifyAuthMode, using "never"', E_USER_NOTICE);
}
}

private function isNotificationEnabled(Account $account)
{
if ($this->notifyMode == self::NOTIFY_ALWAYS || $this->notifyMode == self::NOTIFY_ALWAYS) {
return $this->notifyMode == self::NOTIFY_ALWAYS;
}
// must check Account value
$value = $account->getNotifyAuthSuccess();
if($this->notifyMode == self::NOTIFY_OFF_USER_CAN_OPT_IN) {
return $value == 1 ;
}
if($this->notifyMode == self::NOTIFY_ON_USER_CAN_OPT_OUT) {
return $value != 0 ;
}
}

public function successAuth(Account $account)
{
// notify
if($this->isNotificationEnabled($account)) {
$appInfos = AppInfos::load();
$appName = $appInfos->getLabel();
$email = $account->getEmail();
$mailer = new \jMailer();
$mailer->addAddress($email);
$mailer->Subject = \jLocale::get('account~account.email.auth.success.subject', [$email, $appName]);
$tpl = $mailer->Tpl('account~mailBodyAuthSuccess', true);
$tpl->assign('email', $email);
$tpl->assign('appName', $appName);
$tpl->assign('authDateTime', (new DateTimeImmutable())->format('Y-m-d H:i:s'));
$mailer->send();
}
}

public function canUsersOverwriteNotifConf(): bool
{
return in_array($this->notifyMode, [self::NOTIFY_OFF_USER_CAN_OPT_IN, self::NOTIFY_ON_USER_CAN_OPT_OUT]);
}
}
5 changes: 5 additions & 0 deletions modules/account/locales/en_US/account.UTF-8.properties
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ profile.th.email = Email
profile.th.status = Status
profile.th.createdate = Account's creation date
profile.th.provider = Authentication provider
profile.th.notify_auth_success = Receive an email notification each time you log in
profile.notify_auth_success.text.on= On
profile.notify_auth_success.text.off= Off

profile.button.modify = Modify

Expand All @@ -24,3 +27,5 @@ cancel.and.back.to.profile = Cancel and back to your profile
back.to.profile = Back to your profile

error.no.account=Sorry, there is no account with the login %s into this application.

email.auth.success.subject=New login with e-mail %s on app %s
5 changes: 5 additions & 0 deletions modules/account/locales/fr_FR/account.UTF-8.properties
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ profile.th.email = Email
profile.th.status = Statut
profile.th.createdate = Date de création du compte
profile.th.provider = Service d'authentification
profile.th.notify_auth_success = Recevoir une notification e-mail à chaque connexion
profile.notify_auth_success.text.on= Actif
profile.notify_auth_success.text.off= Inactif

profile.button.modify = Modifier

Expand All @@ -24,3 +27,5 @@ cancel.and.back.to.profile = Annuler et retourner à votre profil
back.to.profile = Retourner à votre profil

error.no.account=Désolé, il n'y a pas de compte avec l'identifiant %s dans cette application.

email.auth.success.subject=Nouvelle connexion du compte %s sur l'application %s
2 changes: 1 addition & 1 deletion modules/account/module.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="http://jelix.org/ns/module/1.0">
<info id="account@jelix.org" name="account" createdate="2021-01-12">
<version date="2025-06-16">0.4.0</version>
<version date="2025-08-22">0.4.1</version>
<label lang="en_US">account</label>
<description lang="en_US" />
<license URL="">All rights reserved</license>
Expand Down
8 changes: 8 additions & 0 deletions modules/account/templates/en_US/mailBodyAuthSuccess.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<p>Hello</p>
<p>
A new login has just been made on the {$appName} application with your email address {$email}
</p><p>
Date and time: {$authDateTime}
</p><p>
If this login corresponds to your activity, you can ignore this message.
</p>
8 changes: 8 additions & 0 deletions modules/account/templates/fr_FR/mailBodyAuthSuccess.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<p>Bonjour</p>
<p>
Une nouvelle connexion vient d'être réalisée sur l'application {$appName} avec votre adresse e-mail {$email}
</p><p>
Date et heure : {$authDateTime}
</p><p>
Si cette connexion correspond à votre activité, vous pouvez ignorer ce message.
</p>
1 change: 1 addition & 0 deletions test/testapp/app/system/mainconfig.ini.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@
sessionHandler=php

signInAlreadyAuthAction="adminui~default:index"
notifyAuthMode=enabled

[sessionauth]
authRequired=off
Expand Down