Skip to content
Draft
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 @@ -102,3 +102,9 @@ See the `Jelix\Authentication\LoginPass\AuthLPCanResetPasswordEvent` class.



`declareIDPlugin`
-----------------

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.
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="declareIDPlugin" />
</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 ondeclareIDPlugin($event)
{
$event->add(['pluginName' => 'loginpass']);
}
}
109 changes: 109 additions & 0 deletions modules/idpadmin/controllers/default.classic.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php

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

class defaultCtrl extends jController
{
public $pluginParams = [
'*' => array('auth.required' => false, 'jacl2.right' => 'idpadmin.view'),
'save' => array('jacl2.right' => '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('idpadmin~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('idpadmin~idp');
$this->buildForm($form);
foreach($this->idpList as $idpInfo) {
$form->setData('chck_'.$idpInfo[0], $idpInfo[1]);
}
return $this->redirect('idpadmin~default:showEdit');
}

public function showEdit()
{
$form = jForms::get('idpadmin~idp');
if(is_null($form)) {
return $this->redirect('idpadmin~default: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::appPath('app/system/mainconfig.ini.php'));

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

if(!$form->check()) {
return $this->redirect('idpadmin~default: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('idpadmin~default:showEdit');
}
$modif->setValues(['idp' => $enabledIdp], 'authentication');
$modif->save();
jForms::destroy('idpadmin~idp');

return $this->redirect('idpadmin~default: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/idpadmin/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\IdpAdmin\AdminUiEventListener">
<event name="adminui.loading" />
</listener>
</events>
6 changes: 6 additions & 0 deletions modules/idpadmin/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/idpadmin/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 idpadminModuleInstaller extends Installer
{
public function install(InstallHelpers $helpers)
{
$groupName = 'idpadmin.subject.group';
// Add rights group
jAcl2DbManager::createRightGroup($groupName, 'idpadmin~default.rights.group.name');

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

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

namespace Jelix\Authentication\IdpAdmin;

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('idpadmin.view')) {
/** @var \Jelix\AdminUI\UIManager $uim */
$uim = $event->uiManager;

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

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

namespace Jelix\Authentication\IdpAdmin;

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('declareIDPlugin')->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/idpadmin/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/idpadmin/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/idpadmin/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="idpadmin@modules.jelix.org" name="idpadmin" createdate="2025-09-08">
<version date="2025-06-16">0.0.1</version>
<label lang="en_US">JelixAuth IdpAdmin</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\IdpAdmin" dir="lib" />
</autoload>
</module>
37 changes: 37 additions & 0 deletions modules/idpadmin/templates/idp.edit.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<h2>{@idpadmin~default.idp.edit.page.title@}</h2>

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

{formcontrols}

<table class="table table-bordered table-striped">
<thead>
<tr><th>{@idpadmin~default.table.th.name@}</th>
<th>{@idpadmin~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/idpadmin/templates/idp.list.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

<h2>{@idpadmin~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>{@idpadmin~default.table.th.name@}</th>
<th>{@idpadmin~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 'idpadmin.edit'}
<a href='{jurl 'idpadmin~default:prepareEdit'}' class='btn btn-primary' >{@jelix~ui.buttons.update@}</a>
{/ifacl2}
</div>
</div>
7 changes: 7 additions & 0 deletions modules/idpadmin/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="default:index" />
<url pathinfo="/pre" action="default:prepareEdit" />
<url pathinfo="/edit" action="default:showEdit" />
<url pathinfo="/save" action="default:save" />
</suburls>
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 idpadmin.view'
docker exec -t -i ${CONTAINER_PREFIX}_php /bin/bash -c 'php test/testapp/console.php acl2:add admins 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
idpadmin.enabled=on
[coordplugins]
sessionauth=on
jacl2=1
Expand Down
Loading