diff --git a/README.md b/README.md index 16459fc..d1e20be 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,11 @@ To define the type of user cache used: To automatically add LDAP users to config.php: * define( 'LDAPAUTH_ADD_NEW', true ); // (optional) Add LDAP users to config.php + +To use Active Directory Sites and Services DNS entry for LDAP server name lookup + * define( 'LDAPAUTH_DNS_SITES_AND_SERVICES', '_ldap._tcp.corporate._sites.yourdomain.com' ); // If using Active Directory, with multiple Domain Controllers, the safe way to use DNS to look up your active LDAP server names. If set, it will be used to override the hostname portion of LDAPAUTH_HOST. + * define( 'LDAPAUTH_HOST', 'ldap://'); // LDAP protocol without hostname. You can use 'ldaps://' for LDAP with TLS. + NOTE: This will require config.php to be writable by your webserver user. This function is now largely unneeded because the database based cache offers similar benefits without the need to make config.php writeable. It is retained for backwards compatability Troubleshooting diff --git a/plugin.php b/plugin.php index 48b2529..017dc20 100644 --- a/plugin.php +++ b/plugin.php @@ -60,6 +60,61 @@ function ldapauth_environment_check() { yourls_add_filter( 'is_valid_user', 'ldapauth_is_valid_user' ); +function ldapauth_shuffle_assoc($list) { + if (!is_array($list)) return $list; + + $keys = array_keys($list); + shuffle($keys); + $random = array(); + foreach ($keys as $key) { + $random[$key] = $list[$key]; + } + return $random; +} + +// return list of Active Directory Ldap servers that are associated with a site and service +// example for $site = = '_ldap._tcp.corporate._sites.company.com' +function ldapauth_get_ad_servers_for_site() { + $results = []; + $ad_servers = dns_get_record(LDAPAUTH_DNS_SITES_AND_SERVICES, DNS_SRV, $authns, $addtl); + foreach ($ad_servers as $ad_server) { + array_push($results, $ad_server['target']); + } + $results = ldapauth_shuffle_assoc($results); #randomize the order + return $results; +} + +// returns ldap connection +function ldapauth_get_ldap_connection() { + if (defined('LDAPAUTH_DNS_SITES_AND_SERVICES')) { + $connection = NULL; + $ldap_servers = ldapauth_get_ad_servers_for_site(); + foreach ($ldap_servers as $ldap_server) { + $ldap_address = LDAPAUTH_HOST . $ldap_server; + try { + $temp_conn = ldap_connect($ldap_address, LDAPAUTH_PORT); # ldap_connect doesn't actually connect it just checks for plausiable parameters. Only ldap_bind connects + if ($temp_conn) { + $connection = $temp_conn; + break; + } else { + error_log('Warning, unable to connect to: ' . $ldap_address . ' on port ' . LDAPAUTH_PORT . '. ' . ldap_error($temp_conn)); + } + } catch (Exception $e) { + error_log('Warning, unable to connect to: ' . $ldap_address . ' on port ' . LDAPAUTH_PORT . '. ' . __FILE__, __FUNCTION__,$e->getMessage()); + } + } + + if ($connection) { + return $connection; + } else { + die("Cannot connect to LDAP for site and service " . LDAPAUTH_DNS_SITES_AND_SERVICES); + } + + } else { + return ldap_connect(LDAPAUTH_HOST, LDAPAUTH_PORT); + } +} + // returns true/false function ldapauth_is_valid_user( $value ) { global $yourls_user_passwords; @@ -106,7 +161,7 @@ function ldapauth_is_valid_user( $value ) { && !empty( $_REQUEST['username'] ) && !empty( $_REQUEST['password'] ) ) { // try to authenticate - $ldapConnection = ldap_connect(LDAPAUTH_HOST, LDAPAUTH_PORT); + $ldapConnection = ldapauth_get_ldap_connection(); if (!$ldapConnection) die("Cannot connect to LDAP " . LDAPAUTH_HOST); ldap_set_option($ldapConnection, LDAP_OPT_PROTOCOL_VERSION, 3); //ldap_set_option($ldapConnection, LDAP_OPT_REFERRALS, 0);