diff --git a/app/Console/Commands/LdapTroubleshooter.php b/app/Console/Commands/LdapTroubleshooter.php index 24c61dc408..f9b9f4bb0d 100644 --- a/app/Console/Commands/LdapTroubleshooter.php +++ b/app/Console/Commands/LdapTroubleshooter.php @@ -197,7 +197,7 @@ class LdapTroubleshooter extends Command } } //$this->line(print_r($settings,true)); - $this->info("STAGE 1: Checking settings"); + $this->line("STAGE 1: Checking settings"); if(!$settings->ldap_enabled) { $this->error("WARNING: Snipe-IT's LDAP setting is not turned on. (That may be OK if you're still trying to figure out settings)"); } @@ -231,10 +231,10 @@ class LdapTroubleshooter extends Command $raw_ips = []; if (inet_pton($parsed['host']) !== false) { - $this->info($parsed['host'] . " already looks like an address; skipping DNS lookup"); + $this->line($parsed['host'] . " already looks like an address; skipping DNS lookup"); $raw_ips[] = $parsed['host']; } else { - $this->info("Performing DNS lookup of: " . $parsed['host']); + $this->line("Performing DNS lookup of: " . $parsed['host']); $ips = dns_get_record($parsed['host']); //$this->info("Host IP is: ".print_r($ips,true)); @@ -260,7 +260,7 @@ class LdapTroubleshooter extends Command } } - $this->info("STAGE 2: Checking basic network connectivity"); + $this->line("STAGE 2: Checking basic network connectivity"); $ports = [636, 389]; if(@$parsed['port'] && !in_array($parsed['port'],$ports)) { $ports[] = $parsed['port']; @@ -272,7 +272,7 @@ class LdapTroubleshooter extends Command $errstr = ''; $timeout = 30.0; $result = ''; - $this->info("Attempting to connect to port: ".$port." - may take up to $timeout seconds"); + $this->line("Attempting to connect to port: " . $port . " - may take up to $timeout seconds"); try { $result = fsockopen($parsed['host'], $port, $errno, $errstr, 30.0); } catch(Exception $e) { @@ -291,7 +291,7 @@ class LdapTroubleshooter extends Command exit(-1); } - $this->info("STAGE 3: Determine encryption algorithm, if any"); + $this->line("STAGE 3: Determine encryption algorithm, if any"); $ldap_urls = []; // [url, cert-check?, start_tls?] $pretty_ldap_urls = []; @@ -361,12 +361,12 @@ class LdapTroubleshooter extends Command exit(1); } - $this->info("STAGE 4: Test Administrative Bind for LDAP Sync"); + $this->line("STAGE 4: Test Administrative Bind for LDAP Sync"); foreach($ldap_urls AS $ldap_url) { $this->test_authed_bind($ldap_url[0], $ldap_url[1], $ldap_url[2], $settings->ldap_uname, Crypt::decrypt($settings->ldap_pword)); } - $this->info("STAGE 5: Test BaseDN"); + $this->line("STAGE 5: Test BaseDN"); //grab all LDAP_ constants and fill up a reversed array mapping from weird LDAP dotted-strings to (Constant Name) $all_defined_constants = get_defined_constants(); $ldap_constants = []; @@ -385,9 +385,9 @@ class LdapTroubleshooter extends Command } } - $this->info("STAGE 6: Test LDAP Login to Snipe-IT"); + $this->line("STAGE 6: Test LDAP Login to Snipe-IT"); foreach($ldap_urls AS $ldap_url) { - $this->info("Starting auth to ".$ldap_url[0]); + $this->line("Starting auth to " . $ldap_url[0]); while(true) { $with_tls = $ldap_url[1] ? "with": "without"; $with_startssl = $ldap_url[2] ? "using": "not using"; @@ -396,7 +396,12 @@ class LdapTroubleshooter extends Command } $username = $this->ask("Username"); $password = $this->secret("Password"); - $this->test_authed_bind($ldap_url[0], $ldap_url[1], $ldap_url[2], $username, $password); // FIXME - should do some other stuff here, maybe with the concatenating or something? maybe? and/or should put up some results? + $results = $this->test_authed_bind($ldap_url[0], $ldap_url[1], $ldap_url[2], $username, $password); // FIXME - should do some other stuff here, maybe with the concatenating or something? maybe? and/or should put up some results? + if ($results) { + $this->info("Success authenticating with " . $username); + } else { + $this->error("Unable to authenticate with " . $username); + } } } @@ -406,21 +411,16 @@ class LdapTroubleshooter extends Command public function connect_to_ldap($ldap_url, $check_cert, $start_tls) { if ($check_cert) { - $this->info("we *ARE* checking certs"); + $this->line("we *ARE* checking certs"); Ldap::ignoreCertificates(false); } else { - $this->info("we are IGNORING certs"); + $this->line("we are IGNORING certs"); Ldap::ignoreCertificates(true); } $lconn = ldap_connect($ldap_url); ldap_set_option($lconn, LDAP_OPT_PROTOCOL_VERSION, 3); // should we 'test' different protocol versions here? Does anyone even use anything other than LDAPv3? // no - it's formally deprecated: https://tools.ietf.org/html/rfc3494 - if(!$check_cert) { - //putenv('LDAPTLS_REQCERT=never'); // This is horrible; is this *really* the only way to do it? - } else { - //putenv('LDAPTLS_REQCERT'); // have to very explicitly and manually *UN* set the env var here to ensure it works - } if($this->settings->ldap_client_tls_cert && $this->settings->ldap_client_tls_key) { // client-side TLS certificate support for LDAP (Google Secure LDAP) putenv('LDAPTLS_CERT=storage/ldap_client_tls.cert'); @@ -449,9 +449,9 @@ class LdapTroubleshooter extends Command return $this->timed_boolean_execute(function () use ($ldap_url, $check_cert , $start_tls) { try { $lconn = $this->connect_to_ldap($ldap_url, $check_cert, $start_tls); - $this->info("gonna try to bind now, this can take a while if we mess it up"); + $this->line("gonna try to bind now, this can take a while if we mess it up"); $bind_results = ldap_bind($lconn); - $this->info("Bind results are: ".$bind_results." which translate into boolean: ".(bool)$bind_results); + $this->line("Bind results are: " . $bind_results . " which translate into boolean: " . (bool)$bind_results); ldap_close($lconn); return (bool)$bind_results; } catch (Exception $e) { @@ -493,20 +493,57 @@ class LdapTroubleshooter extends Command return false; } $this->info("SUCCESS - Able to bind to $ldap_url as $username"); - $result = ldap_read($conn, '', '(objectClass=*)'/* , ['supportedControl']*/); - $results = ldap_get_entries($conn, $result); - $cleaned_results = $this->ldap_results_cleaner($results); - return true; - $this->line(print_r($cleaned_results,true)); - //okay, great - now how do we display those results? I have no idea. + $cleaned_results = []; + try { + // This _may_ only work for Active Directory? + $result = ldap_read($conn, '', '(objectClass=*)'/* , ['supportedControl']*/); + $results = ldap_get_entries($conn, $result); + $cleaned_results = $this->ldap_results_cleaner($results); + //$this->line(print_r($cleaned_results,true)); + $default_naming_contexts = $cleaned_results[0]['namingcontexts']; + $this->info("Default Naming Contexts:"); + $this->info(implode(", ", $default_naming_contexts)); + //okay, great - now how do we display those results? I have no idea. + } catch (\Exception $e) { + $this->error("Unable to get base naming contexts - here's what we *did* get:"); + $this->line(print_r($cleaned_results, true)); + } // I don't see why this throws an Exception for Google LDAP, but I guess we ought to try and catch it? - $this->comment("I guess we're trying to do the ldap search here, but sometimes it takes too long?"); + $this->debugout("I guess we're trying to do the ldap search here, but sometimes it takes too long?"); $this->debugout("Base DN is: ".$settings->ldap_basedn." and filter is: ".parenthesized_filter($settings->ldap_filter)); $search_results = ldap_search($conn, $settings->ldap_basedn, parenthesized_filter($settings->ldap_filter)); + $entries = ldap_get_entries($conn, $search_results); $this->info("Printing first 10 results: "); - for($i=0;$i<10;$i++) { - $this->info($search_results[$i]); + $pretty_data = array_slice($this->ldap_results_cleaner($entries), 0, 10); + //print_r($data); + $headers = []; + foreach ($pretty_data as $row) { + //populate headers + foreach ($row as $key => $value) { + //skip objectsid and objectguid because it junks up output + if ($key == "objectsid" || $key == "objectguid") { + continue; + } + if (!in_array($key, $headers)) { + $headers[] = $key; + } + } } + $table = []; + //repeat again to populate table + foreach ($pretty_data as $row) { + $newrow = []; + foreach ($headers as $header) { + if (is_array(@$row[$header])) { + $newrow[] = "[" . implode(", ", $row[$header]) . "]"; + } else { + $newrow[] = @$row[$header]; + } + } + $table[] = $newrow; + } + + $this->table($headers, $table); } catch (\Exception $e) { $this->error("WARNING: Exception caught during Authed bind to $username - ".$e->getMessage()); return false; @@ -527,7 +564,7 @@ class LdapTroubleshooter extends Command { if(!(function_exists('pcntl_sigtimedwait') && function_exists('posix_getpid') && function_exists('pcntl_fork') && function_exists('posix_kill') && function_exists('pcntl_wifsignaled'))) { // POSIX functions needed for forking aren't present, just run the function inline (ignoring timeout) - $this->info('WARNING: Unable to execute POSIX fork() commands, timeout may not be respected'); + $this->line('WARNING: Unable to execute POSIX fork() commands, timeout may not be respected'); return $function(); } else { $parent_pid = posix_getpid();