Skip to content
Snippets Groups Projects
Commit 3ac01f2d authored by Christoph Seitz's avatar Christoph Seitz
Browse files

Complete the ldap and yubikey authentication.

parent 6fa42f38
No related branches found
No related tags found
No related merge requests found
<?php <?php
namespace Concrete\Package\LdapLogin\Authentication\Ldap; namespace Concrete\Package\LdapLogin\Authentication\Ldap;
use Library\Authentication\AuthYubico;
use Concrete\Core\Authentication\AuthenticationTypeController; use Concrete\Core\Authentication\AuthenticationTypeController;
use Config;
use Exception;
use Package;
use User; use User;
use UserInfo; use UserInfo;
use View; use View;
use Config;
use Loader;
use Exception;
class Controller extends AuthenticationTypeController { class Controller extends AuthenticationTypeController {
...@@ -34,6 +36,7 @@ class Controller extends AuthenticationTypeController { ...@@ -34,6 +36,7 @@ class Controller extends AuthenticationTypeController {
$this->set('yubikeyClientID',\Config::get('auth.ldap.yubikeyClientID', '')); $this->set('yubikeyClientID',\Config::get('auth.ldap.yubikeyClientID', ''));
$this->set('yubikeySecretKey',\Config::get('auth.ldap.yubikeySecretKey', '')); $this->set('yubikeySecretKey',\Config::get('auth.ldap.yubikeySecretKey', ''));
$this->set('yubikeyServerURI',\Config::get('auth.ldap.yubikeyServerURI', '')); $this->set('yubikeyServerURI',\Config::get('auth.ldap.yubikeyServerURI', ''));
$this->set('yubikeyLDAPAtttribute',\Config::get('auth.ldap.yubikeyLDAPAtttribute', 'pager'));
$this->set('yubikeyAllowEmptyKey',\Config::get('auth.ldap.yubikeyAllowEmptyKey', false)); $this->set('yubikeyAllowEmptyKey',\Config::get('auth.ldap.yubikeyAllowEmptyKey', false));
} }
...@@ -49,11 +52,12 @@ class Controller extends AuthenticationTypeController { ...@@ -49,11 +52,12 @@ class Controller extends AuthenticationTypeController {
\Config::save('auth.ldap.yubikeyClientID',$args['yubikeyClientID']); \Config::save('auth.ldap.yubikeyClientID',$args['yubikeyClientID']);
\Config::save('auth.ldap.yubikeySecretKey',$args['yubikeySecretKey']); \Config::save('auth.ldap.yubikeySecretKey',$args['yubikeySecretKey']);
\Config::save('auth.ldap.yubikeyServerURI',$args['yubikeyServerURI']); \Config::save('auth.ldap.yubikeyServerURI',$args['yubikeyServerURI']);
\Config::save('auth.ldap.yubikeyLDAPAtttribute',$args['yubikeyLDAPAtttribute']);
\Config::save('auth.ldap.yubikeyAllowEmptyKey',$args['yubikeyAllowEmptyKey']); \Config::save('auth.ldap.yubikeyAllowEmptyKey',$args['yubikeyAllowEmptyKey']);
} }
public function getAuthenticationTypeIconHTML() { public function getAuthenticationTypeIconHTML() {
return ""; return '<i class="fa fa-folder"></i>';
} }
private function __connect() { private function __connect() {
...@@ -74,32 +78,93 @@ class Controller extends AuthenticationTypeController { ...@@ -74,32 +78,93 @@ class Controller extends AuthenticationTypeController {
} }
} }
private function yubikeyIsOtp($otp) {
if (!preg_match("/^[cbdefghijklnrtuvCBDEFGHIJKLNRTUV]{44}$/", $otp)) {
return FALSE;
}
return TRUE;
}
public function authenticate() { public function authenticate() {
$valc = Loader::helper('concrete/validation');
$post = $this->post(); $post = $this->post();
if (!isset($post['uName']) || !isset($post['uPassword'])) {
//Check for empty username and password
if (empty($post['uName']) || empty($post['uPassword'])) {
throw new Exception(t('Please provide both username and password.')); throw new Exception(t('Please provide both username and password.'));
} }
$uName = $post['uName']; $uName = $post['uName'];
$uPassword = $post['uPassword']; $uPassword = $post['uPassword'];
$uOTP = $post['uOTP'];
//Validate username
if(!$valc->username($uName)) {
throw new \Exception(t('Invalid username or password.'));
}
//Prepare ldap search
$searchFilter = \Config::get('auth.ldap.ldapSearchFilter', "(uid=%u)");
$searchFilter = str_replace("%u",$uName,$searchFilter);
//Connect to ldap, do the search and then auth the user
$this->__connect(); $this->__connect();
$search_result = ldap_search($this->ldap_conn,\Config::get('auth.ldap.ldapBaseDN', ''), $search_result = ldap_search($this->ldap_conn,\Config::get('auth.ldap.ldapBaseDN', ''),
"(uid=$uName)"); $searchFilter);
if (ldap_count_entries($this->ldap_conn,$search_result)!=1) { if (ldap_count_entries($this->ldap_conn,$search_result)!=1) {
throw new \Exception(t('Invalid username or password.')); throw new \Exception(t('Invalid username or password.'));
} }
$entry = ldap_first_entry($this->ldap_conn,$search_result); $entry = ldap_first_entry($this->ldap_conn,$search_result);
//get it here because of the new bind.
if (\Config::get('auth.ldap.yubikeyEnabled',false)) {
$yubikeys = ldap_get_values($this->ldap_conn,$entry,\Config::get('auth.ldap.yubikeyLDAPAtttribute','pager'));
}
$user_bind = ldap_bind($this->ldap_conn,ldap_get_dn($this->ldap_conn,$entry),$uPassword); $user_bind = ldap_bind($this->ldap_conn,ldap_get_dn($this->ldap_conn,$entry),$uPassword);
if (!$user_bind) { if (!$user_bind) {
throw new \Exception(t('Invalid username or password.')); throw new \Exception(t('Invalid username or password.'));
} }
ldap_close($this->ldap_conn);
//Start yubikey two-factor
if (\Config::get('auth.ldap.yubikeyEnabled',false)) {
if ($yubikeys) {
if (!$this->yubikeyIsOtp($uOTP)) {
throw new Exception(t('Invalid username or password.'));
}
//Check the otp and then the key id
$clientID = \Config::get('auth.ldap.yubikeyClientID','');
$secretKey = \Config::get('auth.ldap.yubikeySecretKey','');
$https = 1;
$yubi = new AuthYubico($clientID,$secretKey,$https);
$auth = $yubi->verify($uOTP);
if (\PEAR::isError($auth)) {
throw new Exception(t('Invalid username or password.'));
}
$foundKey = 0;
foreach ($yubikeys as $yubikey) {
if (strcmp($yubikey, substr($uOTP,0,12))==0) {
$foundKey = 1;
break;
}
}
if (!$foundKey) {
throw new Exception(t('Invalid username or password.'));
}
} else {
if (!\Config::get('auth.ldap.yubikeyAllowEmptyKey',false)) {
throw new Exception(t('Yubikey is required to login.'));
}
}
}
//TODO: registration
$userInfo = UserInfo::getByUserName($uName); $userInfo = UserInfo::getByUserName($uName);
if (!is_object($userInfo)) { if (!is_object($userInfo)) {
throw new \Exception(t('Invalid username or password.')); throw new \Exception(t('Invalid username or password.'));
} }
$user = User::loginByUserID($userInfo->uID); $user = User::loginByUserID($userInfo->uID);
if (!is_object($user) || !($user instanceof User) || $user->isError()) { if (!is_object($user) || !($user instanceof User) || $user->isError()) {
switch ($user->getError()) { switch ($user->getError()) {
...@@ -133,7 +198,7 @@ class Controller extends AuthenticationTypeController { ...@@ -133,7 +198,7 @@ class Controller extends AuthenticationTypeController {
} }
public function isAuthenticated(User $u) { public function isAuthenticated(User $u) {
return $u->isLoggedIn();
} }
public function buildHash(User $u) { public function buildHash(User $u) {
......
<?php <?php
defined('C5_EXECUTE') or die('Access denied.'); defined('C5_EXECUTE') or die('Access denied.');
$form = Loader::helper('form'); $form = Loader::helper('form');
$pkg = Package::getByHandle('ldap_login');
$path = $pkg->getRelativePath()."/authentication/ldap/yubiright_16x16.gif"
?> ?>
<form method='post' <form method='post'
action='<?= View::url('/login', 'authenticate', $this->getAuthenticationTypeHandle()) ?>'> action='<?= View::url('/login', 'authenticate', $this->getAuthenticationTypeHandle()) ?>'>
<div class="form-group concrete-login"> <div class="form-group concrete-login">
<span><?= t('Sign in with a ldap account.') ?> </span> <span><?= t('Sign in with a LDAP account.') ?> </span>
<hr> <hr>
</div> </div>
<div class="form-group"> <div class="form-group">
<input name="uName" class="form-control col-sm-12" <input name="uName" class="form-control col-sm-12"
placeholder="<?= Config::get('concrete.user.registration.email_registration') ? t('Email Address') : t('Username')?>" /> placeholder="<?= Config::get('concrete.user.registration.email_registration') ? t('Email Address') : t('Username')?>" />
</div>
<div class="form-group">
<label>&nbsp;</label> <label>&nbsp;</label>
<input name="uPassword" class="form-control" type="password" <input name="uPassword" class="form-control" type="password"
placeholder="<?=t('Password')?>" /> placeholder="<?=t('Password')?>" />
<?php if (\Config::get('auth.ldap.yubikeyEnabled',false)) { ?>
<label>&nbsp;</label>
<div class="input-group">
<div class="input-group-addon"><img src="<?= $path ?>" /></div>
<input name="uOTP" class="form-control" type="password"
placeholder="<?=t('OTP')?>" />
</div>
<?php } ?>
<div class="checkbox">
<label style="font-weight:normal">
<input type="checkbox" name="uMaintainLogin" value="1">
<?= t('Stay signed in for two weeks') ?>
</label>
</div>
</div> </div>
<?php <?php
...@@ -33,7 +46,6 @@ $form = Loader::helper('form'); ...@@ -33,7 +46,6 @@ $form = Loader::helper('form');
<div class="form-group"> <div class="form-group">
<button class="btn btn-primary"><?= t('Log in') ?></button> <button class="btn btn-primary"><?= t('Log in') ?></button>
<a href="<?= View::url('/login', 'concrete', 'forgot_password') ?>" class="btn pull-right"><?= t('Forgot Password') ?></a>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
</div> </div>
<div class='form-group'> <div class='form-group'>
<?= $form->label('ldapBindPassword', t('LDAP Bind Password')) ?> <?= $form->label('ldapBindPassword', t('LDAP Bind Password')) ?>
<?= $form->text('ldapBindPassword', $ldapBindPassword) ?> <?= $form->password('ldapBindPassword', $ldapBindPassword) ?>
</div> </div>
<div class='form-group'> <div class='form-group'>
<?= $form->label('ldapSearchFilter', t('LDAP Search Filter')) ?> <?= $form->label('ldapSearchFilter', t('LDAP Search Filter')) ?>
...@@ -23,9 +23,9 @@ ...@@ -23,9 +23,9 @@
</div> </div>
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>Yubikey Configuration</legend> <legend>Yubikey OTP Configuration</legend>
<div class='form-group'> <div class='form-group'>
<?= $form->label('yubikeyEnabled', t('Enable Yubikey')) ?> <?= $form->label('yubikeyEnabled', t('Enable Yubikey OTP')) ?>
<?= $form->checkbox('yubikeyEnabled', 1, $yubikeyEnabled) ?> <?= $form->checkbox('yubikeyEnabled', 1, $yubikeyEnabled) ?>
</div> </div>
<div id="yubikey-options" style="display: <?= $yubikeyEnabled ? 'block' : 'none' ?>;"> <div id="yubikey-options" style="display: <?= $yubikeyEnabled ? 'block' : 'none' ?>;">
...@@ -35,14 +35,14 @@ ...@@ -35,14 +35,14 @@
</div> </div>
<div class='form-group'> <div class='form-group'>
<?= $form->label('yubikeySecretKey', t('Yubikey Secret Key')) ?> <?= $form->label('yubikeySecretKey', t('Yubikey Secret Key')) ?>
<?= $form->text('yubikeySecretKey', $yubikeySecretKey) ?> <?= $form->password('yubikeySecretKey', $yubikeySecretKey) ?>
</div> </div>
<div class='form-group'> <div class='form-group'>
<?= $form->label('yubikeyServerURI', t('Yubikey Verify URI')) ?> <?= $form->label('yubikeyServerURI', t('Yubikey Verify URI')) ?>
<?= $form->text('yubikeyServerURI', $yubikeyServerURI) ?> <?= $form->text('yubikeyServerURI', $yubikeyServerURI) ?>
</div> </div>
<div class='form-group'> <div class='form-group'>
<?= $form->label('yubikeyLDAPAtttribute', t('Yubikey LDAP Attribute')) ?> <?= $form->label('yubikeyLDAPAtttribute', t('Yubikey Key ID LDAP Attribute')) ?>
<?= $form->text('yubikeyLDAPAtttribute', $yubikeyLDAPAtttribute) ?> <?= $form->text('yubikeyLDAPAtttribute', $yubikeyLDAPAtttribute) ?>
</div> </div>
<div class='form-group'> <div class='form-group'>
......
...@@ -21,6 +21,10 @@ class Controller extends Package { ...@@ -21,6 +21,10 @@ class Controller extends Package {
return "LDAP Login"; return "LDAP Login";
} }
public function getPackageAutoloaderRegistries() {
return array("library/authentication" => "Library\Authentication");
}
public function install() { public function install() {
$pkg = parent::install(); $pkg = parent::install();
$at = AuthenticationType::add('ldap','LDAP',0,$pkg); $at = AuthenticationType::add('ldap','LDAP',0,$pkg);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment