Merge pull request #15 from wheelybird/more_debugging

Added an LDAP debugging option
This commit is contained in:
Brian Lycett 2020-05-04 13:47:32 +01:00 committed by GitHub
commit 8f739c3c02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 100 additions and 35 deletions

View File

@ -101,6 +101,8 @@ Optional:
* `SITE_NAME` (default: *LDAP user manager*): Change this to replace the title in the menu. e.g. "My Company"
* `LDAP_DEBUG` (default: *FALSE*): Set to TRUE to increase the logging level for LDAP connections. This will output passwords to the error log - don't enable this in a production environment.
* `SESSION_DEBUG` (default: *FALSE*): Set to TRUE to increase the logging level for sessions and user authorisation. This will output cookie passkeys to the error log - don't enable this in a production environment.
Webserver SSL setup
---

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
set -e
ssl_dir="/opt/ssl"
@ -13,8 +13,7 @@ if [ "$LDAP_TLS_CACERT" ]; then
sed -i "s/TLS_CACERT.*/TLS_CACERT \/opt\/ca.crt/" /etc/ldap/ldap.conf
fi
if [ "$NO_HTTPS" = "TRUE" ]; then
if [ "${NO_HTTPS,,}" == "true" ]; then
cat <<EoHTTPC >/etc/apache2/sites-enabled/lum.conf
@ -104,7 +103,7 @@ EoCertConf
########################
#Create Apache config
if [ -f "/opt/tls/chain.pem" ]; then $ssl_chain="SSLCertificateChainFile /opt/tls/chain.pem"; fi
if [ -f "/opt/tls/chain.pem" ]; then ssl_chain="SSLCertificateChainFile /opt/tls/chain.pem"; fi
cat <<EoHTTPSC >/etc/apache2/sites-enabled/lum.conf

View File

@ -15,10 +15,10 @@
$LDAP['user_ou'] = (getenv('LDAP_USER_OU') ? getenv('LDAP_USER_OU') : 'people');
$LDAP['group_membership_attribute'] = (getenv('LDAP_GROUP_MEMBERSHIP_ATTRIBUTE') ? getenv('LDAP_GROUP_MEMBERSHIP_ATTRIBUTE') : 'uniquemember');
$LDAP['group_membership_uses_uid'] = ((strcmp(getenv('LDAP_GROUP_MEMBERSHIP_USES_UID'),'TRUE') == 0) ? TRUE : FALSE);
$LDAP['group_membership_uses_uid'] = ((strcasecmp(getenv('LDAP_GROUP_MEMBERSHIP_USES_UID'),'TRUE') == 0) ? TRUE : FALSE);
$LDAP['account_attribute'] = 'uid';
$LDAP['require_starttls'] = ((strcmp(getenv('LDAP_REQUIRE_STARTTLS'),'TRUE') == 0) ? TRUE : FALSE);
$LDAP['require_starttls'] = ((strcasecmp(getenv('LDAP_REQUIRE_STARTTLS'),'TRUE') == 0) ? TRUE : FALSE);
$DEFAULT_USER_GROUP = (getenv('DEFAULT_USER_GROUP') ? getenv('DEFAULT_USER_GROUP') : 'everybody');
$DEFAULT_USER_SHELL = (getenv('DEFAULT_USER_SHELL') ? getenv('DEFAULT_SHELL') : '/bin/bash');
@ -31,6 +31,8 @@
$USERNAME_REGEX = '^[a-z][a-zA-Z0-9\._-]{3,32}$';
#We'll use the username regex for groups too.
$LDAP_DEBUG = ((strcasecmp(getenv('LDAP_DEBUG'),'TRUE') == 0) ? TRUE : FALSE);
$SESSION_DEBUG = ((strcasecmp(getenv('SESSION_DEBUG'),'TRUE') == 0) ? TRUE : FALSE);
###

View File

@ -7,7 +7,7 @@ $LDAP_CONNECTION_WARNING = FALSE;
function open_ldap_connection() {
global $log_prefix, $LDAP, $SENT_HEADERS;
global $log_prefix, $LDAP, $SENT_HEADERS, $LDAP_DEBUG;
$ldap_connection = @ ldap_connect($LDAP['uri']);
@ -40,14 +40,24 @@ function open_ldap_connection() {
ldap_set_option($ldap_connection, LDAP_OPT_PROTOCOL_VERSION, 3);
}
}
elseif ($LDAP_DEBUG == TRUE) {
error_log("$log_prefix Start STARTTLS connection to ${LDAP['uri']}",0);
}
}
$bind_result = @ ldap_bind( $ldap_connection, $LDAP['admin_bind_dn'], $LDAP['admin_bind_pwd']);
if ($bind_result != TRUE) {
$this_error = "Failed to bind to ${LDAP['uri']} as ${LDAP['admin_bind_dn']}";
print "Problem: Failed to bind as ${LDAP['admin_bind_dn']}";
error_log("$log_prefix Failed to bind as ${LDAP['admin_bind_dn']}",0);
if ($LDAP_DEBUG == TRUE) { $this_error .= " with password ${LDAP['admin_bind_pwd']}"; }
error_log("$log_prefix $this_error",0);
exit(1);
}
elseif ($LDAP_DEBUG == TRUE) {
error_log("$log_prefix Bound to ${LDAP['uri']} as ${LDAP['admin_bind_dn']}",0);
}
return $ldap_connection;
@ -62,17 +72,21 @@ function ldap_auth_username($ldap_connection,$username, $password) {
# Search for the DN for the given username. If found, try binding with the DN and user's password.
# If the binding succeeds, return the DN.
global $log_prefix, $LDAP;
global $log_prefix, $LDAP, $LDAP_DEBUG;
$ldap_search_query="${LDAP['account_attribute']}=" . ldap_escape($username, "", LDAP_ESCAPE_FILTER);
$ldap_search = ldap_search( $ldap_connection, $LDAP['base_dn'], $ldap_search_query );
if ($LDAP_DEBUG == TRUE) { "$log_prefix Running LDAP search: $ldap_search_query"; }
if (!$ldap_search) {
error_log("$log_prefix Couldn't search for $username",0);
return FALSE;
}
$result = ldap_get_entries($ldap_connection, $ldap_search);
if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix LDAP search returned ${result["count"]} records for $username",0); }
if ($result["count"] == 1) {
$auth_ldap_connection = open_ldap_connection();
@ -83,8 +97,10 @@ function ldap_auth_username($ldap_connection,$username, $password) {
preg_match("/{$LDAP['account_attribute']}=(.*?),/",$result[0]['dn'],$dn_match);
return $dn_match[1];
ldap_unbind($auth_ldap_connection);
if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix Able to bind as $username",0); }
}
else {
if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix Unable to bind as $username",0); }
return FALSE;
}
@ -100,12 +116,23 @@ function ldap_setup_auth($ldap_connection, $password) {
#For the initial setup we need to make sure that whoever's running it has the default admin user
#credentials as passed in ADMIN_BIND_*
global $log_prefix, $LDAP;
global $log_prefix, $LDAP, $LDAP_DEBUG;
if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix Initial setup: opening another LDAP connection to test authentication as ${LDAP['admin_bind_dn']}.",0); }
$auth_ldap_connection = open_ldap_connection();
$can_bind = @ldap_bind($auth_ldap_connection, $LDAP['admin_bind_dn'], $password);
ldap_close($auth_ldap_connection);
if ($can_bind) { return TRUE; } else { return FALSE; }
if ($can_bind) {
if ($LDAP_DEBUG == TRUE) { error_log("$log_prefix Initial setup: able to authenticate as ${LDAP['admin_bind_dn']}.",0); }
return TRUE;
}
else {
$this_error="Initial setup: Unable to authenticate as ${LDAP['admin_bind_dn']}";
if ($LDAP_DEBUG == TRUE) { $this_error .= " with password $password"; }
$this_error .= ". The password used to authenticate for /setup should be the same as set by LDAP_ADMIN_BIND_PWD.";
error_log("$log_prefix $this_error",0);
return FALSE;
}
}
@ -127,15 +154,17 @@ function ldap_hashed_password($password) {
function ldap_get_user_list($ldap_connection,$start=0,$entries=NULL,$sort="asc",$sort_key=NULL,$filters=NULL,$fields=NULL) {
global $log_prefix, $LDAP;
global $log_prefix, $LDAP, $LDAP_DEBUG;
if (!isset($fields)) { $fields = array_unique( array("${LDAP['account_attribute']}", "givenname", "sn", "mail")); }
if (!isset($sort_key)) { $sort_key = $LDAP['account_attribute']; }
$ldap_search = ldap_search($ldap_connection, "${LDAP['user_dn']}", "(&(${LDAP['account_attribute']}=*)$filters)", $fields);
$this_filter = "(&(${LDAP['account_attribute']}=*)$filters)";
$ldap_search = ldap_search($ldap_connection, "${LDAP['user_dn']}", $this_filter, $fields);
$result = ldap_get_entries($ldap_connection, $ldap_search);
if ($LDAP_DEBUG == TRUE) { error_log("LDAP returned ${result['count']} users for ${LDAP['user_dn']} when using this filter: $this_filter",0); }
$records = array();
foreach ($result as $record) {
@ -164,7 +193,7 @@ function ldap_get_user_list($ldap_connection,$start=0,$entries=NULL,$sort="asc",
function ldap_get_highest_id($ldap_connection,$type="uid") {
global $log_prefix, $LDAP, $min_uid, $min_gid;
global $log_prefix, $LDAP, $LDAP_DEBUG, $min_uid, $min_gid;
if ($type == "uid") {
$this_id = $min_uid;
@ -214,11 +243,13 @@ function ldap_get_highest_id($ldap_connection,$type="uid") {
function ldap_get_group_list($ldap_connection,$start=0,$entries=NULL,$sort="asc",$filters=NULL) {
global $log_prefix, $LDAP;
global $log_prefix, $LDAP, $LDAP_DEBUG;
$ldap_search = ldap_search($ldap_connection, "${LDAP['group_dn']}", "(&(objectclass=*)$filters)");
$this_filter = "(&(objectclass=*)$filters)";
$ldap_search = ldap_search($ldap_connection, "${LDAP['group_dn']}", $this_filter);
$result = ldap_get_entries($ldap_connection, $ldap_search);
if ($LDAP_DEBUG == TRUE) { error_log("LDAP returned ${result['count']} groups for ${LDAP['group_dn']} when using this filter: $this_filter",0); }
$records = array();
foreach ($result as $record) {
@ -242,12 +273,13 @@ function ldap_get_group_list($ldap_connection,$start=0,$entries=NULL,$sort="asc"
function ldap_get_group_members($ldap_connection,$group_name,$start=0,$entries=NULL,$sort="asc") {
global $log_prefix, $LDAP;
global $log_prefix, $LDAP, $LDAP_DEBUG;
$ldap_search_query = "(cn=". ldap_escape($group_name, "", LDAP_ESCAPE_FILTER) . ")";
$ldap_search = ldap_search($ldap_connection, "${LDAP['group_dn']}", $ldap_search_query, array($LDAP['group_membership_attribute']));
$result = ldap_get_entries($ldap_connection, $ldap_search);
if ($LDAP_DEBUG == TRUE) { error_log("LDAP returned ${result['count']} members of ${group_name} when using this search: $ldap_search_query",0); }
$records = array();
foreach ($result[0][$LDAP['group_membership_attribute']] as $record => $value) {
@ -269,7 +301,7 @@ function ldap_get_group_members($ldap_connection,$group_name,$start=0,$entries=N
function ldap_is_group_member($ldap_connection,$group_name,$username) {
global $log_prefix, $LDAP;
global $log_prefix, $LDAP, $LDAP_DEBUG;
$ldap_search_query = "(cn=" . ldap_escape($group_name, "", LDAP_ESCAPE_FILTER) . ")";
$ldap_search = ldap_search($ldap_connection, "${LDAP['group_dn']}", $ldap_search_query);
@ -293,7 +325,7 @@ function ldap_is_group_member($ldap_connection,$group_name,$username) {
function ldap_new_group($ldap_connection,$group_name) {
global $log_prefix, $LDAP;
global $log_prefix, $LDAP, $LDAP_DEBUG;
if (isset($group_name)) {
@ -345,7 +377,7 @@ function ldap_new_group($ldap_connection,$group_name) {
function ldap_delete_group($ldap_connection,$group_name) {
global $log_prefix, $LDAP;
global $log_prefix, $LDAP, $LDAP_DEBUG;
if (isset($group_name)) {
@ -370,7 +402,7 @@ function ldap_delete_group($ldap_connection,$group_name) {
function ldap_get_gid_of_group($ldap_connection,$group_name) {
global $log_prefix, $LDAP;
global $log_prefix, $LDAP, $LDAP_DEBUG;
if (isset($group_name)) {
@ -393,7 +425,7 @@ function ldap_get_gid_of_group($ldap_connection,$group_name) {
function ldap_new_account($ldap_connection,$first_name,$last_name,$username,$password,$email) {
global $log_prefix, $LDAP, $DEFAULT_USER_SHELL, $DEFAULT_USER_GROUP;
global $log_prefix, $LDAP, $LDAP_DEBUG, $DEFAULT_USER_SHELL, $DEFAULT_USER_GROUP;
if (isset($first_name) and isset($last_name) and isset($username) and isset($password)) {
@ -476,7 +508,7 @@ function ldap_new_account($ldap_connection,$first_name,$last_name,$username,$pas
function ldap_delete_account($ldap_connection,$username) {
global $log_prefix, $LDAP;
global $log_prefix, $LDAP, $LDAP_DEBUG;
if (isset($username)) {
@ -501,7 +533,7 @@ function ldap_delete_account($ldap_connection,$username) {
function ldap_add_member_to_group($ldap_connection,$group_name,$username) {
global $log_prefix, $LDAP;
global $log_prefix, $LDAP, $LDAP_DEBUG;
$group_dn = "cn=" . ldap_escape($group_name, "", LDAP_ESCAPE_FILTER) . ",${LDAP['group_dn']}";
@ -528,7 +560,7 @@ function ldap_add_member_to_group($ldap_connection,$group_name,$username) {
function ldap_delete_member_from_group($ldap_connection,$group_name,$username) {
global $log_prefix, $LDAP;
global $log_prefix, $LDAP, $LDAP_DEBUG;
$group_dn = "cn=" . ldap_escape($group_name, "", LDAP_ESCAPE_FILTER) . ",${LDAP['group_dn']}";
@ -555,7 +587,7 @@ function ldap_delete_member_from_group($ldap_connection,$group_name,$username) {
function ldap_change_password($ldap_connection,$username,$new_password) {
global $log_prefix, $LDAP;
global $log_prefix, $LDAP, $LDAP_DEBUG;
#Find DN of user

View File

@ -40,7 +40,7 @@ function set_passkey_cookie($user_id,$is_admin) {
# Create a random value, store it locally and set it in a cookie.
global $LOGIN_TIMEOUT_MINS, $VALIDATED, $USER_ID, $IS_ADMIN;
global $LOGIN_TIMEOUT_MINS, $VALIDATED, $USER_ID, $IS_ADMIN, $SESSION_DEBUG;
$passkey = generate_passkey();
@ -54,7 +54,7 @@ function set_passkey_cookie($user_id,$is_admin) {
$filename = preg_replace('/[^a-zA-Z0-9]/','_', $user_id);
file_put_contents("/tmp/$filename","$passkey:$admin_val:$this_time");
setcookie('orf_cookie', "$user_id:$passkey", $this_time+(60 * $LOGIN_TIMEOUT_MINS), '/', $_SERVER["HTTP_HOST"]);
if ( $SESSION_DEBUG == TRUE) { error_log("$log_prefix Session: user $user_id validated (IS_ADMIN=${IS_ADMIN}), sent orf_cookie to the browser.",0); }
$VALIDATED = TRUE;
}
@ -64,7 +64,7 @@ function set_passkey_cookie($user_id,$is_admin) {
function validate_passkey_cookie() {
global $LOGIN_TIMEOUT_MINS, $IS_ADMIN, $USER_ID, $VALIDATED;
global $LOGIN_TIMEOUT_MINS, $IS_ADMIN, $USER_ID, $VALIDATED, $SESSION_DEBUG;
if (isset($_COOKIE['orf_cookie'])) {
@ -75,6 +75,7 @@ function validate_passkey_cookie() {
$VALIDATED = FALSE;
unset($USER_ID);
$IS_ADMIN = FALSE;
if ( $SESSION_DEBUG == TRUE) { error_log("$log_prefix Session: orf_cookie was sent by the client but the session file wasn't found at /tmp/$filename",0); }
}
else {
list($f_passkey,$f_is_admin,$f_time) = explode(":",$session_file);
@ -83,11 +84,24 @@ function validate_passkey_cookie() {
if ($f_is_admin == 1) { $IS_ADMIN = TRUE; }
$VALIDATED = TRUE;
$USER_ID=$user_id;
if ( $SESSION_DEBUG == TRUE) { error_log("$log_prefix Setup session: Cookie and session file values match for user ${user_id} - VALIDATED (ADMIN = ${IS_ADMIN})",0); }
set_passkey_cookie($USER_ID,$IS_ADMIN);
}
elseif ( $SESSION_DEBUG == TRUE ) {
$this_error="$log_prefix Session: orf_cookie was sent by the client and the session file was found at /tmp/$filename, but";
if ($this_time < $f_time+(60 * $LOGIN_TIMEOUT_MINS)) { $this_error .= " the timestamp was older than the login timeout ($LOGIN_TIMEOUT_MINS);"; }
if (empty($c_passkey)) { $this_error .= " the cookie passkey wasn't set;"; }
if ($c_passkey != $f_passkey) { $this_error .= " the session file passkey didn't match the cookie passkey;"; }
$this_error += " Cookie: ${_COOKIE['orf_cookie']} - Session file contents: $session_file";
error_log($this_error,0);
}
}
}
elseif ( $SESSION_DEBUG == TRUE) {
error_log("$log_prefix Session: orf_cookie wasn't sent by the client.",0);
}
}
######################################################
@ -96,7 +110,7 @@ function set_setup_cookie() {
# Create a random value, store it locally and set it in a cookie.
global $LOGIN_TIMEOUT_MINS, $IS_SETUP_ADMIN;
global $LOGIN_TIMEOUT_MINS, $IS_SETUP_ADMIN, $SESSION_DEBUG;
$passkey = generate_passkey();
$this_time=time();
@ -105,6 +119,7 @@ function set_setup_cookie() {
file_put_contents("/tmp/ldap_setup","$passkey:$this_time");
setcookie('setup_cookie', "$passkey", $this_time+(60 * $LOGIN_TIMEOUT_MINS), '/', $_SERVER["HTTP_HOST"]);
if ( $SESSION_DEBUG == TRUE) { error_log("$log_prefix Setup session: sent setup_cookie to the client.",0); }
}
@ -113,7 +128,7 @@ function set_setup_cookie() {
function validate_setup_cookie() {
global $LOGIN_TIMEOUT_MINS, $IS_SETUP_ADMIN;
global $LOGIN_TIMEOUT_MINS, $IS_SETUP_ADMIN, $SESSION_DEBUG;
if (isset($_COOKIE['setup_cookie'])) {
@ -121,14 +136,26 @@ function validate_setup_cookie() {
$session_file = file_get_contents("/tmp/ldap_setup");
if (!$session_file) {
$IS_SETUP_ADMIN = FALSE;
if ( $SESSION_DEBUG == TRUE) { error_log("$log_prefix Setup session: setup_cookie was sent by the client but the session file wasn't found at /tmp/ldap_setup",0); }
}
list($f_passkey,$f_time) = explode(":",$session_file);
$this_time=time();
if (!empty($c_passkey) and $f_passkey == $c_passkey and $this_time < $f_time+(60 * $LOGIN_TIMEOUT_MINS)) {
$IS_SETUP_ADMIN = TRUE;
if ( $SESSION_DEBUG == TRUE) { error_log("$log_prefix Setup session: Cookie and session file values match - VALIDATED ",0); }
set_setup_cookie();
}
elseif ( $SESSION_DEBUG == TRUE) {
$this_error="$log_prefix Setup session: setup_cookie was sent by the client and the session file was found at /tmp/ldap_setup, but";
if ($this_time < $f_time+(60 * $LOGIN_TIMEOUT_MINS)) { $this_error .= " the timestamp was older than the login timeout ($LOGIN_TIMEOUT_MINS);"; }
if (empty($c_passkey)) { $this_error .= " the cookie passkey wasn't set;"; }
if ($c_passkey != $f_passkey) { $this_error .= " the session file passkey didn't match the cookie passkey;"; }
$this_error += " Cookie: ${_COOKIE['setup_cookie']} - Session file contents: $session_file";
error_log($this_error,0);
}
}
elseif ( $SESSION_DEBUG == TRUE) {
error_log("$log_prefix Session: setup_cookie wasn't sent by the client.",0);
}
}
@ -251,7 +278,7 @@ function render_footer() {
function set_page_access($level) {
global $IS_ADMIN, $IS_SETUP_ADMIN, $VALIDATED;
global $IS_ADMIN, $IS_SETUP_ADMIN, $VALIDATED, $SESSION_DEBUG;
#Set the security level needed to view a page.
#This should be one of the first pieces of code
@ -264,6 +291,7 @@ function set_page_access($level) {
}
else {
header("Location: //" . $_SERVER["HTTP_HOST"] . "/setup/index.php?unauthorised\n\n");
if ( $SESSION_DEBUG == TRUE) { error_log("$log_prefix Session: UNAUTHORISED: page security level is 'setup' but IS_SETUP_ADMIN isn't TRUE",0); }
exit(0);
}
}
@ -274,6 +302,7 @@ function set_page_access($level) {
}
else {
header("Location: //" . $_SERVER["HTTP_HOST"] . "/index.php?unauthorised\n\n");
if ( $SESSION_DEBUG == TRUE) { error_log("$log_prefix Session: UNAUTHORISED: page security level is 'admin' but IS_ADMIN = '${IS_ADMIN}' and VALIDATED = '${VALIDATED}' (user) ",0); }
exit(0);
}
}
@ -284,6 +313,7 @@ function set_page_access($level) {
}
else {
header("Location: //" . $_SERVER["HTTP_HOST"] . "/index.php?unauthorised\n\n");
if ( $SESSION_DEBUG == TRUE) { error_log("$log_prefix Session: UNAUTHORISED: page security level is 'user' but VALIDATED = '${VALIDATED}'",0); }
exit(0);
}
}