Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Active Directory support #156

Merged
merged 40 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
66d7fbb
Switch to LTB LDAP 0.2
coudot Jul 12, 2024
ff60e46
Migration of send_mail function
coudot Jul 12, 2024
657f23a
Migration of connect function
coudot Jul 12, 2024
8f947aa
Migration of ldap_get_mail_for_notification function
coudot Jul 12, 2024
9617d3d
Require autoload in index
coudot Jul 12, 2024
2f8e76f
Migration of search function
coudot Jul 12, 2024
15a6b2c
Use ldapInstance in smarty plugin
coudot Jul 12, 2024
ae68327
Call ldap_bind to check password
coudot Jul 12, 2024
a25da54
Fix typo
coudot Jul 12, 2024
4a13a43
Migrate notify_admin_by_mail function
coudot Jul 12, 2024
30c40ef
Function to convert AD date
coudot Jul 15, 2024
5031278
First mapping between OpenLDAP and AD
coudot Jul 15, 2024
3038c67
Manage other AD specific attributes
coudot Jul 15, 2024
a51fc2b
AD lockout time
coudot Jul 16, 2024
3323ac1
AD identifier
coudot Jul 16, 2024
c3186ab
Move OpenLDAP specific attributes
coudot Jul 16, 2024
dd55136
Work on isLocked function
coudot Jul 18, 2024
259ace4
Merge branch 'master' into 52-active-directory-support
coudot Jul 19, 2024
5c25b59
Use new ltb-common Directory functions
coudot Jul 22, 2024
6d2b636
Hide special value of lockout date
coudot Jul 23, 2024
e220b77
Use ltb-common password expiration functions
coudot Jul 24, 2024
f072663
Use functions to lock/unlock an account
coudot Jul 24, 2024
f692e3b
Use ltb-common function to modify password
coudot Jul 24, 2024
d4d5e21
Use ltb-common resetAtNextConnection function
coudot Jul 24, 2024
0768892
Add feature to enable/disable account
coudot Jul 26, 2024
5fa2ccb
Merge branch 'master' into 52-active-directory-support
coudot Jul 26, 2024
258b483
Remove composer.lock
coudot Jul 26, 2024
e992671
Use new lockDate function to remove OpenLDAP specific code
coudot Aug 21, 2024
ced02ac
Merge branch 'master' into 52-active-directory-support
coudot Aug 21, 2024
892ea3f
Merge branch 'master' into 52-active-directory-support
coudot Aug 23, 2024
8120479
Clean lock account code
coudot Aug 23, 2024
5f887b0
Use Directory interface for search locked account
coudot Aug 23, 2024
0c4ce50
Use Directory interface for search expired passwords
coudot Aug 23, 2024
86de562
Use Directory interface for search idle accounts
coudot Aug 23, 2024
9ac3878
Use Directory interface for search will expire passwords
coudot Aug 23, 2024
eeeabbf
Use password policy configuration from Directory interface
coudot Aug 26, 2024
e1ffa4e
Merge branch 'master' into 52-active-directory-support
coudot Sep 27, 2024
3ee46ee
Fix merge
coudot Sep 27, 2024
6f8356e
Fix merge
coudot Sep 27, 2024
91a0dda
Doc for OpenLDAP/AD
coudot Sep 27, 2024
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
44 changes: 36 additions & 8 deletions conf/config.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
# All the default values are kept here, you should not modify it but use
# config.inc.local.php file instead to override the settings from here.
#==============================================================================

# LDAP
$ldap_type = "openldap";
$ldap_url = "ldap://localhost";
$ldap_starttls = false;
$ldap_binddn = "cn=manager,dc=example,dc=com";
Expand All @@ -39,9 +41,12 @@
$ldap_lastauth_attribute = "authTimestamp";
#$ldap_network_timeout = 10;

# Override LDAP password policy configuration
#$ldap_lockout_duration = 3600; # 1 hour
#$ldap_password_max_age = 7889400; # 3 months

# How display attributes
$attributes_map = array(
'authtimestamp' => array( 'attribute' => 'authtimestamp', 'faclass' => 'lock', 'type' => 'date' ),
'businesscategory' => array( 'attribute' => 'businesscategory', 'faclass' => 'briefcase', 'type' => 'text' ),
'carlicense' => array( 'attribute' => 'carlicense', 'faclass' => 'car', 'type' => 'text' ),
'created' => array( 'attribute' => 'createtimestamp', 'faclass' => 'clock-o', 'type' => 'date' ),
Expand All @@ -52,7 +57,6 @@
'fax' => array( 'attribute' => 'facsimiletelephonenumber', 'faclass' => 'fax', 'type' => 'tel' ),
'firstname' => array( 'attribute' => 'givenname', 'faclass' => 'user-o', 'type' => 'text' ),
'fullname' => array( 'attribute' => 'cn', 'faclass' => 'user-circle', 'type' => 'text' ),
'identifier' => array( 'attribute' => 'uid', 'faclass' => 'user-o', 'type' => 'text' ),
'l' => array( 'attribute' => 'l', 'faclass' => 'globe', 'type' => 'text' ),
'lastname' => array( 'attribute' => 'sn', 'faclass' => 'user-o', 'type' => 'text' ),
'mail' => array( 'attribute' => 'mail', 'faclass' => 'envelope-o', 'type' => 'mailto' ),
Expand All @@ -66,16 +70,28 @@
'phone' => array( 'attribute' => 'telephonenumber', 'faclass' => 'phone', 'type' => 'tel' ),
'postaladdress' => array( 'attribute' => 'postaladdress', 'faclass' => 'map-marker', 'type' => 'address' ),
'postalcode' => array( 'attribute' => 'postalcode', 'faclass' => 'globe', 'type' => 'text' ),
'secretary' => array( 'attribute' => 'secretary', 'faclass' => 'user-circle-o', 'type' => 'dn_link' ),
'state' => array( 'attribute' => 'st', 'faclass' => 'globe', 'type' => 'text' ),
'street' => array( 'attribute' => 'street', 'faclass' => 'map-marker', 'type' => 'text' ),
'title' => array( 'attribute' => 'title', 'faclass' => 'certificate', 'type' => 'text' ),
);

# Directory specific attributes
$openldap_attributes_map = array(
'authtimestamp' => array( 'attribute' => 'authtimestamp', 'faclass' => 'lock', 'type' => 'date' ),
'identifier' => array( 'attribute' => 'uid', 'faclass' => 'user-o', 'type' => 'text' ),
'pwdaccountlockedtime' => array( 'attribute' => 'pwdaccountlockedtime', 'faclass' => 'lock', 'type' => 'date' ),
'pwdchangedtime' => array( 'attribute' => 'pwdchangedtime', 'faclass' => 'lock', 'type' => 'date' ),
'pwdfailuretime' => array( 'attribute' => 'pwdfailuretime', 'faclass' => 'lock', 'type' => 'date' ),
'pwdlastsuccess' => array( 'attribute' => 'pwdlastsuccess', 'faclass' => 'lock', 'type' => 'date' ),
'pwdpolicysubentry' => array( 'attribute' => 'pwdpolicysubentry', 'faclass' => 'lock', 'type' => 'ppolicy_dn' ),
'pwdreset' => array( 'attribute' => 'pwdreset', 'faclass' => 'lock', 'type' => 'boolean' ),
'secretary' => array( 'attribute' => 'secretary', 'faclass' => 'user-circle-o', 'type' => 'dn_link' ),
'state' => array( 'attribute' => 'st', 'faclass' => 'globe', 'type' => 'text' ),
'street' => array( 'attribute' => 'street', 'faclass' => 'map-marker', 'type' => 'text' ),
'title' => array( 'attribute' => 'title', 'faclass' => 'certificate', 'type' => 'text' )
);
$activedirectory_attributes_map = array(
'authtimestamp' => array( 'attribute' => 'lastlogon', 'faclass' => 'lock', 'type' => 'ad_date' ),
'identifier' => array( 'attribute' => 'samaccountname', 'faclass' => 'user-o', 'type' => 'text' ),
'pwdaccountlockedtime' => array( 'attribute' => 'lockouttime', 'faclass' => 'lock', 'type' => 'ad_date' ),
'pwdchangedtime' => array( 'attribute' => 'pwdlastset', 'faclass' => 'lock', 'type' => 'ad_date' ),
'pwdfailuretime' => array( 'attribute' => 'badpasswordtime', 'faclass' => 'lock', 'type' => 'ad_date' ),
);

# Search
Expand All @@ -95,29 +111,41 @@
$display_items = array('identifier', 'firstname', 'lastname', 'title', 'businesscategory', 'employeenumber', 'employeetype', 'mail', 'mailquota', 'phone', 'mobile', 'fax', 'postaladdress', 'street', 'postalcode', 'l', 'state', 'organizationalunit', 'organization', 'manager', 'secretary' );
$display_title = "fullname";
$display_show_undefined = false;
$display_password_items = array('pwdchangedtime', 'pwdreset', 'pwdaccountlockedtime', 'pwdfailuretime','pwdpolicysubentry', 'authtimestamp', 'pwdlastsuccess', 'created', 'modified');
$display_password_items = array('pwdchangedtime', 'pwdfailuretime','pwdpolicysubentry', 'authtimestamp', 'pwdlastsuccess', 'created', 'modified');
$display_password_expiration_date = true;

# Features

$use_checkpassword = true;

$use_resetpassword = true;
$use_resetpassword_resetchoice = true;
$resetpassword_reset_default = true;

$show_lockstatus = true;
$use_unlockaccount = true;
$use_unlockcomment = false;
$use_unlockcomment_required = false;
$use_lockaccount = true;

$use_lockcomment = false;
$use_lockcomment_required = false;

$show_expirestatus = true;

$use_searchlocked = true;

$use_searchexpired = true;

$use_searchwillexpire = true;
$willexpiredays = 14;

$use_searchidle = true;
$idledays = 60;

$use_enableaccount = false;
$use_disableaccount = false;
$show_enablestatus = false;

# Local password policy
# This is applied before directory password policy
Expand Down
33 changes: 33 additions & 0 deletions docs/enableaccount.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
Enable and disable account
==========================

Show enabled status
-------------------

Service Desk will display if account is enabled or not. To allow this feature:

.. code-block:: php
$show_enablestatus = true;
Enable account
--------------

This feature allows to enable the account. The button is only displayed if the account is disabled.

To enable this feature:

.. code-block:: php
$use_enableaccount = true;
Disable account
---------------

This feature allows to disable the account. It is only displayed if the account is enabled.

To enable this feature:

.. code-block:: php
$use_disableaccount = true;
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ LDAP Tool Box Service Desk documentation
checkpassword.rst
resetpassword.rst
lockaccount.rst
enableaccount.rst
hook.rst
dashboards.rst
configuration-mail.rst
Expand Down
22 changes: 21 additions & 1 deletion docs/ldap-parameters.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
LDAP parameters
===============

Type of directory
-----------------

You can define the type of LDAP directory (``openldap`` or ``activedirectory``). The default value is ``openldap``.

.. code-block:: php

$ldap_type = "openldap";

.. tip:: Other configuration parameters could be impacted by this choice, check their documentation.

Server address
--------------

Expand Down Expand Up @@ -40,7 +51,7 @@ Configure DN and password in ``$ldap_bindn`` and ``$ldap_bindpw``:
$ldap_binddn = "cn=manager,dc=example,dc=com";
$ldap_bindpw = "secret";

.. tip:: You can use the LDAP admin account or any service account. The account needs to read users, password policy entries and write ``userPassword`` and ``pwdReset`` attributes in user entries. Note that using the LDAP admin account will bypass any password policy like minimal size or password history when reseting the password.
.. tip:: You can use the LDAP admin account or any service account. The account needs to read users, password policy entries and write password and some other related attributes in user entries. On OpenLDAP, using the LDAP admin account will bypass any password policy like minimal size or password history when reseting the password.

LDAP Base
---------
Expand Down Expand Up @@ -106,6 +117,13 @@ Set ``$ldap_default_ppolicy`` value if a default policy is configured in your LD

.. tip:: Password policy is first searched in ``pwdPolicySubentry`` attribute of user entry, then fallback to default policy.

You can override some policies, like lockout duration or password maximal age:

.. code-block:: php

$ldap_lockout_duration = 3600; # 1 hour
$ldap_password_max_age = 7889400; # 3 months

Last authentication attribute
-----------------------------

Expand All @@ -114,3 +132,5 @@ The last authentication date can be stored in different attributes depending on
.. code-block:: php

$ldap_lastauth_attribute = "pwdLastSuccess";

.. tip:: This attribute is automatically configured for Active Directory.
4 changes: 2 additions & 2 deletions docs/lockaccount.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Lock account
============
Lock and unlock account
=======================

Show lock status
----------------
Expand Down
44 changes: 44 additions & 0 deletions htdocs/disableaccount.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
/*
* Disable account in LDAP directory
*/

$result = "";
$dn = "";
$password = "";

if (isset($_POST["dn"]) and $_POST["dn"]) {
$dn = $_POST["dn"];
} else {
$result = "dnrequired";
}

if (!$use_disableaccount) {
$result = "actionforbidden";
}

if ($result === "") {

require_once("../conf/config.inc.php");
require __DIR__ . '/../vendor/autoload.php';

# Connect to LDAP
$ldap_connection = $ldapInstance->connect();

$ldap = $ldap_connection[0];
$result = $ldap_connection[1];

if ($ldap) {
if ( $directory->disableAccount($ldap, $dn) ) {
$result = "accountdisabled";
} else {
$result = "ldaperror";
}
}
}

if ($audit_log_file) {
auditlog($audit_log_file, $dn, $audit_admin, "disableaccount", $result);
}

header('Location: index.php?page=display&dn='.$dn.'&disableaccountresult='.$result);
50 changes: 29 additions & 21 deletions htdocs/display.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
$prehookresult= "";
$posthookresult= "";
$ldapExpirationDate="";
$canLockAccount="";
$isAccountEnabled = "";
$lockDate = "";

if (isset($_GET["dn"]) and $_GET["dn"]) {
$dn = $_GET["dn"];
Expand Down Expand Up @@ -63,16 +66,14 @@

# Search attributes
$attributes = array();
$search_items = array_merge( $display_items, $display_password_items);
$search_items = array_merge($display_items, $display_password_items);
foreach( $search_items as $item ) {
$attributes[] = $attributes_map[$item]['attribute'];
}
$attributes[] = $attributes_map[$display_title]['attribute'];
$attributes[] = "pwdPolicySubentry";

# Search entry
$search = ldap_read($ldap, $dn, $ldap_user_filter, $attributes);

$errno = ldap_errno($ldap);

if ( $errno ) {
Expand All @@ -93,22 +94,28 @@
$entry[0][$attr] = $values;
}

# Include default password policy
if ( !$entry[0]['pwdpolicysubentry'] and $ldap_default_ppolicy) {
$entry[0]['pwdpolicysubentry'][] = $ldap_default_ppolicy;
}
# Get password policy configuration
$pwdPolicyConfiguration = $directory->getPwdPolicyConfiguration($ldap, $dn, $ldap_default_ppolicy);
if ($ldap_lockout_duration) { $pwdPolicyConfiguration['lockout_duration'] = $ldap_lockout_durantion; }
if ($ldap_password_max_age) { $pwdPolicyConfiguration['password_max_age'] = $ldap_password_max_age; }

if ($display_edit_link) {
# Replace {dn} in URL
$edit_link = str_replace("{dn}", urlencode($dn), $display_edit_link);
}

# Search user active password policy
$pwdPolicy = "";
if (isset($entry[0]['pwdpolicysubentry'][0])) {
$pwdPolicy = $entry[0]['pwdpolicysubentry'][0];
} elseif (isset($ldap_default_ppolicy)) {
$pwdPolicy = $ldap_default_ppolicy;
$lockDate = $directory->getLockDate($ldap, $dn);
$unlockDate = $directory->getUnlockDate($ldap, $dn, $pwdPolicyConfiguration);
$isLocked = $directory->isLocked($ldap, $dn, $pwdPolicyConfiguration);
$canLockAccount = $pwdPolicyConfiguration["lockout_enabled"];

$expirationDate = $directory->getPasswordExpirationDate($ldap, $dn, $pwdPolicyConfiguration);
$isExpired = $directory->isPasswordExpired($ldap, $dn, $pwdPolicyConfiguration);

$resetAtNextConnection = $directory->resetAtNextConnection($ldap, $dn);

if ($show_enablestatus) {
$isAccountEnabled = $directory->isAccountEnabled($ldap, $dn);
}

$isLocked = false;
Expand Down Expand Up @@ -196,9 +203,11 @@
$smarty->assign("show_undef", $display_show_undefined);

$smarty->assign("isLocked", $isLocked);
$smarty->assign("lockDate", $lockDate);
$smarty->assign("unlockDate", $unlockDate);
$smarty->assign("isExpired", $isExpired);
$smarty->assign("ldapExpirationDate", $ldapExpirationDate);
$smarty->assign("ldapExpirationDate", $expirationDate ? $expirationDate->getTimestamp(): NULL);
$smarty->assign("resetAtNextConnection", $resetAtNextConnection);

$smarty->assign("edit_link", $edit_link);

Expand All @@ -208,13 +217,12 @@
$smarty->assign("accountlockresult", $accountlockresult);
$smarty->assign("prehookresult", $prehookresult);
$smarty->assign("posthookresult", $posthookresult);
if ($pwdLockout == false) $smarty->assign("use_lockaccount", $pwdLockout);
if(isset($messages[$resetpasswordresult]))
{
$smarty->assign('msg_resetpasswordresult',$messages[$resetpasswordresult]);
}
else
{
if ($canLockAccount == false) { $smarty->assign("use_lockaccount", $canLockAccount); }
$smarty->assign("isAccountEnabled", $isAccountEnabled);
if (isset($messages[$resetpasswordresult])) {
$smarty->assign('msg_resetpasswordresult', $messages[$resetpasswordresult]);
} else {
$smarty->assign('msg_resetpasswordresult','');
}

?>
44 changes: 44 additions & 0 deletions htdocs/enableaccount.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
/*
* Enable account in LDAP directory
*/

$result = "";
$dn = "";
$password = "";

if (isset($_POST["dn"]) and $_POST["dn"]) {
$dn = $_POST["dn"];
} else {
$result = "dnrequired";
}

if (!$use_enableaccount) {
$result = "actionforbidden";
}

if ($result === "") {

require_once("../conf/config.inc.php");
require __DIR__ . '/../vendor/autoload.php';

# Connect to LDAP
$ldap_connection = $ldapInstance->connect();

$ldap = $ldap_connection[0];
$result = $ldap_connection[1];

if ($ldap) {
if ( $directory->enableAccount($ldap, $dn) ) {
$result = "accountenabled";
} else {
$result = "ldaperror";
}
}
}

if ($audit_log_file) {
auditlog($audit_log_file, $dn, $audit_admin, "enableaccount", $result);
}

header('Location: index.php?page=display&dn='.$dn.'&enableaccountresult='.$result);
Loading
Loading