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(), 'username' => $user->getUsername(), 'full_name' => $user->getFullName(), 'nickname' => $user->getNickname(), 'phone' => $user->getPhone(), 'id_number' => $user->getIdNumber() ]; $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]); } }