Add LDAP authentication
This commit is contained in:
2
Vagrantfile
vendored
2
Vagrantfile
vendored
@@ -6,7 +6,7 @@ VAGRANTFILE_API_VERSION = "2"
|
|||||||
$script = <<SCRIPT
|
$script = <<SCRIPT
|
||||||
# install packages
|
# install packages
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y apache2 php5 php5-sqlite php5-ldap
|
apt-get install -y apache2 php5 php5-sqlite php5-ldap php-5-xdebug
|
||||||
service apache2 restart
|
service apache2 restart
|
||||||
rm -f /var/www/html/index.html
|
rm -f /var/www/html/index.html
|
||||||
date > /etc/vagrant_provisioned_at
|
date > /etc/vagrant_provisioned_at
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ require __DIR__.'/core/translator.php';
|
|||||||
|
|
||||||
$registry = new Core\Registry;
|
$registry = new Core\Registry;
|
||||||
|
|
||||||
$registry->db_version = 12;
|
$registry->db_version = 13;
|
||||||
|
|
||||||
$registry->db = function() use ($registry) {
|
$registry->db = function() use ($registry) {
|
||||||
require __DIR__.'/vendor/PicoDb/Database.php';
|
require __DIR__.'/vendor/PicoDb/Database.php';
|
||||||
@@ -130,3 +130,9 @@ defined('DB_USERNAME') or define('DB_USERNAME', 'root');
|
|||||||
defined('DB_PASSWORD') or define('DB_PASSWORD', '');
|
defined('DB_PASSWORD') or define('DB_PASSWORD', '');
|
||||||
defined('DB_HOSTNAME') or define('DB_HOSTNAME', 'localhost');
|
defined('DB_HOSTNAME') or define('DB_HOSTNAME', 'localhost');
|
||||||
defined('DB_NAME') or define('DB_NAME', 'kanboard');
|
defined('DB_NAME') or define('DB_NAME', 'kanboard');
|
||||||
|
|
||||||
|
// LDAP configuration
|
||||||
|
defined('LDAP_AUTH') or define('LDAP_AUTH', false);
|
||||||
|
defined('LDAP_SERVER') or define('LDAP_SERVER', '');
|
||||||
|
defined('LDAP_PORT') or define('LDAP_PORT', 389);
|
||||||
|
defined('LDAP_USER_DN') or define('LDAP_USER_DN', '%s');
|
||||||
|
|||||||
@@ -65,14 +65,6 @@ class User extends Base
|
|||||||
list($valid, $errors) = $this->user->validateLogin($values);
|
list($valid, $errors) = $this->user->validateLogin($values);
|
||||||
|
|
||||||
if ($valid) {
|
if ($valid) {
|
||||||
|
|
||||||
$this->lastLogin->create(
|
|
||||||
\Model\LastLogin::AUTH_DATABASE,
|
|
||||||
$this->acl->getUserId(),
|
|
||||||
$this->user->getIpAddress(),
|
|
||||||
$this->user->getUserAgent()
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->response->redirect('?controller=app');
|
$this->response->redirect('?controller=app');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -279,4 +279,5 @@ return array(
|
|||||||
// 'No session' => '',
|
// 'No session' => '',
|
||||||
// 'Expiration date' => '',
|
// 'Expiration date' => '',
|
||||||
// 'Remember Me' => '',
|
// 'Remember Me' => '',
|
||||||
|
// 'Creation date' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -279,4 +279,5 @@ return array(
|
|||||||
'No session' => 'Aucune session',
|
'No session' => 'Aucune session',
|
||||||
'Expiration date' => 'Date d\'expiration',
|
'Expiration date' => 'Date d\'expiration',
|
||||||
'Remember Me' => 'Connexion automatique',
|
'Remember Me' => 'Connexion automatique',
|
||||||
|
'Creation date' => 'Date de création',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -284,4 +284,5 @@ return array(
|
|||||||
// 'No session' => '',
|
// 'No session' => '',
|
||||||
// 'Expiration date' => '',
|
// 'Expiration date' => '',
|
||||||
// 'Remember Me' => '',
|
// 'Remember Me' => '',
|
||||||
|
// 'Creation date' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -280,4 +280,5 @@ return array(
|
|||||||
// 'No session' => '',
|
// 'No session' => '',
|
||||||
// 'Expiration date' => '',
|
// 'Expiration date' => '',
|
||||||
// 'Remember Me' => '',
|
// 'Remember Me' => '',
|
||||||
|
// 'Creation date' => '',
|
||||||
);
|
);
|
||||||
|
|||||||
81
models/ldap.php
Normal file
81
models/ldap.php
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Model;
|
||||||
|
|
||||||
|
require_once __DIR__.'/base.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LDAP model
|
||||||
|
*
|
||||||
|
* @package model
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class Ldap extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Authenticate a user
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $username Username
|
||||||
|
* @param string $password Password
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authenticate($username, $password)
|
||||||
|
{
|
||||||
|
if (! function_exists('ldap_connect')) {
|
||||||
|
die('The PHP LDAP extension is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
$ldap = ldap_connect(LDAP_SERVER, LDAP_PORT);
|
||||||
|
|
||||||
|
if (! is_resource($ldap)) {
|
||||||
|
die('Unable to connect to the LDAP server: "'.LDAP_SERVER.'"');
|
||||||
|
}
|
||||||
|
|
||||||
|
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||||
|
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
|
||||||
|
|
||||||
|
if (@ldap_bind($ldap, sprintf(LDAP_USER_DN, $username), $password)) {
|
||||||
|
return $this->create($username);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create automatically a new local user after the LDAP authentication
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $username Username
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function create($username)
|
||||||
|
{
|
||||||
|
$userModel = new User($this->db, $this->event);
|
||||||
|
$user = $userModel->getByUsername($username);
|
||||||
|
|
||||||
|
// There is an existing user account
|
||||||
|
if ($user) {
|
||||||
|
|
||||||
|
if ($user['is_ldap_user'] == 1) {
|
||||||
|
|
||||||
|
// LDAP user already created
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// There is already a local user with that username
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a LDAP user
|
||||||
|
$values = array(
|
||||||
|
'username' => $username,
|
||||||
|
'is_admin' => 0,
|
||||||
|
'is_ldap_user' => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
return $userModel->create($values);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -57,7 +57,7 @@ class User extends Base
|
|||||||
return $this->db
|
return $this->db
|
||||||
->table(self::TABLE)
|
->table(self::TABLE)
|
||||||
->asc('username')
|
->asc('username')
|
||||||
->columns('id', 'username', 'is_admin', 'default_project_id')
|
->columns('id', 'username', 'is_admin', 'default_project_id', 'is_ldap_user')
|
||||||
->findAll();
|
->findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,8 +81,13 @@ class User extends Base
|
|||||||
*/
|
*/
|
||||||
public function create(array $values)
|
public function create(array $values)
|
||||||
{
|
{
|
||||||
if (isset($values['confirmation'])) unset($values['confirmation']);
|
if (isset($values['confirmation'])) {
|
||||||
$values['password'] = \password_hash($values['password'], PASSWORD_BCRYPT);
|
unset($values['confirmation']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($values['password'])) {
|
||||||
|
$values['password'] = \password_hash($values['password'], PASSWORD_BCRYPT);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->db->table(self::TABLE)->save($values);
|
return $this->db->table(self::TABLE)->save($values);
|
||||||
}
|
}
|
||||||
@@ -154,6 +159,7 @@ class User extends Base
|
|||||||
$user['id'] = (int) $user['id'];
|
$user['id'] = (int) $user['id'];
|
||||||
$user['default_project_id'] = (int) $user['default_project_id'];
|
$user['default_project_id'] = (int) $user['default_project_id'];
|
||||||
$user['is_admin'] = (bool) $user['is_admin'];
|
$user['is_admin'] = (bool) $user['is_admin'];
|
||||||
|
$user['is_ldap_user'] = (bool) $user['is_ldap_user'];
|
||||||
|
|
||||||
$_SESSION['user'] = $user;
|
$_SESSION['user'] = $user;
|
||||||
}
|
}
|
||||||
@@ -242,9 +248,9 @@ class User extends Base
|
|||||||
if ($v->execute()) {
|
if ($v->execute()) {
|
||||||
|
|
||||||
// Check password
|
// Check password
|
||||||
$user = $this->getById($_SESSION['user']['id']);
|
list($authenticated,) = $this->authenticate($_SESSION['user']['username'], $values['current_password']);
|
||||||
|
|
||||||
if ($user !== false && \password_verify($values['current_password'], $user['password'])) {
|
if ($authenticated) {
|
||||||
return array(true, array());
|
return array(true, array());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -275,13 +281,23 @@ class User extends Base
|
|||||||
|
|
||||||
if ($result) {
|
if ($result) {
|
||||||
|
|
||||||
$user = $this->getByUsername($values['username']);
|
list($authenticated, $method) = $this->authenticate($values['username'], $values['password']);
|
||||||
|
|
||||||
if ($user !== false && \password_verify($values['password'], $user['password'])) {
|
if ($authenticated === true) {
|
||||||
|
|
||||||
// Create the user session
|
// Create the user session
|
||||||
|
$user = $this->getByUsername($values['username']);
|
||||||
$this->updateSession($user);
|
$this->updateSession($user);
|
||||||
|
|
||||||
|
// Update login history
|
||||||
|
$lastLogin = new LastLogin($this->db, $this->event);
|
||||||
|
$lastLogin->create(
|
||||||
|
$method,
|
||||||
|
$user['id'],
|
||||||
|
$this->getIpAddress(),
|
||||||
|
$this->getUserAgent()
|
||||||
|
);
|
||||||
|
|
||||||
// Setup the remember me feature
|
// Setup the remember me feature
|
||||||
if (! empty($values['remember_me'])) {
|
if (! empty($values['remember_me'])) {
|
||||||
$rememberMe = new RememberMe($this->db, $this->event);
|
$rememberMe = new RememberMe($this->db, $this->event);
|
||||||
@@ -301,6 +317,32 @@ class User extends Base
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authenticate a user
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $username Username
|
||||||
|
* @param string $password Password
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function authenticate($username, $password)
|
||||||
|
{
|
||||||
|
// Database authentication
|
||||||
|
$user = $this->db->table(self::TABLE)->eq('username', $username)->eq('is_ldap_user', 0)->findOne();
|
||||||
|
$authenticated = $user && \password_verify($password, $user['password']);
|
||||||
|
$method = LastLogin::AUTH_DATABASE;
|
||||||
|
|
||||||
|
// LDAP authentication
|
||||||
|
if (! $authenticated && LDAP_AUTH) {
|
||||||
|
require __DIR__.'/ldap.php';
|
||||||
|
$ldap = new Ldap($this->db, $this->event);
|
||||||
|
$authenticated = $ldap->authenticate($username, $password);
|
||||||
|
$method = LastLogin::AUTH_LDAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array($authenticated, $method);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the user agent of the connected user
|
* Get the user agent of the connected user
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
namespace Schema;
|
namespace Schema;
|
||||||
|
|
||||||
|
function version_13($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("ALTER TABLE users ADD COLUMN is_ldap_user TINYINT(1) DEFAULT 0");
|
||||||
|
}
|
||||||
|
|
||||||
function version_12($pdo)
|
function version_12($pdo)
|
||||||
{
|
{
|
||||||
$pdo->exec("
|
$pdo->exec("
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
namespace Schema;
|
namespace Schema;
|
||||||
|
|
||||||
|
function version_13($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec("ALTER TABLE users ADD COLUMN is_ldap_user INTEGER DEFAULT 0");
|
||||||
|
}
|
||||||
|
|
||||||
function version_12($pdo)
|
function version_12($pdo)
|
||||||
{
|
{
|
||||||
$pdo->exec(
|
$pdo->exec(
|
||||||
|
|||||||
@@ -18,6 +18,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
|
<div class="page-header">
|
||||||
|
<h2><?= t('User settings') ?></h2>
|
||||||
|
</div>
|
||||||
|
<section class="settings">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<strong><?= t('My default project:') ?> </strong>
|
||||||
|
<?= (isset($user['default_project_id']) && isset($projects[$user['default_project_id']])) ? Helper\escape($projects[$user['default_project_id']]) : t('None') ?>,
|
||||||
|
<a href="?controller=user&action=edit&user_id=<?= $user['id'] ?>"><?= t('edit') ?></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<?php if ($user['is_admin']): ?>
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h2><?= t('More information') ?></h2>
|
<h2><?= t('More information') ?></h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -54,19 +70,6 @@
|
|||||||
</section>
|
</section>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
<div class="page-header">
|
|
||||||
<h2><?= t('User settings') ?></h2>
|
|
||||||
</div>
|
|
||||||
<section class="settings">
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<strong><?= t('My default project:') ?> </strong>
|
|
||||||
<?= (isset($user['default_project_id']) && isset($projects[$user['default_project_id']])) ? Helper\escape($projects[$user['default_project_id']]) : t('None') ?>,
|
|
||||||
<a href="?controller=user&action=edit&user_id=<?= $user['id'] ?>"><?= t('edit') ?></a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<div class="page-header" id="last-logins">
|
<div class="page-header" id="last-logins">
|
||||||
<h2><?= t('Last logins') ?></h2>
|
<h2><?= t('Last logins') ?></h2>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,18 +9,23 @@
|
|||||||
<form method="post" action="?controller=user&action=update" autocomplete="off">
|
<form method="post" action="?controller=user&action=update" autocomplete="off">
|
||||||
|
|
||||||
<?= Helper\form_hidden('id', $values) ?>
|
<?= Helper\form_hidden('id', $values) ?>
|
||||||
|
<?= Helper\form_hidden('is_ldap_user', $values) ?>
|
||||||
|
|
||||||
<?= Helper\form_label(t('Username'), 'username') ?>
|
<?= Helper\form_label(t('Username'), 'username') ?>
|
||||||
<?= Helper\form_text('username', $values, $errors, array('required')) ?><br/>
|
<?= Helper\form_text('username', $values, $errors, array('required', $values['is_ldap_user'] == 1 ? 'readonly' : '')) ?><br/>
|
||||||
|
|
||||||
<?= Helper\form_label(t('Current password for the user "%s"', Helper\get_username()), 'current_password') ?>
|
<?php if ($values['is_ldap_user'] == 0): ?>
|
||||||
<?= Helper\form_password('current_password', $values, $errors) ?><br/>
|
|
||||||
|
|
||||||
<?= Helper\form_label(t('Password'), 'password') ?>
|
<?= Helper\form_label(t('Current password for the user "%s"', Helper\get_username()), 'current_password') ?>
|
||||||
<?= Helper\form_password('password', $values, $errors) ?><br/>
|
<?= Helper\form_password('current_password', $values, $errors) ?><br/>
|
||||||
|
|
||||||
<?= Helper\form_label(t('Confirmation'), 'confirmation') ?>
|
<?= Helper\form_label(t('Password'), 'password') ?>
|
||||||
<?= Helper\form_password('confirmation', $values, $errors) ?><br/>
|
<?= Helper\form_password('password', $values, $errors) ?><br/>
|
||||||
|
|
||||||
|
<?= Helper\form_label(t('Confirmation'), 'confirmation') ?>
|
||||||
|
<?= Helper\form_password('confirmation', $values, $errors) ?><br/>
|
||||||
|
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
<?= Helper\form_label(t('Default Project'), 'default_project_id') ?>
|
<?= Helper\form_label(t('Default Project'), 'default_project_id') ?>
|
||||||
<?= Helper\form_select('default_project_id', $projects, $values, $errors) ?><br/>
|
<?= Helper\form_select('default_project_id', $projects, $values, $errors) ?><br/>
|
||||||
|
|||||||
Reference in New Issue
Block a user