1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/piwigo_ynh.git synced 2024-09-03 20:06:03 +02:00

Use extra_files feature of ynh_setup_source

This commit is contained in:
Jimmy Monin 2017-06-10 21:38:32 +02:00
parent 8c1d8803c8
commit fcc493af42
46 changed files with 1354 additions and 1358 deletions

View file

@ -106,8 +106,6 @@ sudo ln -sd $datapath/galleries $final_path/galleries
sudo cp -a $TMPDIR/galleries/* $final_path/galleries/ sudo cp -a $TMPDIR/galleries/* $final_path/galleries/
sudo ln -sd $datapath/upload $final_path/upload sudo ln -sd $datapath/upload $final_path/upload
sudo cp -R ../plugins/Ldap_Login $final_path/plugins/Ldap_Login
sudo chown -R $app: $final_path sudo chown -R $app: $final_path
sudo chown -R $app: $datapath sudo chown -R $app: $datapath
sudo chmod 755 -R $final_path/galleries sudo chmod 755 -R $final_path/galleries

View file

@ -108,8 +108,6 @@ sudo cp -a $TMPDIR/!(upload|galleries) $final_path
sudo cp -a $TMPDIR/galleries/* $final_path/galleries/ sudo cp -a $TMPDIR/galleries/* $final_path/galleries/
sudo cp -R ../plugins/Ldap_Login/* $final_path/plugins/Ldap_Login
sudo chown -R $app: $final_path sudo chown -R $app: $final_path
sudo chown -R $app: /home/yunohost.app/$app sudo chown -R $app: /home/yunohost.app/$app
sudo chmod 755 -R $final_path/galleries sudo chmod 755 -R $final_path/galleries

View file

@ -1,20 +1,20 @@
# Ldap_Login # Ldap_Login
LDAP authentication plugin for piwigo with user-group support LDAP authentication plugin for piwigo with user-group support
## Exmaple-Config for an M$-AD: ## Exmaple-Config for an M$-AD:
#### LDAP-Serververbindung #### LDAP-Serververbindung
**LDAP-Server**: srv.emxample.com</br> **LDAP-Server**: srv.emxample.com</br>
(x) **Secure connection** _(--> remember that the LDAPS-Server certificate must be imported on your piwigo server)_</br> (x) **Secure connection** _(--> remember that the LDAPS-Server certificate must be imported on your piwigo server)_</br>
**LDAP-Port**: 636</br> **LDAP-Port**: 636</br>
#### LDAP Attribute #### LDAP Attribute
**Base DN wo LDAP-Benutzer gefunden werden sollen (zB.: ou=users,dc=example,dc=com):**: cn=Users,dc=example,dc=com</br> **Base DN wo LDAP-Benutzer gefunden werden sollen (zB.: ou=users,dc=example,dc=com):**: cn=Users,dc=example,dc=com</br>
**Attribute entsprechend des Benutzernamens**: sAMACcountName</br> **Attribute entsprechend des Benutzernamens**: sAMACcountName</br>
**DN of group for membership-check (memberOf)**: dn=piwigo_users,cn=Users,dc=example,dc=com</br> **DN of group for membership-check (memberOf)**: dn=piwigo_users,cn=Users,dc=example,dc=com</br>
#### LDAP-Verbindungsreferenzen #### LDAP-Verbindungsreferenzen
**Bind DN im LDAP-Style (zB.: cn=admin,dc=example,dc=com).**: cn=binduser,cn=Users,dc=exmaple,dc=com</br> **Bind DN im LDAP-Style (zB.: cn=admin,dc=example,dc=com).**: cn=binduser,cn=Users,dc=exmaple,dc=com</br>
**Bind passwort**: mysecret123</br> **Bind passwort**: mysecret123</br>
</br> </br>
_--> SAVE and enjoy :)_ _--> SAVE and enjoy :)_

View file

@ -1,30 +1,30 @@
TODO : TODO :
auto config (may use ajax): fill in the settings, then the page guess the next settings. auto config (may use ajax): fill in the settings, then the page guess the next settings.
Ex : after filled the host address, the page guess the base dn. The last to guess is the users OU. Ex : after filled the host address, the page guess the base dn. The last to guess is the users OU.
Users OU can come with a select field, as the ld_attr. Users OU can come with a select field, as the ld_attr.
correct init plugin correct init plugin
if mail isn't furnished ? if mail isn't furnished ?
create common piwigo users upon successfull ldap connection when piwigo user doesn't exist => done ! create common piwigo users upon successfull ldap connection when piwigo user doesn't exist => done !
Groups : users may belong to ldap group to allow connection Groups : users may belong to ldap group to allow connection
Groups : users belonging to «sudo» or «admin» ldap group become piwigo admin when created this way Groups : users belonging to «sudo» or «admin» ldap group become piwigo admin when created this way
fetching attributes from ldap (mail…). fetching attributes from ldap (mail…).
config of the previous one (need tabs) config of the previous one (need tabs)
config page to render better config page to render better
######## ########
à faire : à faire :
initialisation du plugin correcte initialisation du plugin correcte
qu'est-ce qu'on fait si le mail est pas fourni ? qu'est-ce qu'on fait si le mail est pas fourni ?
configuration automatique (javascript/ajax probable): entrée des paramètres et la page recherche le paramètre suivant si possible. configuration automatique (javascript/ajax probable): entrée des paramètres et la page recherche le paramètre suivant si possible.
Ex : adresse du serveur -> la page trouve toute seule la racine ldap, reste plus que la OU des utilisateurs (qu'on peut selectionner via une liste déroulante). Ex : adresse du serveur -> la page trouve toute seule la racine ldap, reste plus que la OU des utilisateurs (qu'on peut selectionner via une liste déroulante).
l'attribut d'identification peut être selectionné par une liste déroulante. l'attribut d'identification peut être selectionné par une liste déroulante.
creation d'un utilisateur piwigo suite à une authentification ldap quand l'utilisateur n'existe pas. => fait ! creation d'un utilisateur piwigo suite à une authentification ldap quand l'utilisateur n'existe pas. => fait !
question de groups : les utilisateurs membres du groupe ldap «sudo» ou autre pourraient automatiquement être admins piwigo question de groups : les utilisateurs membres du groupe ldap «sudo» ou autre pourraient automatiquement être admins piwigo
question de groupe : les utilisateurs devraient appartenir à un groupe ldap pour se connecter… question de groupe : les utilisateurs devraient appartenir à un groupe ldap pour se connecter…
récuperer les attributs dans le ldap (mail…). récuperer les attributs dans le ldap (mail…).
page de config à peaufiner, option précédente à intégrer dans un onglet. page de config à peaufiner, option précédente à intégrer dans un onglet.

View file

@ -1,74 +1,74 @@
<?php <?php
if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!'); if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
global $template; global $template;
$template->set_filenames( array('plugin_admin_content' => dirname(__FILE__).'/configuration.tpl') ); $template->set_filenames( array('plugin_admin_content' => dirname(__FILE__).'/configuration.tpl') );
$template->assign( $template->assign(
array( array(
'PLUGIN_ACTION' => get_root_url().'admin.php?page=plugin-Ldap_Login-configuration', 'PLUGIN_ACTION' => get_root_url().'admin.php?page=plugin-Ldap_Login-configuration',
'PLUGIN_CHECK' => get_root_url().'admin.php?page=plugin-Ldap_Login-configuration', 'PLUGIN_CHECK' => get_root_url().'admin.php?page=plugin-Ldap_Login-configuration',
)); ));
$me = new Ldap(); $me = new Ldap();
$me->load_config(); $me->load_config();
//$me = get_plugin_data($plugin_id); //$me = get_plugin_data($plugin_id);
// Save LDAP configuration when submitted // Save LDAP configuration when submitted
if (isset($_POST['save'])){ if (isset($_POST['save'])){
$me->config['host'] = $_POST['HOST']; $me->config['host'] = $_POST['HOST'];
$me->config['basedn'] = $_POST['BASEDN']; $me->config['basedn'] = $_POST['BASEDN'];
$me->config['port'] = $_POST['PORT']; $me->config['port'] = $_POST['PORT'];
$me->config['ld_attr'] = $_POST['LD_ATTR']; $me->config['ld_attr'] = $_POST['LD_ATTR'];
$me->config['ld_group'] = $_POST['LD_GROUP']; $me->config['ld_group'] = $_POST['LD_GROUP'];
$me->config['ld_binddn'] = $_POST['LD_BINDDN']; $me->config['ld_binddn'] = $_POST['LD_BINDDN'];
$me->config['ld_bindpw'] = $_POST['LD_BINDPW']; $me->config['ld_bindpw'] = $_POST['LD_BINDPW'];
if (isset($_POST['LD_USE_SSL'])){ if (isset($_POST['LD_USE_SSL'])){
$me->config['ld_use_ssl'] = True; $me->config['ld_use_ssl'] = True;
} else { } else {
$me->config['ld_use_ssl'] = False; $me->config['ld_use_ssl'] = False;
} }
$me->save_config(); $me->save_config();
} }
// Checki LDAP configuration // Checki LDAP configuration
$me->ldap_conn(); $me->ldap_conn();
if (isset($_POST['check_ldap'])){ if (isset($_POST['check_ldap'])){
//$me->write_log("[function]> admin"); //$me->write_log("[function]> admin");
//$check = $me->ldap_name($_POST['USERNAME']); //$check = $me->ldap_name($_POST['USERNAME']);
$username = $me->ldap_search_dn($_POST['USERNAME']); $username = $me->ldap_search_dn($_POST['USERNAME']);
//$me->write_log("[admin]> bind=".$username); //$me->write_log("[admin]> bind=".$username);
$error=$me->check_ldap(); $error=$me->check_ldap();
if($error==1 && $username) { if($error==1 && $username) {
if ($me->ldap_bind_as($username,$_POST['PASSWORD'])){ if ($me->ldap_bind_as($username,$_POST['PASSWORD'])){
if($me->check_ldap_group_membership($username,$_POST['USERNAME'])){ if($me->check_ldap_group_membership($username,$_POST['USERNAME'])){
$template->assign('LD_CHECK_LDAP','<p style="color:green;">Configuration LDAP OK : '.$username.'</p>'); $template->assign('LD_CHECK_LDAP','<p style="color:green;">Configuration LDAP OK : '.$username.'</p>');
} else { } else {
$template->assign('LD_CHECK_LDAP','<p style="color:orange;">Credentials OK, Check GroupMembership for: '.$username.'</p>'); $template->assign('LD_CHECK_LDAP','<p style="color:orange;">Credentials OK, Check GroupMembership for: '.$username.'</p>');
} }
} }
else { else {
$template->assign('LD_CHECK_LDAP','<p style="color:red;"> Binding OK, but check credentials on server '.$me->config['uri'].' for user '.$username.'</p>'); $template->assign('LD_CHECK_LDAP','<p style="color:red;"> Binding OK, but check credentials on server '.$me->config['uri'].' for user '.$username.'</p>');
} }
} elseif($error==1 && !$username){ } elseif($error==1 && !$username){
$template->assign('LD_CHECK_LDAP','<p style="color:red;">Error : Binding OK, but no valid DN found on server '.$me->config['uri'].' for user '.$_POST['USERNAME'].'</p>'); $template->assign('LD_CHECK_LDAP','<p style="color:red;">Error : Binding OK, but no valid DN found on server '.$me->config['uri'].' for user '.$_POST['USERNAME'].'</p>');
} elseif($error && $username){ } elseif($error && $username){
$template->assign('LD_CHECK_LDAP','<p style="color:red;">Error : Binding OK, but check credentials on '.$me->config['uri'].' for user '.$_POST['USERNAME'].'</p>'); $template->assign('LD_CHECK_LDAP','<p style="color:red;">Error : Binding OK, but check credentials on '.$me->config['uri'].' for user '.$_POST['USERNAME'].'</p>');
} else { } else {
$template->assign('LD_CHECK_LDAP','<p style="color:red;">Error : '.$error.' for binding on server '.$me->config['uri'].' for user '.$_POST['USERNAME'].', check your binding!</p>'); $template->assign('LD_CHECK_LDAP','<p style="color:red;">Error : '.$error.' for binding on server '.$me->config['uri'].' for user '.$_POST['USERNAME'].', check your binding!</p>');
} }
} }
// And build up the form with the new values // And build up the form with the new values
$template->assign('HOST', $me->config['host']); $template->assign('HOST', $me->config['host']);
$template->assign('BASEDN', $me->config['basedn']); // racine ! $template->assign('BASEDN', $me->config['basedn']); // racine !
$template->assign('PORT', $me->config['port']); $template->assign('PORT', $me->config['port']);
$template->assign('LD_ATTR', $me->config['ld_attr']); $template->assign('LD_ATTR', $me->config['ld_attr']);
$template->assign('LD_GROUP', $me->config['ld_group']); $template->assign('LD_GROUP', $me->config['ld_group']);
$template->assign('LD_USE_SSL', $me->config['ld_use_ssl']); $template->assign('LD_USE_SSL', $me->config['ld_use_ssl']);
$template->assign('LD_BINDPW', $me->config['ld_bindpw']); $template->assign('LD_BINDPW', $me->config['ld_bindpw']);
$template->assign('LD_BINDDN', $me->config['ld_binddn']); $template->assign('LD_BINDDN', $me->config['ld_binddn']);
$template->assign_var_from_handle( 'ADMIN_CONTENT', 'plugin_admin_content'); $template->assign_var_from_handle( 'ADMIN_CONTENT', 'plugin_admin_content');
?> ?>

View file

@ -1,114 +1,114 @@
<h2>{'Ldap_Login Plugin'|@translate}</h2> <h2>{'Ldap_Login Plugin'|@translate}</h2>
<div id="configContent"> <div id="configContent">
<p>{'All LDAP users can use their ldap password everywhere on piwigo if needed.'|@translate}</p> <p>{'All LDAP users can use their ldap password everywhere on piwigo if needed.'|@translate}</p>
<form method="post" action="{$PLUGIN_ACTION}" class="general"> <form method="post" action="{$PLUGIN_ACTION}" class="general">
{if (!extension_loaded('ldap'))} {if (!extension_loaded('ldap'))}
<p style="color:red;">{'Warning: LDAP Extension missing.'|@translate}</p> <p style="color:red;">{'Warning: LDAP Extension missing.'|@translate}</p>
<br /> <br />
{/if} {/if}
<fieldset class="mainConf"> <fieldset class="mainConf">
<legend>{'Ldap server host connection'|@translate}</legend> <legend>{'Ldap server host connection'|@translate}</legend>
<ul> <ul>
<li> <li>
<label for="host">{'Ldap server host'|@translate}</label> <label for="host">{'Ldap server host'|@translate}</label>
<br> <br>
<input size="70" type="text" id="host" name="HOST" value="{$HOST}" /> <input size="70" type="text" id="host" name="HOST" value="{$HOST}" />
</li> </li>
<li> <li>
<label for="ld_use_ssl"> <label for="ld_use_ssl">
{if $LD_USE_SSL } {if $LD_USE_SSL }
<input type="checkbox" id="ld_use_ssl" name="LD_USE_SSL" value="{$LD_USE_SSL}" checked /> <input type="checkbox" id="ld_use_ssl" name="LD_USE_SSL" value="{$LD_USE_SSL}" checked />
{else} {else}
<input type="checkbox" id="ld_use_ssl" name="LD_USE_SSL" value="{$LD_USE_SSL}" /> <input type="checkbox" id="ld_use_ssl" name="LD_USE_SSL" value="{$LD_USE_SSL}" />
{/if} {/if}
{'Secure connexion'|@translate}</label> {'Secure connexion'|@translate}</label>
</li> </li>
<li> <li>
<label for="port">{'Ldap port'|@translate}</label> <label for="port">{'Ldap port'|@translate}</label>
<br> <br>
<input type="text" id="port" name="PORT" value="{$PORT}" /> <input type="text" id="port" name="PORT" value="{$PORT}" />
</li> </li>
</ul> </ul>
<i>{'If empty, localhost and standard protocol ports will be used in configuration.'|@translate}</i> <i>{'If empty, localhost and standard protocol ports will be used in configuration.'|@translate}</i>
</fieldset> </fieldset>
<fieldset class="mainConf"> <fieldset class="mainConf">
<legend>{'Ldap attributes'|@translate}</legend> <legend>{'Ldap attributes'|@translate}</legend>
<ul> <ul>
<li> <li>
<label for="basedn">{'Base DN'|@translate}</label> <label for="basedn">{'Base DN'|@translate}</label>
<br> <br>
<input size="70" type="text" id="basedn" name="BASEDN" value="{$BASEDN}" /> <input size="70" type="text" id="basedn" name="BASEDN" value="{$BASEDN}" />
</li> </li>
<li> <li>
<label for="ld_attr">{'Attribute corresponding to the user name'|@translate}</label> <label for="ld_attr">{'Attribute corresponding to the user name'|@translate}</label>
<br> <br>
<input type="text" id="ld_attr" name="LD_ATTR" value="{$LD_ATTR}" /> <input type="text" id="ld_attr" name="LD_ATTR" value="{$LD_ATTR}" />
</li> </li>
<li> <li>
<label for="groupdn">{'DN of group for membership-check (memberOf)'|@translate}</label> <label for="groupdn">{'DN of group for membership-check (memberOf)'|@translate}</label>
<br> <br>
<input size="70" type="text" id="ld_group" name="LD_GROUP" value="{$LD_GROUP}" /> <input size="70" type="text" id="ld_group" name="LD_GROUP" value="{$LD_GROUP}" />
</li> </li>
</ul> </ul>
</fieldset> </fieldset>
<fieldset class="mainConf"> <fieldset class="mainConf">
<legend>{'Ldap connection credentials'|@translate}</legend> <legend>{'Ldap connection credentials'|@translate}</legend>
<ul> <ul>
<li> <li>
<label for="ld_binddn">{'Bind DN, field in full ldap style'|@translate}</label> <label for="ld_binddn">{'Bind DN, field in full ldap style'|@translate}</label>
<br> <br>
<input size="70" type="text" id="ld_binddn" name="LD_BINDDN" value="{$LD_BINDDN}" /> <input size="70" type="text" id="ld_binddn" name="LD_BINDDN" value="{$LD_BINDDN}" />
</li> </li>
<li> <li>
<label for="ld_bindpw">{'Bind password'|@translate}</label> <label for="ld_bindpw">{'Bind password'|@translate}</label>
<br> <br>
<input type="password" id="ld_bindpw" name="LD_BINDPW" /> <input type="password" id="ld_bindpw" name="LD_BINDPW" />
</li> </li>
</ul> </ul>
<i>{'Let the fields blank if the ldap accept anonymous connections.'|@translate}</i> <i>{'Let the fields blank if the ldap accept anonymous connections.'|@translate}</i>
</fieldset> </fieldset>
<p> <p>
<input type="submit" value="{'Save'|@translate}" name="save" /> <input type="submit" value="{'Save'|@translate}" name="save" />
</p> </p>
</form> </form>
<form method="post" action="{$PLUGIN_CHECK}" class="general"> <form method="post" action="{$PLUGIN_CHECK}" class="general">
<fieldset class="mainConf"> <fieldset class="mainConf">
<legend>{'Ldap_Login Test'|@translate}</legend> <legend>{'Ldap_Login Test'|@translate}</legend>
<i>{'You must save the settings with the Save button just up there before testing here.'|@translate}</i> <i>{'You must save the settings with the Save button just up there before testing here.'|@translate}</i>
<ul> <ul>
<li> <li>
<label for="username">{'Username'|@translate}</label> <label for="username">{'Username'|@translate}</label>
<br> <br>
<input type="text" id="username" name="USERNAME" value="{$USERNAME}" /> <input type="text" id="username" name="USERNAME" value="{$USERNAME}" />
</li> </li>
<li> <li>
<label for="ld_attr">{'Your password'|@translate}</label> <label for="ld_attr">{'Your password'|@translate}</label>
<br> <br>
<input type="password" id="password" name="PASSWORD" value="{$PASSWORD}" /> <input type="password" id="password" name="PASSWORD" value="{$PASSWORD}" />
</li> </li>
</ul> </ul>
{if (!empty($LD_CHECK_LDAP))} {if (!empty($LD_CHECK_LDAP))}
{$LD_CHECK_LDAP} {$LD_CHECK_LDAP}
{/if} {/if}
</fieldset> </fieldset>
<p><input type="submit" value="{'Test Settings'|@translate}" name="check_ldap" /></p> <p><input type="submit" value="{'Test Settings'|@translate}" name="check_ldap" /></p>
</form> </form>
</div> </div>

View file

@ -1,50 +1,50 @@
<?php <?php
if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!'); if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
global $template; global $template;
$template->set_filenames( array('plugin_admin_content' => dirname(__FILE__).'/newusers.tpl') ); $template->set_filenames( array('plugin_admin_content' => dirname(__FILE__).'/newusers.tpl') );
$template->assign( $template->assign(
array( array(
'PLUGIN_NEWUSERS' => get_root_url().'admin.php?page=plugin-Ldap_Login-newusers', 'PLUGIN_NEWUSERS' => get_root_url().'admin.php?page=plugin-Ldap_Login-newusers',
)); ));
$me = new Ldap(); $me = new Ldap();
$me->load_config(); $me->load_config();
//$me = get_plugin_data($plugin_id); //$me = get_plugin_data($plugin_id);
// Save LDAP configuration when submitted // Save LDAP configuration when submitted
if (isset($_POST['save'])){ if (isset($_POST['save'])){
if (isset($_POST['ALLOW_NEWUSERS'])){ if (isset($_POST['ALLOW_NEWUSERS'])){
$me->config['allow_newusers'] = True; $me->config['allow_newusers'] = True;
} else { } else {
$me->config['allow_newusers'] = False; $me->config['allow_newusers'] = False;
} }
if (isset($_POST['ADVERTISE_ADMINS'])){ if (isset($_POST['ADVERTISE_ADMINS'])){
$me->config['advertise_admin_new_ldapuser'] = True; $me->config['advertise_admin_new_ldapuser'] = True;
} else { } else {
$me->config['advertise_admin_new_ldapuser'] = False; $me->config['advertise_admin_new_ldapuser'] = False;
} }
if (isset($_POST['SEND_CASUAL_MAIL'])){ if (isset($_POST['SEND_CASUAL_MAIL'])){
$me->config['send_password_by_mail_ldap'] = True; $me->config['send_password_by_mail_ldap'] = True;
} else { } else {
$me->config['send_password_by_mail_ldap'] = False; $me->config['send_password_by_mail_ldap'] = False;
$me->save_config(); $me->save_config();
} }
// do we allow to create new piwigo users in case of auth along the ldap ? // do we allow to create new piwigo users in case of auth along the ldap ?
// does he have to belong an ldap group ? // does he have to belong an ldap group ?
// does ldap groups give some power ? // does ldap groups give some power ?
// what do we do when there's no mail in the ldap ? // what do we do when there's no mail in the ldap ?
// do we send mail to admins ? // do we send mail to admins ?
// And build up the form with the new values // And build up the form with the new values
$template->assign('ALLOW_NEWUSERS', $me->config['allow_newusers']); $template->assign('ALLOW_NEWUSERS', $me->config['allow_newusers']);
$template->assign('ADVERTISE_ADMINS', $me->config['advertise_admin_new_ldapuser']); $template->assign('ADVERTISE_ADMINS', $me->config['advertise_admin_new_ldapuser']);
$template->assign('SEND_CASUAL_MAIL', $me->config['send_password_by_mail_ldap']); $template->assign('SEND_CASUAL_MAIL', $me->config['send_password_by_mail_ldap']);
$template->assign_var_from_handle( 'ADMIN_CONTENT', 'plugin_admin_content'); $template->assign_var_from_handle( 'ADMIN_CONTENT', 'plugin_admin_content');
?> ?>

View file

@ -1,263 +1,263 @@
<?php <?php
global $conf; global $conf;
class Ldap { class Ldap {
var $cnx; var $cnx;
var $config; var $config;
// for debug // for debug
public function write_log($message){ public function write_log($message){
$log = 0; $log = 0;
if($log>0){ if($log>0){
@file_put_contents('/var/log/ldap_login.log',$message."\n",FILE_APPEND); @file_put_contents('/var/log/ldap_login.log',$message."\n",FILE_APPEND);
} }
} }
/** /**
* check ldap configuration * check ldap configuration
* *
* Dans le cas ou l'acces au ldap est anonyme il faut impérativement faire une recherche * Dans le cas ou l'acces au ldap est anonyme il faut impérativement faire une recherche
* pour tester la connection. * pour tester la connection.
* *
* When OpenLDAP 2.x.x is used, ldap_connect() will always return a resource as it does not actually connect * When OpenLDAP 2.x.x is used, ldap_connect() will always return a resource as it does not actually connect
* but just initializes the connecting parameters. The actual connect happens with the next calls * but just initializes the connecting parameters. The actual connect happens with the next calls
* to ldap_* funcs, usually with ldap_bind(). * to ldap_* funcs, usually with ldap_bind().
*/ */
public function check_ldap(){ public function check_ldap(){
//$this->write_log("[function]> check_ldap"); //$this->write_log("[function]> check_ldap");
if (!$this->ldap_conn()) { if (!$this->ldap_conn()) {
return $this->getErrorString(); return $this->getErrorString();
} }
// test du compte root si renseigné // test du compte root si renseigné
if (!empty($this->config['ld_binddn']) && !empty($this->config['ld_bindpw'])){ // if empty ld_binddn, anonymous search if (!empty($this->config['ld_binddn']) && !empty($this->config['ld_bindpw'])){ // if empty ld_binddn, anonymous search
// authentication with rootdn and rootpw for search // authentication with rootdn and rootpw for search
if (!$this->ldap_bind_as($this->config['ld_binddn'],$this->config['ld_bindpw'])){ if (!$this->ldap_bind_as($this->config['ld_binddn'],$this->config['ld_bindpw'])){
return $this->getErrorString(); return $this->getErrorString();
} }
} else { } else {
// sinon recherche du basedn (cf comportement ldap_connect avec OpenLDAP) // sinon recherche du basedn (cf comportement ldap_connect avec OpenLDAP)
if (!$this->ldap_check_basedn()){ // search userdn if (!$this->ldap_check_basedn()){ // search userdn
return $this->getErrorString(); return $this->getErrorString();
} }
} }
return true; return true;
} }
public function load_default_config(){ public function load_default_config(){
$this->config['host'] = 'localhost'; $this->config['host'] = 'localhost';
$this->config['basedn'] = 'ou=people,dc=example,dc=com'; // racine ! $this->config['basedn'] = 'ou=people,dc=example,dc=com'; // racine !
$this->config['port'] = ''; // if port is empty, I count on the software to care of it ! $this->config['port'] = ''; // if port is empty, I count on the software to care of it !
$this->config['ld_attr'] = 'uid'; $this->config['ld_attr'] = 'uid';
$this->config['ld_group'] = 'cn=myPiwigoLDAPGroup,cn=users,dc=example,dc=com'; $this->config['ld_group'] = 'cn=myPiwigoLDAPGroup,cn=users,dc=example,dc=com';
$this->config['ld_use_ssl'] = False; $this->config['ld_use_ssl'] = False;
$this->config['ld_bindpw'] =''; $this->config['ld_bindpw'] ='';
$this->config['ld_binddn'] =''; $this->config['ld_binddn'] ='';
$this->config['allow_newusers'] = False; $this->config['allow_newusers'] = False;
$this->config['advertise_admin_new_ldapuser'] = False; $this->config['advertise_admin_new_ldapuser'] = False;
$this->config['send_password_by_mail_ldap'] = False; $this->config['send_password_by_mail_ldap'] = False;
} }
function load_config() { function load_config() {
// first we load the base config // first we load the base config
$conf_file = @file_get_contents( LDAP_LOGIN_PATH.'data.dat' ); $conf_file = @file_get_contents( LDAP_LOGIN_PATH.'data.dat' );
if ($conf_file!==false) if ($conf_file!==false)
{ {
$this->config = unserialize($conf_file); $this->config = unserialize($conf_file);
} }
} }
function save_config() function save_config()
{ {
$file = fopen( LDAP_LOGIN_PATH.'/data.dat', 'w' ); $file = fopen( LDAP_LOGIN_PATH.'/data.dat', 'w' );
fwrite($file, serialize($this->config) ); fwrite($file, serialize($this->config) );
fclose( $file ); fclose( $file );
} }
function ldap_admin_menu($menu) function ldap_admin_menu($menu)
{ {
array_push($menu, array_push($menu,
array( array(
'NAME' => 'Ldap Login', 'NAME' => 'Ldap Login',
'URL' => get_admin_plugin_menu_link(LDAP_LOGIN_PATH.'/admin.php') ) 'URL' => get_admin_plugin_menu_link(LDAP_LOGIN_PATH.'/admin.php') )
); );
return $menu; return $menu;
} }
// LDAP connection public // LDAP connection public
public function ldap_conn(){ public function ldap_conn(){
if( $this->cnx = $this->make_ldap_conn() ){ if( $this->cnx = $this->make_ldap_conn() ){
return true; return true;
} }
return false; return false;
} }
// LDAP connection private // LDAP connection private
private function make_ldap_conn(){ private function make_ldap_conn(){
if ($this->config['ld_use_ssl'] == 1){ if ($this->config['ld_use_ssl'] == 1){
if (empty($this->config['port'])){ if (empty($this->config['port'])){
$this->config['uri'] = 'ldaps://'.$this->config['host']; $this->config['uri'] = 'ldaps://'.$this->config['host'];
} }
else { else {
$this->config['uri'] = 'ldaps://'.$this->config['host'].':'.$this->config['port']; $this->config['uri'] = 'ldaps://'.$this->config['host'].':'.$this->config['port'];
} }
} }
// now, it's without ssl // now, it's without ssl
else { else {
if (empty($this->config['port'])){ if (empty($this->config['port'])){
$this->config['uri'] = 'ldap://'.$this->config['host']; $this->config['uri'] = 'ldap://'.$this->config['host'];
} }
else { else {
$this->config['uri'] = 'ldap://'.$this->config['host'].':'.$this->config['port']; $this->config['uri'] = 'ldap://'.$this->config['host'].':'.$this->config['port'];
} }
} }
if ($conn = @ldap_connect($this->config['uri'])){ if ($conn = @ldap_connect($this->config['uri'])){
@ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION, 3); // LDAPv3 if possible @ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION, 3); // LDAPv3 if possible
return $conn; return $conn;
} }
return false; return false;
} }
// return ldap error // return ldap error
public function getErrorString(){ public function getErrorString(){
return ldap_err2str(ldap_errno($this->cnx)); return ldap_err2str(ldap_errno($this->cnx));
} }
// authentication public // authentication public
public function ldap_bind_as($user,$user_passwd){ public function ldap_bind_as($user,$user_passwd){
$this->write_log("[function]> ldap_bind_as"); $this->write_log("[function]> ldap_bind_as");
$this->write_log("[ldap_bind_as]> ".$user.",".$user_passwd); $this->write_log("[ldap_bind_as]> ".$user.",".$user_passwd);
if($this->make_ldap_bind_as($this->cnx,$user,$user_passwd)){ if($this->make_ldap_bind_as($this->cnx,$user,$user_passwd)){
$this->write_log("[ldap_bind_as]> Bind was successfull"); $this->write_log("[ldap_bind_as]> Bind was successfull");
return true; return true;
} }
return false; return false;
} }
// authentication private // authentication private
private function make_ldap_bind_as($conn,$user,$user_passwd){ private function make_ldap_bind_as($conn,$user,$user_passwd){
$this->write_log("[function]> make_ldap_bind_as"); $this->write_log("[function]> make_ldap_bind_as");
$this->write_log("[make_ldap_bind_as]> \$conn,".$user.",".$user_passwd); $this->write_log("[make_ldap_bind_as]> \$conn,".$user.",".$user_passwd);
$bind = @ldap_bind($conn,$user,$user_passwd); $bind = @ldap_bind($conn,$user,$user_passwd);
if($bind){ if($bind){
return true; return true;
} }
return false; return false;
} }
public function ldap_get_email($user_dn){ public function ldap_get_email($user_dn){
$sr=@ldap_read($this->cnx, $user_dn, "(objectclass=*)", array('mail')); $sr=@ldap_read($this->cnx, $user_dn, "(objectclass=*)", array('mail'));
$entry = @ldap_get_entries($this->cnx, $sr); $entry = @ldap_get_entries($this->cnx, $sr);
if (!empty($entry[0]['mail'])) { if (!empty($entry[0]['mail'])) {
return $entry[0]['mail'][0]; return $entry[0]['mail'][0];
} }
return null; return null;
} }
public function ldap_get_user_email($username) { public function ldap_get_user_email($username) {
return $this->ldap_email($this->ldap_get_dn($username)); return $this->ldap_email($this->ldap_get_dn($username));
} }
// return userdn (and username) for authentication // return userdn (and username) for authentication
public function ldap_search_dn($value_to_search){ public function ldap_search_dn($value_to_search){
$this->write_log("[function]> ldap_search_dn(".$value_to_search.")"); $this->write_log("[function]> ldap_search_dn(".$value_to_search.")");
$filter = '(&(objectClass=person)('.$this->config['ld_attr'].'='.$value_to_search.'))'; $filter = '(&(objectClass=person)('.$this->config['ld_attr'].'='.$value_to_search.'))';
// connection handling // connection handling
$this->write_log("[ldap_search_dn]> Connecting to server"); $this->write_log("[ldap_search_dn]> Connecting to server");
//if(!$bcnx = $this->make_ldap_conn()){ //if(!$bcnx = $this->make_ldap_conn()){
if(!$this->cnx){ if(!$this->cnx){
$this->write_log("[ldap_search_dn]> Cannot connect to server!"); $this->write_log("[ldap_search_dn]> Cannot connect to server!");
return false; return false;
} }
$this->write_log("[ldap_search_dn]> make_ldap_bind_as(\$this->cnx,".$this->config['ld_binddn'].",".$this->config['ld_bindpw'].")"); $this->write_log("[ldap_search_dn]> make_ldap_bind_as(\$this->cnx,".$this->config['ld_binddn'].",".$this->config['ld_bindpw'].")");
//if(!$this->make_ldap_bind_as($bcnx,$this->config['ld_binddn'],$this->config['ld_bindpw'])){ //if(!$this->make_ldap_bind_as($bcnx,$this->config['ld_binddn'],$this->config['ld_bindpw'])){
if(!$this->make_ldap_bind_as($this->cnx,$this->config['ld_binddn'],$this->config['ld_bindpw'])){ if(!$this->make_ldap_bind_as($this->cnx,$this->config['ld_binddn'],$this->config['ld_bindpw'])){
$this->write_log("[ldap_search_dn]> Cannot bind to server!"); $this->write_log("[ldap_search_dn]> Cannot bind to server!");
return false; return false;
} }
$this->write_log("[ldap_search_dn]> @ldap_search(\$this->cnx,".$this->config['basedn'].",".$filter.",array('dn'),0,1)"); $this->write_log("[ldap_search_dn]> @ldap_search(\$this->cnx,".$this->config['basedn'].",".$filter.",array('dn'),0,1)");
// look for our attribute and get always the DN for login // look for our attribute and get always the DN for login
//if($search = ldap_search($bcnx,$this->config['basedn'],$filter,array('dn'),0,1)){ //if($search = ldap_search($bcnx,$this->config['basedn'],$filter,array('dn'),0,1)){
if($search = @ldap_search($this->cnx,$this->config['basedn'],$filter,array('dn'),0,1)){ if($search = @ldap_search($this->cnx,$this->config['basedn'],$filter,array('dn'),0,1)){
$this->write_log("[ldap_search_dn]> ldap_search successfull"); $this->write_log("[ldap_search_dn]> ldap_search successfull");
//$entry = ldap_get_entries($bcnx, $search); //$entry = ldap_get_entries($bcnx, $search);
$entry = @ldap_get_entries($this->cnx, $search); $entry = @ldap_get_entries($this->cnx, $search);
//if (!empty($entry[0][strtolower($this->config['ld_attr'])][0])) { //if (!empty($entry[0][strtolower($this->config['ld_attr'])][0])) {
if (!empty($entry[0]["dn"])) { if (!empty($entry[0]["dn"])) {
$this->write_log("[ldap_search_dn]> RESULT: ".$entry[0]["dn"]); $this->write_log("[ldap_search_dn]> RESULT: ".$entry[0]["dn"]);
//@ldap_unbind($bcnx); //@ldap_unbind($bcnx);
return $entry[0]["dn"]; return $entry[0]["dn"];
} }
$this->write_log("[ldap_search_dn]> result is empty!"); $this->write_log("[ldap_search_dn]> result is empty!");
return false; return false;
} }
$this->write_log("[ldap_search_dn]> ldap_search NOT successfull:"); $this->write_log("[ldap_search_dn]> ldap_search NOT successfull:");
return false; return false;
} }
// look for LDAP group membership // look for LDAP group membership
public function check_ldap_group_membership($user_dn, $user_login){ public function check_ldap_group_membership($user_dn, $user_login){
$group_dn = $this->config['ld_group']; $group_dn = $this->config['ld_group'];
$this->write_log("[function]> check_ldap_group_membership('$user_dn', '$group_dn', '$user_login')"); $this->write_log("[function]> check_ldap_group_membership('$user_dn', '$group_dn', '$user_login')");
//if no group specified return true //if no group specified return true
if(!$group_dn){ if(!$group_dn){
return true; return true;
} }
if(!$this->cnx){ if(!$this->cnx){
$this->write_log("[check_ldap_group_membership]> Cannot connect to server!"); $this->write_log("[check_ldap_group_membership]> Cannot connect to server!");
return false; return false;
} }
if(!$this->make_ldap_bind_as($this->cnx,$this->config['ld_binddn'],$this->config['ld_bindpw'])){ if(!$this->make_ldap_bind_as($this->cnx,$this->config['ld_binddn'],$this->config['ld_bindpw'])){
$this->write_log("[check_ldap_group_membership]> Cannot bind to server!"); $this->write_log("[check_ldap_group_membership]> Cannot bind to server!");
return false; return false;
} }
// search for all member and memberUid attributes for a group_dn // search for all member and memberUid attributes for a group_dn
$search_filter = "(|(&(objectClass=posixGroup)(memberUid=$user_login))(&(objectClass=group)(member=$user_dn)))"; $search_filter = "(|(&(objectClass=posixGroup)(memberUid=$user_login))(&(objectClass=group)(member=$user_dn)))";
$this->write_log("[check_ldap_group_membership]> @ldap_search(\$this->cnx,'$group_dn', '$search_filter', array('memberOf'),0,1)"); $this->write_log("[check_ldap_group_membership]> @ldap_search(\$this->cnx,'$group_dn', '$search_filter', array('memberOf'),0,1)");
if($search = @ldap_search($this->cnx, $group_dn, $search_filter, array("dn"),0,1)){ if($search = @ldap_search($this->cnx, $group_dn, $search_filter, array("dn"),0,1)){
$entry = @ldap_get_entries($this->cnx, $search); $entry = @ldap_get_entries($this->cnx, $search);
//check if there are dn-attributes //check if there are dn-attributes
if (!empty($entry[0]["dn"])) { if (!empty($entry[0]["dn"])) {
$this->write_log("[check_ldap_group_membership]> match found: ".$entry[0]["dn"]); $this->write_log("[check_ldap_group_membership]> match found: ".$entry[0]["dn"]);
return true; return true;
} else { } else {
$this->write_log("[check_ldap_group_membership]> no group membership for user found for given group and user, check on ldap side"); $this->write_log("[check_ldap_group_membership]> no group membership for user found for given group and user, check on ldap side");
} }
} else { } else {
$this->write_log("[check_ldap_group_membership]> ldap_search NOT successfull: " .$this->getErrorString()); $this->write_log("[check_ldap_group_membership]> ldap_search NOT successfull: " .$this->getErrorString());
} }
$this->write_log("[check_ldap_group_membership]> No matching groups found for given group_dn: ". $group_dn); $this->write_log("[check_ldap_group_membership]> No matching groups found for given group_dn: ". $group_dn);
return false; return false;
} }
public function getAttr() { public function getAttr() {
$search = @ldap_read($this->cnx, "cn=subschema", "(objectClass=*)", array('*', 'subschemasubentry')); $search = @ldap_read($this->cnx, "cn=subschema", "(objectClass=*)", array('*', 'subschemasubentry'));
$entries = @ldap_get_entries($this->cnx, $search); $entries = @ldap_get_entries($this->cnx, $search);
echo count($entries); echo count($entries);
} }
public function getRootDse() { public function getRootDse() {
$search = @ldap_read($this->cnx, NULL, 'objectClass=*', array("*", "+")); $search = @ldap_read($this->cnx, NULL, 'objectClass=*', array("*", "+"));
$entries = @ldap_get_entries($this->cnx, $search); $entries = @ldap_get_entries($this->cnx, $search);
return $entries[0]; return $entries[0];
} }
public function ldap_check_basedn(){ public function ldap_check_basedn(){
if ($read = @ldap_read($this->cnx,$this->config['basedn'],'(objectClass=*)',array('dn'))){ if ($read = @ldap_read($this->cnx,$this->config['basedn'],'(objectClass=*)',array('dn'))){
$entry = @ldap_get_entries($this->cnx, $read); $entry = @ldap_get_entries($this->cnx, $read);
if (!empty($entry[0]['dn'])) { if (!empty($entry[0]['dn'])) {
return true; return true;
} }
} }
return false; return false;
} }
} }
?> ?>

View file

@ -1,113 +1,113 @@
<?php <?php
/* /*
Plugin Name: Ldap_Login Plugin Name: Ldap_Login
Version: auto Version: auto
Description: Allow piwigo authentication along an ldap Description: Allow piwigo authentication along an ldap
Plugin URI: http://piwigo.org/ext/extension_view.php?eid=650 Plugin URI: http://piwigo.org/ext/extension_view.php?eid=650
Author: 22decembre Author: 22decembre
Author URI: http://www.22decembre.eu Author URI: http://www.22decembre.eu
*/ */
if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!'); if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
// +-----------------------------------------------------------------------+ // +-----------------------------------------------------------------------+
// | Define plugin constants | // | Define plugin constants |
// +-----------------------------------------------------------------------+ // +-----------------------------------------------------------------------+
define('LDAP_LOGIN_ID', basename(dirname(__FILE__))); define('LDAP_LOGIN_ID', basename(dirname(__FILE__)));
define('LDAP_LOGIN_PATH' , PHPWG_PLUGINS_PATH . LDAP_LOGIN_ID . '/'); define('LDAP_LOGIN_PATH' , PHPWG_PLUGINS_PATH . LDAP_LOGIN_ID . '/');
define('LDAP_LOGIN_ADMIN', get_root_url() . 'admin.php?page=plugin-' . LDAP_LOGIN_ID); define('LDAP_LOGIN_ADMIN', get_root_url() . 'admin.php?page=plugin-' . LDAP_LOGIN_ID);
define('LDAP_LOGIN_VERSION', '1.2'); define('LDAP_LOGIN_VERSION', '1.2');
include_once(LDAP_LOGIN_PATH.'/class.ldap.php'); include_once(LDAP_LOGIN_PATH.'/class.ldap.php');
// +-----------------------------------------------------------------------+ // +-----------------------------------------------------------------------+
// | Event handlers | // | Event handlers |
// +-----------------------------------------------------------------------+ // +-----------------------------------------------------------------------+
add_event_handler('init', 'ld_init'); add_event_handler('init', 'ld_init');
add_event_handler('try_log_user','login', 0, 4); add_event_handler('try_log_user','login', 0, 4);
add_event_handler('get_admin_plugin_menu_links', array(&$ldap, 'ldap_admin_menu')); add_event_handler('get_admin_plugin_menu_links', array(&$ldap, 'ldap_admin_menu'));
// +-----------------------------------------------------------------------+ // +-----------------------------------------------------------------------+
// | Admin menu loading | // | Admin menu loading |
// +-----------------------------------------------------------------------+ // +-----------------------------------------------------------------------+
$ldap = new Ldap(); $ldap = new Ldap();
$ldap->load_config(); $ldap->load_config();
set_plugin_data($plugin['id'], $ldap); set_plugin_data($plugin['id'], $ldap);
unset($ldap); unset($ldap);
// +-----------------------------------------------------------------------+ // +-----------------------------------------------------------------------+
// | functions | // | functions |
// +-----------------------------------------------------------------------+ // +-----------------------------------------------------------------------+
function random_password( $length = 8 ) { function random_password( $length = 8 ) {
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_-=+;:,.?"; $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_-=+;:,.?";
$password = substr( str_shuffle( $chars ), 0, $length ); $password = substr( str_shuffle( $chars ), 0, $length );
return $password; return $password;
} }
function ld_init(){ function ld_init(){
load_language('plugin.lang', LDAP_LOGIN_PATH); load_language('plugin.lang', LDAP_LOGIN_PATH);
} }
function login($success, $username, $password, $remember_me){ function login($success, $username, $password, $remember_me){
global $conf; global $conf;
$obj = new Ldap(); $obj = new Ldap();
$obj->load_config(); $obj->load_config();
$obj->ldap_conn() or die("Unable to connect LDAP server : ".$ldap->getErrorString()); $obj->ldap_conn() or die("Unable to connect LDAP server : ".$ldap->getErrorString());
$user_dn = $obj->ldap_search_dn($username); // retrieve the userdn $user_dn = $obj->ldap_search_dn($username); // retrieve the userdn
// If we have userdn, attempt to login an check user's group access // If we have userdn, attempt to login an check user's group access
if (!($user_dn && $obj->ldap_bind_as($user_dn,$password) && if (!($user_dn && $obj->ldap_bind_as($user_dn,$password) &&
$obj->check_ldap_group_membership($user_dn, $username))) { $obj->check_ldap_group_membership($user_dn, $username))) {
trigger_notify('login_failure', stripslashes($username)); trigger_notify('login_failure', stripslashes($username));
return false; // wrong user/password or no group access return false; // wrong user/password or no group access
} }
// search user in piwigo database // search user in piwigo database
$query = 'SELECT '.$conf['user_fields']['id'].' AS id FROM '.USERS_TABLE.' WHERE '.$conf['user_fields']['username'].' = \''.pwg_db_real_escape_string($username).'\' ;'; $query = 'SELECT '.$conf['user_fields']['id'].' AS id FROM '.USERS_TABLE.' WHERE '.$conf['user_fields']['username'].' = \''.pwg_db_real_escape_string($username).'\' ;';
$row = pwg_db_fetch_assoc(pwg_query($query)); $row = pwg_db_fetch_assoc(pwg_query($query));
// if query is not empty, it means everything is ok and we can continue, auth is done ! // if query is not empty, it means everything is ok and we can continue, auth is done !
if (!empty($row['id'])) { if (!empty($row['id'])) {
log_user($row['id'], $remember_me); log_user($row['id'], $remember_me);
trigger_notify('login_success', stripslashes($username)); trigger_notify('login_success', stripslashes($username));
return true; return true;
} }
// if query is empty but ldap auth is done we can create a piwigo user if it's said so ! // if query is empty but ldap auth is done we can create a piwigo user if it's said so !
else { else {
// this is where we check we are allowed to create new users upon that. // this is where we check we are allowed to create new users upon that.
if ($obj->config['allow_newusers']) { if ($obj->config['allow_newusers']) {
// retrieve LDAP e-mail address and create a new user // retrieve LDAP e-mail address and create a new user
$mail = $obj->ldap_get_email($user_dn); $mail = $obj->ldap_get_email($user_dn);
$new_id = register_user($username,random_password(8),$mail); $new_id = register_user($username,random_password(8),$mail);
// Login user // Login user
log_user($new_id, False); log_user($new_id, False);
trigger_notify('login_success', stripslashes($username)); trigger_notify('login_success', stripslashes($username));
// in case the e-mail address is empty, redirect to profile page // in case the e-mail address is empty, redirect to profile page
if($mail==NULL) { if($mail==NULL) {
redirect('profile.php'); redirect('profile.php');
} }
return true; return true;
} }
// else : this is the normal behavior ! user is not created. // else : this is the normal behavior ! user is not created.
else { else {
trigger_notify('login_failure', stripslashes($username)); trigger_notify('login_failure', stripslashes($username));
return false; return false;
} }
} }
} }
?> ?>

View file

@ -1,16 +1,16 @@
DO DO
min/ min/
min/index.php min/index.php
min/ldap_login_plugin_admin.php min/ldap_login_plugin_admin.php
min/ldap_login_plugin_admin.tpl min/ldap_login_plugin_admin.tpl
ass.ldap.php ass.ldap.php
dex.php dex.php
nguage/ nguage/
nguage/en_UK/ nguage/en_UK/
nguage/en_UK/plugin.lang.php nguage/en_UK/plugin.lang.php
nguage/fr_CA/ nguage/fr_CA/
nguage/fr_CA/plugin.lang.php nguage/fr_CA/plugin.lang.php
nguage/fr_FR/ nguage/fr_FR/
nguage/fr_FR/plugin.lang.php nguage/fr_FR/plugin.lang.php
nguage/index.php nguage/index.php
in.inc.php in.inc.php