updated plugin AuthLDAP
version 2.5.9
This commit is contained in:
parent
5a3dd4cf21
commit
052743ea8a
6
wp-content/plugins/authldap/.phive/phars.xml
Normal file
6
wp-content/plugins/authldap/.phive/phars.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phive xmlns="https://phar.io/phive">
|
||||
<phar name="phpunit" version="^9.5.21" installed="9.5.21" location="./tools/phpunit" copy="true"/>
|
||||
<phar name="phpcs" version="^3.7.1" installed="3.7.1" location="./tools/phpcs" copy="true"/>
|
||||
<phar name="phpcbf" version="^3.7.1" installed="3.7.1" location="./tools/phpcbf" copy="true"/>
|
||||
</phive>
|
@ -4,12 +4,12 @@
|
||||
|
||||
Use your existing LDAP as authentication-backend for your wordpress!
|
||||
|
||||
[![Build Status](https://travis-ci.org/heiglandreas/authLdap.svg?branch=master)](https://travis-ci.org/heiglandreas/authLdap)
|
||||
[![Build Status](https://github.com/heiglandreas/authLdap/actions/workflows/tests.yml/badge.svg)](https://github.com/heiglandreas/authLdap/actions/workflows/tests.yml)
|
||||
[![WordPress Stats](https://img.shields.io/wordpress/plugin/dt/authldap.svg)](https://wordpress.org/plugins/authldap/stats/)
|
||||
[![WordPress Version](https://img.shields.io/wordpress/plugin/v/authldap.svg)](https://wordpress.org/plugins/authldap/)
|
||||
[![WordPress testet](https://img.shields.io/wordpress/v/authldap.svg)](https://wordpress.org/plugins/authldap/)
|
||||
[![Code Climate](https://codeclimate.com/github/heiglandreas/authLdap/badges/gpa.svg)](https://codeclimate.com/github/heiglandreas/authLdap)
|
||||
[![Test Coverage](https://codeclimate.com/github/heiglandreas/authLdap/badges/coverage.svg)](https://codeclimate.com/github/heiglandreas/authLdap)
|
||||
[![codecov](https://codecov.io/gh/heiglandreas/authLdap/branch/master/graph/badge.svg?token=AYAhEeWtRQ)](https://codecov.io/gh/heiglandreas/authLdap)
|
||||
|
||||
So what are the differences to other Wordpress-LDAP-Authentication-Plugins?
|
||||
|
||||
|
18
wp-content/plugins/authldap/SECURITY.md
Normal file
18
wp-content/plugins/authldap/SECURITY.md
Normal file
@ -0,0 +1,18 @@
|
||||
# Security-Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- |--------------------|
|
||||
| 2.x | :white_check_mark: |
|
||||
| 1.x | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
* Check our security.txt file for details on how to contact us
|
||||
* Contact us before publicly disclosing the issue anywhere else
|
||||
|
||||
This plugin is developed as OpenSource under the MIT licence.
|
||||
There is no money earned from it. Therefore we are not able to
|
||||
provide any bug-bounties whatsoever. You will be mentioned in the
|
||||
release notes of a fix-release though.
|
@ -1,9 +1,10 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
Plugin Name: AuthLDAP
|
||||
Plugin URI: https://github.com/heiglandreas/authLdap
|
||||
Description: This plugin allows you to use your existing LDAP as authentication base for WordPress
|
||||
Version: 2.5.2
|
||||
Version: 2.5.9
|
||||
Author: Andreas Heigl <andreas@heigl.org>
|
||||
Author URI: http://andreas.heigl.org
|
||||
License: MIT
|
||||
@ -12,12 +13,25 @@ License URI: https://opensource.org/licenses/MIT
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
|
||||
use Org_Heigl\AuthLdap\LdapList;
|
||||
use Org_Heigl\AuthLdap\LdapUri;
|
||||
use Org_Heigl\AuthLdap\Manager\Ldap;
|
||||
use Org_Heigl\AuthLdap\UserRoleHandler;
|
||||
use Org_Heigl\AuthLdap\Wrapper\LdapFactory;
|
||||
|
||||
require_once dirname(__FILE__) . '/ldap.php';
|
||||
require_once __DIR__ . '/src/LdapUri.php';
|
||||
require_once __DIR__ . '/src/Wrapper/LdapInterface.php';
|
||||
require_once __DIR__ . '/src/Exception/Error.php';
|
||||
require_once __DIR__ . '/src/Exception/InvalidLdapUri.php';
|
||||
require_once __DIR__ . '/src/Exception/Error.php';
|
||||
require_once __DIR__ . '/src/Exception/InvalidLdapUri.php';
|
||||
require_once __DIR__ . '/src/Exception/MissingValidLdapConnection.php';
|
||||
require_once __DIR__ . '/src/Exception/SearchUnsuccessfull.php';
|
||||
require_once __DIR__ . '/src/Manager/Ldap.php';
|
||||
require_once __DIR__ . '/src/Wrapper/Ldap.php';
|
||||
require_once __DIR__ . '/src/Wrapper/LdapFactory.php';
|
||||
require_once __DIR__ . '/src/LdapList.php';
|
||||
require_once __DIR__ . '/src/LdapUri.php';
|
||||
require_once __DIR__ . '/src/UserRoleHandler.php';
|
||||
|
||||
function authLdap_debug($message)
|
||||
{
|
||||
@ -29,7 +43,7 @@ function authLdap_debug($message)
|
||||
|
||||
function authLdap_addmenu()
|
||||
{
|
||||
if (! is_multisite()) {
|
||||
if (!is_multisite()) {
|
||||
add_options_page(
|
||||
'AuthLDAP',
|
||||
'AuthLDAP',
|
||||
@ -60,7 +74,14 @@ function authLdap_options_panel()
|
||||
wp_enqueue_style('authLdap-style', plugin_dir_url(__FILE__) . 'authLdap.css');
|
||||
|
||||
if (($_SERVER['REQUEST_METHOD'] == 'POST') && array_key_exists('ldapOptionsSave', $_POST)) {
|
||||
$new_options = array(
|
||||
if (!isset($_POST['authLdapNonce'])) {
|
||||
die("Go away!");
|
||||
}
|
||||
if (!wp_verify_nonce($_POST['authLdapNonce'],'authLdapNonce')) {
|
||||
die("Go away!");
|
||||
}
|
||||
|
||||
$new_options = [
|
||||
'Enabled' => authLdap_get_post('authLDAPAuth', false),
|
||||
'CachePW' => authLdap_get_post('authLDAPCachePW', false),
|
||||
'URI' => authLdap_get_post('authLDAPURI'),
|
||||
@ -72,8 +93,8 @@ function authLdap_options_panel()
|
||||
'UidAttr' => authLdap_get_post('authLDAPUidAttr'),
|
||||
'MailAttr' => authLdap_get_post('authLDAPMailAttr'),
|
||||
'WebAttr' => authLdap_get_post('authLDAPWebAttr'),
|
||||
'Groups' => authLdap_get_post('authLDAPGroups', array()),
|
||||
'GroupSeparator'=> authLdap_get_post('authLDAPGroupSeparator', ','),
|
||||
'Groups' => authLdap_get_post('authLDAPGroups', []),
|
||||
'GroupSeparator' => authLdap_get_post('authLDAPGroupSeparator', ','),
|
||||
'Debug' => authLdap_get_post('authLDAPDebug', false),
|
||||
'GroupBase' => authLdap_get_post('authLDAPGroupBase'),
|
||||
'GroupAttr' => authLdap_get_post('authLDAPGroupAttr'),
|
||||
@ -83,7 +104,7 @@ function authLdap_options_panel()
|
||||
'GroupOverUser' => authLdap_get_post('authLDAPGroupOverUser', false),
|
||||
'DoNotOverwriteNonLdapUsers' => authLdap_get_post('authLDAPDoNotOverwriteNonLdapUsers', false),
|
||||
'UserRead' => authLdap_get_post('authLDAPUseUserAccount', false),
|
||||
);
|
||||
];
|
||||
if (authLdap_set_options($new_options)) {
|
||||
echo "<div class='updated'><p>Saved Options!</p></div>";
|
||||
} else {
|
||||
@ -104,7 +125,7 @@ function authLdap_options_panel()
|
||||
$authLDAPUidAttr = authLdap_get_option('UidAttr');
|
||||
$authLDAPWebAttr = authLdap_get_option('WebAttr');
|
||||
$authLDAPGroups = authLdap_get_option('Groups');
|
||||
$authLDAPGroupSeparator= authLdap_get_option('GroupSeparator');
|
||||
$authLDAPGroupSeparator = authLdap_get_option('GroupSeparator');
|
||||
$authLDAPDebug = authLdap_get_option('Debug');
|
||||
$authLDAPGroupBase = authLdap_get_option('GroupBase');
|
||||
$authLDAPGroupAttr = authLdap_get_option('GroupAttr');
|
||||
@ -113,7 +134,7 @@ function authLdap_options_panel()
|
||||
$authLDAPGroupEnable = authLdap_get_option('GroupEnable');
|
||||
$authLDAPGroupOverUser = authLdap_get_option('GroupOverUser');
|
||||
$authLDAPDoNotOverwriteNonLdapUsers = authLdap_get_option('DoNotOverwriteNonLdapUsers');
|
||||
$authLDAPUseUserAccount= authLdap_get_option('UserRead');
|
||||
$authLDAPUseUserAccount = authLdap_get_option('UserRead');
|
||||
|
||||
$tChecked = ($authLDAP) ? ' checked="checked"' : '';
|
||||
$tDebugChecked = ($authLDAPDebug) ? ' checked="checked"' : '';
|
||||
@ -127,7 +148,7 @@ function authLdap_options_panel()
|
||||
$roles = new WP_Roles();
|
||||
|
||||
$action = $_SERVER['REQUEST_URI'];
|
||||
if (! extension_loaded('ldap')) {
|
||||
if (!extension_loaded('ldap')) {
|
||||
echo '<div class="warning">The LDAP-Extension is not available on your '
|
||||
. 'WebServer. Therefore Everything you can alter here does not '
|
||||
. 'make any sense!</div>';
|
||||
@ -160,11 +181,11 @@ function authLdap_get_server()
|
||||
//$authLDAPURI = 'ldap:/foo:bar@server/trallala';
|
||||
authLdap_debug('connect to LDAP server');
|
||||
require_once dirname(__FILE__) . '/src/LdapList.php';
|
||||
$_ldapserver = new \Org_Heigl\AuthLdap\LdapList();
|
||||
$_ldapserver = new LdapList();
|
||||
foreach ($authLDAPURI as $uri) {
|
||||
$_ldapserver->addLdap(new \Org_Heigl\AuthLdap\LDAP(
|
||||
$_ldapserver->addLdap(new Ldap(
|
||||
new LdapFactory(),
|
||||
LdapUri::fromString($uri),
|
||||
$authLDAPDebug,
|
||||
$authLDAPStartTLS
|
||||
));
|
||||
}
|
||||
@ -199,7 +220,7 @@ function authLdap_get_server()
|
||||
function authLdap_login($user, $username, $password, $already_md5 = false)
|
||||
{
|
||||
// don't do anything when authLDAP is disabled
|
||||
if (! authLdap_get_option('Enabled')) {
|
||||
if (!authLdap_get_option('Enabled')) {
|
||||
authLdap_debug(
|
||||
'LDAP disabled in AuthLDAP plugin options (use the first option in the AuthLDAP options to enable it)'
|
||||
);
|
||||
@ -238,27 +259,27 @@ function authLdap_login($user, $username, $password, $already_md5 = false)
|
||||
$authLDAPGroupOverUser = authLdap_get_option('GroupOverUser');
|
||||
$authLDAPUseUserAccount = authLdap_get_option('UserRead');
|
||||
|
||||
if (! $username) {
|
||||
if (!$username) {
|
||||
authLdap_debug('Username not supplied: return false');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $password) {
|
||||
if (!$password) {
|
||||
authLdap_debug('Password not supplied: return false');
|
||||
$error = __('<strong>Error</strong>: The password field is empty.');
|
||||
return false;
|
||||
}
|
||||
// First check for valid values and set appropriate defaults
|
||||
if (! $authLDAPFilter) {
|
||||
if (!$authLDAPFilter) {
|
||||
$authLDAPFilter = '(uid=%s)';
|
||||
}
|
||||
if (! $authLDAPNameAttr) {
|
||||
if (!$authLDAPNameAttr) {
|
||||
$authLDAPNameAttr = 'name';
|
||||
}
|
||||
if (! $authLDAPMailAttr) {
|
||||
if (!$authLDAPMailAttr) {
|
||||
$authLDAPMailAttr = 'mail';
|
||||
}
|
||||
if (! $authLDAPUidAttr) {
|
||||
if (!$authLDAPUidAttr) {
|
||||
$authLDAPUidAttr = 'uid';
|
||||
}
|
||||
|
||||
@ -266,7 +287,7 @@ function authLdap_login($user, $username, $password, $already_md5 = false)
|
||||
// to store LDAP passwords in any
|
||||
// form, we've already replaced the password with the hashed username and LDAP_COOKIE_MARKER
|
||||
if ($already_md5) {
|
||||
if ($password == md5($username).md5($ldapCookieMarker)) {
|
||||
if ($password == md5($username) . md5($ldapCookieMarker)) {
|
||||
authLdap_debug('cookie authentication');
|
||||
return true;
|
||||
}
|
||||
@ -286,7 +307,7 @@ function authLdap_login($user, $username, $password, $already_md5 = false)
|
||||
}
|
||||
|
||||
// Make optional querying from the admin account #213
|
||||
if (! authLdap_get_option('UserRead')) {
|
||||
if (!authLdap_get_option('UserRead')) {
|
||||
// Rebind with the default credentials after the user has been loged in
|
||||
// Otherwise the credentials of the user trying to login will be used
|
||||
// This fixes #55
|
||||
@ -305,13 +326,13 @@ function authLdap_login($user, $username, $password, $already_md5 = false)
|
||||
array_filter(
|
||||
apply_filters(
|
||||
'authLdap_filter_attributes',
|
||||
array(
|
||||
[
|
||||
$authLDAPNameAttr,
|
||||
$authLDAPSecName,
|
||||
$authLDAPMailAttr,
|
||||
$authLDAPWebAttr,
|
||||
$authLDAPUidAttr
|
||||
)
|
||||
$authLDAPUidAttr,
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
@ -323,11 +344,11 @@ function authLdap_login($user, $username, $password, $already_md5 = false)
|
||||
);
|
||||
// First get all the relevant group informations so we can see if
|
||||
// whether have been changes in group association of the user
|
||||
if (! isset($attribs[0]['dn'])) {
|
||||
if (!isset($attribs[0]['dn'])) {
|
||||
authLdap_debug('could not get user attributes from LDAP');
|
||||
throw new UnexpectedValueException('dn has not been returned');
|
||||
}
|
||||
if (! isset($attribs[0][strtolower($authLDAPUidAttr)][0])) {
|
||||
if (!isset($attribs[0][strtolower($authLDAPUidAttr)][0])) {
|
||||
authLdap_debug('could not get user attributes from LDAP');
|
||||
throw new UnexpectedValueException('The user-ID attribute has not been returned');
|
||||
}
|
||||
@ -343,41 +364,58 @@ function authLdap_login($user, $username, $password, $already_md5 = false)
|
||||
|
||||
// This fixes #172
|
||||
if (true == authLdap_get_option('DoNotOverwriteNonLdapUsers', false)) {
|
||||
if (! get_user_meta($uid, 'authLDAP')) {
|
||||
if (!get_user_meta($uid, 'authLDAP')) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
$role = '';
|
||||
$roles = [];
|
||||
|
||||
// we only need this if either LDAP groups are disabled or
|
||||
// if the WordPress role of the user overrides LDAP groups
|
||||
if (!$authLDAPGroupEnable || !$authLDAPGroupOverUser) {
|
||||
$role = authLdap_user_role($uid);
|
||||
if ($role !== '') {
|
||||
$roles[] = $role;
|
||||
}
|
||||
// TODO, this needs to be revised, it seems, like authldap is taking only the first role
|
||||
// even if in WP there are assigned multiple.
|
||||
}
|
||||
|
||||
// do LDAP group mapping if needed
|
||||
// (if LDAP groups override worpress user role, $role is still empty)
|
||||
if (empty($role) && $authLDAPGroupEnable) {
|
||||
$role = authLdap_groupmap($realuid, $dn);
|
||||
authLdap_debug('role from group mapping: ' . $role);
|
||||
if (empty($roles) && $authLDAPGroupEnable) {
|
||||
$mappedRoles = authLdap_groupmap($realuid, $dn);
|
||||
if ($mappedRoles !== []) {
|
||||
$roles = $mappedRoles;
|
||||
authLdap_debug('role from group mapping: ' . json_encode($roles));
|
||||
}
|
||||
}
|
||||
|
||||
// if we don't have a role yet, use default role
|
||||
if (empty($role) && !empty($authLDAPDefaultRole)) {
|
||||
if (empty($roles) && !empty($authLDAPDefaultRole)) {
|
||||
authLdap_debug('no role yet, set default role');
|
||||
$role = $authLDAPDefaultRole;
|
||||
$roles[] = $authLDAPDefaultRole;
|
||||
}
|
||||
|
||||
if (empty($role)) {
|
||||
if (empty($roles)) {
|
||||
// Sorry, but you are not in any group that is allowed access
|
||||
trigger_error('no group found');
|
||||
authLdap_debug('user is not in any group that is allowed access');
|
||||
return false;
|
||||
} else {
|
||||
$roles = new WP_Roles();
|
||||
$wp_roles = new WP_Roles();
|
||||
// not sure if this is needed, but it can't hurt
|
||||
if (!$roles->is_role($role)) {
|
||||
|
||||
// Get rid of unexisting roles.
|
||||
foreach ($roles as $k => $v) {
|
||||
if (!$wp_roles->is_role($v)) {
|
||||
unset($k);
|
||||
}
|
||||
}
|
||||
|
||||
// check if single role or an empty array provided
|
||||
if (empty($roles)) {
|
||||
trigger_error('no group found');
|
||||
authLdap_debug('role is invalid');
|
||||
return false;
|
||||
@ -386,9 +424,8 @@ function authLdap_login($user, $username, $password, $already_md5 = false)
|
||||
|
||||
// from here on, the user has access!
|
||||
// now, lets update some user details
|
||||
$user_info = array();
|
||||
$user_info = [];
|
||||
$user_info['user_login'] = $realuid;
|
||||
$user_info['role'] = $role;
|
||||
$user_info['user_email'] = '';
|
||||
$user_info['user_nicename'] = '';
|
||||
|
||||
@ -454,11 +491,22 @@ function authLdap_login($user, $username, $password, $already_md5 = false)
|
||||
return $userid;
|
||||
}
|
||||
|
||||
// Update user roles.
|
||||
$user = new \WP_User($userid);
|
||||
|
||||
/**
|
||||
* Add hook for custom User-Role assignment
|
||||
*
|
||||
* @param WP_User $user This user-object will be returned. Can be modified as necessary in the actions.
|
||||
* @param array $roles
|
||||
*/
|
||||
do_action('authldap_user_roles', $user, $roles);
|
||||
|
||||
/**
|
||||
* Add hook for custom updates
|
||||
*
|
||||
* @param int $userid User ID.
|
||||
* @param array $attribs[0] Attributes retrieved from LDAP for the user.
|
||||
* @param array $attribs [0] Attributes retrieved from LDAP for the user.
|
||||
*/
|
||||
do_action('authLdap_login_successful', $userid, $attribs[0]);
|
||||
|
||||
@ -468,7 +516,7 @@ function authLdap_login($user, $username, $password, $already_md5 = false)
|
||||
update_user_meta($userid, 'authLDAP', true);
|
||||
|
||||
// return a user object upon positive authorization
|
||||
return new WP_User($userid);
|
||||
return $user;
|
||||
} catch (Exception $e) {
|
||||
authLdap_debug($e->getMessage() . '. Exception thrown in line ' . $e->getLine());
|
||||
trigger_error($e->getMessage() . '. Exception thrown in line ' . $e->getLine());
|
||||
@ -519,8 +567,8 @@ function authLdap_user_role($uid)
|
||||
}
|
||||
|
||||
/** @var array<string, bool> $usercapabilities */
|
||||
$usercapabilities = get_user_meta( $uid, "{$wpdb->prefix}capabilities", true);
|
||||
if ( ! is_array( $usercapabilities ) ) {
|
||||
$usercapabilities = get_user_meta($uid, "{$wpdb->prefix}capabilities", true);
|
||||
if (!is_array($usercapabilities)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -530,7 +578,7 @@ function authLdap_user_role($uid)
|
||||
// By using this approach we are now using the order of the roles from the WP_Roles object
|
||||
// and not from the capabilities any more.
|
||||
$userroles = array_keys(array_intersect_key($editable_roles, $usercapabilities));
|
||||
$role = $userroles[0];
|
||||
$role = ($userroles !== []) ? $userroles[0] : '';
|
||||
|
||||
authLdap_debug("Existing user's role: {$role}");
|
||||
return $role;
|
||||
@ -541,7 +589,7 @@ function authLdap_user_role($uid)
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $dn
|
||||
* @return string role, empty string if no mapping found, first found role otherwise
|
||||
* @return array role, empty array if no mapping found, first or all role(s) found otherwise
|
||||
* @conf array authLDAPGroups, associative array, role => ldap_group
|
||||
* @conf string authLDAPGroupBase, base dn to look up groups
|
||||
* @conf string authLDAPGroupAttr, ldap attribute that holds name of group
|
||||
@ -556,19 +604,19 @@ function authLdap_groupmap($username, $dn)
|
||||
$authLDAPGroupAttr = authLdap_get_option('GroupAttr');
|
||||
$authLDAPGroupFilter = authLdap_get_option('GroupFilter');
|
||||
$authLDAPGroupSeparator = authLdap_get_option('GroupSeparator');
|
||||
if (! $authLDAPGroupAttr) {
|
||||
if (!$authLDAPGroupAttr) {
|
||||
$authLDAPGroupAttr = 'gidNumber';
|
||||
}
|
||||
if (! $authLDAPGroupFilter) {
|
||||
if (!$authLDAPGroupFilter) {
|
||||
$authLDAPGroupFilter = '(&(objectClass=posixGroup)(memberUid=%s))';
|
||||
}
|
||||
if (! $authLDAPGroupSeparator) {
|
||||
if (!$authLDAPGroupSeparator) {
|
||||
$authLDAPGroupSeparator = ',';
|
||||
}
|
||||
|
||||
if (!is_array($authLDAPGroups) || count(array_filter(array_values($authLDAPGroups))) == 0) {
|
||||
authLdap_debug('No group names defined');
|
||||
return '';
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
@ -583,42 +631,52 @@ function authLdap_groupmap($username, $dn)
|
||||
authLdap_debug('Group Base: ' . $authLDAPGroupBase);
|
||||
$groups = authLdap_get_server()->search(
|
||||
sprintf($authLDAPGroupFilter, ldap_escape($username, '', LDAP_ESCAPE_FILTER)),
|
||||
array($authLDAPGroupAttr),
|
||||
[$authLDAPGroupAttr],
|
||||
$authLDAPGroupBase
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
authLdap_debug('Exception getting LDAP group attributes: ' . $e->getMessage());
|
||||
return '';
|
||||
return [];
|
||||
}
|
||||
|
||||
$grp = array();
|
||||
$grp = [];
|
||||
for ($i = 0; $i < $groups ['count']; $i++) {
|
||||
if ($authLDAPGroupAttr == "dn") {
|
||||
$grp[] = $groups[$i]['dn'];
|
||||
} else {
|
||||
for ($k = 0; $k < $groups[$i][strtolower($authLDAPGroupAttr)]['count']; $k++) {
|
||||
$grp[] = $groups[$i][strtolower($authLDAPGroupAttr)][$k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
authLdap_debug('LDAP groups: ' . json_encode($grp));
|
||||
|
||||
// Check whether the user is member of one of the groups that are
|
||||
// allowed acces to the blog. If the user is not member of one of
|
||||
// The groups throw her out! ;-)
|
||||
// If the user is member of more than one group only the first one
|
||||
// will be taken into account!
|
||||
|
||||
$role = '';
|
||||
$roles = [];
|
||||
foreach ($authLDAPGroups as $key => $val) {
|
||||
$currentGroup = explode($authLDAPGroupSeparator, $val);
|
||||
// Remove whitespaces around the group-ID
|
||||
$currentGroup = array_map('trim', $currentGroup);
|
||||
if (0 < count(array_intersect($currentGroup, $grp))) {
|
||||
$role = $key;
|
||||
break;
|
||||
$roles[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
authLdap_debug("Role from LDAP group: {$role}");
|
||||
return $role;
|
||||
// Default: If the user is member of more than one group only the first one
|
||||
// will be taken into account!
|
||||
// This filter allows you to return multiple user roles. WordPress
|
||||
// supports this functionality, but not natively via UI from Users
|
||||
// overview (you need to use a plugin). However, it's still widely used,
|
||||
// for example, by WooCommerce, etc. Use if you know what you're doing.
|
||||
if (apply_filters('authLdap_allow_multiple_roles', false) === false && count($roles) > 1) {
|
||||
$roles = array_slice($roles, 0, 1);
|
||||
}
|
||||
|
||||
authLdap_debug("Roles from LDAP group: " . json_encode($roles));
|
||||
return $roles;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -637,7 +695,7 @@ function authLdap_groupmap($username, $dn)
|
||||
*/
|
||||
function authLdap_show_password_fields($return, $user)
|
||||
{
|
||||
if (! $user) {
|
||||
if (!$user) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -689,7 +747,7 @@ function authLdap_sort_roles_by_capabilities($roles)
|
||||
authLdap_debug(print_r($roles, true));
|
||||
uasort($myRoles, 'authLdap_sortByCapabilitycount');
|
||||
|
||||
$return = array();
|
||||
$return = [];
|
||||
|
||||
foreach ($myRoles as $key => $role) {
|
||||
if (isset($roles[$key])) {
|
||||
@ -736,13 +794,13 @@ function authLdap_load_options($reload = false)
|
||||
$optionFunction = 'get_site_option';
|
||||
}
|
||||
if (is_null($options) || $reload) {
|
||||
$options = $optionFunction('authLDAPOptions', array());
|
||||
$options = $optionFunction('authLDAPOptions', []);
|
||||
}
|
||||
|
||||
// check if option version has changed (or if it's there at all)
|
||||
if (!isset($options['Version']) || ($options['Version'] != $option_version_plugin)) {
|
||||
// defaults for all options
|
||||
$options_default = array(
|
||||
$options_default = [
|
||||
'Enabled' => false,
|
||||
'CachePW' => false,
|
||||
'URI' => '',
|
||||
@ -753,7 +811,7 @@ function authLdap_load_options($reload = false)
|
||||
'UidAttr' => '', // 'uid'
|
||||
'MailAttr' => '', // 'mail'
|
||||
'WebAttr' => '',
|
||||
'Groups' => array(),
|
||||
'Groups' => [],
|
||||
'Debug' => false,
|
||||
'GroupAttr' => '', // 'gidNumber'
|
||||
'GroupFilter' => '', // '(&(objectClass=posixGroup)(memberUid=%s))'
|
||||
@ -762,13 +820,13 @@ function authLdap_load_options($reload = false)
|
||||
'GroupOverUser' => true,
|
||||
'Version' => $option_version_plugin,
|
||||
'DoNotOverwriteNonLdapUsers' => false,
|
||||
);
|
||||
];
|
||||
|
||||
// check if we got a version
|
||||
if (!isset($options['Version'])) {
|
||||
// we just changed to the new option format
|
||||
// read old options, then delete them
|
||||
$old_option_new_option = array(
|
||||
$old_option_new_option = [
|
||||
'authLDAP' => 'Enabled',
|
||||
'authLDAPCachePW' => 'CachePW',
|
||||
'authLDAPURI' => 'URI',
|
||||
@ -785,7 +843,7 @@ function authLdap_load_options($reload = false)
|
||||
'authLDAPDefaultRole' => 'DefaultRole',
|
||||
'authLDAPGroupEnable' => 'GroupEnable',
|
||||
'authLDAPGroupOverUser' => 'GroupOverUser',
|
||||
);
|
||||
];
|
||||
foreach ($old_option_new_option as $old_option => $new_option) {
|
||||
$value = get_option($old_option, null);
|
||||
if (!is_null($value)) {
|
||||
@ -832,7 +890,7 @@ function authLdap_get_option($optionname, $default = null)
|
||||
/**
|
||||
* Set new options
|
||||
*/
|
||||
function authLdap_set_options($new_options = array())
|
||||
function authLdap_set_options($new_options = [])
|
||||
{
|
||||
// initialize the options with what we currently have
|
||||
$options = authLdap_load_options();
|
||||
@ -884,3 +942,5 @@ add_filter('authenticate', 'authLdap_login', 10, 3);
|
||||
/** This only works from WP 4.3.0 on */
|
||||
add_filter('send_password_change_email', 'authLdap_send_change_email', 10, 3);
|
||||
add_filter('send_email_change_email', 'authLdap_send_change_email', 10, 3);
|
||||
$handler = new UserRoleHandler();
|
||||
add_action('authldap_user_roles', [$handler, 'addRolesToUser'], 10, 2);
|
||||
|
@ -1,275 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* $Id: ldap.php 2676679 2022-02-10 18:26:37Z heiglandreas $
|
||||
*
|
||||
* authLdap - Authenticate Wordpress against an LDAP-Backend.
|
||||
* Copyright (c) 2008 Andreas Heigl<andreas@heigl.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* This file handles the basic LDAP-Tasks
|
||||
*
|
||||
* @author Andreas Heigl<andreas@heigl.org>
|
||||
* @package authLdap
|
||||
* @category authLdap
|
||||
* @since 2008
|
||||
*/
|
||||
namespace Org_Heigl\AuthLdap;
|
||||
|
||||
use Exception;
|
||||
use Org_Heigl\AuthLdap\Exception\Error;
|
||||
use function ldap_escape;
|
||||
|
||||
class LDAP
|
||||
{
|
||||
private $server = '';
|
||||
|
||||
private $scheme = 'ldap';
|
||||
|
||||
private $port = 389;
|
||||
|
||||
private $baseDn = '';
|
||||
|
||||
private $debug = false;
|
||||
/**
|
||||
* This property contains the connection handle to the ldap-server
|
||||
*
|
||||
* @var Ressource|Connection|null
|
||||
*/
|
||||
private $ch = null;
|
||||
|
||||
private $username = '';
|
||||
|
||||
private $password = '';
|
||||
|
||||
private $starttls = false;
|
||||
|
||||
public function __construct(LdapUri $URI, $debug = false, $starttls = false)
|
||||
{
|
||||
$this->debug=$debug;
|
||||
$array = parse_url($URI->toString());
|
||||
if (! is_array($array)) {
|
||||
throw new Exception($URI . ' seems not to be a valid URI');
|
||||
}
|
||||
$url = array_map(function ($item) {
|
||||
return urldecode($item);
|
||||
}, $array);
|
||||
|
||||
if (false === $url) {
|
||||
throw new Exception($URI . ' is an invalid URL');
|
||||
}
|
||||
if (! isset($url['scheme'])) {
|
||||
throw new Exception($URI . ' does not provide a scheme');
|
||||
}
|
||||
if (0 !== strpos($url['scheme'], 'ldap')) {
|
||||
throw new Exception($URI . ' is an invalid LDAP-URI');
|
||||
}
|
||||
if (! isset($url['host'])) {
|
||||
throw new Exception($URI . ' does not provide a server');
|
||||
}
|
||||
if (! isset($url['path'])) {
|
||||
throw new Exception($URI . ' does not provide a search-base');
|
||||
}
|
||||
if (1 == strlen($url['path'])) {
|
||||
throw new Exception($URI . ' does not provide a valid search-base');
|
||||
}
|
||||
$this -> server = $url['host'];
|
||||
$this -> scheme = $url['scheme'];
|
||||
$this -> baseDn = substr($url['path'], 1);
|
||||
if (isset($url['user'])) {
|
||||
$this -> username = $url['user'];
|
||||
}
|
||||
if ('' == trim($this -> username)) {
|
||||
$this -> username = 'anonymous';
|
||||
}
|
||||
if (isset($url['pass'])) {
|
||||
$this -> password = $url['pass'];
|
||||
}
|
||||
if (isset($url['port'])) {
|
||||
$this -> port = $url['port'];
|
||||
}
|
||||
$this->starttls = $starttls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the given LDAP-Server
|
||||
*
|
||||
* @return LDAP
|
||||
* @throws Error
|
||||
*/
|
||||
public function connect()
|
||||
{
|
||||
$this -> disconnect();
|
||||
if ('ldaps' == $this->scheme && 389 == $this->port) {
|
||||
$this->port = 636;
|
||||
}
|
||||
|
||||
$this->ch = @ldap_connect($this->scheme . '://' . $this->server . ':' . $this -> port);
|
||||
if (false === $this->ch) {
|
||||
$this->ch = null;
|
||||
throw new Error('Could not connect to the server');
|
||||
}
|
||||
ldap_set_option($this->ch, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||
ldap_set_option($this->ch, LDAP_OPT_REFERRALS, 0);
|
||||
//if configured try to upgrade encryption to tls for ldap connections
|
||||
if ($this->starttls) {
|
||||
ldap_start_tls($this->ch);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from a resource if one is available
|
||||
*
|
||||
* @return LDAP
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
if (null !== $this->ch ) {
|
||||
@ldap_unbind($this->ch);
|
||||
}
|
||||
$this->ch = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind to an LDAP-Server with the given credentials
|
||||
*
|
||||
* @return LDAP
|
||||
* @throw AuthLdap_Exception
|
||||
*/
|
||||
public function bind()
|
||||
{
|
||||
if (! $this->ch) {
|
||||
$this->connect();
|
||||
}
|
||||
if (null === $this->ch) {
|
||||
throw new Error('No valid LDAP connection available');
|
||||
}
|
||||
$bind = false;
|
||||
if (( ( $this->username )
|
||||
&& ( $this->username != 'anonymous') )
|
||||
&& ( $this->password != '' )) {
|
||||
$bind = @ldap_bind($this->ch, $this->username, $this->password);
|
||||
} else {
|
||||
$bind = @ldap_bind($this->ch);
|
||||
}
|
||||
if (! $bind) {
|
||||
throw new Error('bind was not successfull: ' . ldap_error($this->ch));
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getErrorNumber()
|
||||
{
|
||||
return @ldap_errno($this->ch);
|
||||
}
|
||||
|
||||
public function getErrorText()
|
||||
{
|
||||
return @ldap_error($this->ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method does the actual ldap-serch.
|
||||
*
|
||||
* This is using the filter <var>$filter</var> for retrieving the attributes
|
||||
* <var>$attributes</var>
|
||||
*
|
||||
*
|
||||
* @param string $filter
|
||||
* @param array $attributes
|
||||
* @param string $base
|
||||
* @return array
|
||||
*/
|
||||
public function search($filter, $attributes = array('uid'), $base = '')
|
||||
{
|
||||
if (null === $this->ch) {
|
||||
throw new Error('No resource handle avbailable');
|
||||
}
|
||||
if (! $base) {
|
||||
$base = $this->baseDn;
|
||||
}
|
||||
$result = ldap_search($this->ch, $base, $filter, $attributes);
|
||||
if ($result === false) {
|
||||
throw new Error('no result found');
|
||||
}
|
||||
$this->_info = @ldap_get_entries($this->ch, $result);
|
||||
if ($this->_info === false) {
|
||||
throw new Error('invalid results found');
|
||||
}
|
||||
return $this -> _info;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets debugging to ON
|
||||
*/
|
||||
public function debugOn()
|
||||
{
|
||||
$this->debug = true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets debugging to OFF
|
||||
*/
|
||||
public function debugOff()
|
||||
{
|
||||
$this->debug = false;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method authenticates the user <var>$username</var> using the
|
||||
* password <var>$password</var>
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param string $filter OPTIONAL This parameter defines the Filter to be used
|
||||
* when searchin for the username. This MUST contain the string '%s' which
|
||||
* will be replaced by the vaue given in <var>$username</var>
|
||||
* @return boolean true or false depending on successfull authentication or not
|
||||
*/
|
||||
public function authenticate($username, $password, $filter = '(uid=%s)')
|
||||
{
|
||||
//return true;
|
||||
$this->connect();
|
||||
$this->bind();
|
||||
$res = $this->search(sprintf($filter, ldap_escape($username, '', LDAP_ESCAPE_FILTER)));
|
||||
if (! $res || ! is_array($res) || ( $res ['count'] != 1 )) {
|
||||
return false;
|
||||
}
|
||||
$dn = $res[0]['dn'];
|
||||
if ($username && $password) {
|
||||
if (@ldap_bind($this->ch, $dn, $password)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* $this method loggs errors if debugging is set to ON
|
||||
*/
|
||||
public function logError()
|
||||
{
|
||||
if ($this->debug) {
|
||||
$_v = debug_backtrace();
|
||||
throw new Error(
|
||||
'[LDAP_ERROR]' . ldap_errno($this->ch) . ':' . ldap_error($this->ch),
|
||||
$_v[0]['line']
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
22
wp-content/plugins/authldap/phpcs.xml
Normal file
22
wp-content/plugins/authldap/phpcs.xml
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset name="Custom Standard" namespace="MyProject\CS\Standard">
|
||||
<description>authLdap codestyle</description>
|
||||
<file>./src</file>
|
||||
<file>./authLdap.php</file>
|
||||
<file>./tests</file>
|
||||
|
||||
<arg name="colors"/>
|
||||
<arg value="sp"/>
|
||||
|
||||
<autoload>./vendor/autoload.php</autoload>
|
||||
|
||||
<rule ref="PSR12">
|
||||
<exclude name="Generic.WhiteSpace.DisallowTabIndent"/>
|
||||
</rule>
|
||||
<rule ref="Generic.WhiteSpace.ScopeIndent">
|
||||
<properties>
|
||||
<property name="tabIndent" value="true"/>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
</ruleset>
|
@ -2,8 +2,8 @@
|
||||
Contributors: heiglandreas
|
||||
Tags: ldap, auth, authentication, active directory, AD, openLDAP, Open Directory
|
||||
Requires at least: 2.5.0
|
||||
Tested up to: 5.9.0
|
||||
Requires PHP: 7.2
|
||||
Tested up to: 6.3.0
|
||||
Requires PHP: 7.4
|
||||
Stable tag: trunk
|
||||
License: MIT
|
||||
License URI: https://opensource.org/licenses/MIT
|
||||
@ -39,8 +39,36 @@ Go to https://github.com/heiglandreas/authLdap
|
||||
|
||||
Please use the issuetracker at https://github.com/heiglandreas/authLdap/issues
|
||||
|
||||
= Where can I report sensitive security issues with the plugin? =
|
||||
|
||||
In essence: Report a security vulnerability at https://github.com/heiglandreas/authLdap/security/advisories/new
|
||||
|
||||
Please see https://github.com/heiglandreas/authLdap/blob/master/SECURITY.md for more details
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 2.5.9 =
|
||||
|
||||
* Adds information about security-contacts
|
||||
* Addresses CVE-2023-41655
|
||||
|
||||
= 2.5.8 =
|
||||
|
||||
* Fix regression from 2.5.7
|
||||
|
||||
= 2.5.7 =
|
||||
|
||||
* Fix regressions from 2.5.4
|
||||
* Fix CI system
|
||||
|
||||
= 2.5.4 =
|
||||
* Update Tested up to
|
||||
|
||||
= 2.5.3 =
|
||||
* Fix issue with broken role-assignement in combination with WooCommerce
|
||||
* Fix spelling issue
|
||||
* Allow DN as role-definition
|
||||
|
||||
= 2.5.0 =
|
||||
* Ignore the order of capabilities to tell the role. In addition the filter `editable_roles` can be used to limit the roles
|
||||
|
||||
|
6
wp-content/plugins/authldap/security.txt
Normal file
6
wp-content/plugins/authldap/security.txt
Normal file
@ -0,0 +1,6 @@
|
||||
Contact: mailto://andreas@heigl.net
|
||||
Contact: https://github.com/heiglandreas/authLdap/security/advisories/new
|
||||
Expires: 2026-09-07T10:00:00.000Z
|
||||
Encryption: https://andreas.heigl.org/publickey/
|
||||
Encryption: https://heigl.org/.well-known/openpgpkey/hu/sfqdema7hgdj146cwzo4rxgsoujxis31
|
||||
Preferred-Languages: en,de
|
@ -1,13 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Copyright Andrea Heigl <andreas@heigl.org>
|
||||
*
|
||||
* Licenses under the MIT-license. For details see the included file LICENSE.md
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Org_Heigl\AuthLdap\Exception;
|
||||
|
||||
use Exception;
|
||||
|
@ -1,15 +1,74 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright Andreas Heigl <andreas@heigl.org>
|
||||
*
|
||||
* Licenses under the MIT-license. For details see the included file LICENSE.md
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Org_Heigl\AuthLdap\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
class InvalidLdapUri extends RuntimeException
|
||||
{
|
||||
public static function fromLdapUriString(string $ldapUri): InvalidLdapUri
|
||||
public static function cannotparse(string $ldapUri): self
|
||||
{
|
||||
return new self('"%s" is not a valid LDAP-URI.');
|
||||
return new self(sprintf(
|
||||
'%1$s seems not to be a valid URI',
|
||||
$ldapUri
|
||||
));
|
||||
}
|
||||
|
||||
public static function wrongSchema(string $uri): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'%1$s does not start with a valid schema',
|
||||
$uri
|
||||
));
|
||||
}
|
||||
|
||||
public static function noSchema(string $uri): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'%1$s does not provide a schema',
|
||||
$uri
|
||||
));
|
||||
}
|
||||
|
||||
public static function noEnvironmentVariableSet(string $uri): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'The environment variable %1$s does not provide a URI',
|
||||
$uri
|
||||
));
|
||||
}
|
||||
|
||||
public static function noServerProvided(string $uri): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'The LDAP-URI %1$s does not provide a server',
|
||||
$uri
|
||||
));
|
||||
}
|
||||
|
||||
public static function noSearchBaseProvided(string $uri): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'The LDAP-URI %1$s does not provide a search-base',
|
||||
$uri
|
||||
));
|
||||
}
|
||||
|
||||
public static function invalidSearchBaseProvided(string $uri): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'The LDAP-URI %1$s does not provide a valid search-base',
|
||||
$uri
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright Andreas Heigl <andreas@heigl.org>
|
||||
*
|
||||
* Licenses under the MIT-license. For details see the included file LICENSE.md
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Org_Heigl\AuthLdap\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class MissingValidLdapConnection extends Error
|
||||
{
|
||||
public static function get(): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'No valid LDAP connection available'
|
||||
));
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright Andreas Heigl <andreas@heigl.org>
|
||||
*
|
||||
* Licenses under the MIT-license. For details see the included file LICENSE.md
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Org_Heigl\AuthLdap\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class SearchUnsuccessfull extends RuntimeException
|
||||
{
|
||||
public static function fromSearchFilter(string $filter): self
|
||||
{
|
||||
return new self(sprintf(
|
||||
'Search for %1$s was not successfull',
|
||||
$filter
|
||||
));
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (c) Andreas Heigl<andreas@heigl.org>
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -26,23 +27,26 @@
|
||||
|
||||
namespace Org_Heigl\AuthLdap;
|
||||
|
||||
use Exception;
|
||||
use Org_Heigl\AuthLdap\Exception\Error;
|
||||
use Org_Heigl\AuthLdap\Exception\SearchUnsuccessfull;
|
||||
use Org_Heigl\AuthLdap\Manager\Ldap;
|
||||
|
||||
class LdapList
|
||||
{
|
||||
/**
|
||||
* @var \LDAP[]
|
||||
* @var Ldap[]
|
||||
*/
|
||||
protected $items = [];
|
||||
|
||||
public function addLdap(LDAP $ldap)
|
||||
public function addLdap(Ldap $ldap)
|
||||
{
|
||||
$this->items[] = $ldap;
|
||||
}
|
||||
|
||||
public function authenticate($username, $password, $filter = '(uid=%s)')
|
||||
{
|
||||
/** @var LDAP $item */
|
||||
/** @var Ldap $item */
|
||||
foreach ($this->items as $key => $item) {
|
||||
if (! $item->authenticate($username, $password, $filter)) {
|
||||
unset($this->items[$key]);
|
||||
@ -81,10 +85,9 @@ class LdapList
|
||||
$result = $item->search($filter, $attributes, $base);
|
||||
return $result;
|
||||
} catch (Exception $e) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
throw new \AuthLDAP_Exception('No Results found');
|
||||
throw SearchUnsuccessfull::fromSearchFilter($filter);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Copyright (c) Andreas Heigl<andreas@heigl.org>
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@ -27,23 +25,106 @@ declare(strict_types=1);
|
||||
* @link http://github.com/heiglandreas/authLDAP
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Org_Heigl\AuthLdap;
|
||||
|
||||
use Org_Heigl\AuthLdap\Exception\InvalidLdapUri;
|
||||
|
||||
use function array_map;
|
||||
use function error_get_last;
|
||||
use function getenv;
|
||||
use function preg_replace;
|
||||
use function urlencode;
|
||||
use function is_array;
|
||||
use function is_string;
|
||||
use function parse_url;
|
||||
use function preg_replace_callback;
|
||||
use function rawurlencode;
|
||||
use function strlen;
|
||||
use function strpos;
|
||||
use function substr;
|
||||
use function trim;
|
||||
use function urldecode;
|
||||
|
||||
final class LdapUri
|
||||
{
|
||||
private $uri;
|
||||
private $server;
|
||||
|
||||
private $scheme;
|
||||
|
||||
private $port = 389;
|
||||
|
||||
private string $baseDn;
|
||||
|
||||
private $username = '';
|
||||
|
||||
private $password = '';
|
||||
|
||||
private function __construct(string $uri)
|
||||
{
|
||||
if (! preg_match('/^(ldap|ldaps|env)/', $uri)) {
|
||||
throw InvalidLdapUri::fromLdapUriString($uri);
|
||||
if (!preg_match('/^(ldap|ldaps|env)/', $uri)) {
|
||||
throw InvalidLdapUri::wrongSchema($uri);
|
||||
}
|
||||
|
||||
if (strpos($uri, 'env:') === 0) {
|
||||
$newUri = getenv(substr($uri, 4));
|
||||
if (false === $newUri) {
|
||||
throw InvalidLdapUri::noEnvironmentVariableSet($uri);
|
||||
}
|
||||
$uri = (string) $newUri;
|
||||
}
|
||||
|
||||
$uri = $this->injectEnvironmentVariables($uri);
|
||||
|
||||
$array = parse_url($uri);
|
||||
if (!is_array($array)) {
|
||||
throw InvalidLdapUri::cannotparse($uri);
|
||||
}
|
||||
|
||||
$url = array_map(static function ($item) {
|
||||
if (is_int($item)) {
|
||||
return $item;
|
||||
}
|
||||
return urldecode($item);
|
||||
}, $array);
|
||||
|
||||
|
||||
if (!isset($url['scheme'])) {
|
||||
throw InvalidLdapUri::noSchema($uri);
|
||||
}
|
||||
if (0 !== strpos($url['scheme'], 'ldap')) {
|
||||
throw InvalidLdapUri::wrongSchema($uri);
|
||||
}
|
||||
if (!isset($url['host'])) {
|
||||
throw InvalidLdapUri::noServerProvided($uri);
|
||||
}
|
||||
if (!isset($url['path'])) {
|
||||
throw InvalidLdapUri::noSearchBaseProvided($uri);
|
||||
}
|
||||
if (1 === strlen($url['path'])) {
|
||||
throw InvalidLdapUri::invalidSearchBaseProvided($uri);
|
||||
}
|
||||
|
||||
$this->server = $url['host'];
|
||||
$this->scheme = $url['scheme'];
|
||||
$this->baseDn = substr($url['path'], 1);
|
||||
if (isset($url['user'])) {
|
||||
$this->username = $url['user'];
|
||||
}
|
||||
if ('' === trim($this->username)) {
|
||||
$this->username = 'anonymous';
|
||||
}
|
||||
if (isset($url['pass'])) {
|
||||
$this->password = $url['pass'];
|
||||
}
|
||||
if ($this->scheme === 'ldaps' && $this->port = 389) {
|
||||
$this->port = 636;
|
||||
}
|
||||
|
||||
// When someone sets the port in the URL we overwrite whatever is set.
|
||||
// We have to assume they know what they are doing!
|
||||
if (isset($url['port'])) {
|
||||
$this->port = $url['port'];
|
||||
}
|
||||
$this->uri = $uri;
|
||||
}
|
||||
|
||||
public static function fromString(string $uri): LdapUri
|
||||
@ -51,22 +132,48 @@ final class LdapUri
|
||||
return new LdapUri($uri);
|
||||
}
|
||||
|
||||
public function toString(): string
|
||||
private function injectEnvironmentVariables(string $base): string
|
||||
{
|
||||
$uri = $this->uri;
|
||||
if (0 === strpos($uri, 'env:')) {
|
||||
$uri = getenv(substr($this->uri, 4));
|
||||
return preg_replace_callback('/%env:([^%]+)%/', static function (array $matches) {
|
||||
return rawurlencode(getenv($matches[1]));
|
||||
}, $base);
|
||||
}
|
||||
|
||||
$uri = preg_replace_callback('/%env:([^%]+)%/', function (array $matches) {
|
||||
return rawurlencode(getenv($matches[1]));
|
||||
}, $uri);
|
||||
|
||||
return $uri;
|
||||
public function toString(): string
|
||||
{
|
||||
return $this->scheme . '://' . $this->server . ':' . $this->port;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->toString();
|
||||
}
|
||||
|
||||
public function getUsername(): string
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
public function getBaseDn(): string
|
||||
{
|
||||
return $this->baseDn;
|
||||
}
|
||||
|
||||
public function isAnonymous(): bool
|
||||
{
|
||||
if ($this->password === '') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->username === 'anonymous') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
164
wp-content/plugins/authldap/src/Manager/Ldap.php
Normal file
164
wp-content/plugins/authldap/src/Manager/Ldap.php
Normal file
@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* $Id: ldap.php 381646 2011-05-06 09:37:31Z heiglandreas $
|
||||
*
|
||||
* authLdap - Authenticate Wordpress against an LDAP-Backend.
|
||||
* Copyright (c) 2008 Andreas Heigl<andreas@heigl.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* This file handles the basic LDAP-Tasks
|
||||
*
|
||||
* @author Andreas Heigl<andreas@heigl.org>
|
||||
* @package authLdap
|
||||
* @category authLdap
|
||||
* @since 2008
|
||||
*/
|
||||
|
||||
namespace Org_Heigl\AuthLdap\Manager;
|
||||
|
||||
use Org_Heigl\AuthLdap\Exception\Error;
|
||||
use Org_Heigl\AuthLdap\Exception\MissingValidLdapConnection;
|
||||
use Org_Heigl\AuthLdap\LdapUri;
|
||||
use Org_Heigl\AuthLdap\Wrapper\LdapFactory;
|
||||
use Org_Heigl\AuthLdap\Wrapper\LdapInterface;
|
||||
|
||||
class Ldap
|
||||
{
|
||||
/**
|
||||
* This property contains the connection handle to the ldap-server
|
||||
*
|
||||
* @var LdapInterface|null
|
||||
*/
|
||||
private ?LdapInterface $connection;
|
||||
|
||||
private LdapUri $uri;
|
||||
|
||||
private LdapFactory $factory;
|
||||
|
||||
private $starttls;
|
||||
|
||||
public function __construct(LdapFactory $factory, LdapUri $uri, $starttls = false)
|
||||
{
|
||||
$this->starttls = $starttls;
|
||||
$this->uri = $uri;
|
||||
$this->factory = $factory;
|
||||
$this->connection = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the given LDAP-Server
|
||||
*/
|
||||
public function connect(): self
|
||||
{
|
||||
$this->disconnect();
|
||||
|
||||
$this->connection = $this->factory->createFromLdapUri($this->uri->toString());
|
||||
$this->connection->setOption(LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||
$this->connection->setOption(LDAP_OPT_REFERRALS, 0);
|
||||
//if configured try to upgrade encryption to tls for ldap connections
|
||||
if ($this->starttls) {
|
||||
$this->connection->startTls();
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from a resource if one is available
|
||||
*/
|
||||
public function disconnect(): self
|
||||
{
|
||||
if (null !== $this->connection) {
|
||||
$this->connection->unbind();
|
||||
}
|
||||
$this->connection = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind to an LDAP-Server with the given credentials
|
||||
*
|
||||
* @throws Error
|
||||
*/
|
||||
public function bind(): self
|
||||
{
|
||||
if (!$this->connection) {
|
||||
$this->connect();
|
||||
}
|
||||
if (null === $this->connection) {
|
||||
throw MissingValidLdapConnection::get();
|
||||
}
|
||||
if ($this->uri->isAnonymous()) {
|
||||
$bind = $this->connection->bind();
|
||||
} else {
|
||||
$bind = $this->connection->bind($this->uri->getUsername(), $this->uri->getPassword());
|
||||
}
|
||||
if (!$bind) {
|
||||
throw new Error('bind was not successfull: ' . $this->connection->error());
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method does the actual ldap-serch.
|
||||
*
|
||||
* This is using the filter <var>$filter</var> for retrieving the attributes
|
||||
* <var>$attributes</var>
|
||||
*
|
||||
* @return array<string|int, mixed>
|
||||
* @throws Error
|
||||
*/
|
||||
public function search(string $filter, array $attributes = ['uid'], ?string $base = ''): array
|
||||
{
|
||||
if (null === $this->connection) {
|
||||
throw new Error('No resource handle available');
|
||||
}
|
||||
if (!$base) {
|
||||
$base = $this->uri->getBaseDn();
|
||||
}
|
||||
$result = $this->connection->search($base, $filter, $attributes);
|
||||
if ($result === false) {
|
||||
throw new Error('no result found');
|
||||
}
|
||||
$info = $this->connection->getEntries($result);
|
||||
if ($info === false) {
|
||||
throw new Error('invalid results found');
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method authenticates the user <var>$username</var> using the
|
||||
* password <var>$password</var>
|
||||
*
|
||||
* @param string $filter OPTIONAL This parameter defines the Filter to be used
|
||||
* when searchin for the username. This MUST contain the string '%s' which
|
||||
* will be replaced by the vaue given in <var>$username</var>
|
||||
* @throws Error
|
||||
*/
|
||||
public function authenticate(string $username, string $password, string $filter = '(uid=%s)'): bool
|
||||
{
|
||||
$this->connect();
|
||||
$this->bind();
|
||||
$res = $this->search(sprintf($filter, $this->factory->escape($username, '', LDAP_ESCAPE_FILTER)));
|
||||
if ($res ['count'] !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$dn = $res[0]['dn'];
|
||||
return $username && $password && $this->connection->bind($dn, $password);
|
||||
}
|
||||
}
|
54
wp-content/plugins/authldap/src/UserRoleHandler.php
Normal file
54
wp-content/plugins/authldap/src/UserRoleHandler.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright Andreas Heigl <andreas@heigl.org>
|
||||
*
|
||||
* Licenses under the MIT-license. For details see the included file LICENSE.md
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Org_Heigl\AuthLdap;
|
||||
|
||||
use WP_User;
|
||||
|
||||
use function array_search;
|
||||
use function in_array;
|
||||
use function var_dump;
|
||||
|
||||
class UserRoleHandler
|
||||
{
|
||||
/**
|
||||
* @param WP_User $user
|
||||
* @param string[] $roles
|
||||
* @return void
|
||||
*/
|
||||
public function addRolesToUser(WP_User $user, $roles) : void
|
||||
{
|
||||
if ($roles === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($user->roles == $roles) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove unused roles from existing.
|
||||
foreach ($user->roles as $role) {
|
||||
if (!in_array($role, $roles)) {
|
||||
// Remove unused roles.
|
||||
$user->remove_role($role);
|
||||
continue;
|
||||
}
|
||||
// Remove the existing role from roles.
|
||||
if (($key = array_search($role, $roles)) !== false) {
|
||||
unset($roles[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
// Add new ones if not already assigned.
|
||||
foreach ($roles as $role) {
|
||||
$user->add_role($role);
|
||||
}
|
||||
}
|
||||
}
|
92
wp-content/plugins/authldap/src/Wrapper/Ldap.php
Normal file
92
wp-content/plugins/authldap/src/Wrapper/Ldap.php
Normal file
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright Andreas Heigl <andreas@heigl.org>
|
||||
*
|
||||
* Licenses under the MIT-license. For details see the included file LICENSE.md
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Org_Heigl\AuthLdap\Wrapper;
|
||||
|
||||
use function ldap_bind;
|
||||
use function ldap_connect;
|
||||
use function ldap_error;
|
||||
use function ldap_escape;
|
||||
use function ldap_get_entries;
|
||||
use function ldap_set_option;
|
||||
use function ldap_start_tls;
|
||||
use function ldap_unbind;
|
||||
|
||||
final class Ldap implements LdapInterface
|
||||
{
|
||||
private $connection;
|
||||
|
||||
public function __construct(string $ldapUri)
|
||||
{
|
||||
$this->connection = ldap_connect($ldapUri);
|
||||
}
|
||||
|
||||
public function bind($dn = null, $password = null)
|
||||
{
|
||||
if (null === $dn && null === $password) {
|
||||
return ldap_bind($this->connection);
|
||||
}
|
||||
return ldap_bind($this->connection, $dn, $password);
|
||||
}
|
||||
|
||||
public function unbind()
|
||||
{
|
||||
return ldap_unbind($this->connection);
|
||||
}
|
||||
|
||||
public function setOption($option, $value)
|
||||
{
|
||||
return ldap_set_option($this->connection, $option, $value);
|
||||
}
|
||||
|
||||
public function startTls()
|
||||
{
|
||||
return ldap_start_tls($this->connection);
|
||||
}
|
||||
|
||||
public function error()
|
||||
{
|
||||
return ldap_error($this->connection);
|
||||
}
|
||||
|
||||
public function errno()
|
||||
{
|
||||
return ldap_errno($this->connection);
|
||||
}
|
||||
|
||||
public function search(
|
||||
$base,
|
||||
$filter,
|
||||
array $attributes = [],
|
||||
$attributes_only = 0,
|
||||
$sizelimit = -1,
|
||||
$timelimit = -1
|
||||
) {
|
||||
return ldap_search(
|
||||
$this->connection,
|
||||
$base,
|
||||
$filter,
|
||||
$attributes,
|
||||
$attributes_only,
|
||||
$sizelimit,
|
||||
$timelimit
|
||||
);
|
||||
}
|
||||
|
||||
public function getEntries($search_result)
|
||||
{
|
||||
return ldap_get_entries($this->connection, $search_result);
|
||||
}
|
||||
|
||||
public static function escape(string $value, string $ignore = '', int $flags = 0): string
|
||||
{
|
||||
return ldap_escape($value, $ignore, $flags);
|
||||
}
|
||||
}
|
24
wp-content/plugins/authldap/src/Wrapper/LdapFactory.php
Normal file
24
wp-content/plugins/authldap/src/Wrapper/LdapFactory.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright Andreas Heigl <andreas@heigl.org>
|
||||
*
|
||||
* Licenses under the MIT-license. For details see the included file LICENSE.md
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Org_Heigl\AuthLdap\Wrapper;
|
||||
|
||||
class LdapFactory
|
||||
{
|
||||
public function createFromLdapUri(string $ldapUri): LdapInterface
|
||||
{
|
||||
return new Ldap($ldapUri);
|
||||
}
|
||||
|
||||
public function escape($value, $ignore = '', $flags = 0): string
|
||||
{
|
||||
return Ldap::escape($value, $ignore, $flags);
|
||||
}
|
||||
}
|
39
wp-content/plugins/authldap/src/Wrapper/LdapInterface.php
Normal file
39
wp-content/plugins/authldap/src/Wrapper/LdapInterface.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright Andreas Heigl <andreas@heigl.org>
|
||||
*
|
||||
* Licenses under the MIT-license. For details see the included file LICENSE.md
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Org_Heigl\AuthLdap\Wrapper;
|
||||
|
||||
interface LdapInterface
|
||||
{
|
||||
public function bind($dn = null, $password = null);
|
||||
|
||||
public function unbind();
|
||||
|
||||
public function setOption($option, $value);
|
||||
|
||||
public function startTls();
|
||||
|
||||
public function error();
|
||||
|
||||
public function errno();
|
||||
|
||||
public function search(
|
||||
$base,
|
||||
$filter,
|
||||
array $attributes = [],
|
||||
$attributes_only = 0,
|
||||
$sizelimit = -1,
|
||||
$timelimit = -1
|
||||
);
|
||||
|
||||
public function getEntries($search_result);
|
||||
|
||||
public static function escape(string $value, string $ignore = '', int $flags = 0): string;
|
||||
}
|
@ -37,6 +37,7 @@
|
||||
<?php endif ?>
|
||||
<h2>AuthLDAP Options</h2>
|
||||
<form class="authldap-options" method="post" id="authLDAP_options" action="<?php echo $action;?>">
|
||||
<input name="authLdapNonce" type="hidden" value="<?php echo wp_create_nonce('authLdapNonce'); ?>" />
|
||||
<h3 class="title">General Usage of authLDAP</h3>
|
||||
<fieldset class="options">
|
||||
<table class="form-table">
|
||||
|
Loading…
Reference in New Issue
Block a user