Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
php-version: ['8.1', '8.2', '8.3', '8.4']
php-version: ['8.2', '8.3', '8.4', '8.5']
db-type: [sqlite, mysql, pgsql]
prefer-lowest: ['']

Expand Down Expand Up @@ -124,4 +124,4 @@ jobs:
- name: Run phpstan
if: success() || failure()
run: composer stan
continue-on-error: true
continue-on-error: true
15 changes: 10 additions & 5 deletions Docs/Documentation/Authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,21 @@ class Application extends BaseApplication implements AuthenticationServiceProvid
'password' => 'password'
];

// Load identifiers
$service->loadIdentifier('Authentication.Password', compact('fields'));

// Load the authenticators, you want session first
$service->loadAuthenticator('Authentication.Session', [
'skipTwoFactorVerify' => true
'skipTwoFactorVerify' => true,
'identifier' => [
'className' => 'Authentication.Password',
'fields' => $fields,
],
]);
$service->loadAuthenticator('Authentication.Form', [
'fields' => $fields,
'loginUrl' => '/users/login'
'loginUrl' => '/users/login',
'identifier' => [
'className' => 'Authentication.Password',
'fields' => $fields,
],
]);

return $service;
Expand Down
9 changes: 5 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@
"source": "https://github.com/CakeDC/auth"
},
"require": {
"php": ">=8.1",
"cakephp/cakephp": "^5.0"
"php": ">=8.2",
"cakephp/cakephp": "^5.3"
},
"require-dev": {
"phpunit/phpunit": "^10.0",
"phpstan/phpstan": "^2.2.2,<2.2.6",
"phpunit/phpunit": "^10.5 || ^11.1 || ^12.5",
"endroid/qr-code": "^6.0 || ^5.0",
"league/oauth2-facebook": "@stable",
"league/oauth2-instagram": "@stable",
Expand Down Expand Up @@ -70,7 +71,7 @@
"cs-check": "phpcs -n -p --standard=vendor/cakephp/cakephp-codesniffer/CakePHP ./src ./tests",
"cs-fix": "phpcbf --standard=vendor/cakephp/cakephp-codesniffer/CakePHP ./src ./tests",
"test": "phpunit --stderr",
"stan": "phpstan analyse src/",
"stan": "vendor/bin/phpstan analyse src/",
"psalm": "php vendor/psalm/phar/psalm.phar --show-info=false src/ ",
"stan-setup": "cp composer.json composer.backup && composer require --dev phpstan/phpstan:^1.9.0 psalm/phar:^5.1.0 && mv composer.backup composer.json",
"coverage-test": "phpunit --stderr --coverage-clover=clover.xml"
Expand Down
19 changes: 11 additions & 8 deletions config/auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
'redirectUri' => Router::fullBaseUrl() . '/auth/facebook',
'linkSocialUri' => Router::fullBaseUrl() . '/link-social/facebook',
'callbackLinkSocialUri' => Router::fullBaseUrl() . '/callback-link-social/facebook',
]
],
],
'twitter' => [
'service' => 'CakeDC\Auth\Social\Service\OAuth1Service',
Expand All @@ -43,7 +43,7 @@
'redirectUri' => Router::fullBaseUrl() . '/auth/linkedIn',
'linkSocialUri' => Router::fullBaseUrl() . '/link-social/linkedIn',
'callbackLinkSocialUri' => Router::fullBaseUrl() . '/callback-link-social/linkedIn',
]
],
],
'instagram' => [
'service' => 'CakeDC\Auth\Social\Service\OAuth2Service',
Expand All @@ -64,7 +64,7 @@
'redirectUri' => Router::fullBaseUrl() . '/auth/google',
'linkSocialUri' => Router::fullBaseUrl() . '/link-social/google',
'callbackLinkSocialUri' => Router::fullBaseUrl() . '/callback-link-social/google',
]
],
],
'amazon' => [
'service' => 'CakeDC\Auth\Social\Service\OAuth2Service',
Expand All @@ -74,7 +74,7 @@
'redirectUri' => Router::fullBaseUrl() . '/auth/amazon',
'linkSocialUri' => Router::fullBaseUrl() . '/link-social/amazon',
'callbackLinkSocialUri' => Router::fullBaseUrl() . '/callback-link-social/amazon',
]
],
],
'azure' => [
'service' => 'CakeDC\Auth\Social\Service\OAuth2Service',
Expand All @@ -84,7 +84,7 @@
'redirectUri' => Router::fullBaseUrl() . '/auth/azure',
'linkSocialUri' => Router::fullBaseUrl() . '/link-social/azure',
'callbackLinkSocialUri' => Router::fullBaseUrl() . '/callback-link-social/azure',
]
],
],
],
'TwoFactorProcessors' => [
Expand All @@ -110,7 +110,7 @@
// QR-code provider (more on this later)
'qrcodeprovider' => new \RobThree\Auth\Providers\Qr\EndroidQrCodeProvider(),
// Random Number Generator provider (more on this later)
'rngprovider' => null
'rngprovider' => null,
],
'Webauthn2fa' => [
'enabled' => false,
Expand All @@ -122,6 +122,9 @@
'controller' => 'Users',
'action' => 'webauthn2fa',
'prefix' => false,
]
]
],
],
'CakeDC/Auth' => [
'emitEvents' => false,
],
];
27 changes: 25 additions & 2 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,7 +1,30 @@
parameters:
level: 6
checkMissingIterableValueType: false
checkGenericClassInNonGenericObjectType: false
treatPhpDocTypesAsCertain: false
bootstrapFiles:
- tests/bootstrap.php
ignoreErrors:
-
identifier: new.static
reportUnmatched: false
-
identifier: missingType.iterableValue
reportUnmatched: false
-
identifier: missingType.generics
reportUnmatched: false
-
# Public library trait
identifier: trait.unused
path: src/Traits/IsAuthorizedTrait.php
reportUnmatched: false
-
# Testsuite library trait
identifier: trait.unused
path: src/Test/BaseTestTrait.php
reportUnmatched: false
-
# U2F deprecated - classes removed but processor retained
identifier: class.notFound
path: src/Authentication/TwoFactorProcessor/U2FProcessor.php
reportUnmatched: false
1 change: 0 additions & 1 deletion phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
<coverage/>
<php>
<ini name="memory_limit" value="-1"/>
<ini name="apc.enable_cli" value="1"/>
<env name="FIXTURE_SCHEMA_METADATA" value="./tests/schema.php"/>
<!-- SQLite
<env name="DB_URL" value="sqlite:///:memory:"/>
Expand Down
45 changes: 45 additions & 0 deletions src/AuthPlugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);

/**
* Copyright 2010 - 2019, Cake Development Corporation (https://www.cakedc.com)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2010 - 2019, Cake Development Corporation (https://www.cakedc.com)
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
namespace CakeDC\Auth;

use Cake\Core\BasePlugin;
use Cake\Core\Configure;
use Cake\Routing\RouteBuilder;

/**
* Class AuthPlugin
*
* @package CakeDC\Auth
*/
class AuthPlugin extends BasePlugin
{
public const DEPRECATED_MESSAGE_U2F =
'U2F is no longer supported by chrome, we suggest using Webauthn as a replacement';

/**
* @inheritDoc
*/
public function routes(RouteBuilder $routes): void
{
$oauthPath = Configure::read('OAuth.path');
if (is_array($oauthPath)) {
$routes->scope('/auth', function ($routes) use ($oauthPath): void {
$routes->connect(
'/:provider',
$oauthPath,
['provider' => implode('|', array_keys(Configure::read('OAuth.providers')))],
);
});
}
}
}
4 changes: 3 additions & 1 deletion src/Authentication/AuthenticationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
namespace CakeDC\Auth\Authentication;

use Authentication\AuthenticationService as BaseService;
use Authentication\Authenticator\Result;
use Authentication\Authenticator\ResultInterface;
use Authentication\Authenticator\StatelessInterface;
use Cake\Datasource\EntityInterface;
Expand Down Expand Up @@ -62,7 +63,7 @@
{
if ($this->authenticators()->isEmpty()) {
throw new RuntimeException(
'No authenticators loaded. You need to load at least one authenticator.'
'No authenticators loaded. You need to load at least one authenticator.',
);
}

Expand All @@ -71,7 +72,8 @@
foreach ($this->authenticators() as $authenticator) {
$result = $authenticator->authenticate($request);
if ($result->isValid()) {
/** @phpstan-ignore method.notFound */
$skipTwoFactorVerify = $authenticator->getConfig('skipTwoFactorVerify');

Check failure on line 76 in src/Authentication/AuthenticationService.php

View workflow job for this annotation

GitHub Actions / Coding Standard & Static Analysis

UndefinedInterfaceMethod

src/Authentication/AuthenticationService.php:76:56: UndefinedInterfaceMethod: Method Authentication\Authenticator\AuthenticatorInterface::getConfig does not exist (see https://psalm.dev/181)

Check failure on line 76 in src/Authentication/AuthenticationService.php

View workflow job for this annotation

GitHub Actions / Coding Standard & Static Analysis

UndefinedInterfaceMethod

src/Authentication/AuthenticationService.php:76:56: UndefinedInterfaceMethod: Method Authentication\Authenticator\AuthenticatorInterface::getConfig does not exist (see https://psalm.dev/181)

Check failure on line 76 in src/Authentication/AuthenticationService.php

View workflow job for this annotation

GitHub Actions / Coding Standard & Static Analysis

UndefinedInterfaceMethod

src/Authentication/AuthenticationService.php:76:56: UndefinedInterfaceMethod: Method Authentication\Authenticator\AuthenticatorInterface::getConfig does not exist (see https://psalm.dev/181)
$userData = $result->getData();
if ($userData instanceof EntityInterface) {
$userData = $userData->toArray();
Expand Down
121 changes: 121 additions & 0 deletions src/Authentication/TwoFactorProcessor/U2FProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php
declare(strict_types=1);

/**
* Copyright 2010 - 2024, Cake Development Corporation (https://www.cakedc.com)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2010 - 2024, Cake Development Corporation (https://www.cakedc.com)
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
namespace CakeDC\Auth\Authentication\TwoFactorProcessor;

use Authentication\Authenticator\Result;
use Authentication\Authenticator\ResultInterface;
use Cake\Core\Configure;
use CakeDC\Auth\Authentication\TwoFactorProcessorInterface;
use CakeDC\Auth\Authentication\U2fAuthenticationCheckerFactory;
use CakeDC\Auth\Authentication\U2fAuthenticationCheckerInterface;
use CakeDC\Auth\AuthPlugin;
use Psr\Http\Message\ServerRequestInterface;

/**
* U2FProcessor class
*/
class U2FProcessor implements TwoFactorProcessorInterface
{
public const U2F_SESSION_KEY = 'U2f.User';

public const NEED_U2F_VERIFY = 'NEED_U2F_VERIFY';

/**
* Returns processor type.
*
* @return string
*/
public function getType(): string
{
return self::NEED_U2F_VERIFY;
}

/**
* Returns processor session key.
*
* @return string
*/
public function getSessionKey(): string
{
return self::U2F_SESSION_KEY;
}

/**
* Processor status detector.
*
* @return bool
*/
public function enabled(): bool
{
$u2fEnabled = Configure::read('U2f.enabled') !== false;
if ($u2fEnabled) {
trigger_error(AuthPlugin::DEPRECATED_MESSAGE_U2F, E_USER_DEPRECATED);
}

return $u2fEnabled;
}

/**
* Processor status detector.
*
* @return bool
*/
public function isRequired(array $userData): bool
{
return $this->getU2fAuthenticationChecker()->isRequired($userData);

Check failure on line 75 in src/Authentication/TwoFactorProcessor/U2FProcessor.php

View workflow job for this annotation

GitHub Actions / Coding Standard & Static Analysis

UndefinedClass

src/Authentication/TwoFactorProcessor/U2FProcessor.php:75:16: UndefinedClass: Class, interface or enum named CakeDC\Auth\Authentication\U2fAuthenticationCheckerInterface does not exist (see https://psalm.dev/019)

Check failure on line 75 in src/Authentication/TwoFactorProcessor/U2FProcessor.php

View workflow job for this annotation

GitHub Actions / Coding Standard & Static Analysis

UndefinedClass

src/Authentication/TwoFactorProcessor/U2FProcessor.php:75:16: UndefinedClass: Class, interface or enum named CakeDC\Auth\Authentication\U2fAuthenticationCheckerInterface does not exist (see https://psalm.dev/019)

Check failure on line 75 in src/Authentication/TwoFactorProcessor/U2FProcessor.php

View workflow job for this annotation

GitHub Actions / Coding Standard & Static Analysis

UndefinedClass

src/Authentication/TwoFactorProcessor/U2FProcessor.php:75:16: UndefinedClass: Class, interface or enum named CakeDC\Auth\Authentication\U2fAuthenticationCheckerInterface does not exist (see https://psalm.dev/019)
}

/**
* Proceed to 2fa processor after a valid result result.
*
* @param \Psr\Http\Message\ServerRequestInterface $request Request instance.
* @param \Authentication\Authenticator\ResultInterface $result Input result object.
* @return \Authentication\Authenticator\ResultInterface
*/
public function proceed(ServerRequestInterface $request, ResultInterface $result): ResultInterface
{
/**
* @var \Cake\Http\Session $session
*/
$session = $request->getAttribute('session');
$session->write($this->getSessionKey(), $result->getData());
$result = new Result(null, $this->getType());

return $result;
}

/**
* Generates 2fa url, if enable.
*
* @param string $type Processor type.
* @return array|null
*/
public function getUrlByType(string $type): ?array
{
if ($type == $this->getType()) {
return Configure::read('U2f.startAction');
}

return null;
}

/**
* Get the configured u2f authentication checker
*
* @return \CakeDC\Auth\Authentication\U2fAuthenticationCheckerInterface
*/
protected function getU2fAuthenticationChecker(): U2fAuthenticationCheckerInterface

Check failure on line 117 in src/Authentication/TwoFactorProcessor/U2FProcessor.php

View workflow job for this annotation

GitHub Actions / Coding Standard & Static Analysis

UndefinedClass

src/Authentication/TwoFactorProcessor/U2FProcessor.php:117:55: UndefinedClass: Class, interface or enum named CakeDC\Auth\Authentication\U2fAuthenticationCheckerInterface does not exist (see https://psalm.dev/019)

Check failure on line 117 in src/Authentication/TwoFactorProcessor/U2FProcessor.php

View workflow job for this annotation

GitHub Actions / Coding Standard & Static Analysis

UndefinedClass

src/Authentication/TwoFactorProcessor/U2FProcessor.php:117:55: UndefinedClass: Class, interface or enum named CakeDC\Auth\Authentication\U2fAuthenticationCheckerInterface does not exist (see https://psalm.dev/019)

Check failure on line 117 in src/Authentication/TwoFactorProcessor/U2FProcessor.php

View workflow job for this annotation

GitHub Actions / Coding Standard & Static Analysis

UndefinedClass

src/Authentication/TwoFactorProcessor/U2FProcessor.php:117:55: UndefinedClass: Class, interface or enum named CakeDC\Auth\Authentication\U2fAuthenticationCheckerInterface does not exist (see https://psalm.dev/019)
{
return (new U2fAuthenticationCheckerFactory())->build();
}
}
1 change: 1 addition & 0 deletions src/Authenticator/OneTimeTokenAuthenticator.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public function authenticate(ServerRequestInterface $request): ResultInterface

$usersTable = TableRegistry::getTableLocator()->get(Configure::read('Users.table'));

/** @phpstan-ignore method.notFound */
$user = $usersTable->loginWithToken($token);

if (!$user) {
Expand Down
2 changes: 1 addition & 1 deletion src/Authenticator/SocialAuthenticator.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
}

$rawData = $this->getRawData($request, $service);
if (empty($rawData)) {

Check failure on line 66 in src/Authenticator/SocialAuthenticator.php

View workflow job for this annotation

GitHub Actions / Coding Standard & Static Analysis

RiskyTruthyFalsyComparison

src/Authenticator/SocialAuthenticator.php:66:13: RiskyTruthyFalsyComparison: Operand of type array<array-key, mixed>|null contains type array<array-key, mixed>, which can be falsy and truthy. This can cause possibly unexpected behavior. Use strict comparison instead. (see https://psalm.dev/356)

Check failure on line 66 in src/Authenticator/SocialAuthenticator.php

View workflow job for this annotation

GitHub Actions / Coding Standard & Static Analysis

RiskyTruthyFalsyComparison

src/Authenticator/SocialAuthenticator.php:66:13: RiskyTruthyFalsyComparison: Operand of type array<array-key, mixed>|null contains type array<array-key, mixed>, which can be falsy and truthy. This can cause possibly unexpected behavior. Use strict comparison instead. (see https://psalm.dev/356)

Check failure on line 66 in src/Authenticator/SocialAuthenticator.php

View workflow job for this annotation

GitHub Actions / Coding Standard & Static Analysis

RiskyTruthyFalsyComparison

src/Authenticator/SocialAuthenticator.php:66:13: RiskyTruthyFalsyComparison: Operand of type array<array-key, mixed>|null contains type array<array-key, mixed>, which can be falsy and truthy. This can cause possibly unexpected behavior. Use strict comparison instead. (see https://psalm.dev/356)
return new Result(null, Result::FAILURE_IDENTITY_NOT_FOUND);
}

Expand All @@ -79,7 +79,7 @@
protected function identify(array $rawData): Result
{
$user = $this->getIdentifier()->identify([SocialIdentifier::CREDENTIAL_KEY => $rawData]);
if (!empty($user)) {

Check failure on line 82 in src/Authenticator/SocialAuthenticator.php

View workflow job for this annotation

GitHub Actions / Coding Standard & Static Analysis

RiskyTruthyFalsyComparison

src/Authenticator/SocialAuthenticator.php:82:14: RiskyTruthyFalsyComparison: Operand of type ArrayAccess|array<array-key, mixed>|null contains type array<array-key, mixed>, which can be falsy and truthy. This can cause possibly unexpected behavior. Use strict comparison instead. (see https://psalm.dev/356)

Check failure on line 82 in src/Authenticator/SocialAuthenticator.php

View workflow job for this annotation

GitHub Actions / Coding Standard & Static Analysis

RiskyTruthyFalsyComparison

src/Authenticator/SocialAuthenticator.php:82:14: RiskyTruthyFalsyComparison: Operand of type ArrayAccess|array<array-key, mixed>|null contains type array<array-key, mixed>, which can be falsy and truthy. This can cause possibly unexpected behavior. Use strict comparison instead. (see https://psalm.dev/356)

Check failure on line 82 in src/Authenticator/SocialAuthenticator.php

View workflow job for this annotation

GitHub Actions / Coding Standard & Static Analysis

RiskyTruthyFalsyComparison

src/Authenticator/SocialAuthenticator.php:82:14: RiskyTruthyFalsyComparison: Operand of type ArrayAccess|array<array-key, mixed>|null contains type array<array-key, mixed>, which can be falsy and truthy. This can cause possibly unexpected behavior. Use strict comparison instead. (see https://psalm.dev/356)
return new Result($user, Result::SUCCESS);
}

Expand Down Expand Up @@ -108,7 +108,7 @@
$message = sprintf(
"Error getting an access token / retrieving the authorized user's profile data. Error message: %s %s",
$exception->getMessage(),
(string)$exception
(string)$exception,
);
$this->log($message);

Expand Down
2 changes: 1 addition & 1 deletion src/Authenticator/TwoFactorAuthenticator.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ protected function _buildLoginUrlErrorResult(ServerRequestInterface $request): R
sprintf(
'Login URL `%s` did not match `%s`.',
(string)$request->getUri(),
implode('` or `', (array)$this->getConfig('loginUrl'))
implode('` or `', (array)$this->getConfig('loginUrl')),
),
];

Expand Down
Loading
Loading