diff --git a/composer.json b/composer.json
index 0498c033..31228c8a 100644
--- a/composer.json
+++ b/composer.json
@@ -18,7 +18,8 @@
"php-pushover/php-pushover": "dev-master",
"paragonie/random_compat": "^2.0",
"twig/twig": "~1.35",
- "jaxl/jaxl": "^3.1"
+ "jaxl/jaxl": "^3.1",
+ "viharm/psm-ldap-auth": "^1.1"
},
"autoload": {
"files": [
diff --git a/src/lang/en_US.lang.php b/src/lang/en_US.lang.php
index ff6895ac..0d64ce17 100644
--- a/src/lang/en_US.lang.php
+++ b/src/lang/en_US.lang.php
@@ -342,6 +342,53 @@ $sm_lang = array(
'jabber_password' => 'Password',
'jabber_password_description' => 'Fill only to set or change.',
'jabber_check' => 'Check your Jabber account if message was received.',
+ 'dirauth_status' => 'Authenticate with directory service',
+ 'authdir_host_locn' => 'Directory host',
+ 'authdir_host_port' => 'Directory port',
+ 'authdir_type' => 'Service type',
+ 'authdir_type_description' => 'OpenLDAP: Directory is an OpenLDAP service.
AD
+ DS: Directory is an Active Directory Domain Service.
AD
+ LDS: Directory is an Active Directory Lightweight Directory
+ Service.',
+ 'authdir_type_openldap' => 'OpenLDAP',
+ 'authdir_type_adds' => 'AD DS',
+ 'authdir_type_adlds' => 'AD LDS',
+ 'authdir_userdomain' => 'Active Directory domain',
+ 'authdir_userdomain_description' => 'User domain for Active Directory. This is typically the NETBIOS domain
+ for AD DS and the DNS domain for AD LDS. Not used for OpenLDAP
+ directories.',
+ 'authdir_ldapver' => 'LDAP protocol version',
+ 'authdir_ldapver_description' => 'Version of the LDAP specification. This is typically Version 3 (default).
+ Version 2 was deprecated in 2003 (RFC3494).',
+ 'authdir_ldapfollowref' => 'Follow referrals',
+ 'authdir_ldapfollowref_description' => 'Follow referrals if the specified server refers to another server for
+ the required information. Leave unchecked if you are unaware of this
+ functionality.',
+ 'authdir_basedn' => 'Base DN*',
+ 'authdir_basedn_description' => 'Base distinguished name (DN) of the directory service. E.g.,
+ dc=domain,dc=tld. This is a required field.',
+ 'authdir_usernameattrib' => 'Username attribute',
+ 'authdir_usernameattrib_description' => 'Attribute used by the directory service to refer to the username of
+ the user.',
+ 'authdir_groupnameattrib' => 'Group name attribute',
+ 'authdir_groupnameattrib_description' => 'Attribute used by the directory service to refer to the group name
+ of a group. This is used to check for group membership.',
+ 'authdir_groupmemattrib' => 'Group member attribute',
+ 'authdir_groupmemattrib_description' => 'Attribute used by the directory service to refer to the group(s) of
+ which the user is a member. This is used to check for group
+ membership.',
+ 'authdir_usercontainerrdn' => 'User container RDN',
+ 'authdir_usercontainerrdn_description' => 'Relative distinguished name of the users container in the
+ directory. E.g., ou=Users',
+ 'authdir_groupcontainerrdn' => 'Group container RDN',
+ 'authdir_groupcontainerrdn_description' => 'Relative distinguished name of the groups container in the
+ directory. E.g., ou=Groups',
+ 'authdir_groupname' => 'Authorised directory group',
+ 'authdir_groupname_description' => 'Directory group authorised to access application. Directory users not
+ members of this group will not be authenticated (currently not available
+ for AD).',
+ 'authdir_defaultrole' => 'Default role',
+ 'authdir_defaultrole_description' => 'Default role to be assigned to users logging in for the first time.',
'alert_type' => 'Select when you\'d like to be notified.',
'alert_type_description' => 'Status change: You will receive a notification when a server has a change in status. So from online -> offline or offline -> online.
Offline: You will receive a notification when a server goes offline for the *FIRST TIME ONLY*. For example, your cronjob is every 15 minutes and your server goes down at 1 am and stays down till 6 am. You will get 1 notification at 1 am and that\'s it.
Always: You will receive a notification every time the script runs and a site is down, even if the site has been offline for hours.',
'alert_type_status' => 'Status change',
@@ -368,6 +415,7 @@ $sm_lang = array(
'tab_webhook' => 'Webhook',
'tab_telegram' => 'Telegram',
'tab_jabber' => 'Jabber',
+ 'tab_auth' => 'Authentication',
'settings_email' => 'Email settings',
'settings_sms' => 'Text message settings',
'settings_discord' => 'Discord settings',
@@ -378,6 +426,7 @@ $sm_lang = array(
'settings_notification' => 'Notification settings',
'settings_log' => 'Log settings',
'settings_proxy' => 'Proxy settings',
+ 'settings_dirauth' => 'LDAP settings',
'auto_refresh' => 'Auto-refresh',
'auto_refresh_description' => 'Auto-refresh servers page.
Time in seconds, if 0 the page won\'t refresh.',
'test' => 'Test',
diff --git a/src/psm/Module/Config/Controller/ConfigController.php b/src/psm/Module/Config/Controller/ConfigController.php
index df524c4d..c93ca375 100644
--- a/src/psm/Module/Config/Controller/ConfigController.php
+++ b/src/psm/Module/Config/Controller/ConfigController.php
@@ -58,6 +58,8 @@ class ConfigController extends AbstractController
'log_jabber',
'show_update',
'combine_notifications',
+ 'dirauth_status',
+ 'authdir_ldapfollowref',
);
/**
@@ -85,7 +87,18 @@ class ConfigController extends AbstractController
'jabber_username',
'jabber_domain',
'user_agent',
- 'site_title'
+ 'site_title',
+ 'authdir_host_locn',
+ 'authdir_host_port',
+ 'authdir_userdomain',
+ 'authdir_ldapver',
+ 'authdir_basedn',
+ 'authdir_usernameattrib',
+ 'authdir_groupnameattrib',
+ 'authdir_groupmemattrib',
+ 'authdir_usercontainerrdn',
+ 'authdir_groupcontainerrdn',
+ 'authdir_groupname',
);
/**
@@ -162,6 +175,20 @@ class ConfigController extends AbstractController
);
}
+ foreach (array("20", "10") as $authdir_defaultrole) {
+ $tpl_data['authdir_defaultroles'][] = array(
+ 'value' => $authdir_defaultrole,
+ 'label' => psm_get_lang('users', 'level_' . $authdir_defaultrole),
+ );
+ }
+
+ foreach (array("openldap", "adds", "adlds") as $authdir_type) {
+ $tpl_data['authdir_type'][] = array(
+ 'value' => $authdir_type,
+ 'label' => psm_get_lang('config', 'authdir_type_' . $authdir_type),
+ );
+ }
+
$tpl_data['email_smtp_security'] = array(
array(
'value' => '',
@@ -181,6 +208,10 @@ class ConfigController extends AbstractController
$config['sms_gateway'] : current($sms_gateways);
$tpl_data['alert_type_selected'] = isset($config['alert_type']) ?
$config['alert_type'] : '';
+ $tpl_data['authdir_type_selected'] = isset($config['authdir_type']) ?
+ $config['authdir_type'] : '';
+ $tpl_data['authdir_defaultrole_selected'] = isset($config['authdir_defaultrole']) ?
+ $config['authdir_defaultrole'] : '20';
$tpl_data['email_smtp_security_selected'] = isset($config['email_smtp_security']) ?
$config['email_smtp_security'] : '';
$tpl_data['auto_refresh_servers'] = isset($config['auto_refresh_servers']) ?
@@ -244,6 +275,8 @@ class ConfigController extends AbstractController
'site_title' => $_POST['site_title'],
'sms_gateway' => $_POST['sms_gateway'],
'alert_type' => $_POST['alert_type'],
+ 'authdir_defaultrole' => $_POST['authdir_defaultrole'],
+ 'authdir_type' => $_POST['authdir_type'],
'email_smtp_security' =>
in_array($_POST['email_smtp_security'], array('', 'ssl', 'tls'))
? $_POST['email_smtp_security']
@@ -296,6 +329,8 @@ class ConfigController extends AbstractController
if (isset($_POST['general_submit'])) {
$this->default_tab = 'general';
+ } elseif (isset($_POST['auth_submit'])) {
+ $this->default_tab = 'auth';
} elseif (isset($_POST['email_submit']) || !empty($_POST['test_email'])) {
$this->default_tab = 'email';
} elseif (isset($_POST['sms_submit']) || !empty($_POST['test_sms'])) {
@@ -546,6 +581,7 @@ class ConfigController extends AbstractController
'label_tab_webhook' => psm_get_lang('config', 'tab_webhook'),
'label_tab_telegram' => psm_get_lang('config', 'tab_telegram'),
'label_tab_jabber' => psm_get_lang('config', 'tab_jabber'),
+ 'label_tab_auth' => psm_get_lang('config', 'tab_auth'),
'label_settings_email' => psm_get_lang('config', 'settings_email'),
'label_settings_sms' => psm_get_lang('config', 'settings_sms'),
'label_settings_discord' => psm_get_lang('config', 'settings_discord'),
@@ -553,6 +589,7 @@ class ConfigController extends AbstractController
'label_settings_pushover' => psm_get_lang('config', 'settings_pushover'),
'label_settings_telegram' => psm_get_lang('config', 'settings_telegram'),
'label_settings_jabber' => psm_get_lang('config', 'settings_jabber'),
+ 'label_settings_dirauth' => psm_get_lang('config', 'settings_dirauth'),
'label_settings_notification' => psm_get_lang('config', 'settings_notification'),
'label_settings_log' => psm_get_lang('config', 'settings_log'),
'label_settings_proxy' => psm_get_lang('config', 'settings_proxy'),
@@ -613,6 +650,36 @@ class ConfigController extends AbstractController
'label_jabber_domain_description' => psm_get_lang('config', 'jabber_domain_description'),
'label_jabber_password' => psm_get_lang('config', 'jabber_password'),
'label_jabber_password_description' => psm_get_lang('config', 'jabber_password_description'),
+ 'label_dirauth_status' => psm_get_lang('config', 'dirauth_status'),
+ 'label_authdir_host_locn' => psm_get_lang('config', 'authdir_host_locn'),
+ 'label_authdir_host_port' => psm_get_lang('config', 'authdir_host_port'),
+ 'label_authdir_type' => psm_get_lang('config', 'authdir_type'),
+ 'label_authdir_type_description' => psm_get_lang('config', 'authdir_type_description'),
+ 'label_authdir_userdomain' => psm_get_lang('config', 'authdir_userdomain'),
+ 'label_authdir_userdomain_description' => psm_get_lang('config', 'authdir_userdomain_description'),
+ 'label_authdir_ldapver' => psm_get_lang('config', 'authdir_ldapver'),
+ 'label_authdir_ldapver_description' => psm_get_lang('config', 'authdir_ldapver_description'),
+ 'label_authdir_ldapfollowref' => psm_get_lang('config', 'authdir_ldapfollowref'),
+ 'label_authdir_ldapfollowref_description' => psm_get_lang('config', 'authdir_ldapfollowref_description'),
+ 'label_authdir_basedn' => psm_get_lang('config', 'authdir_basedn'),
+ 'label_authdir_basedn_description' => psm_get_lang('config', 'authdir_basedn_description'),
+ 'label_authdir_usernameattrib' => psm_get_lang('config', 'authdir_usernameattrib'),
+ 'label_authdir_usernameattrib_description' => psm_get_lang('config', 'authdir_usernameattrib_description'),
+ 'label_authdir_groupnameattrib' => psm_get_lang('config', 'authdir_groupnameattrib'),
+ 'label_authdir_groupnameattrib_description' =>
+ psm_get_lang('config', 'authdir_groupnameattrib_description'),
+ 'label_authdir_groupmemattrib' => psm_get_lang('config', 'authdir_groupmemattrib'),
+ 'label_authdir_groupmemattrib_description' => psm_get_lang('config', 'authdir_groupmemattrib_description'),
+ 'label_authdir_usercontainerrdn' => psm_get_lang('config', 'authdir_usercontainerrdn'),
+ 'label_authdir_usercontainerrdn_description' =>
+ psm_get_lang('config', 'authdir_usercontainerrdn_description'),
+ 'label_authdir_groupcontainerrdn' => psm_get_lang('config', 'authdir_groupcontainerrdn'),
+ 'label_authdir_groupcontainerrdn_description' =>
+ psm_get_lang('config', 'authdir_groupcontainerrdn_description'),
+ 'label_authdir_groupname' => psm_get_lang('config', 'authdir_groupname'),
+ 'label_authdir_groupname_description' => psm_get_lang('config', 'authdir_groupname_description'),
+ 'label_authdir_defaultrole' => psm_get_lang('config', 'authdir_defaultrole'),
+ 'label_authdir_defaultrole_description' => psm_get_lang('config', 'authdir_defaultrole_description'),
'label_alert_type' => psm_get_lang('config', 'alert_type'),
'label_alert_type_description' => psm_get_lang('config', 'alert_type_description'),
'label_combine_notifications' => psm_get_lang('config', 'combine_notifications'),
diff --git a/src/psm/Module/Install/Controller/InstallController.php b/src/psm/Module/Install/Controller/InstallController.php
index b1b9bc0b..7afd97f1 100644
--- a/src/psm/Module/Install/Controller/InstallController.php
+++ b/src/psm/Module/Install/Controller/InstallController.php
@@ -306,6 +306,7 @@ class InstallController extends AbstractController
'webhook_url' => '',
'webhook_json' => '',
'telegram_id' => '',
+ 'discord' => '',
'jabber' => ''
);
diff --git a/src/psm/Service/User.php b/src/psm/Service/User.php
index fce6213b..bc01db2a 100644
--- a/src/psm/Service/User.php
+++ b/src/psm/Service/User.php
@@ -230,20 +230,51 @@ class User
{
$user_name = trim($user_name);
$user_password = trim($user_password);
+ $ldapauthstatus = false;
if (empty($user_name) && empty($user_password)) {
return false;
}
+
+ $dirauthconfig = psm_get_conf('dirauth_status');
+
+ // LDAP auth enabled
+ if ($dirauthconfig === '1') {
+ $ldaplibpath = realpath(
+ PSM_PATH_SRC . '..' . DIRECTORY_SEPARATOR .
+ 'vendor' . DIRECTORY_SEPARATOR .
+ 'viharm' . DIRECTORY_SEPARATOR .
+ 'psm-ldap-auth' . DIRECTORY_SEPARATOR .
+ 'psmldapauth.php'
+ );
+ // If the library is found
+ if ($ldaplibpath) {
+ // Delegate the authentication to the PsmLDAPauth module.
+ // If LDAP auth fails or if library not found, fall back to native auth
+ include_once($ldaplibpath);
+ $ldapauthstatus = psmldapauth($user_name, $user_password, $GLOBALS['sm_config'], $this->db_connection);
+ }
+ }
+
$user = $this->getUserByUsername($user_name);
- // using PHP 5.5's password_verify() function to check if the provided passwords
- // fits to the hash of that user's password
- if (!isset($user->user_id)) {
- password_verify($user_password, 'dummy_call_against_timing');
- return false;
- } elseif (!password_verify($user_password, $user->password)) {
- return false;
- }
+ // Authenticated
+ if ($ldapauthstatus === true) {
+ // Remove password to prevent it from being saved in the DB.
+ // Otherwise, user may still be authenticated if LDAP is disabled later.
+ $user_password = null;
+ @fn_Debug('Authenticated', $user);
+ } else {
+
+ // using PHP 5.5's password_verify() function to check if the provided passwords
+ // fits to the hash of that user's password
+ if (!isset($user->user_id)) {
+ password_verify($user_password, 'dummy_call_against_timing');
+ return false;
+ } elseif (!password_verify($user_password, $user->password)) {
+ return false;
+ }
+ } // not authenticated
$this->setUserLoggedIn($user->user_id, true);
diff --git a/src/templates/default/module/config/config.tpl.html b/src/templates/default/module/config/config.tpl.html
index ffb36a54..db5ab029 100644
--- a/src/templates/default/module/config/config.tpl.html
+++ b/src/templates/default/module/config/config.tpl.html
@@ -7,6 +7,11 @@
role="tab" aria-controls="config-general" aria-selected="{% if general_active %}true{% else %}false{% endif %}">{{
label_general }}
+