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
6 changes: 6 additions & 0 deletions docs/en/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,9 @@ This event is sent to extend the content of the "view profile" page.
The view profile currently display information of the profile (username, first name, e-mail, ...) and a button to edit values.
use `addContent(string $content, int $position)` to add some content to the page. Initial content is on position 5.

`AuthAdminGetIDPPlugin`
-----------------

This event is sent to build the IDP list (existing regardless the `[authentication]` configuration).

Use the event when you create a module so that it is known by idpadmin module.
109 changes: 109 additions & 0 deletions modules/authadmin/controllers/idpadmin.classic.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

je propose de nommer le module authadmin au lieu de idpadmin. Il portera d'autres pages de configuration générale pour l'authentification. Le contrôleur pourrait être nommé idpadmin plutôt que default (à terme default sera plutôt une sorte de page d'accueil de l'admin auth)


use Jelix\Authentication\AuthAdmin\IdpFinder;
use Jelix\IniFile\IniModifier;

class idpadminCtrl extends jController
{
public $pluginParams = [
'*' => array('auth.required' => false, 'jacl2.right' => 'auth.idpadmin.view'),
'save' => array('jacl2.right' => 'auth.idpadmin.edit'),
];

private $idpList ;

public function __construct(jRequest $req)
{
$idpFinder = new IdpFinder();
$this->idpList = $idpFinder->findAllIDP();
parent::__construct($req);
}

public function index()
{
$resp = $this->getResponse('html');
// build form
$form = jForms::create('authadmin~idp');
$this->buildForm($form);
foreach($this->idpList as $idpInfo) {
$form->setData('chck_'.$idpInfo[0], $idpInfo[1]);
}
$tpl = new jTpl();
$tpl->assign('idps', $this->idpList);
$tpl->assign('form', $form);
$resp->body->assign('MAIN', $tpl->fetch('idp.list'));

return $resp;
}

public function prepareEdit()
{
$form = jForms::create('authadmin~idp');
$this->buildForm($form);
foreach($this->idpList as $idpInfo) {
$form->setData('chck_'.$idpInfo[0], $idpInfo[1]);
}
return $this->redirect('authadmin~idpadmin:showEdit');
}

public function showEdit()
{
$form = jForms::get('authadmin~idp');
if(is_null($form)) {
return $this->redirect('authadmin~idpadmin:prepareEdit');
}
$this->buildForm($form);
$resp = $this->getResponse('html');

$tpl = new jTpl();
$tpl->assign('idps', $this->idpList);
$tpl->assign('form', $form);
$resp->body->assign('MAIN', $tpl->fetch('idp.edit'));

return $resp;
}

public function save()
{
$modif = new IniModifier(jApp::varConfigPath('liveconfig.ini.php'));

// build form
$form = jForms::get('authadmin~idp');
$this->buildForm($form);
$form->initFromRequest();

if(!$form->check()) {
return $this->redirect('authadmin~idpadmin:showEdit');
}

$enabledIdp = [];
foreach($this->idpList as $idp) {
$name = $idp[0];
if ($form->getData('chck_'.$name) == 1) {
$enabledIdp[] = $name;
}
}
$sessionIdp = jAuthentication::session()->getIdentityProviderId();
if (!in_array($sessionIdp, $enabledIdp)) {
$form->setErrorOn('chck_'.$name, jLocale::get('default.form.error.session.idp.disabling.forbidden'));
return $this->redirect('authadmin~idpadmin:showEdit');
}
$modif->setValues(['idp' => $enabledIdp], 'authentication');
$modif->save();
jForms::destroy('authadmin~idp');

return $this->redirect('authadmin~idpadmin:index');
}

protected function buildForm(jFormsBase $form)
{
foreach($this->idpList as $idpInfo) {
$name = $idpInfo[0];
$ctrlStatus = new jFormsControlCheckbox('chck_'.$name);
$ctrlStatus->label = $name;
$ctrlStatus->valueLabelOnCheck = jLocale::get('jelix~ui.buttons.enabled');
$ctrlStatus->valueLabelOnUncheck = jLocale::get('jelix~ui.buttons.disabled');
$form->addControl($ctrlStatus);
}
}
}
5 changes: 5 additions & 0 deletions modules/authadmin/events.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<events xmlns="http://jelix.org/ns/events/1.0">
<listener name="\Jelix\Authentication\AuthAdmin\AdminUiEventListener">
<event name="adminui.loading" />
</listener>
</events>
6 changes: 6 additions & 0 deletions modules/authadmin/forms/idp.form.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://jelix.org/ns/forms/1.1">
<submit ref="submit">
<label locale="account~account.profile.button.modify"/>
</submit>
</form>
19 changes: 19 additions & 0 deletions modules/authadmin/install/install.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

use Jelix\Installer\Module\API\InstallHelpers;
use Jelix\Installer\Module\Installer;

class authadminModuleInstaller extends Installer
{
public function install(InstallHelpers $helpers)
{
$groupName = 'auth.idpadmin.subject.group';
// Add rights group
jAcl2DbManager::createRightGroup($groupName, 'authadmin~default.rights.group.name');

// Add right subject
jAcl2DbManager::createRight('auth.idpadmin.view', 'authadmin~default.idp.view', $groupName);
jAcl2DbManager::createRight('auth.idpadmin.edit', 'authadmin~default.idp.edit', $groupName);

}
}
31 changes: 31 additions & 0 deletions modules/authadmin/lib/AdminUiEventListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Jelix\Authentication\AuthAdmin;

use jAcl2;
use Jelix\AdminUI\SideBar\SubMenu;
use jEventListener;
use jLocale;

class AdminUiEventListener extends jEventListener
{
protected $eventMapping = array(
'adminui.loading' => 'onAdminUILoading',
);

/**
* @param jEvent $event
*/
public function onAdminUILoading($event)
{
if(jAcl2::check('auth.idpadmin.view')) {
/** @var \Jelix\AdminUI\UIManager $uim */
$uim = $event->uiManager;

$adminMenu = new SubMenu('admin', 'Authentification', 10);
$adminMenu->addJelixLinkItem(jLocale::get('authadmin~default.navigation.menu.idp'), 'authadmin~idpadmin:index', array(), 'address-book');
$uim->sidebar()->addMenuItem($adminMenu);
}

}
}
30 changes: 30 additions & 0 deletions modules/authadmin/lib/IdpFinder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Jelix\Authentication\AuthAdmin;

use jAuthentication;
use Jelix\Authentication\Core\IdentityProviderInterface;
use jEvent;

class IdpFinder
{
public function findAllIDP()
{
// use event to find all existing idp plugin
$allIdpResponse = jEvent::notify('AuthAdminGetIDPPlugin')->getResponse();
$authManager = jAuthentication::manager();
$enabledIdps = $authManager->getIdpList();
$enabledIdpNames = array_map(function (IdentityProviderInterface $idp) {return $idp->getId();}, $enabledIdps);
$allIdpName = [];
foreach($allIdpResponse as $idpInfo) {
if (array_key_exists('pluginName', $idpInfo)) {
$pluginName = $idpInfo['pluginName'];
$idpEnabled = (false !== array_search($pluginName, $enabledIdpNames));
$allIdpName[] = [$pluginName, $idpEnabled];
}

}

return $allIdpName;
}
}
9 changes: 9 additions & 0 deletions modules/authadmin/locales/en_US/default.UTF-8.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
rights.group.name=Identity providers
idp.view=View Identity providers
idp.edit=Edit Identity providers
navigation.menu.idp=Identity providers
idp.list.page.title=Installed identity providers
idp.edit.page.title=Edit identity providers
form.error.session.idp.disabling.forbidden=You can't disable the idp uses by current session
table.th.name=Nom
table.th.status=Status
9 changes: 9 additions & 0 deletions modules/authadmin/locales/fr_FR/default.UTF-8.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
rights.group.name=Fournisseurs d'identité
idp.view=Voir les fournisseurs d'identité
idp.edit=Modifier les fournisseurs d'identité
navigation.menu.idp=Fournisseurs d'identité
idp.list.page.title=Fournisseurs d'identité installés
idp.edit.page.title=Modifier les fournisseurs d'identité
form.error.session.idp.disabling.forbidden=Vous ne pouvez pas désactiver le fournisseur utilisé par la session en cours
table.th.name=Nom
table.th.status=Status
19 changes: 19 additions & 0 deletions modules/authadmin/module.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="http://jelix.org/ns/module/1.0">
<info id="authadmin@modules.jelix.org" name="authadmin" createdate="2025-09-08">
<version date="2025-06-16">0.0.1</version>
<label lang="en_US">JelixAuth AuthAdmin</label>
<description lang="en_US">Module adding administration page for IDP</description>
<license>MIT</license>
<copyright>2019-2025 Laurent Jouanneau</copyright>
<creator name="Laurent Jouanneau" email="laurent@jelix.org"/>
<homepageURL>https://jelix.org</homepageURL>
</info>
<dependencies>
<jelix minversion="1.8.0" maxversion="1.9.0-beta.1"/>
<module name="jacl2"/>
</dependencies>
<autoload>
<namespacePathMap name="Jelix\Authentication\AuthAdmin" dir="lib" />
</autoload>
</module>
37 changes: 37 additions & 0 deletions modules/authadmin/templates/idp.edit.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<h2>{@authadmin~default.idp.edit.page.title@}</h2>

<div class="card">
<div class="card-body">
{form $form, 'authadmin~idpadmin:save', [], 'adminlte'}

{formcontrols}

<table class="table table-bordered table-striped">
<thead>
<tr><th>{@authadmin~default.table.th.name@}</th>
<th>{@authadmin~default.table.th.status@}</th>
</tr>
</thead>
<tbody>
{foreach $idps as $idp}
{assign $ctlName = 'chck_'.$idp[0]}
<tr>
<td class="col-sm-4">
{$idp[0]}
</td>
<td class="col-sm-4">
{ctrl_control $ctlName}
</td>
</tr>
{/foreach}
</tbody>
</table>

{/formcontrols}

<div class="form-group row">
<div class="col-sm-10 offset-sm-2 ">{formsubmit}</div>
</div>
{/form}
</div>
</div>
36 changes: 36 additions & 0 deletions modules/authadmin/templates/idp.list.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

<h2>{@authadmin~default.idp.list.page.title@}</h2>
<div class="card">
<div class="card-body">

{formcontrols $form}

<table class="table table-bordered table-striped">
<thead>
<tr>
<th>{@authadmin~default.table.th.name@}</th>
<th>{@authadmin~default.table.th.status@}</th>
</tr>
</thead>
<tbody>

{foreach $idps as $idp}
{assign $ctlName = 'chck_'.$idp[0]}
<tr>
<td class="col-sm-4">
{$idp[0]}
</td>
<td class="col-sm-4">
{ctrl_value $ctlName}
</td>
</tr>
{/foreach}
</tbody>
</table>

{/formcontrols}
{ifacl2 'auth.idpadmin.edit'}
<a href='{jurl 'authadmin~idpadmin:prepareEdit'}' class='btn btn-primary' >{@jelix~ui.buttons.update@}</a>
{/ifacl2}
</div>
</div>
7 changes: 7 additions & 0 deletions modules/authadmin/urls.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<suburls xmlns="http://jelix.org/ns/suburls/1.0">
<url pathinfo="/list" action="idpadmin:index" />
<url pathinfo="/pre" action="idpadmin:prepareEdit" />
<url pathinfo="/edit" action="idpadmin:showEdit" />
<url pathinfo="/save" action="idpadmin:save" />
</suburls>
5 changes: 5 additions & 0 deletions modules/authloginpass/events.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<events xmlns="http://jelix.org/ns/events/1.0">
<listener name="\Jelix\Authentication\LoginPass\AuthCoreEventListener">
<event name="AuthAdminGetIDPPlugin" />
</listener>
</events>
16 changes: 16 additions & 0 deletions modules/authloginpass/lib/AuthCoreEventListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace jelix\Authentication\LoginPass;

use jEventListener;

class AuthCoreEventListener extends jEventListener
{
/**
* @param jEvent $event
*/
public function onAuthAdminGetIDPPlugin($event)
{
$event->add(['pluginName' => 'loginpass']);
}
}
11 changes: 10 additions & 1 deletion test/appctl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ shift

if [ "$COMMAND" == "" ]; then
echo "Error: command is missing"
echo "Possible commands: clean_tmp, reset, install, rights, composer-install, composer-update"
echo "Possible commands: clean_tmp, reset, install, rights, composer-install, composer-update, install-admin"
echo " unit-tests, shell, shellroot"
echo " ldapreset, ldapusers"
exit 1;
Expand Down Expand Up @@ -45,6 +45,15 @@ case $COMMAND in
ldapshell)
docker exec -it ${CONTAINER_PREFIX}_ldap /bin/bash -l
;;
install-admin)
docker exec -t -i ${CONTAINER_PREFIX}_php /bin/bash -c 'php test/testapp/console.php account:create admin admin@example.com'
docker exec -t -i ${CONTAINER_PREFIX}_php /bin/bash -c 'php test/testapp/console.php account:login:create -b daotablesqlite admin -p adminpass'
docker exec -t -i ${CONTAINER_PREFIX}_php /bin/bash -c 'php test/testapp/console.php acl2user:register admin'
docker exec -t -i ${CONTAINER_PREFIX}_php /bin/bash -c 'php test/testapp/console.php acl2user:addgroup admin admins'
docker exec -t -i ${CONTAINER_PREFIX}_php /bin/bash -c 'php test/testapp/console.php acl2:add admins auth.idpadmin.view'
docker exec -t -i ${CONTAINER_PREFIX}_php /bin/bash -c 'php test/testapp/console.php acl2:add admins auth.idpadmin.edit'
echo "admin account created, login admin, password adminpass"
;;
*)
echo "wrong command"
exit 2
Expand Down
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 @@ -32,6 +32,7 @@
account.enabled=on

accountadmin.enabled=on
authadmin.enabled=on
[coordplugins]
sessionauth=on
jacl2=1
Expand Down
Loading