Merge pull request #26 from markkrj/add-ldap-filter
Allow users to define advanced LDAP search filters.
This commit is contained in:
commit
d60ea0e6aa
23
README.md
23
README.md
@ -28,27 +28,36 @@ Configuration
|
|||||||
* define( 'LDAPAUTH_BASE', 'dc=domain,dc=com' ); // Base DN (location of users)
|
* define( 'LDAPAUTH_BASE', 'dc=domain,dc=com' ); // Base DN (location of users)
|
||||||
* define( 'LDAPAUTH_USERNAME_FIELD', 'uid'); // (optional) LDAP field name in which username is store
|
* define( 'LDAPAUTH_USERNAME_FIELD', 'uid'); // (optional) LDAP field name in which username is store
|
||||||
|
|
||||||
To use a privileged account for the user search:
|
### To use a privileged account for the user search:
|
||||||
* define( 'LDAPAUTH_SEARCH_USER', 'cn=your-user,dc=domain,dc=com' ); // (optional) Privileged user to search with
|
* define( 'LDAPAUTH_SEARCH_USER', 'cn=your-user,dc=domain,dc=com' ); // (optional) Privileged user to search with
|
||||||
* define( 'LDAPAUTH_SEARCH_PASS', 'the-pass'); // (optional) (only if LDAPAUTH_SEARCH_USER set) Privileged user pass
|
* define( 'LDAPAUTH_SEARCH_PASS', 'the-pass'); // (optional) (only if LDAPAUTH_SEARCH_USER set) Privileged user pass
|
||||||
|
|
||||||
To define a template to bind using the current user for the search: Use %s as the place holder for the current user name
|
### To define a template to bind using the current user for the search: Use %s as the place holder for the current user name
|
||||||
* define( 'LDAPAUTH_BIND_WITH_USER_TEMPLATE', '%s@myad.domain' ); // (optional) Use %s as the place holder for the current user name
|
* define( 'LDAPAUTH_BIND_WITH_USER_TEMPLATE', '%s@myad.domain' ); // (optional) Use %s as the place holder for the current user name
|
||||||
|
|
||||||
To check group membership before authenticating:
|
### To use a custom LDAP search filter:
|
||||||
|
* define( 'LDAPAUTH_SEARCH_FILTER', '(&(samaccountname=%s)(memberof=YOURLS-ADMINS,OU=Groups,DC=example,DC=com))' ); // Use %s as the place holder for the current user name
|
||||||
|
|
||||||
|
If this option is not set, filter is based only on LDAPAUTH_USERNAME_FIELD (default).
|
||||||
|
This is useful if more advanced filter is needed. Like when using AD nested groups.
|
||||||
|
For searching based on AD Nested group `LDAP_MATCHING_RULE_IN_CHAIN` OID (1.2.840.113556.1.4.1941) must be specified for user's memberof attribute.
|
||||||
|
Example of filter based on AD nested group:
|
||||||
|
`define( 'LDAPAUTH_SEARCH_FILTER', '(&(samaccountname=%s)(memberof:1.2.840.113556.1.4.1941:=YOURLS-ADMINS,OU=Groups,DC=example,DC=com))' );`
|
||||||
|
|
||||||
|
### To check group membership before authenticating:
|
||||||
* define( 'LDAPAUTH_GROUP_ATTR', 'memberof' ); // (optional) LDAP groups attr
|
* define( 'LDAPAUTH_GROUP_ATTR', 'memberof' ); // (optional) LDAP groups attr
|
||||||
* define( 'LDAPAUTH_GROUP_REQ', 'the-group;another-admin-group'); // (only if LDAPAUTH_GROUP_REQ set) Group/s user must be in. Allows multiple, semicolon delimited
|
* define( 'LDAPAUTH_GROUP_REQ', 'the-group;another-admin-group'); // (only if LDAPAUTH_GROUP_REQ set) Group/s user must be in. Allows multiple, semicolon delimited
|
||||||
|
|
||||||
To define the scope of group req search:
|
### To define the scope of group req search:
|
||||||
* define( 'LDAPAUTH_GROUP_SCOP', 'sub' ); // if not defined the default is 'sub', and will check for the user in all the subtree. The other option is 'base', that will search only members of the exactly req
|
* define( 'LDAPAUTH_GROUP_SCOP', 'sub' ); // if not defined the default is 'sub', and will check for the user in all the subtree. The other option is 'base', that will search only members of the exactly req
|
||||||
|
|
||||||
To define the type of user cache used:
|
### To define the type of user cache used:
|
||||||
* define( 'LDAPAUTH_USERCACHE_TYPE', 0); // (optional) Defaults to 1, which caches users in the options table. 0 turns off cacheing. Other values are currently undefined, but may be one day
|
* define( 'LDAPAUTH_USERCACHE_TYPE', 0); // (optional) Defaults to 1, which caches users in the options table. 0 turns off cacheing. Other values are currently undefined, but may be one day
|
||||||
|
|
||||||
To automatically add LDAP users to config.php:
|
### To automatically add LDAP users to config.php:
|
||||||
* define( 'LDAPAUTH_ADD_NEW', true ); // (optional) 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
|
### 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_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.
|
* define( 'LDAPAUTH_HOST', 'ldap://'); // LDAP protocol without hostname. You can use 'ldaps://' for LDAP with TLS.
|
||||||
|
|
||||||
|
98
plugin.php
98
plugin.php
@ -44,7 +44,6 @@ function ldapauth_environment_check() {
|
|||||||
|
|
||||||
if ( !defined( 'LDAPAUTH_USERCACHE_TYPE' ) )
|
if ( !defined( 'LDAPAUTH_USERCACHE_TYPE' ) )
|
||||||
define( 'LDAPAUTH_USERCACHE_TYPE', 1 );
|
define( 'LDAPAUTH_USERCACHE_TYPE', 1 );
|
||||||
|
|
||||||
|
|
||||||
global $ldapauth_authorized_admins;
|
global $ldapauth_authorized_admins;
|
||||||
if ( !isset( $ldapauth_authorized_admins ) ) {
|
if ( !isset( $ldapauth_authorized_admins ) ) {
|
||||||
@ -61,58 +60,58 @@ function ldapauth_environment_check() {
|
|||||||
yourls_add_filter( 'is_valid_user', 'ldapauth_is_valid_user' );
|
yourls_add_filter( 'is_valid_user', 'ldapauth_is_valid_user' );
|
||||||
|
|
||||||
function ldapauth_shuffle_assoc($list) {
|
function ldapauth_shuffle_assoc($list) {
|
||||||
if (!is_array($list)) return $list;
|
if (!is_array($list)) return $list;
|
||||||
|
|
||||||
$keys = array_keys($list);
|
$keys = array_keys($list);
|
||||||
shuffle($keys);
|
shuffle($keys);
|
||||||
$random = array();
|
$random = array();
|
||||||
foreach ($keys as $key) {
|
foreach ($keys as $key) {
|
||||||
$random[$key] = $list[$key];
|
$random[$key] = $list[$key];
|
||||||
}
|
}
|
||||||
return $random;
|
return $random;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return list of Active Directory Ldap servers that are associated with a site and service
|
// return list of Active Directory Ldap servers that are associated with a site and service
|
||||||
// example for $site = = '_ldap._tcp.corporate._sites.company.com'
|
// example for $site = = '_ldap._tcp.corporate._sites.company.com'
|
||||||
function ldapauth_get_ad_servers_for_site() {
|
function ldapauth_get_ad_servers_for_site() {
|
||||||
$results = [];
|
$results = [];
|
||||||
$ad_servers = dns_get_record(LDAPAUTH_DNS_SITES_AND_SERVICES, DNS_SRV, $authns, $addtl);
|
$ad_servers = dns_get_record(LDAPAUTH_DNS_SITES_AND_SERVICES, DNS_SRV, $authns, $addtl);
|
||||||
foreach ($ad_servers as $ad_server) {
|
foreach ($ad_servers as $ad_server) {
|
||||||
array_push($results, $ad_server['target']);
|
array_push($results, $ad_server['target']);
|
||||||
}
|
}
|
||||||
$results = ldapauth_shuffle_assoc($results); #randomize the order
|
$results = ldapauth_shuffle_assoc($results); #randomize the order
|
||||||
return $results;
|
return $results;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns ldap connection
|
// returns ldap connection
|
||||||
function ldapauth_get_ldap_connection() {
|
function ldapauth_get_ldap_connection() {
|
||||||
if (defined('LDAPAUTH_DNS_SITES_AND_SERVICES')) {
|
if (defined('LDAPAUTH_DNS_SITES_AND_SERVICES')) {
|
||||||
$connection = NULL;
|
$connection = NULL;
|
||||||
$ldap_servers = ldapauth_get_ad_servers_for_site();
|
$ldap_servers = ldapauth_get_ad_servers_for_site();
|
||||||
foreach ($ldap_servers as $ldap_server) {
|
foreach ($ldap_servers as $ldap_server) {
|
||||||
$ldap_address = LDAPAUTH_HOST . $ldap_server;
|
$ldap_address = LDAPAUTH_HOST . $ldap_server;
|
||||||
try {
|
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
|
$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) {
|
if ($temp_conn) {
|
||||||
$connection = $temp_conn;
|
$connection = $temp_conn;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
error_log('Warning, unable to connect to: ' . $ldap_address . ' on port ' . LDAPAUTH_PORT . '. ' . ldap_error($temp_conn));
|
error_log('Warning, unable to connect to: ' . $ldap_address . ' on port ' . LDAPAUTH_PORT . '. ' . ldap_error($temp_conn));
|
||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log('Warning, unable to connect to: ' . $ldap_address . ' on port ' . LDAPAUTH_PORT . '. ' . __FILE__, __FUNCTION__,$e->getMessage());
|
error_log('Warning, unable to connect to: ' . $ldap_address . ' on port ' . LDAPAUTH_PORT . '. ' . __FILE__, __FUNCTION__,$e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($connection) {
|
if ($connection) {
|
||||||
return $connection;
|
return $connection;
|
||||||
} else {
|
} else {
|
||||||
die("Cannot connect to LDAP for site and service " . LDAPAUTH_DNS_SITES_AND_SERVICES);
|
die("Cannot connect to LDAP for site and service " . LDAPAUTH_DNS_SITES_AND_SERVICES);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return ldap_connect(LDAPAUTH_HOST, LDAPAUTH_PORT);
|
return ldap_connect(LDAPAUTH_HOST, LDAPAUTH_PORT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns true/false
|
// returns true/false
|
||||||
@ -182,19 +181,26 @@ function ldapauth_is_valid_user( $value ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if using LDAP Filter, otherwise, filter by LDAPAUTH_USERNAME_FIELD only.
|
||||||
|
if ( !defined('LDAPAUTH_SEARCH_FILTER') ){
|
||||||
|
$ldapFilter = LDAPAUTH_USERNAME_FIELD . "=" . $_REQUEST['username'];
|
||||||
|
} else {
|
||||||
|
$ldapFilter = sprintf(LDAPAUTH_SEARCH_FILTER, $_REQUEST['username']);
|
||||||
|
}
|
||||||
|
|
||||||
// Limit the attrs to the ones we need
|
// Limit the attrs to the ones we need
|
||||||
$attrs = array('dn', LDAPAUTH_USERNAME_FIELD);
|
$attrs = array('dn', LDAPAUTH_USERNAME_FIELD);
|
||||||
if (defined('LDAPAUTH_GROUP_ATTR'))
|
if (defined('LDAPAUTH_GROUP_ATTR'))
|
||||||
array_push($attrs, LDAPAUTH_GROUP_ATTR);
|
array_push($attrs, LDAPAUTH_GROUP_ATTR);
|
||||||
|
|
||||||
$searchDn = ldap_search($ldapConnection, LDAPAUTH_BASE, LDAPAUTH_USERNAME_FIELD . "=" . $_REQUEST['username'], $attrs );
|
$searchDn = ldap_search($ldapConnection, LDAPAUTH_BASE, $ldapFilter, $attrs );
|
||||||
if (!$searchDn) return $value;
|
if (!$searchDn) return $value;
|
||||||
$searchResult = ldap_get_entries($ldapConnection, $searchDn);
|
$searchResult = ldap_get_entries($ldapConnection, $searchDn);
|
||||||
if (!$searchResult) return $value;
|
if (!$searchResult) return $value;
|
||||||
$userDn = $searchResult[0]['dn'];
|
$userDn = $searchResult[0]['dn'];
|
||||||
if (!$userDn && !$ldapSuccess) return $value;
|
if (!$userDn && !$ldapSuccess) return $value;
|
||||||
if (empty($ldapSuccess)) { // we don't need to do this if we already bound using username and LDAPAUTH_BIND_WITH_USER_TEMPLATE
|
if (empty($ldapSuccess)) { // we don't need to do this if we already bound using username and LDAPAUTH_BIND_WITH_USER_TEMPLATE
|
||||||
$ldapSuccess = @ldap_bind($ldapConnection, $userDn, $_REQUEST['password']);
|
$ldapSuccess = @ldap_bind($ldapConnection, $userDn, $_REQUEST['password']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// success?
|
// success?
|
||||||
@ -208,7 +214,7 @@ function ldapauth_is_valid_user( $value ) {
|
|||||||
$groups_to_check = explode(";", strtolower(LDAPAUTH_GROUP_REQ)); // This is now an array
|
$groups_to_check = explode(";", strtolower(LDAPAUTH_GROUP_REQ)); // This is now an array
|
||||||
|
|
||||||
foreach($searchResult[0][LDAPAUTH_GROUP_ATTR] as $grps) {
|
foreach($searchResult[0][LDAPAUTH_GROUP_ATTR] as $grps) {
|
||||||
if (in_array(strtolower($grps), $groups_to_check)) { $in_group = true; break; }
|
if (in_array(strtolower($grps), $groups_to_check)) { $in_group = true; break; }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$in_group) die('Not in admin group');
|
if (!$in_group) die('Not in admin group');
|
||||||
@ -263,8 +269,8 @@ yourls_add_action( 'logout', 'ldapauth_logout_hook' );
|
|||||||
|
|
||||||
function ldapauth_logout_hook( $args ) {
|
function ldapauth_logout_hook( $args ) {
|
||||||
if (!defined(LDAPAUTH_USERCACHE_TYPE)) {
|
if (!defined(LDAPAUTH_USERCACHE_TYPE)) {
|
||||||
unset($_SESSION['LDAPAUTH_AUTH_USER']);
|
unset($_SESSION['LDAPAUTH_AUTH_USER']);
|
||||||
setcookie('PHPSESSID', '', 0, '/');
|
setcookie('PHPSESSID', '', 0, '/');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user