Compare commits
	
		
			2 Commits
		
	
	
		
			cac57d7f71
			...
			ecd1da9cb9
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| ecd1da9cb9 | |||
| 61fd393da1 | 
@ -21,3 +21,4 @@ RECAPTCHA_SITEKEY=your_recaptcha_sitekey
 | 
				
			|||||||
RECAPTCHA_SECRET=your_recaptcha_secret
 | 
					RECAPTCHA_SECRET=your_recaptcha_secret
 | 
				
			||||||
JWT_RSA_PRIVATE_KEY=jwt-rsa256-private.pem
 | 
					JWT_RSA_PRIVATE_KEY=jwt-rsa256-private.pem
 | 
				
			||||||
JWT_RSA_PUBLIC_KEY=jwt-rsa256-public.pem
 | 
					JWT_RSA_PUBLIC_KEY=jwt-rsa256-public.pem
 | 
				
			||||||
 | 
					JWT_KEY_KID=1
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					CREATE TABLE `oauth_sessions` (
 | 
				
			||||||
 | 
					  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 | 
				
			||||||
 | 
					  `client_id` varchar(255) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
 | 
				
			||||||
 | 
					  `scope` varchar(255) NOT NULL DEFAULT '',
 | 
				
			||||||
 | 
					  `nonce` varchar(255) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
 | 
				
			||||||
 | 
					  `user_id` int(10) unsigned DEFAULT NULL,
 | 
				
			||||||
 | 
					  `code` varchar(255) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
 | 
				
			||||||
 | 
					  `code_challenge` varchar(128) NULL,
 | 
				
			||||||
 | 
					  `code_challenge_method` enum('plain', 'S256') NULL,
 | 
				
			||||||
 | 
					  `token_claimed` tinyint(1) NOT NULL DEFAULT 0,
 | 
				
			||||||
 | 
					  `created` timestamp NOT NULL DEFAULT current_timestamp(),
 | 
				
			||||||
 | 
					  `expires` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
 | 
				
			||||||
 | 
					  PRIMARY KEY (`id`),
 | 
				
			||||||
 | 
					  UNIQUE KEY `code` (`code`)
 | 
				
			||||||
 | 
					) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALTER TABLE `oauth_tokens`
 | 
				
			||||||
 | 
					ADD `session_id` int(10) unsigned NULL,
 | 
				
			||||||
 | 
					ADD CONSTRAINT `oauth_tokens_session_id` FOREIGN KEY (`session_id`) REFERENCES `oauth_sessions` (`id`),
 | 
				
			||||||
 | 
					DROP INDEX `code`,
 | 
				
			||||||
 | 
					DROP INDEX `access_token`,
 | 
				
			||||||
 | 
					DROP `scope`,
 | 
				
			||||||
 | 
					DROP `nonce`,
 | 
				
			||||||
 | 
					DROP `user_id`,
 | 
				
			||||||
 | 
					DROP `code`,
 | 
				
			||||||
 | 
					DROP `access_token`;
 | 
				
			||||||
@ -5,6 +5,8 @@ use SokoWeb\Database\Query\Modify;
 | 
				
			|||||||
use SokoWeb\Database\Query\Select;
 | 
					use SokoWeb\Database\Query\Select;
 | 
				
			||||||
use SokoWeb\Interfaces\Database\IResultSet;
 | 
					use SokoWeb\Interfaces\Database\IResultSet;
 | 
				
			||||||
use RVR\Repository\UserPasswordResetterRepository;
 | 
					use RVR\Repository\UserPasswordResetterRepository;
 | 
				
			||||||
 | 
					use RVR\Repository\OAuthTokenRepository;
 | 
				
			||||||
 | 
					use RVR\Repository\OAuthSessionRepository;
 | 
				
			||||||
use Symfony\Component\Console\Command\Command;
 | 
					use Symfony\Component\Console\Command\Command;
 | 
				
			||||||
use Symfony\Component\Console\Input\InputInterface;
 | 
					use Symfony\Component\Console\Input\InputInterface;
 | 
				
			||||||
use Symfony\Component\Console\Output\OutputInterface;
 | 
					use Symfony\Component\Console\Output\OutputInterface;
 | 
				
			||||||
@ -13,6 +15,10 @@ class MaintainDatabaseCommand extends Command
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    private UserPasswordResetterRepository $userPasswordResetterRepository;
 | 
					    private UserPasswordResetterRepository $userPasswordResetterRepository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private OAuthTokenRepository $oauthTokenRepository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private OAuthSessionRepository $oauthSessionRepository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function __construct()
 | 
					    public function __construct()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        parent::__construct();
 | 
					        parent::__construct();
 | 
				
			||||||
@ -31,6 +37,8 @@ class MaintainDatabaseCommand extends Command
 | 
				
			|||||||
        try {
 | 
					        try {
 | 
				
			||||||
            $this->deleteExpiredPasswordResetters();
 | 
					            $this->deleteExpiredPasswordResetters();
 | 
				
			||||||
            $this->deleteExpiredSessions();
 | 
					            $this->deleteExpiredSessions();
 | 
				
			||||||
 | 
					            $this->deleteExpiredOauthTokens();
 | 
				
			||||||
 | 
					            $this->deleteExpiredOauthSessions();
 | 
				
			||||||
        } catch (\Exception $e) {
 | 
					        } catch (\Exception $e) {
 | 
				
			||||||
            $output->writeln('<error>Maintenance failed!</error>');
 | 
					            $output->writeln('<error>Maintenance failed!</error>');
 | 
				
			||||||
            $output->writeln('');
 | 
					            $output->writeln('');
 | 
				
			||||||
@ -59,7 +67,7 @@ class MaintainDatabaseCommand extends Command
 | 
				
			|||||||
        //TODO: model may be used for sessions too
 | 
					        //TODO: model may be used for sessions too
 | 
				
			||||||
        $select = new Select(\Container::$dbConnection, 'sessions');
 | 
					        $select = new Select(\Container::$dbConnection, 'sessions');
 | 
				
			||||||
        $select->columns(['id']);
 | 
					        $select->columns(['id']);
 | 
				
			||||||
        $select->where('updated', '<', (new DateTime('-7 days'))->format('Y-m-d H:i:s'));
 | 
					        $select->where('updated', '<', (new DateTime('-1 days'))->format('Y-m-d H:i:s'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $result = $select->execute();
 | 
					        $result = $select->execute();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -69,4 +77,21 @@ class MaintainDatabaseCommand extends Command
 | 
				
			|||||||
            $modify->delete();
 | 
					            $modify->delete();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function deleteExpiredOauthTokens(): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        foreach ($this->oauthTokenRepository->getAllExpired() as $oauthToken) {
 | 
				
			||||||
 | 
					            \Container::$persistentDataManager->deleteFromDb($oauthToken);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function deleteExpiredOauthSessions(): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        foreach ($this->oauthSessionRepository->getAllExpired() as $oauthSession) {
 | 
				
			||||||
 | 
					            if ($this->oauthTokenRepository->countAllBySession($oauthSession) > 0) {
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            \Container::$persistentDataManager->deleteFromDb($oauthSession);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,79 +0,0 @@
 | 
				
			|||||||
<?php namespace RVR\Controller;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use DateTime;
 | 
					 | 
				
			||||||
use RVR\PersistentData\Model\OAuthToken;
 | 
					 | 
				
			||||||
use RVR\PersistentData\Model\User;
 | 
					 | 
				
			||||||
use RVR\Repository\OAuthClientRepository;
 | 
					 | 
				
			||||||
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
 | 
					 | 
				
			||||||
use SokoWeb\Interfaces\Response\IRedirect;
 | 
					 | 
				
			||||||
use SokoWeb\Response\Redirect;
 | 
					 | 
				
			||||||
use SokoWeb\Response\HtmlContent;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class OAuthAuthController implements IAuthenticationRequired
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    private OAuthClientRepository $oAuthClientRepository;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function __construct()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $this->oAuthClientRepository = new OAuthClientRepository();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function isAuthenticationRequired(): bool
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function auth()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $redirectUri = \Container::$request->query('redirect_uri');
 | 
					 | 
				
			||||||
        $clientId = \Container::$request->query('client_id');
 | 
					 | 
				
			||||||
        $scope = \Container::$request->query('scope') ? \Container::$request->query('scope'): '';
 | 
					 | 
				
			||||||
        $state = \Container::$request->query('state');
 | 
					 | 
				
			||||||
        $nonce = \Container::$request->query('nonce') ? \Container::$request->query('nonce'): '';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!$clientId || !$redirectUri || !$state) {
 | 
					 | 
				
			||||||
            return new HtmlContent('oauth/oauth_error', ['error' => 'An invalid request was made. Please start authentication again.']);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $client = $this->oAuthClientRepository->getByClientId($clientId);
 | 
					 | 
				
			||||||
        if ($client === null) {
 | 
					 | 
				
			||||||
            return new HtmlContent('oauth/oauth_error', ['error' => 'Client is not authorized.']);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $redirectUriParsed = parse_url($redirectUri);
 | 
					 | 
				
			||||||
        $redirectUriBase = $redirectUriParsed['scheme'] . '://' . $redirectUriParsed['host'] . $redirectUriParsed['path'];
 | 
					 | 
				
			||||||
        $redirectUriQuery = [];
 | 
					 | 
				
			||||||
        if (isset($redirectUriParsed['query'])) {
 | 
					 | 
				
			||||||
            parse_str($redirectUriParsed['query'], $redirectUriQuery);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!in_array($redirectUriBase, $client->getRedirectUrisArray())) {
 | 
					 | 
				
			||||||
            return new HtmlContent('oauth/oauth_error', ['error' => 'Redirect URI \'' . $redirectUriBase .'\' is not allowed for this client.']);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /**
 | 
					 | 
				
			||||||
        * @var ?User $user
 | 
					 | 
				
			||||||
        */
 | 
					 | 
				
			||||||
        $user = \Container::$request->user();
 | 
					 | 
				
			||||||
        $code = bin2hex(random_bytes(16));
 | 
					 | 
				
			||||||
        $accessToken = bin2hex(random_bytes(16));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $token = new OAuthToken();
 | 
					 | 
				
			||||||
        $token->setNonce($nonce);
 | 
					 | 
				
			||||||
        $token->setScope($scope);
 | 
					 | 
				
			||||||
        $token->setUser($user);
 | 
					 | 
				
			||||||
        $token->setCode($code);
 | 
					 | 
				
			||||||
        $token->setAccessToken($accessToken);
 | 
					 | 
				
			||||||
        $token->setCreatedDate(new DateTime());
 | 
					 | 
				
			||||||
        $token->setExpiresDate(new DateTime('+5 minutes'));
 | 
					 | 
				
			||||||
        \Container::$persistentDataManager->saveToDb($token);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $redirectUriQuery = array_merge($redirectUriQuery, [
 | 
					 | 
				
			||||||
            'state' => $state,
 | 
					 | 
				
			||||||
            'code' => $code
 | 
					 | 
				
			||||||
        ]);
 | 
					 | 
				
			||||||
        $finalRedirectUri = $redirectUriBase . '?' . http_build_query($redirectUriQuery);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return new Redirect($finalRedirectUri, IRedirect::TEMPORARY);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -2,9 +2,16 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use DateTime;
 | 
					use DateTime;
 | 
				
			||||||
use Firebase\JWT\JWT;
 | 
					use Firebase\JWT\JWT;
 | 
				
			||||||
 | 
					use Firebase\JWT\Key;
 | 
				
			||||||
 | 
					use Firebase\JWT\SignatureInvalidException;
 | 
				
			||||||
 | 
					use Firebase\JWT\BeforeValidException;
 | 
				
			||||||
 | 
					use Firebase\JWT\ExpiredException;
 | 
				
			||||||
 | 
					use RVR\Repository\OAuthSessionRepository;
 | 
				
			||||||
use RVR\Repository\OAuthTokenRepository;
 | 
					use RVR\Repository\OAuthTokenRepository;
 | 
				
			||||||
use RVR\Repository\UserRepository;
 | 
					use RVR\Repository\UserRepository;
 | 
				
			||||||
use RVR\PersistentData\Model\User;
 | 
					use RVR\PersistentData\Model\User;
 | 
				
			||||||
 | 
					use RVR\PersistentData\Model\OAuthSession;
 | 
				
			||||||
 | 
					use RVR\PersistentData\Model\OAuthToken;
 | 
				
			||||||
use RVR\Repository\OAuthClientRepository;
 | 
					use RVR\Repository\OAuthClientRepository;
 | 
				
			||||||
use SokoWeb\Interfaces\Response\IContent;
 | 
					use SokoWeb\Interfaces\Response\IContent;
 | 
				
			||||||
use SokoWeb\Response\JsonContent;
 | 
					use SokoWeb\Response\JsonContent;
 | 
				
			||||||
@ -13,6 +20,8 @@ class OAuthController
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    private OAuthClientRepository $oAuthClientRepository;
 | 
					    private OAuthClientRepository $oAuthClientRepository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private OAuthSessionRepository $oAuthSessionRepository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private OAuthTokenRepository $oAuthTokenRepository;
 | 
					    private OAuthTokenRepository $oAuthTokenRepository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private UserRepository $userRepository;
 | 
					    private UserRepository $userRepository;
 | 
				
			||||||
@ -20,60 +29,181 @@ class OAuthController
 | 
				
			|||||||
    public function __construct()
 | 
					    public function __construct()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->oAuthClientRepository = new OAuthClientRepository();
 | 
					        $this->oAuthClientRepository = new OAuthClientRepository();
 | 
				
			||||||
 | 
					        $this->oAuthSessionRepository = new OAuthSessionRepository();
 | 
				
			||||||
        $this->oAuthTokenRepository = new OAuthTokenRepository();
 | 
					        $this->oAuthTokenRepository = new OAuthTokenRepository();
 | 
				
			||||||
        $this->userRepository = new UserRepository();
 | 
					        $this->userRepository = new UserRepository();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function getToken(): ?IContent
 | 
					    public function generateToken(): ?IContent
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $clientId = \Container::$request->post('client_id');
 | 
					        $credentials = $this->getClientCredentials();
 | 
				
			||||||
        $clientSecret = \Container::$request->post('client_secret');
 | 
					 | 
				
			||||||
        $code = \Container::$request->post('code');
 | 
					        $code = \Container::$request->post('code');
 | 
				
			||||||
 | 
					        $redirectUri = \Container::$request->post('redirect_uri');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!$clientId || !$clientSecret || !$code) {
 | 
					        if (!$credentials['clientId'] || !$code || !$redirectUri) {
 | 
				
			||||||
            return new JsonContent([
 | 
					            return new JsonContent([
 | 
				
			||||||
                'error' => 'An invalid request was made.'
 | 
					                'error' => 'An invalid request was made.'
 | 
				
			||||||
            ]);
 | 
					            ]);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $client = $this->oAuthClientRepository->getByClientId($clientId);
 | 
					        $client = $this->oAuthClientRepository->getByClientId($credentials['clientId']);
 | 
				
			||||||
        if ($client === null || $client->getClientSecret() !== $clientSecret) {
 | 
					        if ($client === null) {
 | 
				
			||||||
            return new JsonContent([
 | 
					            return new JsonContent([
 | 
				
			||||||
                'error' => 'Client is not authorized.'
 | 
					                'error' => 'Client is not found.'
 | 
				
			||||||
            ]);
 | 
					            ]);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $token = $this->oAuthTokenRepository->getByCode($code);
 | 
					        $redirectUriBase = explode('?', $redirectUri)[0];
 | 
				
			||||||
        if ($token === null || $token->getExpiresDate() < new DateTime()) {
 | 
					        if (!in_array($redirectUriBase, $client->getRedirectUrisArray())) {
 | 
				
			||||||
 | 
					            return new JsonContent([
 | 
				
			||||||
 | 
					                'error' => 'Redirect URI \'' . $redirectUriBase .'\' is not allowed for this client.'
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $session = $this->oAuthSessionRepository->getByCode($code);
 | 
				
			||||||
 | 
					        if ($session === null || $session->getTokenClaimed() || $session->getExpiresDate() < new DateTime()) {
 | 
				
			||||||
            return new JsonContent([
 | 
					            return new JsonContent([
 | 
				
			||||||
                'error' => 'The provided code is invalid.'
 | 
					                'error' => 'The provided code is invalid.'
 | 
				
			||||||
            ]);
 | 
					            ]);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $payload = array_merge([
 | 
					        $codeChallenge = $session->getCodeChallenge();
 | 
				
			||||||
 | 
					        if ($codeChallenge === null && $client->getClientSecret() !== $credentials['clientSecret']) {
 | 
				
			||||||
 | 
					            return new JsonContent([
 | 
				
			||||||
 | 
					                'error' => 'Client is not authorized.'
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($session->getClientId() !== $credentials['clientId']) {
 | 
				
			||||||
 | 
					            return new JsonContent([
 | 
				
			||||||
 | 
					                'error' => 'This code cannot be used by this client!'
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($codeChallenge !== null) {
 | 
				
			||||||
 | 
					            $codeVerifier = \Container::$request->post('code_verifier') ?: '';
 | 
				
			||||||
 | 
					            if ($session->getCodeChallengeMethod() === 'S256') {
 | 
				
			||||||
 | 
					                $hash = rtrim(strtr(base64_encode(hash('sha256', $codeVerifier, true)), '+/', '-_'), '=');
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                $hash = $codeVerifier;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if ($codeChallenge !== $hash) {
 | 
				
			||||||
 | 
					                return new JsonContent([
 | 
				
			||||||
 | 
					                    'error' => 'Code challenge failed!'
 | 
				
			||||||
 | 
					                ]);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $session->setTokenClaimed(true);
 | 
				
			||||||
 | 
					        \Container::$persistentDataManager->saveToDb($session);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $token = new OAuthToken();
 | 
				
			||||||
 | 
					        $token->setSession($session);
 | 
				
			||||||
 | 
					        $token->setCreatedDate(new DateTime());
 | 
				
			||||||
 | 
					        $token->setExpiresDate(new DateTime('+1 hours'));
 | 
				
			||||||
 | 
					        \Container::$persistentDataManager->saveToDb($token);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $commonPayload = [
 | 
				
			||||||
            'iss' => $_ENV['APP_URL'],
 | 
					            'iss' => $_ENV['APP_URL'],
 | 
				
			||||||
            'iat' => (int)$token->getCreatedDate()->getTimestamp(),
 | 
					            'iat' => $token->getCreatedDate()->getTimestamp(),
 | 
				
			||||||
            'nbf' => (int)$token->getCreatedDate()->getTimestamp(),
 | 
					            'nbf' => $session->getCreatedDate()->getTimestamp(),
 | 
				
			||||||
            'exp' => (int)$token->getExpiresDate()->getTimestamp(),
 | 
					            'exp' => $token->getExpiresDate()->getTimestamp(),
 | 
				
			||||||
            'aud' => $clientId,
 | 
					            'aud' => $session->getClientId(),
 | 
				
			||||||
            'nonce' => $token->getNonce()
 | 
					            'nonce' => $session->getNonce()
 | 
				
			||||||
        ], $this->getUserInfoInternal(
 | 
					        ];
 | 
				
			||||||
            $this->userRepository->getById($token->getUserId()),
 | 
					        $idTokenPayload = array_merge($commonPayload, $this->getUserInfoInternal(
 | 
				
			||||||
            $token->getScopeArray())
 | 
					            $this->userRepository->getById($session->getUserId()),
 | 
				
			||||||
 | 
					            $session->getScopeArray())
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					        $accessTokenPayload = array_merge($commonPayload, [
 | 
				
			||||||
 | 
					            'jti' => $token->getId(),
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $privateKey = file_get_contents(ROOT . '/' . $_ENV['JWT_RSA_PRIVATE_KEY']);
 | 
					        $privateKey = file_get_contents(ROOT . '/' . $_ENV['JWT_RSA_PRIVATE_KEY']);
 | 
				
			||||||
        $jwt = JWT::encode($payload, $privateKey, 'RS256');
 | 
					        $idToken = JWT::encode($idTokenPayload, $privateKey, 'RS256', $_ENV['JWT_KEY_KID']);
 | 
				
			||||||
 | 
					        $accessToken = JWT::encode($accessTokenPayload, $privateKey, 'RS256', $_ENV['JWT_KEY_KID']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return new JsonContent([
 | 
					        return new JsonContent([
 | 
				
			||||||
            'access_token' => $token->getAccessToken(),
 | 
					            'access_token' => $accessToken,
 | 
				
			||||||
            'expires_in' => $token->getExpiresDate()->getTimestamp() - (new DateTime())->getTimestamp(),
 | 
					            'expires_in' => $token->getExpiresDate()->getTimestamp() - (new DateTime())->getTimestamp(),
 | 
				
			||||||
            'scope' => $token->getScope(),
 | 
					            'scope' => $session->getScope(),
 | 
				
			||||||
            'id_token' => $jwt,
 | 
					            'id_token' => $idToken,
 | 
				
			||||||
            'token_type' => 'Bearer'
 | 
					            'token_type' => 'Bearer'
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function introspectToken(): ?IContent
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $credentials = $this->getClientCredentials();
 | 
				
			||||||
 | 
					        $accessToken = \Container::$request->post('token');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!$credentials['clientId'] || !$credentials['clientSecret'] || !$accessToken) {
 | 
				
			||||||
 | 
					            return new JsonContent([
 | 
				
			||||||
 | 
					                'error' => 'An invalid request was made.'
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $client = $this->oAuthClientRepository->getByClientId($credentials['clientId']);
 | 
				
			||||||
 | 
					        if ($client === null || $client->getClientSecret() !== $credentials['clientSecret']) {
 | 
				
			||||||
 | 
					            return new JsonContent([
 | 
				
			||||||
 | 
					                'error' => 'Client is not authorized.'
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $tokenValidated = $this->validateTokenAndSession($accessToken, $token, $session);
 | 
				
			||||||
 | 
					        if (!$tokenValidated) {
 | 
				
			||||||
 | 
					            return new JsonContent([
 | 
				
			||||||
 | 
					                'active' => false
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($session->getClientId() !== $credentials['clientId']) {
 | 
				
			||||||
 | 
					            return new JsonContent([
 | 
				
			||||||
 | 
					                'active' => false
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new JsonContent([
 | 
				
			||||||
 | 
					            'active' => true,
 | 
				
			||||||
 | 
					            'scope' => $session->getScope(),
 | 
				
			||||||
 | 
					            'client_id' => $session->getClientId(),
 | 
				
			||||||
 | 
					            'exp' => $token->getExpiresDate()->getTimestamp(),
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function revokeToken(): ?IContent
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $credentials = $this->getClientCredentials();
 | 
				
			||||||
 | 
					        $accessToken = \Container::$request->post('token');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!$credentials['clientId'] || !$credentials['clientSecret'] || !$accessToken) {
 | 
				
			||||||
 | 
					            return new JsonContent([
 | 
				
			||||||
 | 
					                'error' => 'An invalid request was made.'
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $client = $this->oAuthClientRepository->getByClientId($credentials['clientId']);
 | 
				
			||||||
 | 
					        if ($client === null || $client->getClientSecret() !== $credentials['clientSecret']) {
 | 
				
			||||||
 | 
					            return new JsonContent([
 | 
				
			||||||
 | 
					                'error' => 'Client is not authorized.'
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $tokenValidated = $this->validateTokenAndSession($accessToken, $token, $session);
 | 
				
			||||||
 | 
					        if (!$tokenValidated) {
 | 
				
			||||||
 | 
					            return new JsonContent([]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $session = $this->oAuthSessionRepository->getById($token->getSessionId());
 | 
				
			||||||
 | 
					        if ($session->getClientId() !== $credentials['clientId']) {
 | 
				
			||||||
 | 
					            return new JsonContent([]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        \Container::$persistentDataManager->deleteFromDb($token);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new JsonContent([]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function getUserInfo() : IContent
 | 
					    public function getUserInfo() : IContent
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $authorization = \Container::$request->header('Authorization');
 | 
					        $authorization = \Container::$request->header('Authorization');
 | 
				
			||||||
@ -84,9 +214,8 @@ class OAuthController
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $accessToken = substr($authorization, strlen('Bearer '));
 | 
					        $accessToken = substr($authorization, strlen('Bearer '));
 | 
				
			||||||
        $token = $this->oAuthTokenRepository->getByAccessToken($accessToken);
 | 
					        $tokenValidated = $this->validateTokenAndSession($accessToken, $token, $session);
 | 
				
			||||||
 | 
					        if (!$tokenValidated) {
 | 
				
			||||||
        if ($token === null || $token->getExpiresDate() < new DateTime()) {
 | 
					 | 
				
			||||||
            return new JsonContent([
 | 
					            return new JsonContent([
 | 
				
			||||||
                'error' => 'The provided access token is invalid.'
 | 
					                'error' => 'The provided access token is invalid.'
 | 
				
			||||||
            ]);
 | 
					            ]);
 | 
				
			||||||
@ -94,8 +223,8 @@ class OAuthController
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return new JsonContent(
 | 
					        return new JsonContent(
 | 
				
			||||||
            $this->getUserInfoInternal(
 | 
					            $this->getUserInfoInternal(
 | 
				
			||||||
                $this->userRepository->getById($token->getUserId()),
 | 
					                $this->userRepository->getById($session->getUserId()),
 | 
				
			||||||
                $token->getScopeArray()
 | 
					                $session->getScopeArray()
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -106,7 +235,10 @@ class OAuthController
 | 
				
			|||||||
            'issuer' => $_ENV['APP_URL'],
 | 
					            'issuer' => $_ENV['APP_URL'],
 | 
				
			||||||
            'authorization_endpoint' => \Container::$request->getBase() . \Container::$routeCollection->getRoute('oauth.auth')->generateLink(),
 | 
					            'authorization_endpoint' => \Container::$request->getBase() . \Container::$routeCollection->getRoute('oauth.auth')->generateLink(),
 | 
				
			||||||
            'token_endpoint' => \Container::$request->getBase() . \Container::$routeCollection->getRoute('oauth.token')->generateLink(),
 | 
					            'token_endpoint' => \Container::$request->getBase() . \Container::$routeCollection->getRoute('oauth.token')->generateLink(),
 | 
				
			||||||
 | 
					            'introspection_endpoint' => \Container::$request->getBase() . \Container::$routeCollection->getRoute('oauth.token.introspect')->generateLink(),
 | 
				
			||||||
 | 
					            'revocation_endpoint' => \Container::$request->getBase() . \Container::$routeCollection->getRoute('oauth.token.revoke')->generateLink(),
 | 
				
			||||||
            'userinfo_endpoint' => \Container::$request->getBase() . \Container::$routeCollection->getRoute('oauth.userinfo')->generateLink(),
 | 
					            'userinfo_endpoint' => \Container::$request->getBase() . \Container::$routeCollection->getRoute('oauth.userinfo')->generateLink(),
 | 
				
			||||||
 | 
					            'end_session_endpoint' => \Container::$request->getBase() . \Container::$routeCollection->getRoute('logout')->generateLink(),
 | 
				
			||||||
            'jwks_uri' => \Container::$request->getBase() . \Container::$routeCollection->getRoute('oauth.certs')->generateLink(),
 | 
					            'jwks_uri' => \Container::$request->getBase() . \Container::$routeCollection->getRoute('oauth.certs')->generateLink(),
 | 
				
			||||||
            'response_types_supported' =>
 | 
					            'response_types_supported' =>
 | 
				
			||||||
            [
 | 
					            [
 | 
				
			||||||
@ -128,6 +260,7 @@ class OAuthController
 | 
				
			|||||||
            ],
 | 
					            ],
 | 
				
			||||||
            'token_endpoint_auth_methods_supported' =>
 | 
					            'token_endpoint_auth_methods_supported' =>
 | 
				
			||||||
            [
 | 
					            [
 | 
				
			||||||
 | 
					                'client_secret_basic',
 | 
				
			||||||
                'client_secret_post',
 | 
					                'client_secret_post',
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
            'claims_supported' =>
 | 
					            'claims_supported' =>
 | 
				
			||||||
@ -167,13 +300,66 @@ class OAuthController
 | 
				
			|||||||
                'kty' => 'RSA',
 | 
					                'kty' => 'RSA',
 | 
				
			||||||
                'alg' => 'RS256',
 | 
					                'alg' => 'RS256',
 | 
				
			||||||
                'use' => 'sig',
 | 
					                'use' => 'sig',
 | 
				
			||||||
                'kid' => '1',
 | 
					                'kid' => $_ENV['JWT_KEY_KID'],
 | 
				
			||||||
                'n' => str_replace(['+', '/'], ['-', '_'], base64_encode($keyInfo['rsa']['n'])),
 | 
					                'n' => str_replace(['+', '/'], ['-', '_'], base64_encode($keyInfo['rsa']['n'])),
 | 
				
			||||||
                'e' => str_replace(['+', '/'], ['-', '_'], base64_encode($keyInfo['rsa']['e'])),
 | 
					                'e' => str_replace(['+', '/'], ['-', '_'], base64_encode($keyInfo['rsa']['e'])),
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        ]]);
 | 
					        ]]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function getClientCredentials(): array
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $authorization = \Container::$request->header('Authorization');
 | 
				
			||||||
 | 
					        if ($authorization !== null) {
 | 
				
			||||||
 | 
					            $basicAuthEncoded = substr($authorization, strlen('Basic '));
 | 
				
			||||||
 | 
					            $basicAuth = explode(':', base64_decode($basicAuthEncoded));
 | 
				
			||||||
 | 
					            if (count($basicAuth) === 2) {
 | 
				
			||||||
 | 
					                $clientId = rawurldecode($basicAuth[0]);
 | 
				
			||||||
 | 
					                $clientSecret = rawurldecode($basicAuth[1]);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                $clientId = null;
 | 
				
			||||||
 | 
					                $clientSecret = null;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $clientId = \Container::$request->post('client_id');
 | 
				
			||||||
 | 
					            $clientSecret = \Container::$request->post('client_secret');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return ['clientId' => $clientId, 'clientSecret' => $clientSecret];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function validateTokenAndSession(
 | 
				
			||||||
 | 
					        string $accessToken,
 | 
				
			||||||
 | 
					        ?OAuthToken &$token,
 | 
				
			||||||
 | 
					        ?OAuthSession &$session): bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $publicKey = file_get_contents(ROOT . '/' . $_ENV['JWT_RSA_PUBLIC_KEY']);
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            $payload = JWT::decode($accessToken, new Key($publicKey, 'RS256'));
 | 
				
			||||||
 | 
					            $token = $this->oAuthTokenRepository->getById($payload->jti);
 | 
				
			||||||
 | 
					        } catch (SignatureInvalidException | BeforeValidException | ExpiredException) {
 | 
				
			||||||
 | 
					            $token = null;
 | 
				
			||||||
 | 
					        } catch (\UnexpectedValueException $e) {
 | 
				
			||||||
 | 
					            error_log($e->getMessage() . ' Token was: ' . $accessToken);
 | 
				
			||||||
 | 
					            $token = null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($token === null || $token->getExpiresDate() < new DateTime()) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $session = $this->oAuthSessionRepository->getById($token->getSessionId());
 | 
				
			||||||
 | 
					        if ($session === null) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param User $user
 | 
				
			||||||
 | 
					     * @param string[] $scope
 | 
				
			||||||
 | 
					     * @return array<string, string>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    private function getUserInfoInternal(User $user, array $scope): array
 | 
					    private function getUserInfoInternal(User $user, array $scope): array
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $userInfo = [];
 | 
					        $userInfo = [];
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										90
									
								
								src/Controller/OAuthSessionController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/Controller/OAuthSessionController.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,90 @@
 | 
				
			|||||||
 | 
					<?php namespace RVR\Controller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use DateTime;
 | 
				
			||||||
 | 
					use RVR\PersistentData\Model\OAuthSession;
 | 
				
			||||||
 | 
					use RVR\PersistentData\Model\User;
 | 
				
			||||||
 | 
					use RVR\Repository\OAuthClientRepository;
 | 
				
			||||||
 | 
					use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
 | 
				
			||||||
 | 
					use SokoWeb\Interfaces\Response\IRedirect;
 | 
				
			||||||
 | 
					use SokoWeb\Response\Redirect;
 | 
				
			||||||
 | 
					use SokoWeb\Response\HtmlContent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class OAuthSessionController implements IAuthenticationRequired
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private OAuthClientRepository $oAuthClientRepository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function __construct()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->oAuthClientRepository = new OAuthClientRepository();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function isAuthenticationRequired(): bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function auth(): HtmlContent|Redirect
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $redirectUri = \Container::$request->query('redirect_uri');
 | 
				
			||||||
 | 
					        $clientId = \Container::$request->query('client_id');
 | 
				
			||||||
 | 
					        $scope = \Container::$request->query('scope') ? \Container::$request->query('scope'): '';
 | 
				
			||||||
 | 
					        $state = \Container::$request->query('state');
 | 
				
			||||||
 | 
					        $nonce = \Container::$request->query('nonce') ? \Container::$request->query('nonce'): '';
 | 
				
			||||||
 | 
					        $codeChallenge = \Container::$request->query('code_challenge') ?: null;
 | 
				
			||||||
 | 
					        $codeChallengeMethod = \Container::$request->query('code_challenge_method') ?: null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!$clientId || !$redirectUri || !$state || (!$codeChallenge && $codeChallengeMethod)) {
 | 
				
			||||||
 | 
					            return new HtmlContent('oauth/oauth_error', ['error' => 'An invalid request was made. Please start authentication again.']);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($codeChallenge && (strlen($codeChallenge) < 43 || strlen($codeChallenge) > 128)) {
 | 
				
			||||||
 | 
					            return new HtmlContent('oauth/oauth_error', ['error' => 'Code challenge should be one between 43 and 128 characters long.']);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $possibleCodeChallengeMethods = ['plain', 'S256'];
 | 
				
			||||||
 | 
					        if ($codeChallenge && !in_array($codeChallengeMethod, $possibleCodeChallengeMethods)) {
 | 
				
			||||||
 | 
					            return new HtmlContent('oauth/oauth_error', ['error' => 'Code challenge method should be one of the following: ' . implode(',', $possibleCodeChallengeMethods)]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $client = $this->oAuthClientRepository->getByClientId($clientId);
 | 
				
			||||||
 | 
					        if ($client === null) {
 | 
				
			||||||
 | 
					            return new HtmlContent('oauth/oauth_error', ['error' => 'Client is not found.']);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $redirectUriQueryParsed = [];
 | 
				
			||||||
 | 
					        if (str_contains('?', $redirectUri)) {
 | 
				
			||||||
 | 
					            [$redirectUriBase, $redirectUriQuery] = explode('?', $redirectUri, 2);
 | 
				
			||||||
 | 
					            parse_str($redirectUriQuery, $redirectUriQueryParsed);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $redirectUriBase = $redirectUri;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (!in_array($redirectUriBase, $client->getRedirectUrisArray())) {
 | 
				
			||||||
 | 
					            return new HtmlContent('oauth/oauth_error', ['error' => 'Redirect URI \'' . $redirectUriBase .'\' is not allowed for this client.']);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					        * @var ?User $user
 | 
				
			||||||
 | 
					        */
 | 
				
			||||||
 | 
					        $user = \Container::$request->user();
 | 
				
			||||||
 | 
					        $code = bin2hex(random_bytes(16));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $session = new OAuthSession();
 | 
				
			||||||
 | 
					        $session->setClientId($clientId);
 | 
				
			||||||
 | 
					        $session->setNonce($nonce);
 | 
				
			||||||
 | 
					        $session->setScope($scope);
 | 
				
			||||||
 | 
					        $session->setCodeChallenge($codeChallenge);
 | 
				
			||||||
 | 
					        $session->setCodeChallengeMethod($codeChallengeMethod);
 | 
				
			||||||
 | 
					        $session->setUser($user);
 | 
				
			||||||
 | 
					        $session->setCode($code);
 | 
				
			||||||
 | 
					        $session->setCreatedDate(new DateTime());
 | 
				
			||||||
 | 
					        $session->setExpiresDate(new DateTime('+5 minutes'));
 | 
				
			||||||
 | 
					        \Container::$persistentDataManager->saveToDb($session);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $redirectUriQueryParsed = array_merge($redirectUriQueryParsed, [
 | 
				
			||||||
 | 
					            'state' => $state,
 | 
				
			||||||
 | 
					            'code' => $code
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					        $finalRedirectUri = $redirectUriBase . '?' . http_build_query($redirectUriQueryParsed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new Redirect($finalRedirectUri, IRedirect::TEMPORARY);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										182
									
								
								src/PersistentData/Model/OAuthSession.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								src/PersistentData/Model/OAuthSession.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,182 @@
 | 
				
			|||||||
 | 
					<?php namespace RVR\PersistentData\Model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use DateTime;
 | 
				
			||||||
 | 
					use SokoWeb\PersistentData\Model\Model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class OAuthSession extends Model
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected static string $table = 'oauth_sessions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected static array $fields = ['client_id', 'scope', 'nonce', 'code_challenge', 'code_challenge_method', 'user_id', 'code', 'created', 'expires', 'token_claimed'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected static array $relations = ['user' => User::class];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static array $possibleScopeValues = ['openid', 'email', 'profile', 'union_profile'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static array $possibleCodeChallengeMethodValues = ['plain', 'S256'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private string $clientId = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private array $scope = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private string $nonce = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private ?string $codeChallenge = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private ?string $codeChallengeMethod = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private ?User $user = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private ?int $userId = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private string $code = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private DateTime $created;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private DateTime $expires;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private bool $tokenClaimed = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setScopeArray(array $scope): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->scope = array_intersect($scope, self::$possibleScopeValues);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setClientId(string $clientId): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->clientId = $clientId;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setScope(string $scope): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->setScopeArray(explode(' ', $scope));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setNonce(string $nonce): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->nonce = $nonce;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setCodeChallenge(?string $codeChallenge): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->codeChallenge = $codeChallenge;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setCodeChallengeMethod(?string $codeChallengeMethod): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($codeChallengeMethod !== null && !in_array($codeChallengeMethod, self::$possibleCodeChallengeMethodValues)) {
 | 
				
			||||||
 | 
					            throw new \UnexpectedValueException($codeChallengeMethod . ' is not possible for challengeMethod!');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $this->codeChallengeMethod = $codeChallengeMethod;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setUser(User $user): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->user = $user;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setUserId(int $userId): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->userId = $userId;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setCode(string $code): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->code = $code;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setCreatedDate(DateTime $created): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->created = $created;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setExpiresDate(DateTime $expires): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->expires = $expires;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setCreated(string $created): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->created = new DateTime($created);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setExpires(string $expires): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->expires = new DateTime($expires);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setTokenClaimed(bool $tokenClaimed): void
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->tokenClaimed = $tokenClaimed;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getClientId(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->clientId;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getScope(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return implode(' ', $this->scope);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getScopeArray(): array
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->scope;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getNonce(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->nonce;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getCodeChallenge(): ?string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->codeChallenge;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getCodeChallengeMethod(): ?string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->codeChallengeMethod;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getUser(): ?User
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->user;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getUserId(): ?int
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->userId;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getCode(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->code;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getCreatedDate(): DateTime
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->created;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getCreated(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->created->format('Y-m-d H:i:s');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getExpiresDate(): DateTime
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->expires;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getExpires(): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->expires->format('Y-m-d H:i:s');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getTokenClaimed(): bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->tokenClaimed;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -7,61 +7,26 @@ class OAuthToken extends Model
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    protected static string $table = 'oauth_tokens';
 | 
					    protected static string $table = 'oauth_tokens';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected static array $fields = ['scope', 'nonce', 'user_id', 'code', 'access_token', 'created', 'expires'];
 | 
					    protected static array $fields = ['session_id', 'created', 'expires'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected static array $relations = ['user' => User::class];
 | 
					    protected static array $relations = ['session' => OAuthSession::class];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static array $possibleScopeValues = ['openid', 'email', 'profile'];
 | 
					    private ?OAuthSession $session = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private array $scope = [];
 | 
					    private ?int $sessionId = null;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    private string $nonce = '';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private ?User $user = null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private ?int $userId = null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private string $code = '';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private string $accessToken = '';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private DateTime $created;
 | 
					    private DateTime $created;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private DateTime $expires;
 | 
					    private DateTime $expires;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function setScopeArray(array $scope): void
 | 
					    public function setSession(OAuthSession $session): void
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->scope = array_intersect($scope, self::$possibleScopeValues);
 | 
					        $this->session = $session;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function setScope(string $scope): void
 | 
					    public function setSessionId(int $sessionId): void
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->setScopeArray(explode(' ', $scope));
 | 
					        $this->sessionId = $sessionId;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function setNonce(string $nonce): void
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $this->nonce = $nonce;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function setUser(User $user): void
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $this->user = $user;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function setUserId(int $userId): void
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $this->userId = $userId;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function setCode(string $code): void
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $this->code = $code;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function setAccessToken(string $accessToken): void
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $this->accessToken = $accessToken;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function setCreatedDate(DateTime $created): void
 | 
					    public function setCreatedDate(DateTime $created): void
 | 
				
			||||||
@ -84,39 +49,14 @@ class OAuthToken extends Model
 | 
				
			|||||||
        $this->expires = new DateTime($expires);
 | 
					        $this->expires = new DateTime($expires);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function getScope(): string
 | 
					    public function getSession(): ?OAuthSession
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return implode(' ', $this->scope);
 | 
					        return $this->session;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function getScopeArray(): array
 | 
					    public function getSessionId(): ?int
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->scope;
 | 
					        return $this->sessionId;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function getNonce(): string
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $this->nonce;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function getUser(): ?User
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $this->user;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function getUserId(): ?int
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $this->userId;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function getCode(): string
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $this->code;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function getAccessToken(): string
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $this->accessToken;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function getCreatedDate(): DateTime
 | 
					    public function getCreatedDate(): DateTime
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										30
									
								
								src/Repository/OAuthSessionRepository.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/Repository/OAuthSessionRepository.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					<?php namespace RVR\Repository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use DateTime;
 | 
				
			||||||
 | 
					use Generator;
 | 
				
			||||||
 | 
					use SokoWeb\Database\Query\Select;
 | 
				
			||||||
 | 
					use RVR\PersistentData\Model\OAuthSession;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class OAuthSessionRepository
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function getById(int $id): ?OAuthSession
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return \Container::$persistentDataManager->selectFromDbById($id, OAuthSession::class);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getByCode(string $code): ?OAuthSession
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $select = new Select(\Container::$dbConnection);
 | 
				
			||||||
 | 
					        $select->where('code', '=', $code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return \Container::$persistentDataManager->selectFromDb($select, OAuthSession::class);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getAllExpired(): Generator
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $select = new Select(\Container::$dbConnection);
 | 
				
			||||||
 | 
					        $select->where('expires', '<', (new DateTime())->format('Y-m-d H:i:s'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        yield from \Container::$persistentDataManager->selectMultipleFromDb($select, OAuthSession::class);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -4,6 +4,7 @@ use DateTime;
 | 
				
			|||||||
use Generator;
 | 
					use Generator;
 | 
				
			||||||
use SokoWeb\Database\Query\Select;
 | 
					use SokoWeb\Database\Query\Select;
 | 
				
			||||||
use RVR\PersistentData\Model\OAuthToken;
 | 
					use RVR\PersistentData\Model\OAuthToken;
 | 
				
			||||||
 | 
					use RVR\PersistentData\Model\OAuthSession;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class OAuthTokenRepository
 | 
					class OAuthTokenRepository
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -12,20 +13,16 @@ class OAuthTokenRepository
 | 
				
			|||||||
        return \Container::$persistentDataManager->selectFromDbById($id, OAuthToken::class);
 | 
					        return \Container::$persistentDataManager->selectFromDbById($id, OAuthToken::class);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function getByCode(string $code): ?OAuthToken
 | 
					    public function getAllBySession(OAuthSession $session, bool $useRelations = false, array $withRelations = []): Generator
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $select = new Select(\Container::$dbConnection);
 | 
					        $select = $this->selectAllBySession($session);
 | 
				
			||||||
        $select->where('code', '=', $code);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return \Container::$persistentDataManager->selectFromDb($select, OAuthToken::class);
 | 
					        yield from \Container::$persistentDataManager->selectMultipleFromDb($select, OAuthToken::class, $useRelations, $withRelations);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function getByAccessToken(string $accessToken): ?OAuthToken
 | 
					    public function countAllBySession(OAuthSession $session): int
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $select = new Select(\Container::$dbConnection);
 | 
					        return $this->selectAllBySession($session)->count();
 | 
				
			||||||
        $select->where('access_token', '=', $accessToken);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return \Container::$persistentDataManager->selectFromDb($select, OAuthToken::class);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function getAllExpired(): Generator
 | 
					    public function getAllExpired(): Generator
 | 
				
			||||||
@ -35,4 +32,11 @@ class OAuthTokenRepository
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        yield from \Container::$persistentDataManager->selectMultipleFromDb($select, OAuthToken::class);
 | 
					        yield from \Container::$persistentDataManager->selectMultipleFromDb($select, OAuthToken::class);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function selectAllBySession(OAuthSession $session): Select
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $select = new Select(\Container::$dbConnection, OAuthToken::getTable());
 | 
				
			||||||
 | 
					        $select->where('session_id', '=', $session->getId());
 | 
				
			||||||
 | 
					        return $select;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										10
									
								
								web.php
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								web.php
									
									
									
									
									
								
							@ -7,7 +7,7 @@ use SokoWeb\Request\Request;
 | 
				
			|||||||
use SokoWeb\Request\Session;
 | 
					use SokoWeb\Request\Session;
 | 
				
			||||||
use RVR\Controller\HomeController;
 | 
					use RVR\Controller\HomeController;
 | 
				
			||||||
use RVR\Controller\LoginController;
 | 
					use RVR\Controller\LoginController;
 | 
				
			||||||
use RVR\Controller\OAuthAuthController;
 | 
					use RVR\Controller\OAuthSessionController;
 | 
				
			||||||
use RVR\Controller\OAuthController;
 | 
					use RVR\Controller\OAuthController;
 | 
				
			||||||
use RVR\Controller\UserController;
 | 
					use RVR\Controller\UserController;
 | 
				
			||||||
use RVR\Controller\UserSearchController;
 | 
					use RVR\Controller\UserSearchController;
 | 
				
			||||||
@ -37,8 +37,10 @@ Container::$routeCollection->group('login', function (RouteCollection $routeColl
 | 
				
			|||||||
    $routeCollection->get('login.google-action', 'google/code', [LoginController::class, 'loginWithGoogle']);
 | 
					    $routeCollection->get('login.google-action', 'google/code', [LoginController::class, 'loginWithGoogle']);
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
Container::$routeCollection->group('oauth', function (RouteCollection $routeCollection) {
 | 
					Container::$routeCollection->group('oauth', function (RouteCollection $routeCollection) {
 | 
				
			||||||
    $routeCollection->get('oauth.auth', 'auth', [OAuthAuthController::class, 'auth']);
 | 
					    $routeCollection->get('oauth.auth', 'auth', [OAuthSessionController::class, 'auth']);
 | 
				
			||||||
    $routeCollection->post('oauth.token', 'token', [OAuthController::class, 'getToken']);
 | 
					    $routeCollection->post('oauth.token', 'token', [OAuthController::class, 'generateToken']);
 | 
				
			||||||
 | 
					    $routeCollection->post('oauth.token.introspect', 'token/introspect', [OAuthController::class, 'introspectToken']);
 | 
				
			||||||
 | 
					    $routeCollection->post('oauth.token.revoke', 'token/revoke', [OAuthController::class, 'revokeToken']);
 | 
				
			||||||
    $routeCollection->get('oauth.userinfo', 'userinfo', [OAuthController::class, 'getUserInfo']);
 | 
					    $routeCollection->get('oauth.userinfo', 'userinfo', [OAuthController::class, 'getUserInfo']);
 | 
				
			||||||
    $routeCollection->get('oauth.config', '.well-known/openid-configuration', [OAuthController::class, 'getConfig']);
 | 
					    $routeCollection->get('oauth.config', '.well-known/openid-configuration', [OAuthController::class, 'getConfig']);
 | 
				
			||||||
    $routeCollection->get('oauth.certs', 'certs', [OAuthController::class, 'getCerts']);
 | 
					    $routeCollection->get('oauth.certs', 'certs', [OAuthController::class, 'getCerts']);
 | 
				
			||||||
@ -116,7 +118,7 @@ Container::$routeCollection->group('communities', function (RouteCollection $rou
 | 
				
			|||||||
Container::$sessionHandler = new DatabaseSessionHandler(
 | 
					Container::$sessionHandler = new DatabaseSessionHandler(
 | 
				
			||||||
    Container::$dbConnection,
 | 
					    Container::$dbConnection,
 | 
				
			||||||
    'sessions',
 | 
					    'sessions',
 | 
				
			||||||
    new DateTime('-7 days')
 | 
					    new DateTime('-1 days')
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
session_set_save_handler(Container::$sessionHandler, true);
 | 
					session_set_save_handler(Container::$sessionHandler, true);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user