This repository has been archived by the owner on Dec 27, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'pu/pm/MFAYubicoImpl' into '2021.11'
yubico MFA impl See merge request tine20/tine20!176
- Loading branch information
Showing
12 changed files
with
450 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
<?php declare(strict_types=1); | ||
/** | ||
* Tine 2.0 | ||
* | ||
* @package Tinebase | ||
* @subpackage Auth | ||
* @license http://www.gnu.org/licenses/agpl.html AGPL Version 3 | ||
* @copyright Copyright (c) 2021 Metaways Infosystems GmbH (http://www.metaways.de) | ||
* @author Paul Mehrer <p.mehrer@metaways.de> | ||
*/ | ||
|
||
use Tinebase_Auth_MFA_YubicoUtil as Yubico; | ||
|
||
/** | ||
* Yubico OTP SecondFactor Auth Adapter | ||
* | ||
* @package Tinebase | ||
* @subpackage Auth | ||
*/ | ||
class Tinebase_Auth_MFA_YubicoOTPAdapter implements Tinebase_Auth_MFA_AdapterInterface | ||
{ | ||
protected $_mfaId; | ||
|
||
public function __construct(Tinebase_Record_Interface $_config, string $id) | ||
{ | ||
$this->_mfaId = $id; | ||
} | ||
|
||
public function sendOut(Tinebase_Model_MFA_UserConfig $_userCfg): bool | ||
{ | ||
return true; | ||
} | ||
|
||
public function validate($_data, Tinebase_Model_MFA_UserConfig $_userCfg): bool | ||
{ | ||
if (!$_userCfg->{Tinebase_Model_MFA_UserConfig::FLD_CONFIG} instanceof Tinebase_Model_MFA_YubicoOTPUserConfig) { | ||
return false; | ||
} | ||
/** @var Tinebase_Model_MFA_YubicoOTPUserConfig $yubicoOTPCfg */ | ||
$yubicoOTPCfg = $_userCfg->{Tinebase_Model_MFA_UserConfig::FLD_CONFIG}; | ||
|
||
if (!preg_match("/^([cbdefghijklnrtuv]{0,16})([cbdefghijklnrtuv]{32})$/", $_data, $matches)) { | ||
return false; | ||
} | ||
$id = $matches[1]; | ||
$modhex_ciphertext = $matches[2]; | ||
|
||
if ($id !== $yubicoOTPCfg->{Tinebase_Model_MFA_YubicoOTPUserConfig::FLD_PUBLIC_ID}) { | ||
return false; | ||
} | ||
|
||
/** @var Tinebase_Model_CredentialCache $cc */ | ||
$cc = Tinebase_Auth_CredentialCache::getInstance()->get( | ||
$yubicoOTPCfg->{Tinebase_Model_MFA_YubicoOTPUserConfig::FLD_CC_ID}); | ||
$cc->key = Tinebase_Config::getInstance()->{Tinebase_Config::CREDENTIAL_CACHE_SHARED_KEY}; | ||
Tinebase_Auth_CredentialCache::getInstance()->getCachedCredentials($cc); | ||
|
||
$ciphertext = Yubico::modhex2hex($modhex_ciphertext); | ||
$plaintext = Yubico::aes128ecb_decrypt($cc->password, $ciphertext); | ||
|
||
if (!Yubico::crc_is_good($plaintext)) { | ||
return false; | ||
} | ||
|
||
if (substr($plaintext, 0, 12) !== $cc->username) { | ||
return false; | ||
} | ||
$counter = intval(substr($plaintext, 14, 2) . substr($plaintext, 12, 2), 16); | ||
$session = intval(substr($plaintext, 22, 2), 16); | ||
|
||
if ($counter > intval($yubicoOTPCfg->{Tinebase_Model_MFA_YubicoOTPUserConfig::FLD_COUNTER}) || ( | ||
$counter === intval($yubicoOTPCfg->{Tinebase_Model_MFA_YubicoOTPUserConfig::FLD_COUNTER}) && | ||
$session > intval($yubicoOTPCfg->{Tinebase_Model_MFA_YubicoOTPUserConfig::FLD_SESSIONC}))) { | ||
$user = Tinebase_User::getInstance()->getUserById( | ||
$yubicoOTPCfg->{Tinebase_Model_MFA_YubicoOTPUserConfig::FLD_ACCOUNT_ID}, Tinebase_Model_FullUser::class); | ||
if (!($cfg = $user->mfa_configs->getById($_userCfg->getId()))) { | ||
return false; | ||
} | ||
$cfg->{Tinebase_Model_MFA_UserConfig::FLD_CONFIG}->{Tinebase_Model_MFA_YubicoOTPUserConfig::FLD_COUNTER} = | ||
$counter; | ||
$cfg->{Tinebase_Model_MFA_UserConfig::FLD_CONFIG}->{Tinebase_Model_MFA_YubicoOTPUserConfig::FLD_SESSIONC} = | ||
$session; | ||
Tinebase_User::getInstance()->updateUser($user); | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
<?php declare(strict_types=1); | ||
/** | ||
* Tine 2.0 | ||
* | ||
* @package Tinebase | ||
* @subpackage Auth | ||
* @license http://www.gnu.org/licenses/agpl.html AGPL Version 3 | ||
* @copyright Copyright (c) 2021 Metaways Infosystems GmbH (http://www.metaways.de) | ||
* @author Paul Mehrer <p.mehrer@metaways.de> | ||
*/ | ||
|
||
# this code is based on https://github.com/Yubico/yubikey-ksm/blob/master/ykksm-utils.php | ||
# Written by Simon Josefsson <simon@josefsson.org>. | ||
# Copyright (c) 2009-2013 Yubico AB | ||
# All rights reserved. | ||
# | ||
# Redistribution and use in source and binary forms, with or without | ||
# modification, are permitted provided that the following conditions are | ||
# met: | ||
# | ||
# * Redistributions of source code must retain the above copyright | ||
# notice, this list of conditions and the following disclaimer. | ||
# | ||
# * Redistributions in binary form must reproduce the above | ||
# copyright notice, this list of conditions and the following | ||
# disclaimer in the documentation and/or other materials provided | ||
# with the distribution. | ||
# | ||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
|
||
|
||
/** | ||
* Yubico Util class | ||
* | ||
* @package Tinebase | ||
* @subpackage Auth | ||
*/ | ||
final class Tinebase_Auth_MFA_YubicoUtil | ||
{ | ||
static public function yubi_hex2bin(string $h): string | ||
{ | ||
$r = ''; | ||
for ($a = 0; $a < strlen($h); $a += 2) { | ||
$r .= chr(hexdec($h[$a] . $h[($a + 1)])); | ||
} | ||
return $r; | ||
} | ||
|
||
static public function modhex2hex(string $m): string | ||
{ | ||
return strtr($m, "cbdefghijklnrtuv", "0123456789abcdef"); | ||
} | ||
|
||
static public function aes128ecb_decrypt(string $key, string $in): ?string | ||
{ | ||
if (false === ($result = openssl_decrypt(self::yubi_hex2bin($in), 'AES-128-CBC', self::yubi_hex2bin($key), | ||
OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, self::yubi_hex2bin('00000000000000000000000000000000')))) { | ||
return null; | ||
} | ||
return bin2hex($result); | ||
} | ||
|
||
static public function calculate_crc(string $token): int | ||
{ | ||
$crc = 0xffff; | ||
|
||
for ($i = 0; $i < 16; $i++) { | ||
$b = hexdec($token[$i * 2] . $token[($i * 2) + 1]); | ||
$crc = $crc ^ ($b & 0xff); | ||
for ($j = 0; $j < 8; $j++) { | ||
$n = $crc & 1; | ||
$crc = $crc >> 1; | ||
if ($n != 0) { | ||
$crc = $crc ^ 0x8408; | ||
} | ||
} | ||
} | ||
return $crc; | ||
} | ||
|
||
static public function crc_is_good(string $token): bool | ||
{ | ||
$crc = self::calculate_crc($token); | ||
return $crc === 0xf0b8; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<?php declare(strict_types=1); | ||
/** | ||
* Tine 2.0 | ||
* | ||
* @package Tinebase | ||
* @subpackage Auth | ||
* @license http://www.gnu.org/licenses/agpl.html AGPL Version 3 | ||
* @copyright Copyright (c) 2021 Metaways Infosystems GmbH (http://www.metaways.de) | ||
* @author Paul Mehrer <p.mehrer@metaways.de> | ||
*/ | ||
|
||
/** | ||
* Yubico OTP MFA Config Model | ||
* | ||
* @package Tinebase | ||
* @subpackage Auth | ||
*/ | ||
class Tinebase_Model_MFA_YubicoOTPConfig extends Tinebase_Auth_MFA_AbstractUserConfig | ||
{ | ||
public const MODEL_NAME_PART = 'MFA_YubicoOTPConfig'; | ||
|
||
/** | ||
* Holds the model configuration (must be assigned in the concrete class) | ||
* | ||
* @var array | ||
*/ | ||
protected static $_modelConfiguration = [ | ||
self::APP_NAME => Tinebase_Config::APP_NAME, | ||
self::MODEL_NAME => self::MODEL_NAME_PART, | ||
|
||
self::FIELDS => [ | ||
] | ||
]; | ||
|
||
/** | ||
* holds the configuration object (must be declared in the concrete class) | ||
* | ||
* @var Tinebase_ModelConfiguration | ||
*/ | ||
protected static $_configurationObject = NULL; | ||
} |
Oops, something went wrong.