diff options
-rw-r--r-- | Vagrantfile | 2 | ||||
-rw-r--r-- | common.php | 8 | ||||
-rw-r--r-- | controllers/user.php | 8 | ||||
-rw-r--r-- | locales/es_ES/translations.php | 1 | ||||
-rw-r--r-- | locales/fr_FR/translations.php | 1 | ||||
-rw-r--r-- | locales/pl_PL/translations.php | 1 | ||||
-rw-r--r-- | locales/pt_BR/translations.php | 1 | ||||
-rw-r--r-- | models/ldap.php | 81 | ||||
-rw-r--r-- | models/user.php | 56 | ||||
-rw-r--r-- | schemas/mysql.php | 5 | ||||
-rw-r--r-- | schemas/sqlite.php | 5 | ||||
-rw-r--r-- | templates/config_index.php | 29 | ||||
-rw-r--r-- | templates/user_edit.php | 19 |
13 files changed, 180 insertions, 37 deletions
diff --git a/Vagrantfile b/Vagrantfile index 502ebec9..1568b325 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -6,7 +6,7 @@ VAGRANTFILE_API_VERSION = "2" $script = <<SCRIPT # install packages 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 rm -f /var/www/html/index.html date > /etc/vagrant_provisioned_at @@ -6,7 +6,7 @@ require __DIR__.'/core/translator.php'; $registry = new Core\Registry; -$registry->db_version = 12; +$registry->db_version = 13; $registry->db = function() use ($registry) { 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_HOSTNAME') or define('DB_HOSTNAME', 'localhost'); 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'); diff --git a/controllers/user.php b/controllers/user.php index 9e964a4e..cc180976 100644 --- a/controllers/user.php +++ b/controllers/user.php @@ -65,14 +65,6 @@ class User extends Base list($valid, $errors) = $this->user->validateLogin($values); if ($valid) { - - $this->lastLogin->create( - \Model\LastLogin::AUTH_DATABASE, - $this->acl->getUserId(), - $this->user->getIpAddress(), - $this->user->getUserAgent() - ); - $this->response->redirect('?controller=app'); } diff --git a/locales/es_ES/translations.php b/locales/es_ES/translations.php index 628e292b..35a3367f 100644 --- a/locales/es_ES/translations.php +++ b/locales/es_ES/translations.php @@ -279,4 +279,5 @@ return array( // 'No session' => '', // 'Expiration date' => '', // 'Remember Me' => '', + // 'Creation date' => '', ); diff --git a/locales/fr_FR/translations.php b/locales/fr_FR/translations.php index 3529582d..cb9c402c 100644 --- a/locales/fr_FR/translations.php +++ b/locales/fr_FR/translations.php @@ -279,4 +279,5 @@ return array( 'No session' => 'Aucune session', 'Expiration date' => 'Date d\'expiration', 'Remember Me' => 'Connexion automatique', + 'Creation date' => 'Date de création', ); diff --git a/locales/pl_PL/translations.php b/locales/pl_PL/translations.php index f11a6d8d..eafa1e02 100644 --- a/locales/pl_PL/translations.php +++ b/locales/pl_PL/translations.php @@ -284,4 +284,5 @@ return array( // 'No session' => '', // 'Expiration date' => '', // 'Remember Me' => '', + // 'Creation date' => '', ); diff --git a/locales/pt_BR/translations.php b/locales/pt_BR/translations.php index b8d80569..30351f3d 100644 --- a/locales/pt_BR/translations.php +++ b/locales/pt_BR/translations.php @@ -280,4 +280,5 @@ return array( // 'No session' => '', // 'Expiration date' => '', // 'Remember Me' => '', + // 'Creation date' => '', ); diff --git a/models/ldap.php b/models/ldap.php new file mode 100644 index 00000000..95401211 --- /dev/null +++ b/models/ldap.php @@ -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); + } +} diff --git a/models/user.php b/models/user.php index 5815b673..c5017ac6 100644 --- a/models/user.php +++ b/models/user.php @@ -57,7 +57,7 @@ class User extends Base return $this->db ->table(self::TABLE) ->asc('username') - ->columns('id', 'username', 'is_admin', 'default_project_id') + ->columns('id', 'username', 'is_admin', 'default_project_id', 'is_ldap_user') ->findAll(); } @@ -81,8 +81,13 @@ class User extends Base */ public function create(array $values) { - if (isset($values['confirmation'])) unset($values['confirmation']); - $values['password'] = \password_hash($values['password'], PASSWORD_BCRYPT); + if (isset($values['confirmation'])) { + unset($values['confirmation']); + } + + if (isset($values['password'])) { + $values['password'] = \password_hash($values['password'], PASSWORD_BCRYPT); + } return $this->db->table(self::TABLE)->save($values); } @@ -154,6 +159,7 @@ class User extends Base $user['id'] = (int) $user['id']; $user['default_project_id'] = (int) $user['default_project_id']; $user['is_admin'] = (bool) $user['is_admin']; + $user['is_ldap_user'] = (bool) $user['is_ldap_user']; $_SESSION['user'] = $user; } @@ -242,9 +248,9 @@ class User extends Base if ($v->execute()) { // 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()); } else { @@ -275,13 +281,23 @@ class User extends Base 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 + $user = $this->getByUsername($values['username']); $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 if (! empty($values['remember_me'])) { $rememberMe = new RememberMe($this->db, $this->event); @@ -302,6 +318,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 * * @access public diff --git a/schemas/mysql.php b/schemas/mysql.php index 245232bd..e688be8d 100644 --- a/schemas/mysql.php +++ b/schemas/mysql.php @@ -2,6 +2,11 @@ namespace Schema; +function version_13($pdo) +{ + $pdo->exec("ALTER TABLE users ADD COLUMN is_ldap_user TINYINT(1) DEFAULT 0"); +} + function version_12($pdo) { $pdo->exec(" diff --git a/schemas/sqlite.php b/schemas/sqlite.php index 4a69751c..c2ac29c1 100644 --- a/schemas/sqlite.php +++ b/schemas/sqlite.php @@ -2,6 +2,11 @@ namespace Schema; +function version_13($pdo) +{ + $pdo->exec("ALTER TABLE users ADD COLUMN is_ldap_user INTEGER DEFAULT 0"); +} + function version_12($pdo) { $pdo->exec( diff --git a/templates/config_index.php b/templates/config_index.php index 899a4b0c..6c610d2b 100644 --- a/templates/config_index.php +++ b/templates/config_index.php @@ -18,6 +18,22 @@ </div> </form> </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"> <h2><?= t('More information') ?></h2> </div> @@ -54,19 +70,6 @@ </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> - <div class="page-header" id="last-logins"> <h2><?= t('Last logins') ?></h2> </div> diff --git a/templates/user_edit.php b/templates/user_edit.php index 0c82793d..07ae5738 100644 --- a/templates/user_edit.php +++ b/templates/user_edit.php @@ -9,18 +9,23 @@ <form method="post" action="?controller=user&action=update" autocomplete="off"> <?= Helper\form_hidden('id', $values) ?> + <?= Helper\form_hidden('is_ldap_user', $values) ?> <?= 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') ?> - <?= Helper\form_password('current_password', $values, $errors) ?><br/> + <?php if ($values['is_ldap_user'] == 0): ?> - <?= Helper\form_label(t('Password'), 'password') ?> - <?= Helper\form_password('password', $values, $errors) ?><br/> + <?= Helper\form_label(t('Current password for the user "%s"', Helper\get_username()), 'current_password') ?> + <?= Helper\form_password('current_password', $values, $errors) ?><br/> - <?= Helper\form_label(t('Confirmation'), 'confirmation') ?> - <?= Helper\form_password('confirmation', $values, $errors) ?><br/> + <?= Helper\form_label(t('Password'), 'password') ?> + <?= 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_select('default_project_id', $projects, $values, $errors) ?><br/> |