Repository: fr05t1k/esia
Branch: master
Commit: c1750575b7eb
Files: 42
Total size: 73.0 KB
Directory structure:
gitextract_ro8_8jf5/
├── .gitignore
├── .travis.yml
├── README.md
├── _config.yml
├── codeception.yml
├── composer.json
├── src/
│ └── Esia/
│ ├── Config.php
│ ├── Exceptions/
│ │ ├── AbstractEsiaException.php
│ │ ├── ForbiddenException.php
│ │ ├── InvalidConfigurationException.php
│ │ └── RequestFailException.php
│ ├── Http/
│ │ ├── Exceptions/
│ │ │ └── HttpException.php
│ │ └── GuzzleHttpClient.php
│ ├── OpenId.php
│ └── Signer/
│ ├── AbstractSignerPKCS7.php
│ ├── CliSignerPKCS7.php
│ ├── Exceptions/
│ │ ├── CannotGenerateRandomIntException.php
│ │ ├── CannotReadCertificateException.php
│ │ ├── CannotReadPrivateKeyException.php
│ │ ├── NoSuchCertificateFileException.php
│ │ ├── NoSuchKeyFileException.php
│ │ ├── NoSuchTmpDirException.php
│ │ └── SignFailException.php
│ ├── SignerInterface.php
│ └── SignerPKCS7.php
└── tests/
├── .configure-gost-openssl.sh
├── _bootstrap.php
├── _data/
│ ├── server-gost.crt
│ ├── server-gost.key
│ ├── server.crt
│ ├── server.csr
│ └── server.key
├── _support/
│ ├── Helper/
│ │ └── Unit.php
│ ├── UnitTester.php
│ └── _generated/
│ └── UnitTesterActions.php
├── unit/
│ ├── ConfigTest.php
│ ├── Http/
│ │ └── GuzzleHttpClientTest.php
│ ├── OpenIdCliOpensslTest.php
│ ├── OpenIdTest.php
│ ├── Signer/
│ │ └── SignerPKCS7Test.php
│ └── _bootstrap.php
└── unit.suite.yml
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.idea
tests/tmp/*
tests/_output/*
public/*
vendor
tests/_data/non_readable_file
================================================
FILE: .travis.yml
================================================
dist: bionic
language: php
addons:
apt:
packages:
- libengine-gost-openssl1.1
before_install:
- sudo bash tests/.configure-gost-openssl.sh
php:
- 7.1
- 7.2
- 7.3
- 7.4
- 8.0
install:
- travis_retry composer self-update
- travis_retry composer --version
- travis_retry composer update --prefer-dist --no-interaction
script:
- chmod 000 tests/_data/non_readable_file
- php vendor/codeception/codeception/codecept run
================================================
FILE: README.md
================================================
# Единая система идентификации и аутентификации (ЕСИА) OpenId
[](https://travis-ci.org/fr05t1k/esia)
# Описание
Компонент для авторизации на портале "Госуслуги".
# Внимание!
Получив токен вы можете выполнять любые API запросы. Библиотека не поддерживает все существующие методы в API, а предоставляет только самые базовые. Основная цель библиотеки - получение токена.
# Установка
При помощи [composer](https://getcomposer.org/download/):
```
composer require --prefer-dist fr05t1k/esia
```
Или добавьте в composer.json
```
"fr05t1k/esia" : "^2.0"
```
# Как использовать
Пример получения ссылки для авторизации
```php
'INSP03211',
'redirectUrl' => 'http://my-site.com/response.php',
'portalUrl' => 'https://esia-portal1.test.gosuslugi.ru/',
'scope' => ['fullname', 'birthdate'],
]);
$esia = new \Esia\OpenId($config);
$esia->setSigner(new \Esia\Signer\SignerPKCS7(
'my-site.com.pem',
'my-site.com.pem',
'password',
'/tmp'
));
?>
Войти через портал госуслуги
```
После редиректа на ваш `redirectUrl` вы получите в `$_GET['code']` код для получения токена
Пример получения токена и информации о пользователе
```php
$esia = new \Esia\OpenId($config);
// Вы можете использовать токен в дальнейшем вместе с oid
$token = $esia->getToken($_GET['code']);
$personInfo = $esia->getPersonInfo();
$addressInfo = $esia->getAddressInfo();
$contactInfo = $esia->getContactInfo();
$documentInfo = $esia->getDocInfo();
```
# Конфиг
`clientId` - ID вашего приложения.
`redirectUrl` - URL куда будет перенаправлен ответ с кодом.
`portalUrl` - по умолчанию: `https://esia-portal1.test.gosuslugi.ru/`. Домен портала для авторизация (только домен).
`codeUrlPath` - по умолчанию: `aas/oauth2/ac`. URL для получения кода.
`tokenUrlPath` - по умолчанию: `aas/oauth2/te`. URL для получение токена.
`scope` - по умолчанию: `fullname birthdate gender email mobile id_doc snils inn`. Запрашиваемые права у пользователя.
`privateKeyPath` - путь до приватного ключа.
`privateKeyPassword` - пароль от приватного ключа.
`certPath` - путь до сертификата.
`tmpPath` - путь до дериктории где будет проходить подпись (должна быть доступна для записи).
# Токен и oid
Токен - jwt токен которые вы получаете от ЕСИА для дальнейшего взаимодействия
oid - уникальный идентификатор владельца токена
## Как получить oid?
Если 2 способа:
1. oid содержится в jwt токене, расшифровав его
2. После получения токена oid сохраняется в config и получить можно так
```php
$esia->getConfig()->getOid();
```
## Переиспользование Токена
Дополнительно укажите токен и идентификатор в конфиге
```php
$config->setToken($jwt);
$config->setOid($oid);
```
================================================
FILE: _config.yml
================================================
theme: jekyll-theme-cayman
================================================
FILE: codeception.yml
================================================
actor: Tester
paths:
tests: tests
log: tests/_output
data: tests/_data
support: tests/_support
envs: tests/_envs
bootstrap: _bootstrap.php
settings:
colors: true
memory_limit: 1024M
extensions:
enabled:
- Codeception\Extension\RunFailed
coverage:
enabled: true
remote: false
whitelist:
include:
- src/*
================================================
FILE: composer.json
================================================
{
"name": "fr05t1k/esia",
"license": "MIT",
"description": "OpenID ESIA authenticating",
"keywords": [
"esia",
"openid",
"egov"
],
"autoload": {
"psr-4": {
"Esia\\": "src/Esia"
}
},
"autoload-dev": {
"psr-4": {
"tests\\" : "tests"
}
},
"require": {
"php": "^7.1|^8.0",
"guzzlehttp/guzzle": "^6.1.0|^7.0",
"psr/log": "^1.0",
"psr/http-message": "^1.0",
"psr/http-client": "^1.0"
},
"suggest": {
"ext-openssl": "SignerPKCS7 support"
},
"require-dev": {
"roave/security-advisories": "dev-latest",
"codeception/codeception": "^4.0",
"codeception/module-asserts": "^1.3"
}
}
================================================
FILE: src/Esia/Config.php
================================================
clientId = $config['clientId'] ?? $this->clientId;
if (!$this->clientId) {
throw new InvalidConfigurationException('Please provide clientId');
}
$this->redirectUrl = $config['redirectUrl'] ?? $this->redirectUrl;
if (!$this->redirectUrl) {
throw new InvalidConfigurationException('Please provide redirectUrl');
}
$this->privateKeyPath = $config['privateKeyPath'] ?? $this->privateKeyPath;
if (!$this->privateKeyPath) {
throw new InvalidConfigurationException('Please provide privateKeyPath');
}
$this->certPath = $config['certPath'] ?? $this->certPath;
if (!$this->certPath) {
throw new InvalidConfigurationException('Please provide certPath');
}
$this->portalUrl = $config['portalUrl'] ?? $this->portalUrl;
$this->tokenUrlPath = $config['tokenUrlPath'] ?? $this->tokenUrlPath;
$this->codeUrlPath = $config['codeUrlPath'] ?? $this->codeUrlPath;
$this->personUrlPath = $config['personUrlPath'] ?? $this->personUrlPath;
$this->logoutUrlPath = $config['logoutUrlPath'] ?? $this->logoutUrlPath;
$this->privateKeyPassword = $config['privateKeyPassword'] ?? $this->privateKeyPassword;
$this->oid = $config['oid'] ?? $this->oid;
$this->scope = $config['scope'] ?? $this->scope;
if (!is_array($this->scope)) {
throw new InvalidConfigurationException('scope must be array of strings');
}
$this->responseType = $config['responseType'] ?? $this->responseType;
$this->accessType = $config['accessType'] ?? $this->accessType;
$this->tmpPath = $config['tmpPath'] ?? $this->tmpPath;
$this->token = $config['token'] ?? $this->token;
}
public function getPortalUrl(): string
{
return $this->portalUrl;
}
public function getPrivateKeyPath(): string
{
return $this->privateKeyPath;
}
public function getPrivateKeyPassword(): string
{
return $this->privateKeyPassword;
}
public function getCertPath(): string
{
return $this->certPath;
}
public function getOid(): string
{
return $this->oid;
}
public function setOid(string $oid): void
{
$this->oid = $oid;
}
public function getScope(): array
{
return $this->scope;
}
public function getScopeString(): string
{
return implode(' ', $this->scope);
}
public function getResponseType(): string
{
return $this->responseType;
}
public function getAccessType(): string
{
return $this->accessType;
}
public function getTmpPath(): string
{
return $this->tmpPath;
}
public function getToken(): ?string
{
return $this->token;
}
public function setToken(string $token): void
{
$this->token = $token;
}
public function getClientId(): string
{
return $this->clientId;
}
public function getRedirectUrl(): string
{
return $this->redirectUrl;
}
/**
* Return an url for request to get an access token
*/
public function getTokenUrl(): string
{
return $this->portalUrl . $this->tokenUrlPath;
}
/**
* Return an url for request to get an authorization code
*/
public function getCodeUrl(): string
{
return $this->portalUrl . $this->codeUrlPath;
}
/**
* @return string
* @throws InvalidConfigurationException
*/
public function getPersonUrl(): string
{
if (!$this->oid) {
throw new InvalidConfigurationException('Please provide oid');
}
return $this->portalUrl . $this->personUrlPath . '/' . $this->oid;
}
/**
* Return an url for logout
*/
public function getLogoutUrl(): string
{
return $this->portalUrl . $this->logoutUrlPath;
}
}
================================================
FILE: src/Esia/Exceptions/AbstractEsiaException.php
================================================
guzzle = $guzzle;
}
/**
* Sends a PSR-7 request and returns a PSR-7 response.
*
* Every technically correct HTTP response MUST be returned as is, even if it represents a HTTP
* error response or a redirect instruction. The only special case is 1xx responses, which MUST
* be assembled in the HTTP client.
*
* The client MAY do modifications to the Request before sending it. Because PSR-7 objects are
* immutable, one cannot assume that the object passed to ClientInterface::sendRequest() will be the same
* object that is actually sent. For example the Request object that is returned by an exception MAY
* be a different object than the one passed to sendRequest, so comparison by reference (===) is not possible.
*
* {@link https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-7-http-message-meta.md#why-value-objects}
*
* @param RequestInterface $request
*
* @return ResponseInterface
*
* @throws ClientExceptionInterface If an error happens during processing the request.
*/
public function sendRequest(RequestInterface $request): ResponseInterface
{
try {
return $this->guzzle->send($request);
} catch (GuzzleException $e) {
throw new HttpException($e->getMessage(), $e->getCode(), $e);
}
}
}
================================================
FILE: src/Esia/OpenId.php
================================================
config = $config;
$this->client = $client ?? new GuzzleHttpClient(new Client());
$this->logger = new NullLogger();
$this->signer = new SignerPKCS7(
$config->getCertPath(),
$config->getPrivateKeyPath(),
$config->getPrivateKeyPassword(),
$config->getTmpPath()
);
}
/**
* Replace default signer
*/
public function setSigner(SignerInterface $signer): void
{
$this->signer = $signer;
}
/**
* Get config
*/
public function getConfig(): Config
{
return $this->config;
}
/**
* Return an url for authentication
*
* ```php
* Login
* ```
*
* @return string|false
* @throws SignFailException
*/
public function buildUrl()
{
$timestamp = $this->getTimeStamp();
$state = $this->buildState();
$message = $this->config->getScopeString()
. $timestamp
. $this->config->getClientId()
. $state;
$clientSecret = $this->signer->sign($message);
$url = $this->config->getCodeUrl() . '?%s';
$params = [
'client_id' => $this->config->getClientId(),
'client_secret' => $clientSecret,
'redirect_uri' => $this->config->getRedirectUrl(),
'scope' => $this->config->getScopeString(),
'response_type' => $this->config->getResponseType(),
'state' => $state,
'access_type' => $this->config->getAccessType(),
'timestamp' => $timestamp,
];
$request = http_build_query($params);
return sprintf($url, $request);
}
/**
* Return an url for logout
*/
public function buildLogoutUrl(string $redirectUrl = null): string
{
$url = $this->config->getLogoutUrl() . '?%s';
$params = [
'client_id' => $this->config->getClientId(),
];
if ($redirectUrl) {
$params['redirect_url'] = $redirectUrl;
}
$request = http_build_query($params);
return sprintf($url, $request);
}
/**
* Method collect a token with given code
*
* @throws SignFailException
* @throws AbstractEsiaException
*/
public function getToken(string $code): string
{
$timestamp = $this->getTimeStamp();
$state = $this->buildState();
$clientSecret = $this->signer->sign(
$this->config->getScopeString()
. $timestamp
. $this->config->getClientId()
. $state
);
$body = [
'client_id' => $this->config->getClientId(),
'code' => $code,
'grant_type' => 'authorization_code',
'client_secret' => $clientSecret,
'state' => $state,
'redirect_uri' => $this->config->getRedirectUrl(),
'scope' => $this->config->getScopeString(),
'timestamp' => $timestamp,
'token_type' => 'Bearer',
'refresh_token' => $state,
];
$payload = $this->sendRequest(
new Request(
'POST',
$this->config->getTokenUrl(),
[
'Content-Type' => 'application/x-www-form-urlencoded',
],
http_build_query($body)
)
);
$this->logger->debug('Payload: ', $payload);
$token = $payload['access_token'];
$this->config->setToken($token);
# get object id from token
$chunks = explode('.', $token);
$payload = json_decode($this->base64UrlSafeDecode($chunks[1]), true);
$this->config->setOid($payload['urn:esia:sbj_id']);
return $token;
}
/**
* Fetch person info from current person
*
* You must collect token person before
* calling this method
*
* @throws AbstractEsiaException
*/
public function getPersonInfo(): array
{
$url = $this->config->getPersonUrl();
return $this->sendRequest(new Request('GET', $url));
}
/**
* Fetch contact info about current person
*
* You must collect token person before
* calling this method
*
* @throws Exceptions\InvalidConfigurationException
* @throws AbstractEsiaException
*/
public function getContactInfo(): array
{
$url = $this->config->getPersonUrl() . '/ctts';
$payload = $this->sendRequest(new Request('GET', $url));
if ($payload && $payload['size'] > 0) {
return $this->collectArrayElements($payload['elements']);
}
return $payload;
}
/**
* Fetch address from current person
*
* You must collect token person before
* calling this method
*
* @throws Exceptions\InvalidConfigurationException
* @throws AbstractEsiaException
*/
public function getAddressInfo(): array
{
$url = $this->config->getPersonUrl() . '/addrs';
$payload = $this->sendRequest(new Request('GET', $url));
if ($payload['size'] > 0) {
return $this->collectArrayElements($payload['elements']);
}
return $payload;
}
/**
* Fetch documents info about current person
*
* You must collect token person before
* calling this method
*
* @throws Exceptions\InvalidConfigurationException
* @throws AbstractEsiaException
*/
public function getDocInfo(): array
{
$url = $this->config->getPersonUrl() . '/docs';
$payload = $this->sendRequest(new Request('GET', $url));
if ($payload && $payload['size'] > 0) {
return $this->collectArrayElements($payload['elements']);
}
return $payload;
}
/**
* This method can iterate on each element
* and fetch entities from esia by url
*
* @throws AbstractEsiaException
*/
private function collectArrayElements($elements): array
{
$result = [];
foreach ($elements as $elementUrl) {
$elementPayload = $this->sendRequest(new Request('GET', $elementUrl));
if ($elementPayload) {
$result[] = $elementPayload;
}
}
return $result;
}
/**
* @throws AbstractEsiaException
*/
private function sendRequest(RequestInterface $request): array
{
try {
if ($this->config->getToken()) {
/** @noinspection CallableParameterUseCaseInTypeContextInspection */
$request = $request->withHeader('Authorization', 'Bearer ' . $this->config->getToken());
}
$response = $this->client->sendRequest($request);
$responseBody = json_decode($response->getBody()->getContents(), true);
if (!is_array($responseBody)) {
throw new RuntimeException(
sprintf(
'Cannot decode response body. JSON error (%d): %s',
json_last_error(),
json_last_error_msg()
)
);
}
return $responseBody;
} catch (ClientExceptionInterface $e) {
$this->logger->error('Request was failed', ['exception' => $e]);
$prev = $e->getPrevious();
// Only for Guzzle
if ($prev instanceof BadResponseException
&& $prev->getResponse() !== null
&& $prev->getResponse()->getStatusCode() === 403
) {
throw new ForbiddenException('Request is forbidden', 0, $e);
}
throw new RequestFailException('Request is failed', 0, $e);
} catch (RuntimeException $e) {
$this->logger->error('Cannot read body', ['exception' => $e]);
throw new RequestFailException('Cannot read body', 0, $e);
} catch (InvalidArgumentException $e) {
$this->logger->error('Wrong header', ['exception' => $e]);
throw new RequestFailException('Wrong header', 0, $e);
}
}
private function getTimeStamp(): string
{
return date('Y.m.d H:i:s O');
}
/**
* Generate state with uuid
*
* @throws SignFailException
*/
private function buildState(): string
{
try {
return sprintf(
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
random_int(0, 0xffff),
random_int(0, 0xffff),
random_int(0, 0xffff),
random_int(0, 0x0fff) | 0x4000,
random_int(0, 0x3fff) | 0x8000,
random_int(0, 0xffff),
random_int(0, 0xffff),
random_int(0, 0xffff)
);
} catch (Exception $e) {
throw new CannotGenerateRandomIntException('Cannot generate random integer', $e);
}
}
/**
* Url safe for base64
*/
private function base64UrlSafeDecode(string $string): string
{
$base64 = strtr($string, '-_', '+/');
return base64_decode($base64);
}
}
================================================
FILE: src/Esia/Signer/AbstractSignerPKCS7.php
================================================
certPath = $certPath;
$this->privateKeyPath = $privateKeyPath;
$this->privateKeyPassword = $privateKeyPassword;
$this->tmpPath = $tmpPath;
$this->logger = new NullLogger();
}
/**
* Temporary directory for message signing (must me writable)
*
* @var string
*/
protected $tmpPath;
/**
* @throws SignFailException
*/
protected function checkFilesExists(): void
{
if (!file_exists($this->certPath)) {
throw new NoSuchCertificateFileException('Certificate does not exist');
}
if (!is_readable($this->certPath)) {
throw new CannotReadCertificateException('Cannot read the certificate');
}
if (!file_exists($this->privateKeyPath)) {
throw new NoSuchKeyFileException('Private key does not exist');
}
if (!is_readable($this->privateKeyPath)) {
throw new CannotReadPrivateKeyException('Cannot read the private key');
}
if (!file_exists($this->tmpPath)) {
throw new NoSuchTmpDirException('Temporary folder is not found');
}
if (!is_writable($this->tmpPath)) {
throw new NoSuchTmpDirException('Temporary folder is not writable');
}
}
/**
* Generate random unique string
*/
protected function getRandomString(): string
{
return md5(uniqid(mt_rand(), true));
}
/**
* Url safe for base64
*/
protected function urlSafe(string $string): string
{
return rtrim(strtr(trim($string), '+/', '-_'), '=');
}
}
================================================
FILE: src/Esia/Signer/CliSignerPKCS7.php
================================================
checkFilesExists();
// random unique directories for sign
$messageFile = $this->tmpPath . DIRECTORY_SEPARATOR . $this->getRandomString();
$signFile = $this->tmpPath . DIRECTORY_SEPARATOR . $this->getRandomString();
file_put_contents($messageFile, $message);
$this->run(
'openssl ' .
'smime -engine gost -sign -binary -outform DER -noattr ' .
'-signer ' . escapeshellarg($this->certPath) . ' ' .
'-inkey ' . escapeshellarg($this->privateKeyPath) . ' ' .
'-passin ' . escapeshellarg('pass:' . $this->privateKeyPassword) . ' ' .
'-in ' . escapeshellarg($messageFile) . ' ' .
'-out ' . escapeshellarg($signFile)
);
$signed = file_get_contents($signFile);
if ($signed === false) {
$message = sprintf('cannot read %s file', $signFile);
$this->logger->error($message);
throw new SignFailException($message);
}
$sign = $this->urlSafe(base64_encode($signed));
unlink($signFile);
unlink($messageFile);
return $sign;
}
/**
* @throws SignFailException
*/
private function run(string $command): void
{
$process = proc_open(
$command,
[
['pipe', 'w'], // stdout
['pipe', 'w'], // stderr
],
$pipes
);
$result = stream_get_contents($pipes[0]);
fclose($pipes[0]);
$errors = stream_get_contents($pipes[1]);
fclose($pipes[1]);
$code = proc_close($process);
if (0 !== $code || $result === false) {
$errors = $errors ?: 'unknown';
$this->logger->error('Sign fail');
$this->logger->error('SSL error: ' . $errors);
throw new SignFailException($errors);
}
}
}
================================================
FILE: src/Esia/Signer/Exceptions/CannotGenerateRandomIntException.php
================================================
pkcs7Flags |= $pkcs7Flag;
}
/**
* @throws SignFailException
*/
public function sign(string $message): string
{
$this->checkFilesExists();
$certContent = file_get_contents($this->certPath);
$keyContent = file_get_contents($this->privateKeyPath);
$cert = openssl_x509_read($certContent);
if ($cert === false) {
throw new CannotReadCertificateException('Cannot read the certificate: ' . openssl_error_string());
}
$this->logger->debug('Cert: ' . print_r($cert, true), ['cert' => $cert]);
$privateKey = openssl_pkey_get_private($keyContent, $this->privateKeyPassword);
if ($privateKey === false) {
throw new CannotReadPrivateKeyException('Cannot read the private key: ' . openssl_error_string());
}
$this->logger->debug('Private key: : ' . print_r($privateKey, true), ['privateKey' => $privateKey]);
// random unique directories for sign
$messageFile = $this->tmpPath . DIRECTORY_SEPARATOR . $this->getRandomString();
$signFile = $this->tmpPath . DIRECTORY_SEPARATOR . $this->getRandomString();
file_put_contents($messageFile, $message);
$signResult = openssl_pkcs7_sign(
$messageFile,
$signFile,
$cert,
$privateKey,
[],
$this->pkcs7Flags
);
if ($signResult) {
$this->logger->debug('Sign success');
} else {
$this->logger->error('Sign fail');
$this->logger->error('SSL error: ' . openssl_error_string());
throw new SignFailException('Cannot sign the message');
}
$signed = file_get_contents($signFile);
# split by section
$signed = explode("\n\n", $signed);
# get third section which contains sign and join into one line
$sign = str_replace("\n", '', $this->urlSafe($signed[3]));
unlink($signFile);
unlink($messageFile);
return $sign;
}
}
================================================
FILE: tests/.configure-gost-openssl.sh
================================================
sed -i '1iopenssl_conf=openssl_def' /usr/lib/ssl/openssl.cnf
tee -a /usr/lib/ssl/openssl.cnf <assertEquals(5, $element->getChildrenCount());
* ```
*
* Floating-point example:
* ```php
* assertEquals(0.3, $calculator->add(0.1, 0.2), 'Calculator should add the two numbers correctly.', 0.01);
* ```
*
* @param $expected
* @param $actual
* @param string $message
* @param float $delta
* @see \Codeception\Module\Asserts::assertEquals()
*/
public function assertEquals($expected, $actual, $message = null, $delta = null) {
return $this->getScenario()->runStep(new Action('assertEquals', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that two variables are not equal. If you're comparing floating-point values,
* you can specify the optional "delta" parameter which dictates how great of a precision
* error are you willing to tolerate in order to consider the two values not equal.
*
* Regular example:
* ```php
* assertNotEquals(0, $element->getChildrenCount());
* ```
*
* Floating-point example:
* ```php
* assertNotEquals(0.4, $calculator->add(0.1, 0.2), 'Calculator should add the two numbers correctly.', 0.01);
* ```
*
* @param $expected
* @param $actual
* @param string $message
* @param float $delta
* @see \Codeception\Module\Asserts::assertNotEquals()
*/
public function assertNotEquals($expected, $actual, $message = null, $delta = null) {
return $this->getScenario()->runStep(new Action('assertNotEquals', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that two variables are same
*
* @param $expected
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertSame()
*/
public function assertSame($expected, $actual, $message = null) {
return $this->getScenario()->runStep(new Action('assertSame', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that two variables are not same
*
* @param $expected
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertNotSame()
*/
public function assertNotSame($expected, $actual, $message = null) {
return $this->getScenario()->runStep(new Action('assertNotSame', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that actual is greater than expected
*
* @param $expected
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertGreaterThan()
*/
public function assertGreaterThan($expected, $actual, $message = null) {
return $this->getScenario()->runStep(new Action('assertGreaterThan', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that actual is greater or equal than expected
*
* @param $expected
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertGreaterThanOrEqual()
*/
public function assertGreaterThanOrEqual($expected, $actual, $message = null) {
return $this->getScenario()->runStep(new Action('assertGreaterThanOrEqual', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that actual is less than expected
*
* @param $expected
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertLessThan()
*/
public function assertLessThan($expected, $actual, $message = null) {
return $this->getScenario()->runStep(new Action('assertLessThan', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that actual is less or equal than expected
*
* @param $expected
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertLessThanOrEqual()
*/
public function assertLessThanOrEqual($expected, $actual, $message = null) {
return $this->getScenario()->runStep(new Action('assertLessThanOrEqual', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that haystack contains needle
*
* @param $needle
* @param $haystack
* @param string $message
* @see \Codeception\Module\Asserts::assertContains()
*/
public function assertContains($needle, $haystack, $message = null) {
return $this->getScenario()->runStep(new Action('assertContains', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that haystack doesn't contain needle.
*
* @param $needle
* @param $haystack
* @param string $message
* @see \Codeception\Module\Asserts::assertNotContains()
*/
public function assertNotContains($needle, $haystack, $message = null) {
return $this->getScenario()->runStep(new Action('assertNotContains', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that string match with pattern
*
* @param string $pattern
* @param string $string
* @param string $message
* @see \Codeception\Module\Asserts::assertRegExp()
*/
public function assertRegExp($pattern, $string, $message = null) {
return $this->getScenario()->runStep(new Action('assertRegExp', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that string not match with pattern
*
* @param string $pattern
* @param string $string
* @param string $message
* @see \Codeception\Module\Asserts::assertNotRegExp()
*/
public function assertNotRegExp($pattern, $string, $message = null) {
return $this->getScenario()->runStep(new Action('assertNotRegExp', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that a string starts with the given prefix.
*
* @param string $prefix
* @param string $string
* @param string $message
* @see \Codeception\Module\Asserts::assertStringStartsWith()
*/
public function assertStringStartsWith($prefix, $string, $message = null) {
return $this->getScenario()->runStep(new Action('assertStringStartsWith', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that a string doesn't start with the given prefix.
*
* @param string $prefix
* @param string $string
* @param string $message
* @see \Codeception\Module\Asserts::assertStringStartsNotWith()
*/
public function assertStringStartsNotWith($prefix, $string, $message = null) {
return $this->getScenario()->runStep(new Action('assertStringStartsNotWith', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that variable is empty.
*
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertEmpty()
*/
public function assertEmpty($actual, $message = null) {
return $this->getScenario()->runStep(new Action('assertEmpty', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that variable is not empty.
*
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertNotEmpty()
*/
public function assertNotEmpty($actual, $message = null) {
return $this->getScenario()->runStep(new Action('assertNotEmpty', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that variable is NULL
*
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertNull()
*/
public function assertNull($actual, $message = null) {
return $this->getScenario()->runStep(new Action('assertNull', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that variable is not NULL
*
* @param $actual
* @param string $message
* @see \Codeception\Module\Asserts::assertNotNull()
*/
public function assertNotNull($actual, $message = null) {
return $this->getScenario()->runStep(new Action('assertNotNull', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that condition is positive.
*
* @param $condition
* @param string $message
* @see \Codeception\Module\Asserts::assertTrue()
*/
public function assertTrue($condition, $message = null)
{
return $this->getScenario()->runStep(new Action('assertTrue', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that the condition is NOT true (everything but true)
*
* @param $condition
* @param string $message
* @see \Codeception\Module\Asserts::assertNotTrue()
*/
public function assertNotTrue($condition, $message = null)
{
return $this->getScenario()->runStep(new Action('assertNotTrue', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that condition is negative.
*
* @param $condition
* @param string $message
* @see \Codeception\Module\Asserts::assertFalse()
*/
public function assertFalse($condition, $message = null)
{
return $this->getScenario()->runStep(new Action('assertFalse', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that the condition is NOT false (everything but false)
*
* @param $condition
* @param string $message
* @see \Codeception\Module\Asserts::assertNotFalse()
*/
public function assertNotFalse($condition, $message = null)
{
return $this->getScenario()->runStep(new Action('assertNotFalse', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks if file exists
*
* @param string $filename
* @param string $message
* @see \Codeception\Module\Asserts::assertFileExists()
*/
public function assertFileExists($filename, $message = null)
{
return $this->getScenario()->runStep(new Action('assertFileExists', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks if file doesn't exist
*
* @param string $filename
* @param string $message
* @see \Codeception\Module\Asserts::assertFileNotExists()
*/
public function assertFileNotExists($filename, $message = null) {
return $this->getScenario()->runStep(new Action('assertFileNotExists', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* @param $expected
* @param $actual
* @param $description
* @see \Codeception\Module\Asserts::assertGreaterOrEquals()
*/
public function assertGreaterOrEquals($expected, $actual, $description = null) {
return $this->getScenario()->runStep(new Action('assertGreaterOrEquals', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* @param $expected
* @param $actual
* @param $description
* @see \Codeception\Module\Asserts::assertLessOrEquals()
*/
public function assertLessOrEquals($expected, $actual, $description = null) {
return $this->getScenario()->runStep(new Action('assertLessOrEquals', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* @param $actual
* @param $description
* @see \Codeception\Module\Asserts::assertIsEmpty()
*/
public function assertIsEmpty($actual, $description = null) {
return $this->getScenario()->runStep(new Action('assertIsEmpty', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* @param $key
* @param $actual
* @param $description
* @see \Codeception\Module\Asserts::assertArrayHasKey()
*/
public function assertArrayHasKey($key, $actual, $description = null) {
return $this->getScenario()->runStep(new Action('assertArrayHasKey', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* @param $key
* @param $actual
* @param $description
* @see \Codeception\Module\Asserts::assertArrayNotHasKey()
*/
public function assertArrayNotHasKey($key, $actual, $description = null) {
return $this->getScenario()->runStep(new Action('assertArrayNotHasKey', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Checks that array contains subset.
*
* @param array $subset
* @param array $array
* @param bool $strict
* @param string $message
* @see \Codeception\Module\Asserts::assertArraySubset()
*/
public function assertArraySubset($subset, $array, $strict = null, $message = null) {
return $this->getScenario()->runStep(new Action('assertArraySubset', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* @param $expectedCount
* @param $actual
* @param $description
* @see \Codeception\Module\Asserts::assertCount()
*/
public function assertCount($expectedCount, $actual, $description = null) {
return $this->getScenario()->runStep(new Action('assertCount', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* @param $class
* @param $actual
* @param $description
* @see \Codeception\Module\Asserts::assertInstanceOf()
*/
public function assertInstanceOf($class, $actual, $description = null) {
return $this->getScenario()->runStep(new Action('assertInstanceOf', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* @param $class
* @param $actual
* @param $description
* @see \Codeception\Module\Asserts::assertNotInstanceOf()
*/
public function assertNotInstanceOf($class, $actual, $description = null) {
return $this->getScenario()->runStep(new Action('assertNotInstanceOf', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* @param $type
* @param $actual
* @param $description
* @see \Codeception\Module\Asserts::assertInternalType()
*/
public function assertInternalType($type, $actual, $description = null) {
return $this->getScenario()->runStep(new Action('assertInternalType', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Fails the test with message.
*
* @param $message
* @see \Codeception\Module\Asserts::fail()
*/
public function fail($message) {
return $this->getScenario()->runStep(new Action('fail', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Handles and checks exception called inside callback function.
* Either exception class name or exception instance should be provided.
*
* ```php
* expectException(MyException::class, function() {
* $this->doSomethingBad();
* });
*
* $I->expectException(new MyException(), function() {
* $this->doSomethingBad();
* });
* ```
* If you want to check message or exception code, you can pass them with exception instance:
* ```php
* expectException(new MyException("Don't do bad things"), function() {
* $this->doSomethingBad();
* });
* ```
*
* @param $exception string or \Exception
* @param $callback
*
* @deprecated Use expectThrowable instead
* @see \Codeception\Module\Asserts::expectException()
*/
public function expectException($exception, $callback)
{
return $this->getScenario()->runStep(new Action('expectException', func_get_args()));
}
/**
* [!] Method is generated. Documentation taken from corresponding module.
*
* Handles and checks throwables (Exceptions/Errors) called inside the callback function.
* Either throwable class name or throwable instance should be provided.
*
* ```php
* expectThrowable(MyThrowable::class, function() {
* $this->doSomethingBad();
* });
*
* $I->expectThrowable(new MyException(), function() {
* $this->doSomethingBad();
* });
* ```
* If you want to check message or throwable code, you can pass them with throwable instance:
* ```php
* expectThrowable(new MyError("Don't do bad things"), function() {
* $this->doSomethingBad();
* });
* ```
*
* @param $throwable string or \Throwable
* @param $callback
* @see \Codeception\Module\Asserts::expectThrowable()
*/
public function expectThrowable($throwable, $callback)
{
return $this->getScenario()->runStep(new Action('expectThrowable', func_get_args()));
}
}
================================================
FILE: tests/unit/ConfigTest.php
================================================
'test',
'redirectUrl' => 'http://google.com',
'privateKeyPath' => '/tmp',
'certPath' => '/tmp',
'scope' => ['test', 'test2', 'test3'],
]);
$this->assertSame('test test2 test3', $config->getScopeString());
}
/**
* Data provider for @see ConfigTest::testConstruct()
*
* @return array
*/
public function dataProviderForConstructor(): array
{
return [
'min' => [
[
'clientId' => 'test',
'redirectUrl' => 'http://google.com',
'privateKeyPath' => '/tmp',
'certPath' => '/tmp',
'scope' => ['test', 'test2', 'test3'],
],
null,
],
'max' => [
[
'clientId' => 'test',
'redirectUrl' => 'http://google.com',
'privateKeyPath' => '/tmp',
'certPath' => '/tmp',
'portalUrl' => 'google.com',
'tokenUrlPath' => 'test',
'codeUrlPath' => 'test',
'personUrlPath' => 'test',
'logoutUrlPath' => 'test',
'privateKeyPassword' => 'test',
'oid' => 'test',
'responseType' => 'test',
'accessType' => 'test',
'tmpPath' => 'test',
'token' => 'test',
'scope' => ['test', 'test2', 'test3'],
],
null,
],
'No cert path' => [
[
'clientId' => 'test',
'redirectUrl' => 'http://google.com',
'privateKeyPath' => '/tmp',
'scope' => ['test', 'test2', 'test3'],
],
InvalidConfigurationException::class,
],
'No private key path' => [
[
'clientId' => 'test',
'redirectUrl' => 'http://google.com',
'certPath' => '/tmp',
'scope' => ['test', 'test2', 'test3'],
],
InvalidConfigurationException::class,
],
'No redirect url' => [
[
'clientId' => 'test',
'privateKeyPath' => '/tmp',
'certPath' => '/tmp',
'scope' => ['test', 'test2', 'test3'],
],
InvalidConfigurationException::class,
],
'No client id' => [
[
'redirectUrl' => 'http://google.com',
'privateKeyPath' => '/tmp',
'certPath' => '/tmp',
'scope' => ['test', 'test2', 'test3'],
],
InvalidConfigurationException::class,
],
'invalid scope' => [
[
'redirectUrl' => 'http://google.com',
'privateKeyPath' => '/tmp',
'certPath' => '/tmp',
'scope' => 'test test2 test3',
],
InvalidConfigurationException::class,
],
];
}
/**
* @param $config
* @param string|null $expectedException
* @throws \Esia\Exceptions\InvalidConfigurationException
*
* @dataProvider dataProviderForConstructor
*/
public function testConstruct($config, string $expectedException = null): void
{
if ($expectedException) {
$this->expectException($expectedException);
}
new Config($config);
}
/**
* @throws InvalidConfigurationException
*/
public function testGetTokenUrl(): void
{
$config = new Config([
'clientId' => 'test',
'redirectUrl' => 'http://google.com',
'privateKeyPath' => '/tmp',
'certPath' => '/tmp',
'portalUrl' => 'https://google.com/',
'tokenUrlPath' => 'test',
'scope' => ['test', 'test2', 'test3'],
]);
$this->assertSame('https://google.com/test', $config->getTokenUrl());
}
/**
* @throws InvalidConfigurationException
*/
public function testGetCodeUrl(): void
{
$config = new Config([
'clientId' => 'test',
'redirectUrl' => 'http://google.com',
'privateKeyPath' => '/tmp',
'certPath' => '/tmp',
'portalUrl' => 'https://google.com/',
'codeUrlPath' => 'test',
'scope' => ['test', 'test2', 'test3'],
]);
$this->assertSame('https://google.com/test', $config->getCodeUrl());
}
/**
* @throws InvalidConfigurationException
*/
public function testGetPersonUrl(): void
{
$config = new Config([
'clientId' => 'test',
'redirectUrl' => 'http://google.com',
'privateKeyPath' => '/tmp',
'certPath' => '/tmp',
'portalUrl' => 'https://google.com/',
'personUrlPath' => 'test',
'oid' => 'test',
'scope' => ['test', 'test2', 'test3'],
]);
$this->assertSame('https://google.com/test/test', $config->getPersonUrl());
}
/**
* @throws InvalidConfigurationException
*/
public function testGetPersonUrlWithoutOid(): void
{
$config = new Config([
'clientId' => 'test',
'redirectUrl' => 'http://google.com',
'privateKeyPath' => '/tmp',
'certPath' => '/tmp',
'portalUrl' => 'https://google.com/',
'personUrlPath' => 'test',
'scope' => ['test', 'test2', 'test3'],
]);
$this->expectException(InvalidConfigurationException::class);
$this->assertSame('https://google.com/test/test', $config->getPersonUrl());
}
/**
* @throws InvalidConfigurationException
*/
public function testGetLogoutUrl(): void
{
$config = new Config([
'clientId' => 'test',
'redirectUrl' => 'http://google.com',
'privateKeyPath' => '/tmp',
'certPath' => '/tmp',
'portalUrl' => 'https://google.com/',
'logoutUrlPath' => 'test',
'scope' => ['test', 'test2', 'test3'],
]);
$this->assertSame('https://google.com/test', $config->getLogoutUrl());
}
}
================================================
FILE: tests/unit/Http/GuzzleHttpClientTest.php
================================================
$handler]);
$client = new GuzzleHttpClient($guzzleClient);
$response = $client->sendRequest(new Request('GET', '/'));
self::assertSame(200, $response->getStatusCode());
$this->expectException(ClientExceptionInterface::class);
$client->sendRequest(new Request('GET', '/'));
}
}
================================================
FILE: tests/unit/OpenIdCliOpensslTest.php
================================================
config = [
'clientId' => 'INSP03211',
'redirectUrl' => 'http://my-site.com/response.php',
'portalUrl' => 'https://esia-portal1.test.gosuslugi.ru/',
'privateKeyPath' => codecept_data_dir('server-gost.key'),
'privateKeyPassword' => 'test',
'certPath' => codecept_data_dir('server-gost.crt'),
'tmpPath' => codecept_log_dir(),
];
$config = new Config($this->config);
$this->openId = new OpenId($config);
$this->openId->setSigner(new CliSignerPKCS7(
$this->config['certPath'],
$this->config['privateKeyPath'],
$this->config['privateKeyPassword'],
$this->config['tmpPath']
));
}
/**
* @throws AbstractEsiaException
* @throws InvalidConfigurationException
*/
public function testGetToken(): void
{
$config = new Config($this->config);
$oid = '123';
$oidBase64 = base64_encode('{ "urn:esia:sbj_id" : ' . $oid . '}');
$client = $this->buildClientWithResponses([
new Response(200, [], '{ "access_token": "test.' . $oidBase64 . '.test"}'),
]);
$openId = new OpenId($config, $client);
$openId->setSigner(new CliSignerPKCS7(
$this->config['certPath'],
$this->config['privateKeyPath'],
$this->config['privateKeyPassword'],
$this->config['tmpPath']
));
$token = $openId->getToken('test');
self::assertNotEmpty($token);
self::assertSame($oid, $openId->getConfig()->getOid());
}
}
================================================
FILE: tests/unit/OpenIdTest.php
================================================
config = [
'clientId' => 'INSP03211',
'redirectUrl' => 'http://my-site.com/response.php',
'portalUrl' => 'https://esia-portal1.test.gosuslugi.ru/',
'privateKeyPath' => codecept_data_dir('server.key'),
'privateKeyPassword' => 'test',
'certPath' => codecept_data_dir('server.crt'),
'tmpPath' => codecept_log_dir(),
];
$config = new Config($this->config);
$this->openId = new OpenId($config);
}
/**
* @throws SignFailException
* @throws AbstractEsiaException
* @throws InvalidConfigurationException
*/
public function testGetToken(): void
{
$config = new Config($this->config);
$oid = '123';
$oidBase64 = base64_encode('{ "urn:esia:sbj_id" : ' . $oid . '}');
$client = $this->buildClientWithResponses([
new Response(200, [], '{ "access_token": "test.' . $oidBase64 . '.test"}'),
]);
$openId = new OpenId($config, $client);
$token = $openId->getToken('test');
self::assertNotEmpty($token);
self::assertSame($oid, $openId->getConfig()->getOid());
}
/**
* @throws InvalidConfigurationException
* @throws AbstractEsiaException
*/
public function testGetPersonInfo(): void
{
$config = new Config($this->config);
$oid = '123';
$config->setOid($oid);
$config->setToken('test');
$client = $this->buildClientWithResponses([
new Response(200, [], '{"username": "test"}'),
]);
$openId = new OpenId($config, $client);
$info = $openId->getPersonInfo();
self::assertNotEmpty($info);
self::assertSame(['username' => 'test'], $info);
}
/**
* @throws InvalidConfigurationException
* @throws AbstractEsiaException
*/
public function testGetContactInfo(): void
{
$config = new Config($this->config);
$oid = '123';
$config->setOid($oid);
$config->setToken('test');
$client = $this->buildClientWithResponses([
new Response(200, [], '{"size": 2, "elements": ["phone", "email"]}'),
new Response(200, [], '{"phone": "555 555 555"}'),
new Response(200, [], '{"email": "test@gmail.com"}'),
]);
$openId = new OpenId($config, $client);
$info = $openId->getContactInfo();
self::assertNotEmpty($info);
self::assertSame([['phone' => '555 555 555'], ['email' => 'test@gmail.com']], $info);
}
/**
* @throws InvalidConfigurationException
* @throws AbstractEsiaException
*/
public function testGetAddressInfo(): void
{
$config = new Config($this->config);
$oid = '123';
$config->setOid($oid);
$config->setToken('test');
$client = $this->buildClientWithResponses([
new Response(200, [], '{"size": 2, "elements": ["phone", "email"]}'),
new Response(200, [], '{"phone": "555 555 555"}'),
new Response(200, [], '{"email": "test@gmail.com"}'),
]);
$openId = new OpenId($config, $client);
$info = $openId->getAddressInfo();
self::assertNotEmpty($info);
self::assertSame([['phone' => '555 555 555'], ['email' => 'test@gmail.com']], $info);
}
/**
* @throws InvalidConfigurationException
* @throws AbstractEsiaException
*/
public function testGetDocInfo(): void
{
$config = new Config($this->config);
$oid = '123';
$config->setOid($oid);
$config->setToken('test');
$client = $this->buildClientWithResponses([
new Response(200, [], '{"size": 2, "elements": ["phone", "email"]}'),
new Response(200, [], '{"phone": "555 555 555"}'),
new Response(200, [], '{"email": "test@gmail.com"}'),
]);
$openId = new OpenId($config, $client);
$info = $openId->getDocInfo();
self::assertNotEmpty($info);
self::assertSame([['phone' => '555 555 555'], ['email' => 'test@gmail.com']], $info);
}
/**
* @throws InvalidConfigurationException
*/
public function testBuildLogoutUrl(): void
{
$config = $this->openId->getConfig();
$url = $config->getLogoutUrl() . '?client_id=' . $config->getClientId();
$logoutUrl = $this->openId->buildLogoutUrl();
self::assertSame($url, $logoutUrl);
}
/**
* @throws InvalidConfigurationException
*/
public function testBuildLogoutUrlWithRedirect(): void
{
$config = $this->openId->getConfig();
$redirectUrl = 'test.example.com';
$url = $config->getLogoutUrl() . '?client_id=' . $config->getClientId() . '&redirect_url=' . $redirectUrl;
$logoutUrl = $this->openId->buildLogoutUrl($redirectUrl);
self::assertSame($url, $logoutUrl);
}
/**
* Client with prepared responses
*
* @param array $responses
* @return ClientInterface
*/
protected function buildClientWithResponses(array $responses): ClientInterface
{
$mock = new MockHandler($responses);
$handler = HandlerStack::create($mock);
$guzzleClient = new Client(['handler' => $handler]);
return new GuzzleHttpClient($guzzleClient);
}
}
================================================
FILE: tests/unit/Signer/SignerPKCS7Test.php
================================================
sign('test');
self::assertNotEmpty($sign);
}
/**
* @throws SignFailException
*/
public function testSignCertDoesNotExists(): void
{
$signer = new SignerPKCS7(
'/test',
codecept_data_dir('server.key'),
'test',
codecept_log_dir()
);
$this->expectException(NoSuchCertificateFileException::class);
$signer->sign('test');
}
/**
* @throws SignFailException
*/
public function testPrivateKeyDoesNotExists(): void
{
$signer = new SignerPKCS7(
codecept_data_dir('server.crt'),
'/test',
'test',
codecept_log_dir()
);
$this->expectException(NoSuchKeyFileException::class);
$signer->sign('test');
}
/**
* @throws SignFailException
*/
public function testTmpDirDoesNotExists(): void
{
$signer = new SignerPKCS7(
codecept_data_dir('server.crt'),
codecept_data_dir('server.key'),
'test',
'/'
);
$this->expectException(NoSuchTmpDirException::class);
$signer->sign('test');
}
/**
* @throws SignFailException
*/
public function testTmpDirIsNotWritable(): void
{
$signer = new SignerPKCS7(
codecept_data_dir('server.crt'),
codecept_data_dir('server.key'),
'test',
codecept_log_dir('non_writable_directory')
);
$this->expectException(NoSuchTmpDirException::class);
$signer->sign('test');
}
/**
* @throws SignFailException
*/
public function testCertificateIsNotReadable(): void
{
$signer = new SignerPKCS7(
codecept_data_dir('non_readable_file'),
codecept_data_dir('server.key'),
'test',
codecept_log_dir()
);
$this->expectException(CannotReadCertificateException::class);
$signer->sign('test');
}
/**
* @throws SignFailException
*/
public function testPrivateKeyIsNotReadable(): void
{
$signer = new SignerPKCS7(
codecept_data_dir('server.crt'),
codecept_data_dir('non_readable_file'),
'test',
codecept_log_dir()
);
$this->expectException(CannotReadPrivateKeyException::class);
$signer->sign('test');
}
}
================================================
FILE: tests/unit/_bootstrap.php
================================================