Skip to content
Snippets Groups Projects
Select Git revision
  • 6485af5ea56b7b9bfd7f784caf4e3e148b0872a6
  • main default protected
  • Kelvinrr-patch-3
  • radius_update
  • revert-616-apollo_pan
  • vims
  • 0.10
  • Kelvinrr-patch-2
  • revert-563-minirf_fix
  • Kelvinrr-patch-1
  • 0.9
  • acpaquette-patch-3
  • acpaquette-patch-2
  • acpaquette-patch-1
  • spiceql
  • ci-coverage
  • 0.10.0
  • 0.9.1
  • 0.9.0
  • 0.8.7
  • 0.8.8
  • 0.8.6
  • 0.8.3
  • 0.8.4
  • 0.8.5
  • 0.8.2
  • 0.8.1
  • 0.8.0
  • 0.7.3
  • 0.7.2
  • 0.7.1
  • 0.7.0
  • 0.6.5
  • 0.6.4
  • 0.6.3
  • 0.6.2
36 results

conf.py

Blame
  • OAuth2RequestHandler.php 6.70 KiB
    <?php
    
    namespace RAP;
    
    use \Firebase\JWT\JWT;
    
    class OAuth2RequestHandler {
    
        private $locator;
    
        public function __construct(\RAP\Locator $locator) {
            $this->locator = $locator;
        }
    
        public function handleAuthorizeRequest($params) {
    
            if ($params['client_id'] === null) {
                throw new BadRequestException("Client id is required");
            }
    
            if ($params['redirect_uri'] === null) {
                throw new BadRequestException("Redirect URI is required");
            }
    
            $client = $this->locator->getOAuth2ClientDAO()->getOAuth2ClientByClientId($params['client_id']);
            if ($client === null) {
                throw new BadRequestException("Invalid client id: " . $params['client_id']);
            }
            if ($client->redirectUrl !== $params['redirect_uri']) {
                throw new BadRequestException("Invalid client redirect URI: " . $params['redirect_uri']);
            }
    
            $alg = $params['alg'];
            if ($alg === null) {
                $alg = "RS256";
            }
    
            $state = $params['state'];
            if ($state === null) {
                throw new BadRequestException("State is required");
            }
    
            // Storing OAuth2 data in session
            $oauth2Data = new \RAP\OAuth2Data();
            $oauth2Data->clientId = $client->client;
            $oauth2Data->redirectUrl = $client->redirectUrl;
            $oauth2Data->state = $state;
    
            $scope = $params['scope'];
            if ($scope !== null) {
                $oauth2Data->scope = explode(' ', $scope);
            }
    
            $session = $this->locator->getSession();
            $session->setOAuth2Data($oauth2Data);
        }
    
        public function getCodeResponseUrl(): string {
    
            $session = $this->locator->getSession();
    
            $accessToken = new \RAP\AccessToken();
            $accessToken->code = base64_encode(bin2hex(openssl_random_pseudo_bytes(64)));
            $accessToken->token = base64_encode(bin2hex(openssl_random_pseudo_bytes(128)));
            $accessToken->userId = $session->getUser()->id;
            $accessToken->clientId = $session->getOAuth2Data()->clientId;
            $accessToken->redirectUri = $session->getOAuth2Data()->redirectUrl;
            $accessToken->scope = $session->getOAuth2Data()->scope;
    
            $this->locator->getAccessTokenDAO()->createAccessToken($accessToken);
    
            $state = $session->getOAuth2Data()->state;
    
            $redirectUrl = $session->getOAuth2Data()->redirectUrl
                    . '?code=' . $accessToken->code . '&scope=profile&state=' . $state;
    
            return $redirectUrl;
        }
    
        public function handleAccessTokenRequest($params): array {
    
            $this->validateAccessTokenRequest($params);
    
            $accessToken = $this->locator->getAccessTokenDAO()->retrieveAccessTokenFromCode($params['code']);
    
            if ($accessToken === null) {
                throw new BadRequestException("No token for given code");
            }
    
            if ($accessToken->redirectUri !== $params['redirect_uri']) {
                throw new BadRequestException("Invalid redirect URI: " . $params['redirect_uri']);
            }
    
            $result = [];
            $result['access_token'] = $accessToken->token;
            $result['token_type'] = 'Bearer';
            $result['expires_in'] = $this->getExpiresIn($accessToken);
    
            if ($accessToken->scope !== null && in_array('openid', $accessToken->scope)) {
                $result['id_token'] = $this->locator->getIdTokenBuilder()->getIdToken($accessToken);
            }
    
            return $result;
        }
    
        private function validateAccessTokenRequest($params) {
    
            if ($params['grant_type'] === null) {
                throw new BadRequestException("grant_type is required");
            } else if ($params['grant_type'] !== 'authorization_code') {
                throw new BadRequestException("grant_type must be authorization_code");
            }
    
            if ($params['code'] === null) {
                throw new BadRequestException("code id is required");
            }
    
            if ($params['redirect_uri'] === null) {
                throw new BadRequestException("Redirect URI is required");
            }
    
            // Note: theorically the standard wants also the client_id here,
            // however some clients don't send it
        }
    
        public function handleCheckTokenRequest($token): array {
    
            if (!isset($_POST['token'])) {
                throw new BadRequestException("Access token id is required");
            }
    
            $accessToken = $this->locator->getAccessTokenDAO()->getAccessToken($token);
            $user = $this->locator->getUserDAO()->findUserById($accessToken->userId);
    
            $result = [];
            $result['exp'] = $this->getExpiresIn($accessToken);
            $result['user_name'] = $user->id;
            $result['client_id'] = $accessToken->clientId;
    
            if ($accessToken->scope !== null) {
                $result['scope'] = $accessToken->scope;
                if (in_array('openid', $accessToken->scope)) {
                    $result['id_token'] = $this->locator->getIdTokenBuilder()->getIdToken($accessToken);
                }
            }
    
            return $result;
        }
    
        private function getExpiresIn(AccessToken $accessToken) {
            $expTime = strtotime($accessToken->expirationTime);
            $now = time();
            return $expTime - $now;
        }
    
        public function validateToken(): void {
            $headers = apache_request_headers();
    
            if (!isset($headers['Authorization'])) {
                throw new BadRequestException("Missing Authorization header");
            }
    
            $authorizationHeader = explode(" ", $headers['Authorization']);
            if ($authorizationHeader[0] === "Bearer") {
                $bearer_token = $authorizationHeader[1];
            } else {
                throw new BadRequestException("Invalid token type");
            }
    
            $accessToken = $this->locator->getAccessTokenDAO()->getAccessToken($bearer_token);
            if ($accessToken === null) {
                $this->attemptJWTTokenValidation($bearer_token);
            } else if ($accessToken->expired) {
                throw new UnauthorizedException("Access token is expired");
            }
        }
    
        private function attemptJWTTokenValidation($jwt): void {
    
            $jwtParts = explode('.', $jwt);
            if (count($jwtParts) === 0) {
                throw new UnauthorizedException("Invalid token");
            }
    
            $header = JWT::jsonDecode(JWT::urlsafeB64Decode($jwtParts[0]));
            if (!isset($header->kid)) {
                throw new UnauthorizedException("Invalid token: missing kid in header");
            }
    
            $keyPair = $this->locator->getJWKSDAO()->getRSAKeyPairById($header->kid);
            if ($keyPair === null) {
                throw new UnauthorizedException("Invalid kid: no key found");
            }
    
            try {
                JWT::decode($jwt, $keyPair->publicKey, [$keyPair->alg]);
            } catch (\Firebase\JWT\ExpiredException $ex) {
                throw new UnauthorizedException("Access token is expired");
            }
        }
    
    }