<?php

abstract class CfBaseResource extends Resource
{
    public $oAuthServer = null;
    public $username = null;
    public $accessToken = null;


    public function __construct($parameters)
    {
        parent::__construct($parameters);
    }

    public function _checkBasicAuthencication(array $headers = [])
    {
        $cfAuthService = new CFAuthService();
        if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW']) || !$user = $cfAuthService->auth($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])) {
            throw new ResponseException("Not authenticated", Response::UNAUTHORIZED);
        }

        $cfUser = new CfUsers($user);
        $isTwoFaEnforced = (CfSettings::getInstance())->getSetting(SettingsHelper::ENFORCE_2FA);
        if ($cfUser->isUserLockedByTwoFaEnforcement($isTwoFaEnforced)) {
            throw new ResponseException('Your account has been locked. Please contact the administrator.', Response::FORBIDDEN);
        }

        // set fist login after 2FA enforced timestamp if enforce 2FA settings enabled and user does not have it
        if ($isTwoFaEnforced && !$cfUser->getFirstLoginAfter2faEnforced()) {
            $cfUser->setFirstLoginAfter2faEnforced();
        }

        TwoFaHelper::verifyRequest((new CfUsers($user)), $headers);

        $this->username = $user;
    }

    public function _checkOauthAuthentication()
    {
        $this->oAuthServer = Utils::getOauthServer();
        $oAuth2Request = OAuth2\Request::createFromGlobals();

        if (!$this->oAuthServer->verifyResourceRequest($oAuth2Request)) {
            $oAuthResponse = $this->oAuthServer->getResponse();
            $oAuthException = new OauthException();
            $oAuthException->oauthBody = $oAuthResponse->getResponseBody('json');
            $oAuthException->oauthCode = $oAuthResponse->getStatusCode();
            $oAuthException->oAuthHeaders = $oAuthResponse->getHttpHeaders();
            throw $oAuthException;
        }

        $token = $this->oAuthServer->getAccessTokenData($oAuth2Request);
        $this->username = $token['user_id'] ?? null;
        $this->accessToken = $token['access_token'] ?? null;
    }
    /**
     * This is replacement function for web server that does not have apache_request_headers() function defined such as nginx.
     * @return array array of headers
     */
    public function _getallheaders()
    {
        $headers = array();


        foreach ($_SERVER as $name => $value) {
            if (substr($name, 0, 5) == 'HTTP_') {
                $name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))));
                $headers[$name] = $value;
            } elseif ($name == "CONTENT_TYPE") {
                $headers["Content-Type"] = $value;
            } elseif ($name == "CONTENT_LENGTH") {
                $headers["Content-Length"] = $value;
            }
        }
        return $headers;
    }

    public function _checkAuthentication()
    {
        $headers = function_exists('apache_request_headers') ? apache_request_headers() : $this->_getallheaders();


        $authorization = !empty($headers['Authorization']) ? $headers['Authorization'] : 'basic'; // default to basic

        $authenticationScheme = 'basic';

        if (strpos(strtolower($authorization), 'bearer') === 0) {
            $authenticationScheme = 'oAuth2';
        }


        /**
        * Every basic authentication request (when username:password are passed in Authorization header)
        * will be checked for the 2FA, if enabled.
        *
        * Requests that are authenticated by tokens (Oauth) do not need this check,
        * as the issue token request already does this.
        */
        switch ($authenticationScheme) {
            case 'oAuth2':
                {
                    $this->_checkOauthAuthentication();
                    break;
                }
            default:
                $this->_checkBasicAuthencication($headers);
        }
    }

    public function accessRequired()
    {
        $this->_checkAuthentication();
    }
}

class CfProtectedResource extends CfBaseResource
{
    public $username = null;
    public $oAuthServer = null;

    public function __construct($parameters)
    {
        parent::__construct($parameters);
        $this->accessRequired();
    }

    protected function checkHostAccessAndReturnName($username, $hostkey)
    {
        // check if a user has RBAC access to this host
        // if not cfapi_host_get will throw access exception
        $payload = cfapi_host_get($username, $hostkey);
        $payload = json_decode($payload, true);

        return $payload['data'][0]['hostname'] ?? null;
    }
}
