All checks were successful
		
		
	
	rvr-nextgen/pipeline/pr-master This commit looks good
				
			
		
			
				
	
	
		
			125 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			125 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php namespace RVR\Controller;
 | 
						|
 | 
						|
use DateTime;
 | 
						|
use Firebase\JWT\JWT;
 | 
						|
use RVR\PersistentData\Model\OAuthToken;
 | 
						|
use RVR\Repository\OAuthTokenRepository;
 | 
						|
use RVR\Repository\UserRepository;
 | 
						|
use RVR\PersistentData\Model\User;
 | 
						|
use SokoWeb\Interfaces\Request\IRequest;
 | 
						|
use SokoWeb\Interfaces\Response\IContent;
 | 
						|
use SokoWeb\Interfaces\Response\IRedirect;
 | 
						|
use SokoWeb\Response\Redirect;
 | 
						|
use SokoWeb\PersistentData\PersistentDataManager;
 | 
						|
use SokoWeb\Response\HtmlContent;
 | 
						|
use SokoWeb\Response\JsonContent;
 | 
						|
 | 
						|
class OAuthLoginController
 | 
						|
{
 | 
						|
    private IRequest $request;
 | 
						|
 | 
						|
    private PersistentDataManager $pdm;
 | 
						|
 | 
						|
    public function __construct(IRequest $request)
 | 
						|
    {
 | 
						|
        $this->request = $request;
 | 
						|
        $this->pdm = new PersistentDataManager();
 | 
						|
    }
 | 
						|
 | 
						|
    public function startOauth()
 | 
						|
    {
 | 
						|
        $redirectUri = $this->request->query('redirect_uri');
 | 
						|
        $state = $this->request->query('state');
 | 
						|
        $nonce = $this->request->query('nonce');
 | 
						|
 | 
						|
        if (!$redirectUri || !$state) {
 | 
						|
            return new HtmlContent('oauth/oauth_error', ['error' => 'An invalid request was made. Please start authentication again.']);
 | 
						|
        }
 | 
						|
 | 
						|
        $this->request->session()->set('oauth_payload', [
 | 
						|
            'redirect_uri' => $redirectUri,
 | 
						|
            'state' => $state,
 | 
						|
            'nonce' => $nonce === null ? '' : $nonce
 | 
						|
        ]);
 | 
						|
 | 
						|
        $this->request->session()->set('redirect_after_login', \Container::$routeCollection->getRoute('oauth-finish')->generateLink());
 | 
						|
 | 
						|
        return new Redirect(\Container::$routeCollection->getRoute('login')->generateLink(), IRedirect::TEMPORARY);
 | 
						|
    }
 | 
						|
 | 
						|
    public function finishOauth()
 | 
						|
    {
 | 
						|
        $oAuthPayload = $this->request->session()->get('oauth_payload');
 | 
						|
        if ($oAuthPayload === null) {
 | 
						|
            return new HtmlContent('oauth/oauth_error', ['error' => 'An invalid request was made. Please start authentication again.']);
 | 
						|
        }
 | 
						|
 | 
						|
        $this->request->session()->delete('oauth_payload');
 | 
						|
 | 
						|
        /**
 | 
						|
         * @var ?User $user
 | 
						|
         */
 | 
						|
        $user = $this->request->user();
 | 
						|
        if ($user === null) {
 | 
						|
            return new HtmlContent('oauth/oauth_error', ['error' => 'You are not logged in. Please start authentication again.']);
 | 
						|
        }
 | 
						|
 | 
						|
        $code = bin2hex(random_bytes(16));
 | 
						|
 | 
						|
        $token = new OAuthToken();
 | 
						|
        $token->setNonce($oAuthPayload['nonce']);
 | 
						|
        $token->setUser($user);
 | 
						|
        $token->setCode($code);
 | 
						|
        $token->setCreatedDate(new DateTime());
 | 
						|
        $token->setExpiresDate(new DateTime('+5 minutes'));
 | 
						|
        $this->pdm->saveToDb($token);
 | 
						|
 | 
						|
        $redirectUri = $oAuthPayload['redirect_uri'];
 | 
						|
        $additionalUriParams = [
 | 
						|
            'state' => $oAuthPayload['state'],
 | 
						|
            'code' => $code
 | 
						|
        ];
 | 
						|
        $and = (strpos($redirectUri, '?') !== false) ? '&' : '?';
 | 
						|
        $finalRedirectUri = $redirectUri . $and .  http_build_query($additionalUriParams);
 | 
						|
 | 
						|
        return new Redirect($finalRedirectUri, IRedirect::TEMPORARY);
 | 
						|
    }
 | 
						|
 | 
						|
    public function getToken(): ?IContent
 | 
						|
    {
 | 
						|
        $oAuthTokenRepository = new OAuthTokenRepository();
 | 
						|
        $userRepository = new UserRepository();
 | 
						|
        $token = $oAuthTokenRepository->getByCode($this->request->post('code'));
 | 
						|
 | 
						|
        if ($token === null || $token->getExpiresDate() < new DateTime()) {
 | 
						|
            return new JsonContent([
 | 
						|
                'error' => 'The provided code is invalid.'
 | 
						|
            ]);
 | 
						|
        }
 | 
						|
 | 
						|
        $user = $userRepository->getById($token->getUserId());
 | 
						|
 | 
						|
        $payload = [
 | 
						|
            'iss' => $_ENV['APP_URL'],
 | 
						|
            'iat' => (int)$token->getCreatedDate()->format('U'),
 | 
						|
            'nbf' => (int)$token->getCreatedDate()->format('U'),
 | 
						|
            'exp' => (int)$token->getExpiresDate()->format('U'),
 | 
						|
            'nonce' => $token->getNonce(),
 | 
						|
            'sub' => $user->getId(),
 | 
						|
            'email' => $user->getEmail()
 | 
						|
        ];
 | 
						|
        $privateKey = file_get_contents(ROOT . '/' . $_ENV['JWT_RSA_PRIVATE_KEY']);
 | 
						|
        $jwt = JWT::encode($payload, $privateKey, 'RS256');
 | 
						|
 | 
						|
        return new JsonContent([
 | 
						|
            'id_token' => $jwt
 | 
						|
        ]);
 | 
						|
    }
 | 
						|
 | 
						|
    public function getJwtPublicKey(): IContent
 | 
						|
    {
 | 
						|
        $publicKey = file_get_contents(ROOT . '/' . $_ENV['JWT_RSA_PUBLIC_KEY']);
 | 
						|
        return new JsonContent(['pubkey' => $publicKey]);
 | 
						|
    }
 | 
						|
}
 |