diff --git a/authentication/ldap/controller.php b/authentication/ldap/controller.php index d01b105b5e88ce3f6e007b87755f01a38b2df498..dd5ab8061ef2abb75165d6cecd196a581e0baf3c 100644 --- a/authentication/ldap/controller.php +++ b/authentication/ldap/controller.php @@ -1,13 +1,15 @@ <?php namespace Concrete\Package\LdapLogin\Authentication\Ldap; +use Library\Authentication\AuthYubico; use Concrete\Core\Authentication\AuthenticationTypeController; + +use Config; +use Exception; +use Package; use User; use UserInfo; use View; -use Config; -use Loader; -use Exception; class Controller extends AuthenticationTypeController { @@ -34,6 +36,7 @@ class Controller extends AuthenticationTypeController { $this->set('yubikeyClientID',\Config::get('auth.ldap.yubikeyClientID', '')); $this->set('yubikeySecretKey',\Config::get('auth.ldap.yubikeySecretKey', '')); $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)); } @@ -49,11 +52,12 @@ class Controller extends AuthenticationTypeController { \Config::save('auth.ldap.yubikeyClientID',$args['yubikeyClientID']); \Config::save('auth.ldap.yubikeySecretKey',$args['yubikeySecretKey']); \Config::save('auth.ldap.yubikeyServerURI',$args['yubikeyServerURI']); + \Config::save('auth.ldap.yubikeyLDAPAtttribute',$args['yubikeyLDAPAtttribute']); \Config::save('auth.ldap.yubikeyAllowEmptyKey',$args['yubikeyAllowEmptyKey']); } public function getAuthenticationTypeIconHTML() { - return ""; + return '<i class="fa fa-folder"></i>'; } private function __connect() { @@ -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() { + $valc = Loader::helper('concrete/validation'); $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.')); } + $uName = $post['uName']; $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(); $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) { throw new \Exception(t('Invalid username or password.')); } $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); if (!$user_bind) { 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); if (!is_object($userInfo)) { throw new \Exception(t('Invalid username or password.')); } - $user = User::loginByUserID($userInfo->uID); if (!is_object($user) || !($user instanceof User) || $user->isError()) { switch ($user->getError()) { @@ -133,7 +198,7 @@ class Controller extends AuthenticationTypeController { } public function isAuthenticated(User $u) { - + return $u->isLoggedIn(); } public function buildHash(User $u) { diff --git a/authentication/ldap/form.php b/authentication/ldap/form.php index 73470afa3700851f2957f0f782c285324c3d0b79..27050e4a3f7ea9bff0df61e8bda7465184010a5c 100644 --- a/authentication/ldap/form.php +++ b/authentication/ldap/form.php @@ -1,44 +1,56 @@ <?php defined('C5_EXECUTE') or die('Access denied.'); $form = Loader::helper('form'); +$pkg = Package::getByHandle('ldap_login'); +$path = $pkg->getRelativePath()."/authentication/ldap/yubiright_16x16.gif" ?> <form method='post' action='<?= View::url('/login', 'authenticate', $this->getAuthenticationTypeHandle()) ?>'> - <div class="form-group concrete-login"> - <span><?= t('Sign in with a ldap account.') ?> </span> - <hr> - </div> - <div class="form-group"> - <input name="uName" class="form-control col-sm-12" - placeholder="<?= Config::get('concrete.user.registration.email_registration') ? t('Email Address') : t('Username')?>" /> + <div class="form-group concrete-login"> + <span><?= t('Sign in with a LDAP account.') ?> </span> + <hr> + </div> + <div class="form-group"> + <input name="uName" class="form-control col-sm-12" + placeholder="<?= Config::get('concrete.user.registration.email_registration') ? t('Email Address') : t('Username')?>" /> + <label> </label> + <input name="uPassword" class="form-control" type="password" + placeholder="<?=t('Password')?>" /> + <?php if (\Config::get('auth.ldap.yubikeyEnabled',false)) { ?> + <label> </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> + <?php + if (isset($locales) && is_array($locales) && count($locales) > 0) { + ?> <div class="form-group"> - <label> </label> - <input name="uPassword" class="form-control" type="password" - placeholder="<?=t('Password')?>" /> + <label for="USER_LOCALE" class="control-label"><?= t('Language') ?></label> + <?= $form->select('USER_LOCALE', $locales) ?> </div> + <?php + } + ?> - <?php - if (isset($locales) && is_array($locales) && count($locales) > 0) { - ?> - <div class="form-group"> - <label for="USER_LOCALE" class="control-label"><?= t('Language') ?></label> - <?= $form->select('USER_LOCALE', $locales) ?> - </div> - <?php - } - ?> - - <div class="form-group"> - <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 class="form-group"> + <button class="btn btn-primary"><?= t('Log in') ?></button> + </div> - <script type="text/javascript"> - document.querySelector('input[name=uName]').focus(); - </script> + <script type="text/javascript"> + document.querySelector('input[name=uName]').focus(); + </script> - <?php Loader::helper('validation/token')->output('login_' . $this->getAuthenticationTypeHandle()); ?> + <?php Loader::helper('validation/token')->output('login_' . $this->getAuthenticationTypeHandle()); ?> </form> diff --git a/authentication/ldap/type_form.php b/authentication/ldap/type_form.php index 75ac8fe4c244afb993d64dbe0f72dc667ff92498..c1d2736d829b31e0a5a52ca06d6f6af3ee84f8eb 100644 --- a/authentication/ldap/type_form.php +++ b/authentication/ldap/type_form.php @@ -15,7 +15,7 @@ </div> <div class='form-group'> <?= $form->label('ldapBindPassword', t('LDAP Bind Password')) ?> - <?= $form->text('ldapBindPassword', $ldapBindPassword) ?> + <?= $form->password('ldapBindPassword', $ldapBindPassword) ?> </div> <div class='form-group'> <?= $form->label('ldapSearchFilter', t('LDAP Search Filter')) ?> @@ -23,9 +23,9 @@ </div> </fieldset> <fieldset> - <legend>Yubikey Configuration</legend> + <legend>Yubikey OTP Configuration</legend> <div class='form-group'> - <?= $form->label('yubikeyEnabled', t('Enable Yubikey')) ?> + <?= $form->label('yubikeyEnabled', t('Enable Yubikey OTP')) ?> <?= $form->checkbox('yubikeyEnabled', 1, $yubikeyEnabled) ?> </div> <div id="yubikey-options" style="display: <?= $yubikeyEnabled ? 'block' : 'none' ?>;"> @@ -35,14 +35,14 @@ </div> <div class='form-group'> <?= $form->label('yubikeySecretKey', t('Yubikey Secret Key')) ?> - <?= $form->text('yubikeySecretKey', $yubikeySecretKey) ?> + <?= $form->password('yubikeySecretKey', $yubikeySecretKey) ?> </div> <div class='form-group'> <?= $form->label('yubikeyServerURI', t('Yubikey Verify URI')) ?> <?= $form->text('yubikeyServerURI', $yubikeyServerURI) ?> </div> <div class='form-group'> - <?= $form->label('yubikeyLDAPAtttribute', t('Yubikey LDAP Attribute')) ?> + <?= $form->label('yubikeyLDAPAtttribute', t('Yubikey Key ID LDAP Attribute')) ?> <?= $form->text('yubikeyLDAPAtttribute', $yubikeyLDAPAtttribute) ?> </div> <div class='form-group'> diff --git a/controller.php b/controller.php index dfd9b3bc17553d9bec8b624515ea09738b0ef767..00442e4cf44d2e05920e4c531be72e86e246dd83 100644 --- a/controller.php +++ b/controller.php @@ -21,6 +21,10 @@ class Controller extends Package { return "LDAP Login"; } + public function getPackageAutoloaderRegistries() { + return array("library/authentication" => "Library\Authentication"); + } + public function install() { $pkg = parent::install(); $at = AuthenticationType::add('ldap','LDAP',0,$pkg);