Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LDAP over SSL cert and key for secure LDAP servers like Google Secure LDAP and few minor improvements #115

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ config_ldap.php
config_db.php
data
certs

.vscode
3 changes: 3 additions & 0 deletions Demo/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ services:
ldap_filter: "(objectClass=*)"
ldap_bind_dn: "cn=butler,dc=example,dc=com"
ldap_bind_pass: "readonly"
ldap_secure: 0
ldap_cert_path: "/var/www/html/oauth/certs/cert.crt"
ldap_key_path: "/var/www/html/oauth/certs/private.key"
db_host: "database"
db_port: "5432"
db_type: "pgsql"
Expand Down
18 changes: 11 additions & 7 deletions Docker/php-ldap-pgsql/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
FROM php:fpm
FROM php:8.3.4-fpm-alpine

RUN set -x \
&& apt-get update \
&& apt-get install -y libpq-dev libldap2-dev git\
&& rm -rf /var/lib/apt/lists/* \
&& apk update \
&& apk add --no-cache libpq-dev git \
&& docker-php-ext-configure pgsql --with-pgsql=/usr/local/pgsql \
&& docker-php-ext-install pdo pdo_pgsql pgsql \
&& docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu/ \
&& docker-php-ext-install ldap
&& docker-php-ext-install pdo pdo_pgsql pgsql

RUN set -x \
&& apk add --no-cache --virtual .build-dependencies-in-virtual-world openldap-dev \
&& apk add --no-cache libldap \
&& docker-php-ext-install ldap \
&& docker-php-ext-enable ldap \
&& apk del .build-dependencies-in-virtual-world

# Enable development php.ini config (Solve empty answer from token.php)
RUN ln -s /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@ Edit `oauth/LDAP/config_ldap.php` and adapt prameters with your LDAP configurati
| ldap_base_dn | The base directory name of your LDAP server | `ou=People,o=Company` |
| ldap_bind_dn | The LDAP Directory Name of an service account to allow LDAP search | |
| ldap_bind_pass | The password associated to the service account to allow LDAP search | |
| ldap_secure | LDAP over ldaps (ex:ldaps://ldap.google.com) | `false` |
| ldap_cert_path | LDAP certificate file for secure LDAP | `/var/www/html/oauth/certs/certificate.crt`|
| ldap_key_path | LDAP private key file for secure LDAP | `/var/www/html/oauth/certs/key.key`|

For openLDAP server, the 'ldap_search_attribute' should be `uid`, and for AD server this must be `sAMAccountName`. Nevertheless, 'email' or 'cn' could be used, this depends on your LDAP configuration.

Expand Down
47 changes: 32 additions & 15 deletions oauth/LDAP/LDAP.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,26 @@ class LDAP implements LDAPInterface
protected $ldap_server;

/**
* LDAP Resource
*
* @param string @ldap_host
* Either a hostname or, with OpenLDAP 2.x.x and later, a full LDAP URI
* @param int @ldap_port
* An optional int to specify ldap server port, by default : 389
* @param int @ldap_version
* An optional int to specify ldap version, by default LDAP V3 protocol is used
* @param boolean @ldap_start_tls
* An optional boolean to use ldap over STARTTLS, by default LDAP STARTTLS is not used
*
* Initiate LDAP connection by creating an associated resource
*/
public function __construct($ldap_host, $ldap_port = 389, $ldap_version = 3, $ldap_start_tls = false)
* LDAP Resource
*
* @param string @ldap_host
* Either a hostname or, with OpenLDAP 2.x.x and later, a full LDAP URI
* @param int @ldap_port
* An optional int to specify ldap server port, by default : 389
* @param int @ldap_version
* An optional int to specify ldap version, by default LDAP V3 protocol is used
* @param boolean @ldap_start_tls
* An optional boolean to use ldap over STARTTLS, by default LDAP STARTTLS is not used
* @param string @ldap_cert_path
* An optional string to specify the path to the certificate file
* @param string @ldap_key_path
* An optional string to specify the path to the key file
* @param boolean @ldap_secure
* An optional boolean to use ldap over secure connection, by default LDAP secure connection is not used
*
* Initiate LDAP connection by creating an associated resource
*/
public function __construct($ldap_host, $ldap_port = 389, $ldap_version = 3, $ldap_start_tls = false, $ldap_cert_path, $ldap_key_path, $ldap_secure = false)
{
if (!is_string($ldap_host)) {
throw new InvalidArgumentException('First argument to LDAP must be the hostname of a ldap server (string). Ex: ldap//example.com/ ');
Expand All @@ -37,12 +43,23 @@ public function __construct($ldap_host, $ldap_port = 389, $ldap_version = 3, $ld
throw new InvalidArgumentException('Second argument to LDAP must be the ldap server port (int). Ex : 389');
}

// Connect to LDAP server using secure connection with certificate and key
if ($ldap_secure === true) {
if (!is_string($ldap_cert_path)) {
throw new InvalidArgumentException('Fifth argument to LDAP must be the path to the certificate file (string).');
}
if (!is_string($ldap_key_path)) {
throw new InvalidArgumentException('Sixth argument to LDAP must be the path to the key file (string).');
}
}

$ldap = ldap_connect($ldap_host, $ldap_port)
or die("Unable to connect to the ldap server : $ldaphost ! Please check your configuration.");
or die("Unable to connect to the ldap server : $ldap_host ! Please check your configuration.");

// Support LDAP V3 since many users have encountered difficulties with LDAP V3.
if (is_int($ldap_version) && $ldap_version <= 3 && $ldap_version > 0) {
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, $ldap_version);
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
} else {
throw new InvalidArgumentException('Third argument to LDAP must be the ldap version (int). Ex : 3');
}
Expand Down
6 changes: 6 additions & 0 deletions oauth/LDAP/config_ldap.php.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ $ldap_host = getenv('ldap_host') ?: "ldap://ldap.company.com/";
$ldap_port = intval(getenv('ldap_port')) ?: 389;
$ldap_version = intval(getenv('ldap_version')) ?: 3;
$ldap_start_tls = boolval(getenv('ldap_start_tls')) ?: false;
$ldap_secure = boolval(getenv('ldap_secure')) ?: false;

// Certificates
$ldap_cert_path = getenv('ldap_cert_path') ?: "/var/www/html/oauth/certs/certificate.crt";
$ldap_key_path = getenv('ldap_key_path') ?: "/var/www/html/oauth/certs/key.key";

// Attribute use to identify user on LDAP - ex : uid, mail, sAMAccountName
$ldap_search_attribute = getenv('ldap_search_attribute') ?: "uid";
Expand All @@ -15,3 +20,4 @@ $ldap_filter = getenv('ldap_filter') ?: "(objectClass=*)";
// ldap service user to allow search in ldap
$ldap_bind_dn = getenv('ldap_bind_dn') ?: "";
$ldap_bind_pass = getenv('ldap_bind_pass') ?: "";

102 changes: 46 additions & 56 deletions oauth/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@


// include our LDAP object
require_once __DIR__.'/LDAP/LDAP.php';
require_once __DIR__.'/LDAP/config_ldap.php';
require_once __DIR__ . '/LDAP/LDAP.php';
require_once __DIR__ . '/LDAP/config_ldap.php';

$prompt_template = new DOMDocument();
$prompt_template->loadHTMLFile('form_prompt.html');


function messageShow($html_template, $message = 'No Msg') {
function messageShow($html_template, $message = 'No Msg')
{
$modification_node = $html_template->getElementsByTagName('div')->item(5);
$page_fragment = $html_template->createDocumentFragment();
$page_fragment->appendXML($message);
Expand All @@ -24,66 +25,55 @@ function messageShow($html_template, $message = 'No Msg') {
echo $html_template->saveHTML();
}


// Verify all fields have been filled
if (empty($_POST['user']) || empty($_POST['password']))
{
if (empty($_POST['user'])) {
messageShow($prompt_template, 'Username field can\'t be empty.');
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
// If user is already authenticated, redirect him to the authorize page
messageShow($prompt_template, "");
} elseif ($_SERVER['REQUEST_METHOD'] !== 'POST') {
// Verify all fields have been filled
if (empty($_POST['user']) || empty($_POST['password'])) {
if (empty($_POST['user'])) {
messageShow($prompt_template, 'Username field can\'t be empty.');
} else {
messageShow($prompt_template, 'Password field can\'t be empty.');
}
} else {
messageShow($prompt_template, 'Password field can\'t be empty.');
}
}
else
{
// Check received data length (to prevent code injection)
if (strlen($_POST['user']) > 64)
{
messageShow($prompt_template, 'Username has incorrect format ... Please try again');
}
elseif (strlen($_POST['password']) > 64)
{
messageShow($prompt_template, 'Password has incorrect format ... Please try again');
}
else
{
// Remove every html tag and useless space on username (to prevent XSS)
$user=strtolower(strip_tags(htmlspecialchars(trim($_POST['user']))));
$password=$_POST['password'];
// Check received data length (to prevent code injection)
if (strlen($_POST['user']) > 64) {
messageShow($prompt_template, 'Username has incorrect format ... Please try again');
} elseif (strlen($_POST['password']) > 64) {
messageShow($prompt_template, 'Password has incorrect format ... Please try again');
} else {
// Remove every html tag and useless space on username (to prevent XSS)
$user = strtolower(strip_tags(htmlspecialchars(trim($_POST['user']))));
$password = $_POST['password'];

// Open a LDAP connection
$ldap = new LDAP($ldap_host,$ldap_port,$ldap_version,$ldap_start_tls);
// Open a LDAP connection
$ldap = new LDAP($ldap_host, $ldap_port, $ldap_version, $ldap_start_tls, $ldap_cert_path, $ldap_key_path, $ldap_secure);

// Check user credential on LDAP
try{
$authenticated = $ldap->checkLogin($user,$password,$ldap_search_attribute,$ldap_filter,$ldap_base_dn,$ldap_bind_dn,$ldap_bind_pass);
}
catch (Exception $e)
{
$authenticated = false;
}
// Check user credential on LDAP
try {
$authenticated = $ldap->checkLogin($user, $password, $ldap_search_attribute, $ldap_filter, $ldap_base_dn, $ldap_bind_dn, $ldap_bind_pass);
} catch (Exception $e) {
$authenticated = false;
}

// If user is authenticated
if ($authenticated)
{
$_SESSION['uid']=$user;
// If user is authenticated
if ($authenticated) {
$_SESSION['uid'] = $user;

// If user came here with an autorize request, redirect him to the authorize page. Else prompt a simple message.
if (isset($_SESSION['auth_page']))
{
$auth_page=$_SESSION['auth_page'];
header('Location: ' . $auth_page);
exit();
// If user came here with an autorize request, redirect him to the authorize page. Else prompt a simple message.
if (isset($_SESSION['auth_page'])) {
$auth_page = $_SESSION['auth_page'];
header('Location: ' . $auth_page);
exit();
} else {
messageShow($prompt_template, 'Congratulation you are authenticated ! <br /><br /> However there is nothing to do here ...');
}
}
else
{
messageShow($prompt_template, 'Congratulation you are authenticated ! <br /><br /> However there is nothing to do here ...');
// check login on LDAP has failed. Login and password were invalid or LDAP is unreachable
else {
messageShow($prompt_template, 'Authentication failed ... Check your username and password.<br />If the error persists contact your administrator.<br /><br />');
}
}
// check login on LDAP has failed. Login and password were invalid or LDAP is unreachable
else
{
messageShow($prompt_template, 'Authentication failed ... Check your username and password.<br />If the error persists contact your administrator.<br /><br />');
}
}
}
2 changes: 1 addition & 1 deletion oauth/resource.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
$assoc_id = intval($info_oauth["assoc_id"]);

// Open a LDAP connection
$ldap = new LDAP($ldap_host, $ldap_port, $ldap_version, $ldap_start_tls);
$ldap = new LDAP($ldap_host, $ldap_port, $ldap_version, $ldap_start_tls, $ldap_cert_path, $ldap_key_path, $ldap_secure);

// Try to get user data on the LDAP
try {
Expand Down