diff --git a/lib/MagentaBearer/InvalidTokenException.php b/lib/MagentaBearer/InvalidTokenException.php new file mode 100644 index 00000000..af97581b --- /dev/null +++ b/lib/MagentaBearer/InvalidTokenException.php @@ -0,0 +1,8 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\UserOIDC\MagentaBearer; + +use OCA\UserOIDC\AppInfo\Application; +use OCA\UserOIDC\Db\Provider; +use OCA\UserOIDC\Db\ProviderMapper; +use OCA\UserOIDC\Db\UserMapper; +use OCA\UserOIDC\Event\TokenValidatedEvent; +use OCA\UserOIDC\Service\DiscoveryService; +use OCA\UserOIDC\Service\ProviderService; +use OCA\UserOIDC\Service\ProvisioningDeniedException; +use OCA\UserOIDC\Service\ProvisioningEventService; +use OCA\UserOIDC\User\AbstractOidcBackend; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\IConfig; +use OCP\IRequest; +use OCP\ISession; +use OCP\IURLGenerator; +use OCP\IUserManager; +use OCP\Security\ICrypto; +use Psr\Log\LoggerInterface; + +class MBackend extends AbstractOidcBackend { + + /** + * @var TokenService + */ + protected $mtokenService; + + /** + * @var ProvisioningEventService + */ + protected $provisioningService; + + /** + * @var ICrypto + */ + protected $crypto; + + public function __construct(IConfig $config, + UserMapper $userMapper, + LoggerInterface $logger, + IRequest $request, + ISession $session, + IURLGenerator $urlGenerator, + IEventDispatcher $eventDispatcher, + DiscoveryService $discoveryService, + ProviderMapper $providerMapper, + ProviderService $providerService, + IUserManager $userManager, + ICrypto $crypto, + TokenService $mtokenService, + ProvisioningEventService $provisioningService, + ) { + parent::__construct($config, $userMapper, $logger, $request, $session, + $urlGenerator, $eventDispatcher, $discoveryService, + $providerMapper, $providerService, $userManager); + + $this->mtokenService = $mtokenService; + $this->provisioningService = $provisioningService; + $this->crypto = $crypto; + } + + public function getBackendName(): string { + return Application::APP_ID . '\\MagentaBearer'; + } + + /** + * Backend is activated if header bearer token is detected. + * + * @return bool ture if bearer header found + */ + public function isSessionActive(): bool { + // if this returns true, getCurrentUserId is called + // not sure if we should rather to the validation in here as otherwise it might fail for other backends or bave other side effects + $headerToken = $this->request->getHeader(Application::OIDC_API_REQ_HEADER); + // session is active if we have a bearer token (API request) OR if we logged in via user_oidc (we have a provider ID in the session) + return (preg_match('/^\s*bearer\s+/i', $headerToken) != false); + } + + /** + * Return the id of the current user + * @return string + */ + public function getCurrentUserId(): string { + // get the bearer token from headers + $headerToken = $this->request->getHeader(Application::OIDC_API_REQ_HEADER); + $headerToken = preg_replace('/^bearer\s+/i', '', $headerToken); + if ($headerToken === '') { + $this->logger->debug('No Bearer token'); + return ''; + } + + $providers = $this->providerMapper->getProviders(); + if (count($providers) === 0) { + $this->logger->debug('no OIDC providers'); + return ''; + } + + // we implement only Telekom behavior (which includes auto-provisioning) + // so we neglect switches from the upstream Nexrcloud oidc handling + + // try to validate with all providers + foreach ($providers as $provider) { + if ($this->providerService->getSetting($provider->getId(), ProviderService::SETTING_CHECK_BEARER, '0') === '1') { + try { + $sharedSecret = $this->crypto->decrypt($provider->getBearerSecret()); + $bearerToken = $this->mtokenService->decryptToken($headerToken, $sharedSecret); + $this->mtokenService->verifySignature($bearerToken, $sharedSecret); + $payload = $this->mtokenService->decode($bearerToken); + $this->mtokenService->verifyClaims($payload, ['http://auth.magentacloud.de']); + } catch (InvalidTokenException $eToken) { + // there is + $this->logger->debug('Invalid token:' . $eToken->getMessage() . '. Trying another provider.'); + continue; + } catch (SignatureException $eSignature) { + // only the key seems not to fit, so try the next provider + $this->logger->debug($eSignature->getMessage() . '. Trying another provider.'); + continue; + } catch (\Throwable $e) { + // there is + $this->logger->debug('General non matching provider problem:' . $e->getMessage()); + continue; + } + + $uidAttribute = $this->providerService->getSetting($provider->getId(), ProviderService::SETTING_MAPPING_UID, 'sub'); + $userId = $payload->{$uidAttribute}; + if ($userId === null) { + $this->logger->debug('No extractable user id, check mapping!'); + return ''; + } + + // check bearercache here, not skipping validation for security reasons + + // Telekom bearer does not support refersh_token, so the pupose of TokenValidatedEvent is not given, + // but could produce trouble if not send with the field, apart from performance aspects. + // + // $discovery = $this->discoveryService->obtainDiscovery($provider); + // $this->eventDispatcher->dispatchTyped(new TokenValidatedEvent(['token' => $payload], $provider, $discovery)); + + try { + $this->provisioningService->provisionUser($userId, $provider->getId(), $payload); + $this->checkFirstLogin($userId); // create the folders same as on web login + return $userId; + } catch (ProvisioningDeniedException $denied) { + $this->logger->error('Bearer token access denied: ' . $denied->getMessage()); + return ''; + } + } + } + + $this->logger->debug('Could not find provider for token'); + return ''; + } + + /** + * FIXXME: send proper error status from BAckend errors + * + * This function sets an https status code here (early in the failing backend operation) + * to pass on bearer errors cleanly with correct status code and a readable reason + * + * For this, there is a "tricky" setting of a header needed to make it working in all + * known situations, see + * https://stackoverflow.com/questions/3258634/php-how-to-send-http-response-code + */ + // protected function sendHttpStatus(int $httpStatusCode, string $httpStatusMsg) { + // $phpSapiName = substr(php_sapi_name(), 0, 3); + // if ($phpSapiName == 'cgi' || $phpSapiName == 'fpm') { + // header('Status: ' . $httpStatusCode . ' ' . $httpStatusMsg); + // } else { + // $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0'; + // header($protocol . ' ' . $httpStatusCode . ' ' . $httpStatusMsg); + // } + // } +} diff --git a/lib/MagentaBearer/SignatureException.php b/lib/MagentaBearer/SignatureException.php new file mode 100644 index 00000000..ef04a4e0 --- /dev/null +++ b/lib/MagentaBearer/SignatureException.php @@ -0,0 +1,6 @@ + + * + * @author Bernd Rederlechner + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +declare(strict_types=1); + +namespace OCA\UserOIDC\MagentaBearer; + +use Jose\Component\Core\Algorithm; +use Jose\Component\Core\AlgorithmManager; + +use Jose\Component\Core\JWK; +use Jose\Component\Encryption\Algorithm\ContentEncryption\A256CBCHS512; +use Jose\Component\Encryption\Algorithm\KeyEncryption\ECDHESA256KW; + +use Jose\Component\Encryption\Algorithm\KeyEncryption\PBES2HS512A256KW; +use Jose\Component\Encryption\Algorithm\KeyEncryption\RSAOAEP256; +use Jose\Component\Encryption\Compression\CompressionMethodManager; + +use Jose\Component\Encryption\Compression\Deflate; +use Jose\Component\Encryption\JWEDecrypter; +use Jose\Component\Signature\Algorithm\HS256; +use Jose\Component\Signature\Algorithm\HS384; + +use Jose\Component\Signature\Algorithm\HS512; +use Jose\Component\Signature\JWS; +use Jose\Component\Signature\JWSVerifier; +use OCP\AppFramework\Utility\ITimeFactory; +use Psr\Log\LoggerInterface; + +class TokenService { + + /** @var LoggerInterface */ + private $logger; + + /** @var ITimeFactory */ + private $timeFactory; + + /** @var DiscoveryService */ + private $discoveryService; + + public function __construct(LoggerInterface $logger, + ITimeFactory $timeFactory) { + $this->logger = $logger; + $this->timeFactory = $timeFactory; + + // The key encryption algorithm manager with the A256KW algorithm. + $keyEncryptionAlgorithmManager = new AlgorithmManager([ + new PBES2HS512A256KW(), + new RSAOAEP256(), + new ECDHESA256KW() ]); + + // The content encryption algorithm manager with the A256CBC-HS256 algorithm. + $contentEncryptionAlgorithmManager = new AlgorithmManager([ + new A256CBCHS512(), + ]); + + // The compression method manager with the DEF (Deflate) method. + $compressionMethodManager = new CompressionMethodManager([ + new Deflate(), + ]); + + $signatureAlgorithmManager = new AlgorithmManager([ + new HS256(), + new HS384(), + new HS512(), + ]); + + // We instantiate our JWE Decrypter. + $this->jweDecrypter = new JWEDecrypter( + $keyEncryptionAlgorithmManager, + $contentEncryptionAlgorithmManager, + $compressionMethodManager + ); + + // We try to load the token. + $this->encryptionSerializerManager = new \Jose\Component\Encryption\Serializer\JWESerializerManager([ + new \Jose\Component\Encryption\Serializer\CompactSerializer(), + ]); + + + // We instantiate our JWS Verifier. + $this->jwsVerifier = new JWSVerifier( + $signatureAlgorithmManager + ); + + // The serializer manager. We only use the JWE Compact Serialization Mode. + $this->serializerManager = new \Jose\Component\Signature\Serializer\JWSSerializerManager([ + new \Jose\Component\Signature\Serializer\CompactSerializer(), + ]); + } + + /** + * Implement JOSE decryption for SAM3 tokens + */ + public function decryptToken(string $rawToken, string $decryptKey) : JWS { + + // web-token library does not like underscores in headers, so replace them with - (which is valid in JWT) + $numSegments = substr_count($rawToken, '.') + 1; + $this->logger->debug('Bearer access token(segments=' . $numSegments . ')=' . $rawToken); + if ($numSegments > 3) { + // trusted authenticator and myself share the client secret, + // so use it is used for encrypted web tokens + $clientSecret = new JWK([ + 'kty' => 'oct', + 'k' => $decryptKey + ]); + + $jwe = $this->encryptionSerializerManager->unserialize($rawToken); + + // We decrypt the token. This method does NOT check the header. + if ($this->jweDecrypter->decryptUsingKey($jwe, $clientSecret, 0)) { + return $this->serializerManager->unserialize($jwe->getPayload()); + } else { + throw new InvalidTokenException('Unknown bearer encryption format'); + } + } else { + return $this->serializerManager->unserialize($rawToken); + } + } + + /** + * Get claims (even before verification to access e.g. aud standard field ...) + * Transform them in a format compatible with id_token representation. + */ + public function decode(JWS $decodedToken) : object { + $this->logger->debug('Telekom SAM3 access token: ' . $decodedToken->getPayload()); + $samContent = json_decode($decodedToken->getPayload(), false); + + // remap all the custom claims + // adapt into OpenId id_token format (as far as possible) + $claimArray = $samContent->{'urn:telekom.com:idm:at:attributes'}; + foreach ($claimArray as $claimKeyValue) { + $samContent->{'urn:telekom.com:' . $claimKeyValue->name} = $claimKeyValue->value; + } + unset($samContent->{'urn:telekom.com:idm:at:attributes'}); + + $this->logger->debug('Adapted OpenID-like token; ' . json_encode($samContent)); + return $samContent; + } + + + public function verifySignature(JWS $decodedToken, string $signKey) { + $accessSecret = new JWK([ + 'kty' => 'oct', + 'k' => $signKey + ]); // TODO: take the additional access key secret from settings + + if (!$this->jwsVerifier->verifyWithKey($decodedToken, $accessSecret, 0)) { + throw new SignatureException('Invalid Signature'); + } + } + + public function verifyClaims(object $claims, array $audiences = [], int $leeway = 60) { + $timestamp = $this->timeFactory->getTime(); + + // Check the nbf if it is defined. This is the time that the + // token can actually be used. If it's not yet that time, abort. + if (isset($claims->nbf) && $claims->nbf > ($timestamp + $leeway)) { + throw new InvalidTokenException( + 'Cannot handle token prior to ' . \date(DateTime::ISO8601, $claims->nbf) + ); + } + + // Check that this token has been created before 'now'. This prevents + // using tokens that have been created for later use (and haven't + // correctly used the nbf claim). + if (isset($claims->iat) && $claims->iat > ($timestamp + $leeway)) { + throw new InvalidTokenException( + 'Cannot handle token prior to ' . \date(DateTime::ISO8601, $claims->iat) + ); + } + + // Check if this token has expired. + if (isset($claims->exp) && ($timestamp - $leeway) >= $claims->exp) { + throw new InvalidTokenException('Expired token'); + } + + // Check target audience (if given) + // Check if this token has expired. + if (empty(array_intersect($claims->aud, $audiences))) { + throw new InvalidTokenException('No acceptable audience in token.'); + } + } +} diff --git a/lib/User/AbstractOidcBackend.php b/lib/User/AbstractOidcBackend.php new file mode 100644 index 00000000..d1e5de7b --- /dev/null +++ b/lib/User/AbstractOidcBackend.php @@ -0,0 +1,220 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\UserOIDC\User; + +use OCA\UserOIDC\Db\ProviderMapper; +use OCA\UserOIDC\Db\UserMapper; +use OCA\UserOIDC\Service\DiscoveryService; +use OCA\UserOIDC\Service\ProviderService; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\Authentication\IApacheBackend; +use OCP\DB\Exception; +use OCP\EventDispatcher\GenericEvent; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\NotPermittedException; +use OCP\IConfig; +use OCP\IRequest; +use OCP\ISession; +use OCP\IURLGenerator; +use OCP\IUser; +use OCP\IUserManager; +use OCP\User\Backend\ABackend; +use OCP\User\Backend\ICustomLogout; +use OCP\User\Backend\IGetDisplayNameBackend; +use OCP\User\Backend\IPasswordConfirmationBackend; +use Psr\Log\LoggerInterface; + +/** + * Introduce a baseclass to derive multiple backend from depending on + * the required bearer behavior. + * + * The class contains the OIDC part without the bearer aspects. + * + * FIXME: we should derive also the previous standard bearer backend from + * this class + */ +abstract class AbstractOidcBackend extends ABackend implements IPasswordConfirmationBackend, IGetDisplayNameBackend, IApacheBackend, ICustomLogout { + + /** @var UserMapper */ + protected $userMapper; + /** @var LoggerInterface */ + protected $logger; + /** @var IRequest */ + protected $request; + /** @var ProviderMapper */ + protected $providerMapper; + /** + * @var ProviderService + */ + protected $providerService; + /** + * @var IConfig + */ + protected $config; + /** + * @var IEventDispatcher + */ + protected $eventDispatcher; + /** + * @var DiscoveryService + */ + protected $discoveryService; + /** + * @var IURLGenerator + */ + protected $urlGenerator; + /** + * @var ISession + */ + protected $session; + /** + * @var IUserManager + */ + protected $userManager; + + public function __construct(IConfig $config, + UserMapper $userMapper, + LoggerInterface $logger, + IRequest $request, + ISession $session, + IURLGenerator $urlGenerator, + IEventDispatcher $eventDispatcher, + DiscoveryService $discoveryService, + ProviderMapper $providerMapper, + ProviderService $providerService, + IUserManager $userManager) { + $this->config = $config; + $this->userMapper = $userMapper; + $this->logger = $logger; + $this->request = $request; + $this->providerMapper = $providerMapper; + $this->providerService = $providerService; + $this->eventDispatcher = $eventDispatcher; + $this->discoveryService = $discoveryService; + $this->session = $session; + $this->urlGenerator = $urlGenerator; + $this->userManager = $userManager; + } + + public function deleteUser($uid): bool { + try { + $user = $this->userMapper->getUser($uid); + $this->userMapper->delete($user); + return true; + } catch (Exception $e) { + $this->logger->error('Failed to delete user', [ 'exception' => $e ]); + return false; + } + } + + public function getUsers($search = '', $limit = null, $offset = null) { + return array_map(function ($user) { + return $user->getUserId(); + }, $this->userMapper->find($search, $limit, $offset)); + } + + public function userExists($uid): bool { + return $this->userMapper->userExists($uid); + } + + public function getDisplayName($uid): string { + try { + $user = $this->userMapper->getUser($uid); + } catch (DoesNotExistException $e) { + return $uid; + } + + return $user->getDisplayName(); + } + + public function getDisplayNames($search = '', $limit = null, $offset = null): array { + return $this->userMapper->findDisplayNames($search, $limit, $offset); + } + + public function hasUserListings(): bool { + return true; + } + + public function canConfirmPassword(string $uid): bool { + return false; + } + + /** + * As session cannot be injected in the constructor here, we inject it later + * + * @param ISession $session + * @return void + */ + public function injectSession(ISession $session): void { + $this->session = $session; + } + + /** + * {@inheritdoc} + */ + public function getLogoutUrl(): string { + return $this->urlGenerator->linkToRouteAbsolute( + 'user_oidc.login.singleLogoutService', + [ + 'requesttoken' => \OC::$server->getCsrfTokenManager()->getToken()->getEncryptedValue(), + ] + ); + } + + + /** + * Inspired by lib/private/User/Session.php::prepareUserLogin() + * + * @param string $userId + * @return bool + * @throws NotFoundException + */ + protected function checkFirstLogin(string $userId): bool { + $user = $this->userManager->get($userId); + + if ($user === null) { + return false; + } + + $firstLogin = $user->getLastLogin() === 0; + if ($firstLogin) { + \OC_Util::setupFS($userId); + // trigger creation of user home and /files folder + $userFolder = \OC::$server->getUserFolder($userId); + try { + // copy skeleton + \OC_Util::copySkeleton($userId, $userFolder); + } catch (NotPermittedException $ex) { + // read only uses + } + + // trigger any other initialization + \OC::$server->getEventDispatcher()->dispatch(IUser::class . '::firstLogin', new GenericEvent($user)); + } + $user->updateLastLoginTimestamp(); + return $firstLogin; + } +} diff --git a/tests/unit/MagentaCloud/BearerTokenServiceTest.php b/tests/unit/MagentaCloud/BearerTokenServiceTest.php new file mode 100644 index 00000000..2c6ab49c --- /dev/null +++ b/tests/unit/MagentaCloud/BearerTokenServiceTest.php @@ -0,0 +1,103 @@ + + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +declare(strict_types=1); + + +use OCA\UserOIDC\MagentaBearer\SignatureException; +use OCA\UserOIDC\MagentaBearer\TokenService; + +use PHPUnit\Framework\TestCase; + +class BearerTokenServiceTest extends TestCase { + public const EXPIRED_TOKEN = 'eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJzdHMwMC5pZG0udmVyLnN1bC50LW9ubGluZS5kZSIsInVybjp0ZWxla29tLmNvbTppZG06YXQ6c3ViamVjdFR5cGUiOnsiZm9ybWF0IjoidXJuOmNvbTp0ZWxla29tOmlkbToxLjA6bmFtZWlkLWZvcm1hdDphbmlkIiwicmVhbG0iOiJ2ZXIuc3VsLnQtb25saW5lLmRlIn0sImFjciI6InVybjp0ZWxla29tOm5hbWVzOmlkbTpUSE86MS4wOmFjOmNsYXNzZXM6cHdkIiwic3ViIjoiMTIwMDQ5MDEwMDAwMDAwMDA3MjEwMjA3IiwiaWF0IjoxNjM1NTgxODAyLCJuYmYiOjE2MzU1ODE4MDIsImV4cCI6MTYzNTU4OTAwMiwidXJuOnRlbGVrb20uY29tOmlkbTphdDphdXRoTlN0YXRlbWVudHMiOnsidXJuOnRlbGVrb206bmFtZXM6aWRtOlRITzoxLjA6YWM6Y2xhc3Nlczpwd2QiOnsiYXV0aGVudGljYXRpbmdBdXRob3JpdHkiOm51bGwsImF1dGhOSW5zdGFudCI6MTYzNTU4MTUzNX19LCJhdWQiOlsiaHR0cDovL2F1dGgubWFnZW50YWNsb3VkLmRlIl0sImp0aSI6IlNUUy0xZTIyYTA2Zi03OTBjLTQwZmItYWQxZC02ZGUyZGRjZjI0MzEiLCJ1cm46dGVsZWtvbS5jb206aWRtOmF0OmF0dHJpYnV0ZXMiOlt7Im5hbWUiOiJjbGllbnRfaWQiLCJuYW1lRm9ybWF0IjoidXJuOmNvbTp0ZWxla29tOmlkbToxLjA6YXR0cm5hbWUtZm9ybWF0OmZpZWxkIiwidmFsdWUiOiIxMFRWTDBTQU0zMDAwMDAwNDkwMU5FWFRNQUdFTlRBQ0xPVUQwMDAwIn0seyJuYW1lIjoiZGlzcGxheW5hbWUiLCJuYW1lRm9ybWF0IjoidXJuOmNvbTp0ZWxla29tOmlkbToxLjA6YXR0cm5hbWUtZm9ybWF0OmZpZWxkIiwidmFsdWUiOiJubWNsb3VkMDFAdmVyLnN1bC50LW9ubGluZS5kZSJ9LHsibmFtZSI6ImVtYWlsIiwibmFtZUZvcm1hdCI6InVybjpjb206dGVsZWtvbTppZG06MS4wOmF0dHJuYW1lLWZvcm1hdDpmaWVsZCIsInZhbHVlIjoibm1jbG91ZDAxQHZlci5zdWwudC1vbmxpbmUuZGUifSx7Im5hbWUiOiJhbmlkIiwibmFtZUZvcm1hdCI6InVybjpjb206dGVsZWtvbTppZG06MS4wOmF0dHJuYW1lLWZvcm1hdDpmaWVsZCIsInZhbHVlIjoiMTIwMDQ5MDEwMDAwMDAwMDA3MjEwMjA3In0seyJuYW1lIjoiZDU1NiIsIm5hbWVGb3JtYXQiOiJ1cm46Y29tOnRlbGVrb206aWRtOjEuMDphdHRybmFtZS1mb3JtYXQ6ZmllbGQiLCJ2YWx1ZSI6IjAifSx7Im5hbWUiOiJkb210IiwibmFtZUZvcm1hdCI6InVybjpjb206dGVsZWtvbTppZG06MS4wOmF0dHJuYW1lLWZvcm1hdDpmaWVsZCIsInZhbHVlIjoidmVyLnN1bC50LW9ubGluZS5kZSJ9LHsibmFtZSI6ImYwNDgiLCJuYW1lRm9ybWF0IjoidXJuOmNvbTp0ZWxla29tOmlkbToxLjA6YXR0cm5hbWUtZm9ybWF0OmZpZWxkIiwidmFsdWUiOiIxIn0seyJuYW1lIjoiZjA0OSIsIm5hbWVGb3JtYXQiOiJ1cm46Y29tOnRlbGVrb206aWRtOjEuMDphdHRybmFtZS1mb3JtYXQ6ZmllbGQiLCJ2YWx1ZSI6IjEifSx7Im5hbWUiOiJmMDUxIiwibmFtZUZvcm1hdCI6InVybjpjb206dGVsZWtvbTppZG06MS4wOmF0dHJuYW1lLWZvcm1hdDpmaWVsZCIsInZhbHVlIjoiMCJ9LHsibmFtZSI6ImY0NjAiLCJuYW1lRm9ybWF0IjoidXJuOmNvbTp0ZWxla29tOmlkbToxLjA6YXR0cm5hbWUtZm9ybWF0OmZpZWxkIiwidmFsdWUiOiIwIn0seyJuYW1lIjoiZjQ2NyIsIm5hbWVGb3JtYXQiOiJ1cm46Y29tOnRlbGVrb206aWRtOjEuMDphdHRybmFtZS1mb3JtYXQ6ZmllbGQiLCJ2YWx1ZSI6IjAifSx7Im5hbWUiOiJmNDY4IiwibmFtZUZvcm1hdCI6InVybjpjb206dGVsZWtvbTppZG06MS4wOmF0dHJuYW1lLWZvcm1hdDpmaWVsZCIsInZhbHVlIjoiMCJ9LHsibmFtZSI6ImY0NjkiLCJuYW1lRm9ybWF0IjoidXJuOmNvbTp0ZWxla29tOmlkbToxLjA6YXR0cm5hbWUtZm9ybWF0OmZpZWxkIiwidmFsdWUiOiIwIn0seyJuYW1lIjoiZjQ3MSIsIm5hbWVGb3JtYXQiOiJ1cm46Y29tOnRlbGVrb206aWRtOjEuMDphdHRybmFtZS1mb3JtYXQ6ZmllbGQiLCJ2YWx1ZSI6IjAifSx7Im5hbWUiOiJmNTU2IiwibmFtZUZvcm1hdCI6InVybjpjb206dGVsZWtvbTppZG06MS4wOmF0dHJuYW1lLWZvcm1hdDpmaWVsZCIsInZhbHVlIjoiMSJ9LHsibmFtZSI6ImY3MzQiLCJuYW1lRm9ybWF0IjoidXJuOmNvbTp0ZWxla29tOmlkbToxLjA6YXR0cm5hbWUtZm9ybWF0OmZpZWxkIiwidmFsdWUiOiIwIn0seyJuYW1lIjoibWFpbkVtYWlsIiwibmFtZUZvcm1hdCI6InVybjpjb206dGVsZWtvbTppZG06MS4wOmF0dHJuYW1lLWZvcm1hdDpmaWVsZCIsInZhbHVlIjoibm1jbG91ZDAxQHZlci5zdWwudC1vbmxpbmUuZGUifSx7Im5hbWUiOiJzNTU2IiwibmFtZUZvcm1hdCI6InVybjpjb206dGVsZWtvbTppZG06MS4wOmF0dHJuYW1lLWZvcm1hdDpmaWVsZCIsInZhbHVlIjoiMCJ9LHsibmFtZSI6InVzdGEiLCJuYW1lRm9ybWF0IjoidXJuOmNvbTp0ZWxla29tOmlkbToxLjA6YXR0cm5hbWUtZm9ybWF0OmZpZWxkIiwidmFsdWUiOiIxIn1dLCJ1cm46dGVsZWtvbS5jb206aWRtOmF0OnZlcnNpb24iOiIxLjAifQ.5zbr7Uvx2KmU8uR412jHhptWEjykJ_n2awBRcQL8fLE'; + public const INVALID_SIGN_TOKEN = 'eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJzdHMwMC5pZG0udmVyLnN1bC50LW9ubGluZS5kZSIsInVybjp0ZWxla29tLmNvbTppZG06YXQ6c3ViamVjdFR5cGUiOnsiZm9ybWF0IjoidXJuOmNvbTp0ZWxla29tOmlkbToxLjA6bmFtZWlkLWZvcm1hdDphbmlkIiwicmVhbG0iOiJ2ZXIuc3VsLnQtb25saW5lLmRlIn0sImFjciI6InVybjp0ZWxla29tOm5hbWVzOmlkbTpUSE86MS4wOmFjOmNsYXNzZXM6cHdkIiwic3ViIjoiMTIwMDQ5MDEwMDAwMDAwMDA3MjEwMjA3IiwiaWF0IjoxNjM1NTgxODAyLCJuYmYiOjE2MzU1ODE4MDIsImV4cCI6MTYzNTU4OTAwMiwidXJuOnRlbGVrb20uY29tOmlkbTphdDphdXRoTlN0YXRlbWVudHMiOnsidXJuOnRlbGVrb206bmFtZXM6aWRtOlRITzoxLjA6YWM6Y2xhc3Nlczpwd2QiOnsiYXV0aGVudGljYXRpbmdBdXRob3JpdHkiOm51bGwsImF1dGhOSW5zdGFudCI6MTYzNTU4MTUzNX19LCJhdWQiOlsiaHR0cDovL2F1dGgubWFnZW50YWNsb3VkLmRlIl0sImp0aSI6IlNUUy0xZTIyYTA2Zi03OTBjLTQwZmItYWQxZC02ZGUyZGRjZjI0MzEiLCJ1cm46dGVsZWtvbS5jb206aWRtOmF0OmF0dHJpYnV0ZXMiOlt7Im5hbWUiOiJjbGllbnRfaWQiLCJuYW1lRm9ybWF0IjoidXJuOmNvbTp0ZWxla29tOmlkbToxLjA6YXR0cm5hbWUtZm9ybWF0OmZpZWxkIiwidmFsdWUiOiIxMFRWTDBTQU0zMDAwMDAwNDkwMU5FWFRNQUdFTlRBQ0xPVUQwMDAwIn0seyJuYW1lIjoiZGlzcGxheW5hbWUiLCJuYW1lRm9ybWF0IjoidXJuOmNvbTp0ZWxla29tOmlkbToxLjA6YXR0cm5hbWUtZm9ybWF0OmZpZWxkIiwidmFsdWUiOiJubWNsb3VkMDFAdmVyLnN1bC50LW9ubGluZS5kZSJ9LHsibmFtZSI6ImVtYWlsIiwibmFtZUZvcm1hdCI6InVybjpjb206dGVsZWtvbTppZG06MS4wOmF0dHJuYW1lLWZvcm1hdDpmaWVsZCIsInZhbHVlIjoibm1jbG91ZDAxQHZlci5zdWwudC1vbmxpbmUuZGUifSx7Im5hbWUiOiJhbmlkIiwibmFtZUZvcm1hdCI6InVybjpjb206dGVsZWtvbTppZG06MS4wOmF0dHJuYW1lLWZvcm1hdDpmaWVsZCIsInZhbHVlIjoiMTIwMDQ5MDEwMDAwMDAwMDA3MjEwMjA3In0seyJuYW1lIjoiZDU1NiIsIm5hbWVGb3JtYXQiOiJ1cm46Y29tOnRlbGVrb206aWRtOjEuMDphdHRybmFtZS1mb3JtYXQ6ZmllbGQiLCJ2YWx1ZSI6IjAifSx7Im5hbWUiOiJkb210IiwibmFtZUZvcm1hdCI6InVybjpjb206dGVsZWtvbTppZG06MS4wOmF0dHJuYW1lLWZvcm1hdDpmaWVsZCIsInZhbHVlIjoidmVyLnN1bC50LW9ubGluZS5kZSJ9LHsibmFtZSI6ImYwNDgiLCJuYW1lRm9ybWF0IjoidXJuOmNvbTp0ZWxla29tOmlkbToxLjA6YXR0cm5hbWUtZm9ybWF0OmZpZWxkIiwidmFsdWUiOiIxIn0seyJuYW1lIjoiZjA0OSIsIm5hbWVGb3JtYXQiOiJ1cm46Y29tOnRlbGVrb206aWRtOjEuMDphdHRybmFtZS1mb3JtYXQ6ZmllbGQiLCJ2YWx1ZSI6IjEifSx7Im5hbWUiOiJmMDUxIiwibmFtZUZvcm1hdCI6InVybjpjb206dGVsZWtvbTppZG06MS4wOmF0dHJuYW1lLWZvcm1hdDpmaWVsZCIsInZhbHVlIjoiMCJ9LHsibmFtZSI6ImY0NjAiLCJuYW1lRm9ybWF0IjoidXJuOmNvbTp0ZWxla29tOmlkbToxLjA6YXR0cm5hbWUtZm9ybWF0OmZpZWxkIiwidmFsdWUiOiIwIn0seyJuYW1lIjoiZjQ2NyIsIm5hbWVGb3JtYXQiOiJ1cm46Y29tOnRlbGVrb206aWRtOjEuMDphdHRybmFtZS1mb3JtYXQ6ZmllbGQiLCJ2YWx1ZSI6IjAifSx7Im5hbWUiOiJmNDY4IiwibmFtZUZvcm1hdCI6InVybjpjb206dGVsZWtvbTppZG06MS4wOmF0dHJuYW1lLWZvcm1hdDpmaWVsZCIsInZhbHVlIjoiMCJ9LHsibmFtZSI6ImY0NjkiLCJuYW1lRm9ybWF0IjoidXJuOmNvbTp0ZWxla29tOmlkbToxLjA6YXR0cm5hbWUtZm9ybWF0OmZpZWxkIiwidmFsdWUiOiIwIn0seyJuYW1lIjoiZjQ3MSIsIm5hbWVGb3JtYXQiOiJ1cm46Y29tOnRlbGVrb206aWRtOjEuMDphdHRybmFtZS1mb3JtYXQ6ZmllbGQiLCJ2YWx1ZSI6IjAifSx7Im5hbWUiOiJmNTU2IiwibmFtZUZvcm1hdCI6InVybjpjb206dGVsZWtvbTppZG06MS4wOmF0dHJuYW1lLWZvcm1hdDpmaWVsZCIsInZhbHVlIjoiMSJ9LHsibmFtZSI6ImY3MzQiLCJuYW1lRm9ybWF0IjoidXJuOmNvbTp0ZWxla29tOmlkbToxLjA6YXR0cm5hbWUtZm9ybWF0OmZpZWxkIiwidmFsdWUiOiIwIn0seyJuYW1lIjoibWFpbkVtYWlsIiwibmFtZUZvcm1hdCI6InVybjpjb206dGVsZWtvbTppZG06MS4wOmF0dHJuYW1lLWZvcm1hdDpmaWVsZCIsInZhbHVlIjoibm1jbG91ZDAxQHZlci5zdWwudC1vbmxpbmUuZGUifSx7Im5hbWUiOiJzNTU2IiwibmFtZUZvcm1hdCI6InVybjpjb206dGVsZWtvbTppZG06MS4wOmF0dHJuYW1lLWZvcm1hdDpmaWVsZCIsInZhbHVlIjoiMCJ9LHsibmFtZSI6InVzdGEiLCJuYW1lRm9ybWF0IjoidXJuOmNvbTp0ZWxla29tOmlkbToxLjA6YXR0cm5hbWUtZm9ybWF0OmZpZWxkIiwidmFsdWUiOiIxIn1dLCJ1cm46dGVsZWtvbS5jb206aWRtOmF0OnZlcnNpb24iOiIxLjAifQ.5zbr7Uvx2KmU8uR412jHhptWEjykJ_n2awBRcQL9fLE'; + public const ENCRPYT1_SIGN_TOKEN = 'eyJwMnMiOiI4VzhYY21iaHJPSSIsInAyYyI6MTAwMCwiY3R5IjoiSldUIiwiZW5jIjoiQTI1NkNCQy1IUzUxMiIsImFsZyI6IlBCRVMyLUhTNTEyK0EyNTZLVyJ9.5bA_ctLbQOnMojJW3MPo83AIvCAu3MpmaaD7j2GzqBv5_-D4w69ONqcPEsc6LYMG9B-rw3HDXng4Mqye4KqpW70ECpf9HXV6.6zl4Zqp4wbcO_AqqmpA3sQ.y7dHcwxXveYkuh4UaqHhE4nvP_avZsxaf7aAbnJdDHHKbBKvEKKqHkPg593i14ypWuRHd2i9Opsuyppfxx9Hw7C7N7LJ8UCTYMihHqlJkHecB08xgJ3ciE0L2Qtvg9hfxQbHNVV4p1_KL3ubAXt9ovwDCOJvN6PXyixUDtYYF1D_Km7Ze1ptUNbwS2H4vf-MKHwwrm5uhTvXOppGNO-0tYnIMOZ8BkiTtrrlO6IQbRcC4EMw74PzbFsQXY9u1xsNZ9IOrzbBl_EyPBLr5ool1BGlvNog4XFsHLgxUa5cjIcZVRMgZSLWdToTiXYFAWdO6fbQrRWT8ERRDWjiDxJEaPlfI_61G5NzJN2NKnSAY7fR8i3Rfs_JoF1TtpR5dGU28Lk1vcLjKYBLqp2hjW97QsANVgmalkkJMUpiAvNN48ZSCK9T3vTfiH7unFRNWvTKvZXyHIkYQPZ0-b3Z9s5oLMx93Snvcq9jQVKA1dWU_bEUIOnwP65ADU_FIkYB8gsZXp5Za3HrK63u03Lij6rwkJpEPbwcnxhBkMhtKOOwQVZm1ZBf_lVyn39MFXmLN_gDD052vFpxl1NnG0KEg8XJQ_usE9e64q7W6IG4gRm9NYG6rdeik6Dm45K8fA4oUiyjdgHjveR6GW8uXQR-tWXf3IC-_2jws2PJ31acdoEbDU30XlVeCqENW-ylPJ10rP28XxboQVJMRrzMiEzu39IH3c02czHh81U09TREVsO2S8CCQcahboaplDg9kpr1UZpsRrjg40bEtdm2cKubTbczGiXiF7sI0qE-kHm0aiK5c6mO8fHETMCmvh2vhxcYo_T6q7VklbwiZVbn47z-oriEDyPlLrB_PzYR6fNRbtObttj0CHRgf-NI69RU2pAGxujSi2lEhNkG-CAFNfASKm8uSUCg8UPr7v38c5vr4IuYC1gYjxgebXIh0EFX4G8jZM6ljPSzmMFDyErWJQ5OrtJjuKrUa96Yp3oOZTemtCwc--mrDXmpwVlaBMCuuJDz6zucxwSeVK0mP0t56zHeK59jxz0OfV62TrcVeZaLqSl3o-pVsY5KrLxL1qf2QIry-uy_c1zi9AuZnSbH3t1RvmyG5-QIh5WSPOLXG9ivuHKAdQTvBnchXWfkUVkoPYuPFyBydlPAhpRQyBLHboqdT6lIdoQ5lBRI8vsGb9wQVSQx08hbpEFOPMe-SJqzjZp36sUurJrgj_ethbIWkTSe_HPkcvBv8X0kyvhnyTKYJoroE5HDM0dtgFW8xK8NmOZOuREzJW5fpqzJML8iY0p1IX3bvGrCeVMEJtM0T6KSJFdPHBAzkWNNMBUc2jhuxa6B2cSaMz60bwSCw8n5NWz8wkXUFJJkHKEnK8tFbtOQXHeGG48k7Wl6kgrQkAFAHZqQt9gRDdmGcYAYHVK7cESjABV9LWQIQYy0eyveU0sWE5sYXKCwsk8rLiKt5GmZlRQ0rOltuFXRTu_EZYuqR0DCRXrjQWVN1zLTy0LMqAvDR-PJcFtekbT9CXLEW6M6GHzJhYfNyMc_cPitG8QwS5EWGzJjQIiNsJBRyV7cPlHeMhKzDtEk3DR3l-qQJa9-54RQB-kStJjB0AAZ21ku7eBS6orT0lljj935eghlHxAzyr1fvlDjIpHc--ob_7DOPc9sBGqcwdYoZ28zD1d02rpJujOwTe4zgll4vffJ_aFP8hm19pmroCwFsZPWIK6GN_cllJaxnllkJ_9c-7eBj1rKkNX0DLyNwKoMYttugeQFWAxaaqWhoOpQXnRHaVt5hTzoexi5C2j_aVBUAzyMPZtvuYgY1uc8zeKt5X8rAy3Y7WqYeOy8Q6IezVyTE6p0kzYgzUT1Vg2XZEr7dBgNkv8ySfYQNG5d8_PtvBHX-SOy25rtes7oUHHgZx0AkpomhNGSwfrW4dyIWCa6j5qUexqs3TPip_FAJwdW38OnyfPQ5SHLTt8D6OCOLN70MdbPpeoFkGnx1oj1Xjx_UW8mtueWAkxidv6Lamf_D5j8sJvkksne8Nos2YvGNkaGZwQK8YfjvPP-VVdukLMqoloovOuvgxLVLSvnDYcRRjfwAdiKwFNGdMbdV5LwfAzVAlncyWPJso3Lk9fPYd88YW8e6o7xiboiushcbDQU0ZN_Zh9YGk-8R4VnvAuI3yWxLrBB8NFUwKYkNBupVWrxRHJbJEebsLv9r_PZstBHHfMFpcQYX05NYfQiezhQ9l-aseC9Ay4FLbcxyXkIiPEBfiwZESqQbYoL3OeBQYzsV8AFe4GVdUUwPCuPjKR52UlkPiUJthxGkLFfcEPbqfX_lByN5YZRMSruOt6yKysbBIw0gcC6n7wuA_URaFNSPfyHe6nqAtveh1YjZpwZszAERyk2ziFXKFYFppdjMPvxF37uWoH_BEpv9Bs7yaxPRK7pfniS105RBsDFS093-3sUYM6W7IrmPfKAe71OtdWtQQqQKOAX3WGFShCIKyz-aOJWJPRG35Q2DOGu0nehFetGVsSnt-ehmru-Zuv4IanlF0_3SjQ7l7l6gg3Sfyy6sN8SVvxTtw4jLkaAM6cpmVMQVP8uQeJ9IFSHyq1kFceQcguh5tbwMknJzcMNzmZ9zEOG4ifyk9zmeulX9Rtf3lIXIOU-1lEs5bVm42eg1IKpxaY8PeTrT4qvPIyVkOprpKGIAcGyD0tP11vvDCvbltEWBo72gdbtD9tUdUPK0XRD_TgEPy2YU6I6BsKBStd40Fk6nOCGrq-mjYmH6OK3JUF3EVV7E0fEg7BgnYPLxcla0l7H6LpY4sqmFwapDqknjhgbqK0dyZDGWEPJ7Ph_5K6BazKuV_1bf6ZFOuRbm72cmT6vAJM8BhihAdTQt92QbTPikjLS2he5AfSV1ieDgLT26dsLNuLkyExyBqUGkrFoojh4fvW9K-wDKtgvQwCYZYABlC9JY72gtpaV2OV2UrB4aXuJX6n1NNXaSzpPqSupAIGK3Gaw39yrzBgBjTYAe0nnRu10BO7-gNRvKGIMCBTa7c-c0o0eNGe81xv1w8_-6auoKZYS8rzXQ8T6XLUjC1mRZD_cGxnfEra2G96-Cqm9WZO5hVX5fpXZhybz7neyGKlUKZG_An-jGmc9j_m03-5EEOfKAXJNlmOT1IynNVudtzTTrh8O5Dp4nD6fKsyOrg-6yRePCiP4FeItLCH6uVLWWdR65WZzklQuPrBELg58OzIsaBuKCKNjODSA4dGVE4JurhmgnnSmaqz2z6s0Zd1gXERebk_1WEmkWd03jO7dXMk3hOM9zV9BrZALOAll3GsvCqgh9kfouX-3ZNSNO7Lah6ecLD_zK228ap6r1MeY2VK-PiHUEnH58jh2HuutZB1Ge0GVvsYBue_r0FjGVNh6a9XYwIaf1Um2Z81WgHpWHZ-pLVZlkbN1vxgqLNBpjDy6UWpPJzOUv829C31WID92Wa6XPsfq6sIvYRUEx03DE2sbXKjUNX2t8InuLCgC6_wmq-GOoZ5vLKt1KHMicJUM9YFZYYKd-7c25X6DLplAnP-Hw_URgRINQdD8kOWzZ_70SiEq0om6OWniva6czSiwrcml_UBDA5Xr8pNtSWqtNbHh1LJzJenVIZl9gPLRs_o-OxB9gylqk7HwQZgKPCbvccYyh162Iy_Kg2j07hnDuoiUyZ93o9x_3Asf8Ms_E_ov6CqpFgKICX6rEE0oOgFO_pKvwtNH8fF-uNkVGKQwNYX6S33SlWh_pULYLSl-YrXVP0hLLmGlunnOGXUIVTXjQcc6AheR8Dmg9jDIefpgHMH6hegAnoZL0_AVuG-yd9LSRSh2qH_rABtJHTOx-0qQ6yYnrzHcMuvatCwDuIePK5DcxBj8KhKq9F4y_i5Ym9drIskRvAzwygZuIIuT3uyXl5nI6YE_jd6F9w4PZ7SkOs9JvfCnt-Wm7UKI6dxLnCRoTarUwop1wDZ77-rRwYoo5zYwF73BragZBZuWNB8ImLlktcAyCBF6P2_F2j4jvnQNLShYZ5HsJKsJNljjIiKYEAeJ2ScT2tjPSfMsdssWQPPByDgwnWtGpx2z6JTFGLUHaj_WbQe3hciyl7jGM2U1JrA610-Jb0X_OiGslZuYBasmPkEXFbDhZy_QZ4Pjs4RddBqrS15-H4FphxsB4knYHtfAzvJno80QmR69zvIfBSIScEx48foHjbeObNpW51IGbg2-yhssa9YtLpjpafnc1-yJ5xj6tJWYZcpskhgADRQvoxF8Xa7BE8o0D9-I7r2Yp0wMfYrbX8NCTBUWczxBZt2juBIERwgjHZzphIGVXNJ6ARm9F12UMf2OwUEk56J6SiSfB1ho7EDdARwj6Nfkm1LjpYLDhii-IRVJUN8tphw6SHVJBbMucYsXsL8viafUwdh7MbBwLKOPgZM4H9BqWFePgEglf7nzrALd2WV40tOai-sm4e4UCKh9bQ1qNw-uHQLP81NNzMA.bMWJdVmxAg2RZm7NE9wTz4H4LwjDb21tFV8hGtTKGFI'; + public const ENCRPYT2_SIGN_TOKEN = 'eyJwMnMiOiI2UWMyblpRYkxyRSIsInAyYyI6MTAwMCwiY3R5IjoiSldUIiwiZW5jIjoiQTI1NkNCQy1IUzUxMiIsImFsZyI6IlBCRVMyLUhTNTEyK0EyNTZLVyJ9.WqxhY5Qk2uYhlwqtH7JLb3l8QLxjo9Keq4p0iT_Xy4gIxbnQvIlkOYyf9b7QcBiOlStPm9-RMvt-MmgV_dibTvmrDtEq9CFy.J1NxAp-hkYrh4SHjvErdhw.cb9NQdiQDAoAJKn0jGm_nK9UzuxGcAdaycTwYv1IkYOPg4nteGXUoEZH0Yzh6KJh95vNBbVVhpKnQaYmYfnR7WzcufJJ9XpvsHGP2_KV_kItWTijClXun8Eyg5DDY5lK0Z656-f_walGoZnUxCGTxmra_3yOGbKMKaEq-lxBuf1lPdmi3IpGm1H4IOiiHLpu0ZjEUt_S-L4mOLmnc4TR17sEgB260e7-8np_GqwN5vns7ug3-M_AGFJUyDqKV6hRGu3qn7lLJynldNhIEitT759O-PWyCEff353WZv9d9PwdOQDE8N_pHRgm2JVDGeagDRzygEqhSMwct5o_IWJWNQs6zllnNYGyaB8B9fu9UhFq2dutIS24JwERnlNUcy_RXGq8CGEmnctEX_Has3fXUHanBqBGPJW7cZ2sei5O64YkndCMvePAWaScyd3j9QGvYHrBsriecxk565wjU905OHyXBax_UupbPeCKivDYOWou-HESV_xMHJhFqLJKDiCT7g-33OgXpLPpkzNi4a66KCYXngkYeCUhoGV_W7sVYHDe7GPwz99V7-6YuFnCI4qAvZkUQuzUtDILzrP8PBvsQ6DikYWkqcp9ypAMdej3OTh0TNZdu1ROEYFQB5eNv6I5N-V1ifD9WO1ch5ijYJ1xX-4FbUGt9d6Y-voPzR-6LK5NKhLs9xhNVv26mUZ3HNH78-qoZxXTrHtiarrkE7qc60-oh9BH0XZKsSZcCLpxukX8ibFl4-adYsFhFRAzU-XZT_LdXsBmX3U4DRGC-maM4Bqretaj5DdtjQrPuSETVNO8cMb8rf4UdLBKdXYpp2uqtbIhu327BDCtSptQ5uiZjwlxkMzYFBWCx0W6KN9PPvXhrKpPUzZ_rN98JdSZ0AtyQbR0Oqos7jF5OXs2HDEtOa9EQora3hVGiaOpy-u-AruQ-5SDl0Yh_1n3O2sI0HMO1fMvPEwq6GbetLg3a_xHNvPV6gTZv4-vhVG7b53m526pvx86pYqRp1XKCzQwBTsVUSDAW4mIqtu1R2Yilnb0Ep6wHic0n710YRco4H_tkRr7nYd526WxXYe_neEdD2du-3m3eakZ1IKOdcqiSNvPXyNTDpAPl6U9ap7VsqzksfO3Xo06RwbMv9HcLf9hqWYS6HYRvVVLcShTF9yVMc-XWIZaS0tL_M4jcD7SJsFhLo5p021j68vYoZFcniqFKRwC7ChoBv2Vh4L-eu9o9qlLkUm56g5QhZWQr7OuLxtoKpfoNuRcsg6cNl2TPDl1Hd36s6LtpHneEDaBuRY-s-46pa_gdYWN5i_LHUO807ZE6OmvFBLXy9qY38L5zoXm1FUtP6Td1kXnsiYiluSz8PFelqmkqYALRc1byfvjtjnZBAyMQ9P4xTP3_mEaPKw18O3NYtANYTJjvPvzxuDi7h_slKryJqtvkUcUUd1g45Qibj-jIW9WZdEEWjmDFQ9PA5CB32CfLIq0BqPCuwpFSHiukQ9ZKIpkw0aaDDS25MtwTc3zieiFxfvLSh3Y0lZrcStogk8f4FZecIM7Gi2joGBKZEHg5l30C4JlrZhnxVoIW197XVDDcXl_tRUFaxKAjyRCqQRMcFbapH1pTdA5Hqbwwron6GPnfZbSQoZmSNUuVbphK4DMMDlaMi9nNmIc5ckcR93m0io7fQkcMzAMjwcmMdWqy9boEva8ZEagmRlFoF0ryTsWNCe839dYtZAYuvDzh2JlG6lkisH5Begrx2sK6krKg0hKuvl2oy-eL0iPHff8AxGyrXp8VKF_afikaZyepIavfyW4AXg_1eSh_CP_WVxIvUpCUwdamoowYP0bvTNn_5dwywWD4lgF6FiQygBPCs7A3mQRUsvTyja0sS2LI7yRMWKiJ98mLt3aLNWUCwc4T37Uprk3yQjwFWZXBLsb40sCy_pOwuBzRsabANLbQ9KBThoeLp4FTrCXAK8VdVgUvZyzW8cuOix_EuV32V0HTYQpfbOVlOriAvT2_u2p7QQD8NjgTwy2XEI6zoIXOiXCZJ1ijowCKdmck95nOr4C50_bOFhQTInt3FAlxaAnKRWpdZ5IQ5xDqCsIY4T5gMAbm5SmHmDbwvGTsC7Ugsd6yattg907pmpFF_S9oR6hxKoxV9QfWdVcpXBgvYAc8k0zia1RyCUChAr76AMwHSpmuqGobhBU0J0Cpz11WA9QCQJMNcIezw07Dj-cf-XHbrVxGuXnJy7D1HrKddj8naPuTiRXw4UreJo4yBYQJxu2u1NXZfWyqgVdNi5hyH8F6l2fkMUD4Zmesplmp-NGsCxWV4KCioZXtZit_bpViBeqGQ1GTzvmYCgftqrZ_lJRCAbYjkZ_jZKfnysErxpp5fBpJYgBIUMLaKo4X47edQdygqZGC-58DFO5PTeCRSDcILYUgddTLG4D4lXg2l4SFGdidct-WSNHQhbTpjZeZZ4cX-fgZ2MzjcMf60rNRvp_AkvEqfdXEmnbWhL0820szKWaSPaJXqyapAaW4L4CYJGaIS8q9o8sZNQaMcAOzBVBdFS84AhnnIJeNQHxyUiVhR966KXewj7qKgxP9_bIkRLp3CoWvN8YsJXpg2NjryJNgTeswBdxTJiNeYM1v15rRMDBkpkLB-MfuGRjBnPiNB_KpTMfHdPi_J1d3wyOYT3bk27BIl43Mpubmz-2kyyyCZko9C7QvELaEgGNpKDgMfv6viqHw3BpLvBcMIsLxaT1arAHagSMyPu5KDKuAfD93Xl1ydEnkkSN11zmTks7rk7S3oc3kMPNyKrjhzXFMShgpjHBmJvSBimZgBUG9R4VmjSEjffvw55PZakAzA4f0TfN2hEgFdH1ABZoqGDrJXFRmjZY9hlGREwZ5DzV61144OShZ4yIagF2Efd7T4JBcu_9NLFg74M_CNCIJdJRerdOUhk2i7v2jcVT-N19Uo3CB6oQ9YfOecRqcl9jbX-r1GjnpYjdzEtYuuce03XNLVH5R__WgUssTYvupvCcPa8C9ZASSUQKVnM0r3-dD52E2JEBON123Z69OkUfx9QXqgJirT2mfwlpbarZ5Fk9DgE9J5M960DjUdRi31iP-KC8TDLJpoMyCvKLYKVdrqFwDx2xJRTOhpN02TWpkqMGXUech3QUndyEORq_FVgY3Xl1RXd9XFKK9Bv403lPIqt0421IFazWA6UAB5La0nf1iPrbkF9x-4uUBnLrEV20mlXWNh8X5FqVErjmqhQoAZwON1F-wRBju_bS8JZDpSYnzE6_8_550b-d9ZXtY1FD5b0uuF-6sU0gjiZmR9NuSc5JN-g_M8IrU8wCeuBovKobuvmUh1v2PXjJJ5iG1sjs3U3UnoaMdKMaUiMGf_yZLRTZFaMGpFfynJfksYUETaQ58hpjG4hIoNEBkMiC41O0SlsqyBAJ2R249K9BByULup504LdwVdRkyhoDRulZ7pEHxZbU9jKMvjPq9bfvfzHqPnSXzzFuQpO_HOsJZlk0Z1f8FtPAFCwCCclpRdvXOursYEnTIcpYLx4mZrr0wWUsmsxCYZHbEXEdtwTm9tJEsOMcLzNic2C9FZgQuE56Hyh5cLTOsEA3C8eoZBhVfxpVExJTSFal63_1wMvymXdXbLiDlGHTAnnPhL5RtaD6aFprNVEiK56vd7cyao7P_g2pciVkJ6EpvjdYCKOI_9uQGZTrdU2HEM__5l_b6ejIXh1EzcttCdqUOb3dUNEGfdMCMJdIYfYttlVmEGALlXTnvy4kH-XgaiGZiKxAU0ZKvCysqbd8GtXbSyHQ5AS8qHx3pxR8_Mws6rV55O5uycGYYCYWTfeZ0-8UBEKFAnSWi8MvIilsurAmYj8r9etUOLZ9ah-lKjedmURU3jQfYFa7r_-dcTJbRipzY5cNUKE6hJkdn0i9s3mz-fT-j0LcKEGyLfij55zUkKFQrkwyj3X6f1X_YcTkxXoSOZ23_zLisQIecOSgaPTyIiKQr7G_cwnoUBLNgUH_GB66uirM5Q2hhBD8DIToJYybaSD8XwScGtp3PirfVmP2ZbkFdh1021Mx65u3lh5Lpy9NVfyZ0m4GWGFRwPjqL7AcEtoPGi-PqEh61NrXNlKwsT_IMc3_D1hOb1CAYaNX3QjGYfgncc3tSpz--ZJvq7eDGNj6Z63qudum-pm7Sfgu9eBcknlw_TKjp67Ttnzt6UECZD47DFAgcAAnCs9nEthOU6B-J9hLYaLy2z3vGFyBPfaEH-B-YHRlriIaM5vCTHEmV3gY2iJxFA1DD7VDj3vx6Qw9uMLbcfl4eVXQRNs-HiW-ML6yUv0_zxIspC8HTX1l62vMi2_ofue9lDtjKfxVV-2inRhjae1fhViHb7DcwArnw2XaZYlTC0Oe_neA2pY4DuTAAuMikfQbaf50sU-gszAD_Xmmh6WvDHr4FdrTtf8ew3I1YCmP5lguc_w0QuC-fAAsVvz7bsIcSMFSFWGB71H9dAGSQ53bmboqUrRL-kUjLEF2hF9FqnVGmsx6lH9eMn9tWCApwm1zQNNMM5c.a1VctJwTCcJQ9LC1xGoyKn_2743jHhGpU5G8ucFR2ts'; + + /** + * @var ProviderService + */ + private $provider; + + /** + * @var tokenService + */ + private $tokenService; + + public function setUp(): void { + parent::setUp(); + $this->tokenService = \OC::$server->get(TokenService::class); + $this->access_secret = \Base64Url\Base64Url::encode('JQ17C99A-DAF8-4E27-FBW4-GV23B043C993'); + } + + public function testDecodeAndValidSignature() { + $testtoken = self::EXPIRED_TOKEN; + + $serializerManager = new \Jose\Component\Signature\Serializer\JWSSerializerManager([ + new \Jose\Component\Signature\Serializer\CompactSerializer() + ]); + + $decodedToken = $this->tokenService->decryptToken($testtoken, $this->access_secret); + $this->tokenService->verifySignature($decodedToken, $this->access_secret); + $claims = $this->tokenService->decode($decodedToken); + $this->assertNotNull($claims->exp); + $this->assertNotNull($claims->aud); + } + + public function decryptDecodeAndValidate(string $testtoken) { + $serializerManager = new \Jose\Component\Signature\Serializer\JWSSerializerManager([ + new \Jose\Component\Signature\Serializer\CompactSerializer() + ]); + + $decodedToken = $this->tokenService->decryptToken($testtoken, $this->access_secret); + $this->tokenService->verifySignature($decodedToken, $this->access_secret); + $claims = $this->tokenService->decode($decodedToken); + $this->assertNotNull($claims->exp); + $this->assertNotNull($claims->aud); + return $claims; + } + + public function testDecryptDecodeAndValidSignature1() { + //this is not a good unittest style: $this->expectNotToPerformAssertions(); + $claims = $this->decryptDecodeAndValidate(self::ENCRPYT1_SIGN_TOKEN); + $this->assertEquals('10TESTSAM30000004901VOLKERKRIEGEL0000000', $claims->{'urn:telekom.com:client_id'}); + } + + public function testDecryptDecodeAndValidSignature2() { + //this is not a good unittest style: $this->expectNotToPerformAssertions(); + $claims = $this->decryptDecodeAndValidate(self::ENCRPYT2_SIGN_TOKEN); + } + + public function testDecodeAndInvalidSignature() { + $this->expectException(SignatureException::class); + $testtoken = self::INVALID_SIGN_TOKEN; + + $serializerManager = new \Jose\Component\Signature\Serializer\JWSSerializerManager([ + new \Jose\Component\Signature\Serializer\CompactSerializer() + ]); + + $decodedToken = $this->tokenService->decryptToken($testtoken, $this->access_secret); + $this->tokenService->verifySignature($decodedToken, $this->access_secret); + } +} diff --git a/tests/unit/MagentaCloud/BearerTokenTestCase.php b/tests/unit/MagentaCloud/BearerTokenTestCase.php new file mode 100644 index 00000000..16a6615f --- /dev/null +++ b/tests/unit/MagentaCloud/BearerTokenTestCase.php @@ -0,0 +1,225 @@ +realExampleClaims; + } + + /** + * Test bearer secret + */ + public function getTestBearerSecret() { + return \Base64Url\Base64Url::encode('JQ17C99A-DAF8-4E27-FBW4-GV23B043C993'); + } + + + public function setUp(): void { + parent::setUp(); + + $this->app = new App(Application::APP_ID); + + $this->tokenService = $this->app->getContainer()->get(TokenService::class); + $this->realExampleClaims = [ + 'iss' => 'sts00.idm.ver.sul.t-online.de', + 'urn:telekom.com:idm:at:subjectType' => [ + 'format' => 'urn:com:telekom:idm:1.0:nameid-format:anid', + 'realm' => 'ver.sul.t-online.de' + ], + 'acr' => 'urn:telekom:names:idm:THO:1.0:ac:classes:pwd', + 'sub' => '1200490100000000100XXXXX', + 'iat' => time(), + 'nbf' => time(), + 'exp' => time() + 7200, + 'urn:telekom.com:idm:at:authNStatements' => [ + 'urn:telekom:names:idm:THO:1.0:ac:classes:pwd' => [ + 'authenticatingAuthority' => null, + 'authNInstant' => time() ] + ], + 'aud' => ['http://auth.magentacloud.de'], + 'jti' => 'STS-1e22a06f-790c-40fb-ad1d-6de2ddcf2431', + 'urn:telekom.com:idm:at:attributes' => [ + [ 'name' => 'client_id', + 'nameFormat' => 'urn:com:telekom:idm:1.0:attrname-format:field', + 'value' => '10TVL0SAM30000004901NEXTMAGENTACLOUDTEST'], + [ 'name' => 'displayname', + 'nameFormat' => 'urn:com:telekom:idm:1.0:attrname-format:field', + 'value' => 'nmc01@ver.sul.t-online.de'], + [ 'name' => 'email', + 'nameFormat' => 'urn:com:telekom:idm:1.0:attrname-format:field', + 'value' => 'nmc01@ver.sul.t-online.de'], + [ 'name' => 'anid', + 'nameFormat' => 'urn:com:telekom:idm:1.0:attrname-format:field', + 'value' => '1200490100000000100XXXXX'], + [ 'name' => 'd556', + 'nameFormat' => 'urn:com:telekom:idm:1.0:attrname-format:field', + 'value' => '0'], + [ 'name' => 'domt', + 'nameFormat' => 'urn:com:telekom:idm:1.0:attrname-format:field', + 'value' => 'ver.sul.t-online.de'], + [ 'name' => 'f048', + 'nameFormat' => 'urn:com:telekom:idm:1.0:attrname-format:field', + 'value' => '1'], + [ 'name' => 'f049', + 'nameFormat' => 'urn:com:telekom:idm:1.0:attrname-format:field', + 'value' => '1'], + [ 'name' => 'f051', + 'nameFormat' => 'urn:com:telekom:idm:1.0:attrname-format:field', + 'value' => '0'], + [ 'name' => 'f460', + 'nameFormat' => 'urn:com:telekom:idm:1.0:attrname-format:field', + 'value' => '0'], + [ 'name' => 'f467', + 'nameFormat' => 'urn:com:telekom:idm:1.0:attrname-format:field', + 'value' => '0'], + [ 'name' => 'f468', + 'nameFormat' => 'urn:com:telekom:idm:1.0:attrname-format:field', + 'value' => '0'], + [ 'name' => 'f469', + 'nameFormat' => 'urn:com:telekom:idm:1.0:attrname-format:field', + 'value' => '0'], + [ 'name' => 'f471', + 'nameFormat' => 'urn:com:telekom:idm:1.0:attrname-format:field', + 'value' => '0'], + [ 'name' => 'f556', + 'nameFormat' => 'urn:com:telekom:idm:1.0:attrname-format:field', + 'value' => '1'], + [ 'name' => 'f734', + 'nameFormat' => 'urn:com:telekom:idm:1.0:attrname-format:field', + 'value' => '0'], + [ 'name' => 'mainEmail', + 'nameFormat' => 'urn:com:telekom:idm:1.0:attrname-format:field', + 'value' => 'nmc01@ver.sul.t-online.de'], + [ 'name' => 's556', + 'nameFormat' => 'urn:com:telekom:idm:1.0:attrname-format:field', + 'value' => '0'], + [ 'name' => 'usta', + 'nameFormat' => 'urn:com:telekom:idm:1.0:attrname-format:field', + 'value' => '1']], + 'urn:telekom.com:idm:at:version' => '1.0']; + } + + protected function signToken(array $claims, string $signKey, bool $invalidate = false) : JWS { + // The algorithm manager with the HS256 algorithm. + $algorithmManager = new AlgorithmManager([ + new HS256(), + ]); + + if (!$invalidate) { + $jwk = new JWK([ + 'kty' => 'oct', + 'k' => $signKey]); + } else { + // use a different key for an invalid signature + $jwk = new JWK([ + 'kty' => 'oct', + 'k' => 'BnWHlEdffC0hfKSxrh01g7/M3djHIiOU6jNwJChYWP8=']); + } + // We instantiate our JWS Builder. + $jwsBuilder = new JWSBuilder($algorithmManager); + + $jws = $jwsBuilder->create() // We want to create a new JWS + ->withPayload(json_encode($claims)) // We set the payload + ->addSignature($jwk, ['alg' => 'HS256']) // We add a signature with a simple protected header + ->build(); + + return $jws; + } + + protected function setupSignedToken(array $claims, string $signKey) { + $serializer = new \Jose\Component\Signature\Serializer\CompactSerializer(); + return $serializer->serialize($this->signToken($claims, $signKey), 0); + } + + protected function setupEncryptedToken(JWS $token, string $decryptKey) { + // The key encryption algorithm manager with the A256KW algorithm. + $keyEncryptionAlgorithmManager = new AlgorithmManager([ + new PBES2HS512A256KW(), + new RSAOAEP256(), + new ECDHESA256KW() + ]); + // The content encryption algorithm manager with the A256CBC-HS256 algorithm. + $contentEncryptionAlgorithmManager = new AlgorithmManager([ + new A256CBCHS512(), + ]); + // The compression method manager with the DEF (Deflate) method. + $compressionMethodManager = new CompressionMethodManager([ + new Deflate(), + ]); + $signSerializer = new \Jose\Component\Signature\Serializer\CompactSerializer(); + + $jwk = new JWK([ + 'kty' => 'oct', + 'k' => $decryptKey]); + + // We instantiate our JWE Builder. + $jweBuilder = new JWEBuilder( + $keyEncryptionAlgorithmManager, + $contentEncryptionAlgorithmManager, + $compressionMethodManager + ); + + $jwe = $jweBuilder + ->create() // We want to create a new JWE + ->withPayload($signSerializer->serialize($token, 0)) // We set the payload + ->withSharedProtectedHeader([ + 'alg' => 'PBES2-HS512+A256KW', // Key Encryption Algorithm + 'enc' => 'A256CBC-HS512', // Content Encryption Algorithm + 'zip' => 'DEF' // We enable the compression (just for the example). + ]) + ->addRecipient($jwk) + ->build(); // We build it + + $encryptionSerializer = new \Jose\Component\Encryption\Serializer\CompactSerializer(); // The serializer + return $encryptionSerializer->serialize($jwe, 0); + } + + + protected function setupSignEncryptToken(array $claims, string $secret, bool $invalidate = false) { + return $this->setupEncryptedToken($this->signToken($claims, $secret, $invalidate), $secret); + } +} diff --git a/tests/unit/MagentaCloud/HeaderBearerTokenTest.php b/tests/unit/MagentaCloud/HeaderBearerTokenTest.php new file mode 100644 index 00000000..842b9466 --- /dev/null +++ b/tests/unit/MagentaCloud/HeaderBearerTokenTest.php @@ -0,0 +1,236 @@ + + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +declare(strict_types=1); + +use OCA\UserOIDC\AppInfo\Application; +use OCA\UserOIDC\BaseTest\BearerTokenTestCase; + +use OCA\UserOIDC\Db\Provider; +use OCA\UserOIDC\Db\ProviderMapper; +use OCA\UserOIDC\Db\UserMapper; +use OCA\UserOIDC\MagentaBearer\MBackend; +use OCA\UserOIDC\MagentaBearer\TokenService; +use OCA\UserOIDC\Service\DiscoveryService; +use OCA\UserOIDC\Service\ProviderService; + +use OCA\UserOIDC\Service\ProvisioningEventService; +use OCP\EventDispatcher\IEventDispatcher; + +use OCP\IConfig; + +//use OCA\UserOIDC\Db\User; +use OCP\IRequest; +use OCP\ISession; +use OCP\IURLGenerator; +use OCP\IUser; +use OCP\IUserManager; + +use OCP\Security\ICrypto; +use Psr\Log\LoggerInterface; + +class HeaderBearerTokenTest extends BearerTokenTestCase { + + /** + * @var ProviderService + */ + private $provider; + + /** + * @var MBackend + */ + private $backend; + + /** + * @var IConfig; + */ + private $config; + + public function setUp(): void { + parent::setUp(); + + $app = new \OCP\AppFramework\App(Application::APP_ID); + $this->requestMock = $this->createMock(IRequest::class); + + $this->config = $this->createMock(IConfig::class); + $this->config->expects(self::any()) + ->method('getAppValue') + ->willReturnMap([ + [Application::APP_ID, 'provider-2-' . ProviderService::SETTING_MAPPING_UID, 'sub', 'uid'], + [Application::APP_ID, 'provider-2-' . ProviderService::SETTING_MAPPING_DISPLAYNAME, 'urn:telekom.com:displayname', 'dn'], + [Application::APP_ID, 'provider-2-' . ProviderService::SETTING_MAPPING_EMAIL, 'urn:telekom.com:mainEmail', 'mail'], + [Application::APP_ID, 'provider-2-' . ProviderService::SETTING_MAPPING_QUOTA, 'quota', '1g'], + [Application::APP_ID, 'provider-2-' . ProviderService::SETTING_UNIQUE_UID, '0', '0'], + ]); + + $crypto = $app->getContainer()->get(ICrypto::class); + $this->b64BearerToken = $this->getTestBearerSecret(); + $encryptedB64BearerToken = $crypto->encrypt($this->getTestBearerSecret()); + + $this->providerMapper = $this->createMock(ProviderMapper::class); + $provider1 = $this->getMockBuilder(Provider::class) + ->addMethods(['getId', 'getIdentifier', 'getClientId', 'getClientSecret', + 'getBearerSecret'])->getMock(); + $provider1->expects(self::any())->method('getId')->willReturn(1); + $provider1->expects(self::any())->method('getIdentifier')->willReturn('Fraesbook'); + $provider1->expects(self::any())->method('getClientId')->willReturn('FraesRein1'); + $provider1->expects(self::any())->method('getClientSecret')->willReturn('client****'); + $provider1->expects(self::any())->method('getBearerSecret')->willReturn('xx***'); + + $provider2 = $this->getMockBuilder(Provider::class) + ->addMethods(['getId', 'getIdentifier', 'getClientId', 'getClientSecret', + 'getBearerSecret', 'getDiscoveryEndpoint'])->getMock(); + $provider2->expects(self::any())->method('getId')->willReturn(2); + $provider2->expects(self::any())->method('getIdentifier')->willReturn('Telekom'); + $provider2->expects(self::any())->method('getClientId')->willReturn('10TVL0SAM30000004901NEXTMAGENTACLOUDTEST'); + $provider2->expects(self::any())->method('getClientSecret')->willReturn('client****'); + $provider2->expects(self::any())->method('getBearerSecret')->willReturn($encryptedB64BearerToken); + $provider2->expects(self::any())->method('getDiscoveryEndpoint')->willReturn('https://accounts.login00.idm.ver.sul.t-online.de/.well-known/openid-configuration'); + + $this->providerMapper->expects(self::any()) + ->method('getProviders') + ->willReturn([ $provider1, $provider2 ]); + + $this->providerService = $this->createMock(ProviderService::class); + $this->providerService->expects($this->any()) + ->method('getSetting') + ->with($this->anything(), $this->logicalOr($this->equalTo(ProviderService::SETTING_CHECK_BEARER), + $this->equalTo(ProviderService::SETTING_MAPPING_UID))) + ->willReturnCallback(function ($id, $field, $default) :string { + if ($field === ProviderService::SETTING_MAPPING_UID) { + return 'sub'; + } elseif ($field === ProviderService::SETTING_CHECK_BEARER) { + return '1'; + } else { + return ''; + } + }); + + + $user = $this->createMock(IUser::class); + $user->expects($this->any()) + ->method('getUID') + ->willReturn('1200490100000000100XXXXX'); + $user->expects($this->any()) + ->method('getDisplayName') + ->willReturn('nmc01'); + $user->expects($this->any()) + ->method('getEMailAddress') + ->willReturn('nmc01@ver.sul.t-online.de'); + + $userManager = $this->createMock(IUserManager::class); + $userManager->expects($this->any()) + ->method('get') + ->willReturn($user); + + $provisioningService = $this->createMock(ProvisioningEventService::class); + $provisioningService->expects($this->any()) + ->method('provisionUser') + ->willReturn($user); + + $this->backend = new MBackend($app->getContainer()->get(IConfig::class), + $app->getContainer()->get(UserMapper::class), + $app->getContainer()->get(LoggerInterface::class), + $this->requestMock, + $app->getContainer()->get(ISession::class), + $app->getContainer()->get(IURLGenerator::class), + $app->getContainer()->get(IEventDispatcher::class), + $app->getContainer()->get(DiscoveryService::class), + $this->providerMapper, + $this->providerService, + $userManager, + $crypto, + $app->getContainer()->get(TokenService::class), + $provisioningService); + } + + public function testValidSignature() { + $testtoken = $this->setupSignedToken($this->getRealExampleClaims(), $this->b64BearerToken); + $this->requestMock->expects($this->any()) + ->method('getHeader') + ->with($this->equalTo(Application::OIDC_API_REQ_HEADER)) + ->willReturn('Bearer ' . $testtoken); + + $this->assertTrue($this->backend->isSessionActive()); + $this->assertEquals('1200490100000000100XXXXX', $this->backend->getCurrentUserId()); + } + + public function testInvalidSignature() { + $testtoken = $this->setupSignedToken($this->getRealExampleClaims(), $this->b64BearerToken); + $invalidSignToken = mb_substr($testtoken, 0, -1); // shorten sign to invalidate + $this->requestMock->expects($this->any()) + ->method('getHeader') + ->with($this->equalTo(Application::OIDC_API_REQ_HEADER)) + ->willReturn('Bearer ' . $invalidSignToken); + + $this->assertTrue($this->backend->isSessionActive()); + $this->assertEquals('', $this->backend->getCurrentUserId()); + } + + public function testEncryptedValidSignature() { + $testtoken = $this->setupSignEncryptToken($this->getRealExampleClaims(), $this->b64BearerToken); + $this->requestMock->expects($this->any()) + ->method('getHeader') + ->with($this->equalTo(Application::OIDC_API_REQ_HEADER)) + ->willReturn('Bearer ' . $testtoken); + + $this->assertTrue($this->backend->isSessionActive()); + $this->assertEquals('1200490100000000100XXXXX', $this->backend->getCurrentUserId()); + } + + public function testEncryptedInvalidSignature() { + $invalidEncToken = $this->setupSignEncryptToken($this->getRealExampleClaims(), + $this->b64BearerToken, true); + $this->requestMock->expects($this->any()) + ->method('getHeader') + ->with($this->equalTo(Application::OIDC_API_REQ_HEADER)) + ->willReturn('Bearer ' . $invalidEncToken); + + $this->assertTrue($this->backend->isSessionActive()); + $this->assertEquals('', $this->backend->getCurrentUserId()); + } + + public const ENCRPYT1_SIGN_TOKEN = 'eyJwMnMiOiI4VzhYY21iaHJPSSIsInAyYyI6MTAwMCwiY3R5IjoiSldUIiwiZW5jIjoiQTI1NkNCQy1IUzUxMiIsImFsZyI6IlBCRVMyLUhTNTEyK0EyNTZLVyJ9.5bA_ctLbQOnMojJW3MPo83AIvCAu3MpmaaD7j2GzqBv5_-D4w69ONqcPEsc6LYMG9B-rw3HDXng4Mqye4KqpW70ECpf9HXV6.6zl4Zqp4wbcO_AqqmpA3sQ.y7dHcwxXveYkuh4UaqHhE4nvP_avZsxaf7aAbnJdDHHKbBKvEKKqHkPg593i14ypWuRHd2i9Opsuyppfxx9Hw7C7N7LJ8UCTYMihHqlJkHecB08xgJ3ciE0L2Qtvg9hfxQbHNVV4p1_KL3ubAXt9ovwDCOJvN6PXyixUDtYYF1D_Km7Ze1ptUNbwS2H4vf-MKHwwrm5uhTvXOppGNO-0tYnIMOZ8BkiTtrrlO6IQbRcC4EMw74PzbFsQXY9u1xsNZ9IOrzbBl_EyPBLr5ool1BGlvNog4XFsHLgxUa5cjIcZVRMgZSLWdToTiXYFAWdO6fbQrRWT8ERRDWjiDxJEaPlfI_61G5NzJN2NKnSAY7fR8i3Rfs_JoF1TtpR5dGU28Lk1vcLjKYBLqp2hjW97QsANVgmalkkJMUpiAvNN48ZSCK9T3vTfiH7unFRNWvTKvZXyHIkYQPZ0-b3Z9s5oLMx93Snvcq9jQVKA1dWU_bEUIOnwP65ADU_FIkYB8gsZXp5Za3HrK63u03Lij6rwkJpEPbwcnxhBkMhtKOOwQVZm1ZBf_lVyn39MFXmLN_gDD052vFpxl1NnG0KEg8XJQ_usE9e64q7W6IG4gRm9NYG6rdeik6Dm45K8fA4oUiyjdgHjveR6GW8uXQR-tWXf3IC-_2jws2PJ31acdoEbDU30XlVeCqENW-ylPJ10rP28XxboQVJMRrzMiEzu39IH3c02czHh81U09TREVsO2S8CCQcahboaplDg9kpr1UZpsRrjg40bEtdm2cKubTbczGiXiF7sI0qE-kHm0aiK5c6mO8fHETMCmvh2vhxcYo_T6q7VklbwiZVbn47z-oriEDyPlLrB_PzYR6fNRbtObttj0CHRgf-NI69RU2pAGxujSi2lEhNkG-CAFNfASKm8uSUCg8UPr7v38c5vr4IuYC1gYjxgebXIh0EFX4G8jZM6ljPSzmMFDyErWJQ5OrtJjuKrUa96Yp3oOZTemtCwc--mrDXmpwVlaBMCuuJDz6zucxwSeVK0mP0t56zHeK59jxz0OfV62TrcVeZaLqSl3o-pVsY5KrLxL1qf2QIry-uy_c1zi9AuZnSbH3t1RvmyG5-QIh5WSPOLXG9ivuHKAdQTvBnchXWfkUVkoPYuPFyBydlPAhpRQyBLHboqdT6lIdoQ5lBRI8vsGb9wQVSQx08hbpEFOPMe-SJqzjZp36sUurJrgj_ethbIWkTSe_HPkcvBv8X0kyvhnyTKYJoroE5HDM0dtgFW8xK8NmOZOuREzJW5fpqzJML8iY0p1IX3bvGrCeVMEJtM0T6KSJFdPHBAzkWNNMBUc2jhuxa6B2cSaMz60bwSCw8n5NWz8wkXUFJJkHKEnK8tFbtOQXHeGG48k7Wl6kgrQkAFAHZqQt9gRDdmGcYAYHVK7cESjABV9LWQIQYy0eyveU0sWE5sYXKCwsk8rLiKt5GmZlRQ0rOltuFXRTu_EZYuqR0DCRXrjQWVN1zLTy0LMqAvDR-PJcFtekbT9CXLEW6M6GHzJhYfNyMc_cPitG8QwS5EWGzJjQIiNsJBRyV7cPlHeMhKzDtEk3DR3l-qQJa9-54RQB-kStJjB0AAZ21ku7eBS6orT0lljj935eghlHxAzyr1fvlDjIpHc--ob_7DOPc9sBGqcwdYoZ28zD1d02rpJujOwTe4zgll4vffJ_aFP8hm19pmroCwFsZPWIK6GN_cllJaxnllkJ_9c-7eBj1rKkNX0DLyNwKoMYttugeQFWAxaaqWhoOpQXnRHaVt5hTzoexi5C2j_aVBUAzyMPZtvuYgY1uc8zeKt5X8rAy3Y7WqYeOy8Q6IezVyTE6p0kzYgzUT1Vg2XZEr7dBgNkv8ySfYQNG5d8_PtvBHX-SOy25rtes7oUHHgZx0AkpomhNGSwfrW4dyIWCa6j5qUexqs3TPip_FAJwdW38OnyfPQ5SHLTt8D6OCOLN70MdbPpeoFkGnx1oj1Xjx_UW8mtueWAkxidv6Lamf_D5j8sJvkksne8Nos2YvGNkaGZwQK8YfjvPP-VVdukLMqoloovOuvgxLVLSvnDYcRRjfwAdiKwFNGdMbdV5LwfAzVAlncyWPJso3Lk9fPYd88YW8e6o7xiboiushcbDQU0ZN_Zh9YGk-8R4VnvAuI3yWxLrBB8NFUwKYkNBupVWrxRHJbJEebsLv9r_PZstBHHfMFpcQYX05NYfQiezhQ9l-aseC9Ay4FLbcxyXkIiPEBfiwZESqQbYoL3OeBQYzsV8AFe4GVdUUwPCuPjKR52UlkPiUJthxGkLFfcEPbqfX_lByN5YZRMSruOt6yKysbBIw0gcC6n7wuA_URaFNSPfyHe6nqAtveh1YjZpwZszAERyk2ziFXKFYFppdjMPvxF37uWoH_BEpv9Bs7yaxPRK7pfniS105RBsDFS093-3sUYM6W7IrmPfKAe71OtdWtQQqQKOAX3WGFShCIKyz-aOJWJPRG35Q2DOGu0nehFetGVsSnt-ehmru-Zuv4IanlF0_3SjQ7l7l6gg3Sfyy6sN8SVvxTtw4jLkaAM6cpmVMQVP8uQeJ9IFSHyq1kFceQcguh5tbwMknJzcMNzmZ9zEOG4ifyk9zmeulX9Rtf3lIXIOU-1lEs5bVm42eg1IKpxaY8PeTrT4qvPIyVkOprpKGIAcGyD0tP11vvDCvbltEWBo72gdbtD9tUdUPK0XRD_TgEPy2YU6I6BsKBStd40Fk6nOCGrq-mjYmH6OK3JUF3EVV7E0fEg7BgnYPLxcla0l7H6LpY4sqmFwapDqknjhgbqK0dyZDGWEPJ7Ph_5K6BazKuV_1bf6ZFOuRbm72cmT6vAJM8BhihAdTQt92QbTPikjLS2he5AfSV1ieDgLT26dsLNuLkyExyBqUGkrFoojh4fvW9K-wDKtgvQwCYZYABlC9JY72gtpaV2OV2UrB4aXuJX6n1NNXaSzpPqSupAIGK3Gaw39yrzBgBjTYAe0nnRu10BO7-gNRvKGIMCBTa7c-c0o0eNGe81xv1w8_-6auoKZYS8rzXQ8T6XLUjC1mRZD_cGxnfEra2G96-Cqm9WZO5hVX5fpXZhybz7neyGKlUKZG_An-jGmc9j_m03-5EEOfKAXJNlmOT1IynNVudtzTTrh8O5Dp4nD6fKsyOrg-6yRePCiP4FeItLCH6uVLWWdR65WZzklQuPrBELg58OzIsaBuKCKNjODSA4dGVE4JurhmgnnSmaqz2z6s0Zd1gXERebk_1WEmkWd03jO7dXMk3hOM9zV9BrZALOAll3GsvCqgh9kfouX-3ZNSNO7Lah6ecLD_zK228ap6r1MeY2VK-PiHUEnH58jh2HuutZB1Ge0GVvsYBue_r0FjGVNh6a9XYwIaf1Um2Z81WgHpWHZ-pLVZlkbN1vxgqLNBpjDy6UWpPJzOUv829C31WID92Wa6XPsfq6sIvYRUEx03DE2sbXKjUNX2t8InuLCgC6_wmq-GOoZ5vLKt1KHMicJUM9YFZYYKd-7c25X6DLplAnP-Hw_URgRINQdD8kOWzZ_70SiEq0om6OWniva6czSiwrcml_UBDA5Xr8pNtSWqtNbHh1LJzJenVIZl9gPLRs_o-OxB9gylqk7HwQZgKPCbvccYyh162Iy_Kg2j07hnDuoiUyZ93o9x_3Asf8Ms_E_ov6CqpFgKICX6rEE0oOgFO_pKvwtNH8fF-uNkVGKQwNYX6S33SlWh_pULYLSl-YrXVP0hLLmGlunnOGXUIVTXjQcc6AheR8Dmg9jDIefpgHMH6hegAnoZL0_AVuG-yd9LSRSh2qH_rABtJHTOx-0qQ6yYnrzHcMuvatCwDuIePK5DcxBj8KhKq9F4y_i5Ym9drIskRvAzwygZuIIuT3uyXl5nI6YE_jd6F9w4PZ7SkOs9JvfCnt-Wm7UKI6dxLnCRoTarUwop1wDZ77-rRwYoo5zYwF73BragZBZuWNB8ImLlktcAyCBF6P2_F2j4jvnQNLShYZ5HsJKsJNljjIiKYEAeJ2ScT2tjPSfMsdssWQPPByDgwnWtGpx2z6JTFGLUHaj_WbQe3hciyl7jGM2U1JrA610-Jb0X_OiGslZuYBasmPkEXFbDhZy_QZ4Pjs4RddBqrS15-H4FphxsB4knYHtfAzvJno80QmR69zvIfBSIScEx48foHjbeObNpW51IGbg2-yhssa9YtLpjpafnc1-yJ5xj6tJWYZcpskhgADRQvoxF8Xa7BE8o0D9-I7r2Yp0wMfYrbX8NCTBUWczxBZt2juBIERwgjHZzphIGVXNJ6ARm9F12UMf2OwUEk56J6SiSfB1ho7EDdARwj6Nfkm1LjpYLDhii-IRVJUN8tphw6SHVJBbMucYsXsL8viafUwdh7MbBwLKOPgZM4H9BqWFePgEglf7nzrALd2WV40tOai-sm4e4UCKh9bQ1qNw-uHQLP81NNzMA.bMWJdVmxAg2RZm7NE9wTz4H4LwjDb21tFV8hGtTKGFI'; + + public function testEncryptedRealSignature1() { + $this->requestMock->expects($this->any()) + ->method('getHeader') + ->with($this->equalTo(Application::OIDC_API_REQ_HEADER)) + ->willReturn('Bearer ' . self::ENCRPYT1_SIGN_TOKEN); + + $this->assertTrue($this->backend->isSessionActive()); + $this->assertEquals('', $this->backend->getCurrentUserId()); + } + + public const ENCRPYT2_SIGN_TOKEN = 'eyJwMnMiOiJWSTRQS0ZCeVRyUSIsInAyYyI6MTAwMCwiY3R5IjoiSldUIiwiZW5jIjoiQTI1NkNCQy1IUzUxMiIsImFsZyI6IlBCRVMyLUhTNTEyK0EyNTZLVyJ9.YQlaJwr-og6DNQhCkszfsts2z2NLuWsP5czCbMQdyhqjBuhutAvdZlqkFD6el4OeupoXXkTb7XkNyNZVq5S-rfUNGptv27J9.mNCv0KWUDXJoVLxkyppGqg.BdjbqWD14kmuJfLhVMWInuDjTh5O_qxjF9n9rD3viGH1WXZvQtiPT9U2ZKN17jLyzhLXtmvPP_bGZZPrGc5p68WoAteCSxzwJRGcF0hzO6gBhgvx_CcddG0jWcfaXgsFbOeLBpZMKR3w8_6I6shxDcrm0vwL_xeSOd_m4me_VVPQGkaOPKrMy4Ywlh-H7DTquI4NgC1vqt-B7Mpowj82PifFSgEDVrFPkNsustl4PE_2IiL5s_YAPme-OKq50wXzjcjsKAWEbgfsTk5iPoEJNaNWPyWUKiQ8Zp3w6qQgsiY7EGKB5D_-cgbkpq7GmASTiV0FbWHlKleQmHlZ0yJe-WMn0Ai_feVrNwsDM1X5QJ0YMyk5otef-s_64vnLCyo4VbLexO3d67dUqut03xdb9c2SLrupLzpONAJ-nNJ2vNbfr2EBZiSHYjttsmRXlAXgRhiJZIdUGDxBJO-ydEaR22VtPK8pdX9s2Sv8t609xeNQA9hjxCT6IRtEv7vJ0sODV-LSJetO3RKYdBOzNUUvz5VHDE6ogLWNF5blvQ8JoImJd8XP4rNmasassb1NHOPFr4lO7r4ZIn4vmb_idBjzWO2940o48vO5MoRT9gN9rUZDhTwK2enuKdek10PmsVIII5Q18DwvDZhRfM1ZbqZRdkKpnkVb-nWqXChHcSgFcR-TXZGmh3WaH6OJWKpckBAoQ1OHZDl2h_lIfCJ7-eOHR2i3tpXEp6URi31iABcsUZniv8hxB1XYORu9Bl63BQ_t6ns3L-wlMb-LAcvk_sruyObIAuhiZzCyJGxaugje0znGMd3vSXi4U-oqnuGKlKu_1-o7-qB-f1Pkfl6UCk5mS6Vnq-P78FN0iIGaeT8FwsrX-uAFpO8HH4YYEeE8yTi0CQShXVYPiisAQIQFg6QBjy5zEXUZnMBfG-iQ4lfxBJg2sGZ7-HAZpYB2RXDVXAUi4fqI8A1RdHpQofqFGyQZtfVPviOhfNw9Xx79GXb7Cw7viaHFFeyocbyk-55bqjRKpWPP758oxsmP7LZn7yVbMRciCiGDB0LNA1_vJ-7qi9oIUFGdoEW0r3y9I8Su3TH2H2P7HjVaIojOwY4z5_EuADg3lzoSACPvR_I7_r5zMqm7g89HDOo7b-_wh46JVpORbCemQwvJQehN6MUJTbBv_rLKCJ_wjNNMF9sa29yUvoUmEFvlLLy2e2p_r-4AnfGP5P1givxxh12pS_c64XZ1SLqaALTARRwkv1HCnufTNmit80-5rRghgAANf4KXcppXDoMqKW-mrI1Q_ckrkVb7vJuEHaPB1cka5MLIpQ9dFz2iwAEZcFDXXpx2u_ySSDSzRItgazuSOk7DMJzTER_aMTOP2IwzVPoGK8K3RT7wS0lNGfalepX-BAcAbZz4md2PAgHPcfKt1czhdBO5DO9mhKLSSHNA2cc4MmE4_3Ir3BfQCL7mQExvy5mESVr05eTIvLBAzae6SimwzkAUz3o6sxU0neTfxyM47zwQYutOvyC5MCHcA00HdLcyRG9PaE3Bsu5n1WJpIY8i217eFvBZXTIBM-b9vS2_lfC_nNC9DB4N33B2DFEkH02uk9L8vOY90vunGKX-qLXahFOWV_WrFxi_jKzav1FIGV0FcK8QPU8UC9tF9cbxKE1DyLu_G1I9XHP8KO7y9bKOGNv1sRDSUiGZX1_COPM6cifpJsEhOLsucmGsybKg2C77cXhuou9OSen89Devr2ZzWtSZOg1HQdAJuFVkQhjAKcygW49mKqvXsUytRkWEN1mOPsuIJgmt3t4-bxvxeH9qITjy7gR8KYCY5sgdeaIhiEmc2hVp1cBo_HMQNo1E1ew0l8K5X1gavEbUd3RCcRBEtsekwTsfGFoQ6rivH_F5PwAlhMde9jN-I3fnPZMlPnTQEBpb3RdcPV8YNJ7RzRVbQJktdDqb_be1L3BYzKuK8hnv4aEu4Y0wYLRkBxYNIW70X06bIeyCC7B07xn5yLrUaC0MS4UxO9gSPEdauj1OBP7Z_va7zNIbOr4CI68QLfUwtoWpYLPag1exLADeQO3Cdd1qX9LU2trhNVNsw_NapqVkguAI3A3YTuaCQpt68kKGhsugiJ7DsxHuWoNzou4hejBQAvJ1Lm-N38DFKB47gDrwraafpRAezpCyclpaQeYbMK_rz12YCbl35PkFqDefL7B4EESJyk_Wzqpl6Y3AU81rrXK2aVaO0iuVuunWc492tullX_TQ4rtcX_URyZBKz9eF6dxwMJM5UNTtnz7uq-oOmxL3o80XSLpSbfHM4p9elkZGsXfsgpPj0DQJ7EAneLGRqncdLC-6d_ry2E5HwtcC8iWS51CFttDoVyatDDdEWOB7WxD0wy63uc8XK58PPc_ped8W53bid3jB2E5Bg0_c63KQ83U7fezzMtFhUzLIc83FzsG9D4hAPGvZowj3IOAh-E1FlvjvHThse_iH2lIoA1sC9WHpUFx3RkalAaN76fAWP-3xO-bckk9AR3XX1pPxYnx0kOq0a4GR9G7y_ylBt6zGZ0E8TUg8VHS5i834V_rh15R3o8pHncq8b7kwAA--EWCuiLP8B7gTgMqS58r9G89PfZa7u9Wf4NkjoBvZbKzfbnZmPzXkuSLPyC4VBcAp9hZSzdTTd67zLYikGij5dSZ3TRFFG6MSvGDBYvs2P9KaixhcJbY6a7ULGbeBpB29rnq4OEXoGMjOoyG171ZzIeuXAvZnk_ujhEWlCFvznvfQu8H5mTjtFb17I9BJ4YS5gT3E5UwHEH_bAaJI8KtRjfbhKkv09cxaYqRjCMoPlLEPnwDxc2Ousux5SHOjgIqWp9z1acIUzLqkbK3euZNL1YpCNRJTMn4qDPhel5gyY9IjoqgEhfQFJ4ckp2_DLGcFZj3Wwwh-WGmkduvTr2TE_kIA-SmXcqwyGdLse3n7JUHVxcumvXgr5oxe2I_h6UQGSPLxz-KwKxeIUAARQhM9f2mjBcnJ3hkaJj-ciuAjof-WBVCZJsjlccogXhXtxLbjz8ZSntQuaLdjb-ci2wMANhPWnWh9R2KqnREhp-PTllAG4Bj-BWmpzTTRy7tZGkFKoL1xiZMCFA_5egS9V1lqwz62BVOVZ7AeZ5NK8hjGnzSgq6E3bhLoTDupPJLUl3f7fC16PqHQjb049Srme9lK13s8oR79g9UUufW-jQloUhA5fRql45ArveLSTSgg-nUCk22Dso1-Cjk7BIqsEFmeBcyhQoqpjCiuKT6iiVTuEnQXAJ8WEi_hJKTXJ2NxEOdaCG1VaZNycggvX4urmkD53HLpXABitdYpBqJvu-DkO-K8OZA0v8tThBZx4zrIY5EMUPi9YikMrWOqeJtXhA6ZYpeUjK8FHM-sAb3i377lw0CarC8XDzzeNCHRJvaksZdhviuBqNjWXQ_VtU6xEqXsXc8FSftvK2SoSiW19qgiQkrUMJxSy6A_daXT0b7FucBACN1O3YDQ2-x6juM1uMjLico4I1OeFP0RsbUazYVdW0wL6CXiC81ygyTk_XE85xyWwNyiooBuJc377qapNcbUVAYca6R5YVHLVsVLjr3h_BlO1KWv064dypH1faO8cYatSwXp5ttcUg8xoI6E_q0N3IUepfTleZBiCRncoFyKcOT7xUlqojhkC4YirwgtV5Pv3hp6MQ9hjibUeX8mNLFepE1tDFyzZmMXM2kr0Q99WVINbRqv8vGjt82wuZScuJiBy8P6BV-FJLAXsECrAtauSQlDP7YTWsibeqQ3_LEDRd4G9BMj7RorJg6Z0jFloIVfzQOHkZCEZITbh8ifrDrnpMO84l-__kRVImb1rW6I-1KdTubMAaZbAYPhpiYWmC5FJfmyyCSA7uuqeP7RWSm3fZeJK-YinLKH6dUHgwchPQ1godY97ywznP5YuM9pmve75iaNcd3ILuljGx8eBj2Ig7lkPK00JId6FfDwfg9h9cgAKfqueZRBPEN0D3grwZkplG7-_6B1ZhmwjRHaFY88L4EUVnqNh9F73190G-oOuM8Ztw0ItfLU-EvshvMLZ_4W-FUN8B_okqAGH0F088j5ZADxS7HdWMq0DNDIaXpDgPjPhLT7mng20O7BWfG8nTSMEqTBGfvpgoeTL5LjBuDESG4H7FhxGXlfum8asCs8WgdhZ0Zh-SRV8bcLTcpOSEuutdCOK0DxMjs30MTijfLDfpHQP9_fWuG__3n-9g-7Rs6OIaU9jwJ2yWarC-CfPX7yzZcgcsAbT_UEHqRZXQU5vhepV5tmvM5RTv9k7a16b6xIEJIBNLaDRw7LZaauowiaF40vrMNZNGnqqTED_bqMcnfYXvp2R0QFZihNgey1rh2ndhYcSmXSC0F4Wm6r4T6q9VfW_T4Y7NGb31a001Mq_edR2xa_uSBETzybCsHNUq5bD_F3Qj4JUivq2nyh-UAbxP71MdlGE8RN5RYL7b5j25o1oyw5tSYbndIjfp_oVHkdWtnYJsH6T131lUwM0-DwMWWtLParbukDjDjy08aTEDR0vW6LaJJ9bh1_Po-XR6sG4lAeTcJo7XjptIWQCbkSrV6gD7GXOOJgF2qVlvM02ARNLl6DNo3Y7ar_H4LkZ3aAkkV1Yy7-vnVpIEx-UoSnilNRQN_rp6icTwNilt1UnuuLutxKISHRMDP3Pv9vEATDQy-z.w6KkNgIIeh8SPlMtA6l7dbywsDAKFLkTmrVc65q-BL8'; + + public function testEncryptedRealSignature2() { + $this->requestMock->expects($this->any()) + ->method('getHeader') + ->with($this->equalTo(Application::OIDC_API_REQ_HEADER)) + ->willReturn('Bearer ' . self::ENCRPYT2_SIGN_TOKEN); + + $this->assertTrue($this->backend->isSessionActive()); + $this->assertEquals('', $this->backend->getCurrentUserId()); + } +} diff --git a/tests/unit/MagentaCloud/SamBearerTokenTest.php b/tests/unit/MagentaCloud/SamBearerTokenTest.php new file mode 100644 index 00000000..0c87a33f --- /dev/null +++ b/tests/unit/MagentaCloud/SamBearerTokenTest.php @@ -0,0 +1,85 @@ + + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +declare(strict_types=1); + +use OCA\UserOIDC\BaseTest\BearerTokenTestCase; + + +use OCA\UserOIDC\MagentaBearer\InvalidTokenException; +use OCA\UserOIDC\MagentaBearer\SignatureException; + +class SamBearerTokenTest extends BearerTokenTestCase { + + /** + * @var ProviderService + */ + private $provider; + + + public function setUp(): void { + parent::setUp(); + } + + public function testValidSignature() { + $this->expectNotToPerformAssertions(); + $testtoken = $this->setupSignedToken($this->getRealExampleClaims(), $this->getTestBearerSecret()); + //fwrite(STDERR, '[' . $testtoken . ']'); + $bearerToken = $this->tokenService->decryptToken($testtoken, $this->getTestBearerSecret()); + $this->tokenService->verifySignature($bearerToken, $this->getTestBearerSecret()); + $claims = $this->tokenService->decode($bearerToken); + $this->tokenService->verifyClaims($claims, ['http://auth.magentacloud.de']); + } + + public function testInvalidSignature() { + $this->expectException(SignatureException::class); + $testtoken = $this->setupSignedToken($this->getRealExampleClaims(), $this->getTestBearerSecret()); + $invalidSignToken = mb_substr($testtoken, 0, -1); // shorten sign to invalidate + // fwrite(STDERR, '[' . $testtoken . ']'); + $bearerToken = $this->tokenService->decryptToken($invalidSignToken, $this->getTestBearerSecret()); + $this->tokenService->verifySignature($bearerToken, $this->getTestBearerSecret()); + $claims = $this->tokenService->decode($bearerToken); + $this->tokenService->verifyClaims($claims, ['http://auth.magentacloud.de']); + } + + public function testEncryptedValidSignature() { + $this->expectNotToPerformAssertions(); + $testtoken = $this->setupSignEncryptToken($this->getRealExampleClaims(), $this->getTestBearerSecret()); + //fwrite(STDERR, '[' . $testtoken . ']'); + $bearerToken = $this->tokenService->decryptToken($testtoken, $this->getTestBearerSecret()); + $this->tokenService->verifySignature($bearerToken, $this->getTestBearerSecret()); + $claims = $this->tokenService->decode($bearerToken); + $this->tokenService->verifyClaims($claims, ['http://auth.magentacloud.de']); + } + + public function testEncryptedInvalidEncryption() { + $this->expectException(InvalidTokenException::class); + $testtoken = $this->setupSignEncryptToken($this->getRealExampleClaims(), $this->getTestBearerSecret()); + $invalidEncryption = mb_substr($testtoken, 0, -1); // shorten sign to invalidate + //fwrite(STDERR, '[' . $testtoken . ']'); + $bearerToken = $this->tokenService->decryptToken($invalidEncryption, $this->getTestBearerSecret()); + $this->tokenService->verifySignature($bearerToken, $this->getTestBearerSecret()); + $claims = $this->tokenService->decode($bearerToken); + $this->tokenService->verifyClaims($claims, ['http://auth.magentacloud.de']); + } +}