Uname:Linux ip-11-115-0-196 6.8.0-1039-aws #41~22.04.1-Ubuntu SMP Thu Sep 11 10:54:48 UTC 2025 x86_64

403WebShell
403Webshell
Server IP : 13.126.101.145  /  Your IP : 216.73.217.50
Web Server : Apache/2.4.52 (Ubuntu)
System : Linux ip-11-115-0-196 6.8.0-1039-aws #41~22.04.1-Ubuntu SMP Thu Sep 11 10:54:48 UTC 2025 x86_64
User : www-data ( 33)
PHP Version : 8.3.17
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /var/www/html/rentals_updated/wp-content/plugins/wpo365-login/Services/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/html/rentals_updated/wp-content/plugins/wpo365-login/Services/Id_Token_Service.php
<?php

namespace Wpo\Services;

use \Wpo\Core\WordPress_Helpers;
use \Wpo\Services\Authentication_Service;
use \Wpo\Services\Error_Service;
use \Wpo\Services\Jwt_Token_Service;
use \Wpo\Services\Log_Service;
use \Wpo\Services\Nonce_Service;
use \Wpo\Services\Options_Service;
use \Wpo\Services\Request_Service;

// Prevent public access to this script
defined('ABSPATH') or die();

if (!class_exists('\Wpo\Services\Id_Token_Service')) {

    class Id_Token_Service
    {

        /**
         * Constructs the oauth authorize URL that is the end point where the user will be sent for authorization.
         * 
         * @since 4.0
         * 
         * @since 11.0 Dropped support for the v1 endpoint.
         * 
         * @param $login_hint string Login hint that will be added to Open Connect ID link
         * @param $redirect_to string Link where the user will be redirected to
         * 
         * @return string if everthing is configured OK a valid authorization URL
         */
        public static function get_openidconnect_url($login_hint = null, $redirect_to = null)
        {
            Log_Service::write_log('DEBUG', '##### -> ' . __METHOD__);

            $application_id = Options_Service::get_aad_option('application_id');
            $directory_id = Options_Service::get_aad_option('tenant_id');
            $oidc_flow = Options_Service::get_aad_option('oidc_flow');
            $multi_tenanted = Options_Service::get_global_boolean_var('multi_tenanted') && !Options_Service::get_global_boolean_var('use_b2c');

            /**
             * @since 24.0 Filters the AAD Redirect URI e.g. to set it dynamically to the current host.
             */

            $redirect_uri = Options_Service::get_aad_option('redirect_url');
            $redirect_uri = apply_filters('wpo365/aad/redirect_uri', $redirect_uri);

            $redirect_to = !empty($redirect_to)
                ? $redirect_to
                : (
                    (isset($_SERVER['HTTP_REFERER'])
                        ? $_SERVER['HTTP_REFERER']
                        : $GLOBALS['WPO_CONFIG']['url_info']['wp_site_url'])
                );

            /**
             * @since 30.0  Replace a possible "#" because add_query_arg and parse_url cannot handle it
             */

            $redirect_to = str_replace('#', '_____', $redirect_to);

            /**
             * @since   16.0    Filters the redirect_to url
             */
            $redirect_to = apply_filters('wpo365/cookie/remove/url', $redirect_to);

            $request_service = Request_Service::get_instance();
            $request = $request_service->get_request($GLOBALS['WPO_CONFIG']['request_id']);

            /**
             * @since   27.0    Adds the IDP ID to the state URL
             */
            if (!empty($idp_id = $request->get_item('idp_id'))) {
                $redirect_to = add_query_arg(
                    array('idp_id' => $idp_id),
                    $redirect_to
                );
            }

            $redirect_to = urlencode($redirect_to);

            /**
             * @since   21.9    Premium extensions of the WPO365 plugin require User.Read to update core WP user fields.
             */

            if (class_exists('\Wpo\Services\User_Create_Update_Service')) {
                $tld = !empty($tld = Options_Service::get_global_string_var('tld')) ? $tld : '.com';
                $scope = "https://graph.microsoft$tld/user.read openid email profile";
            } else {
                $scope = 'openid email profile';
            }

            if (empty($response_mode = Options_Service::get_aad_option('oidc_response_mode')) || $oidc_flow != 'code') {
                $response_mode = 'form_post';
            }

            $params = array(
                'client_id'             => $application_id,
                'redirect_uri'          => $redirect_uri,
                'response_mode'         => $response_mode,
                'scope'                 => $scope,
                'state'                 => $redirect_to,
                'nonce'                 => Nonce_Service::create_nonce(),
            );

            $params['response_type'] = $oidc_flow == 'code' ? 'code' : 'id_token code';

            // Add Proof Key for Code Exchange challenge if required
            if (Options_Service::get_global_boolean_var('use_pkce') && class_exists('\Wpo\Services\Pkce_Service')) {
                \Wpo\Services\Pkce_Service::add_and_memoize_verifier($params);
            }

            /**
             * @since 9.4
             * 
             * Add ability to configure a domain hint to prevent Microsoft from
             * signing in users that are already logged in to a different O365 tenant.
             */
            $domain_hint = Options_Service::get_global_string_var('domain_hint');

            if (!empty($domain_hint)) {
                $params['domain_hint'] = $domain_hint;
            }

            if (!empty($login_hint)) {
                $params['login_hint'] = $login_hint;
            }

            if (true === Options_Service::get_global_boolean_var('add_select_account_prompt')) {
                $params['prompt'] = 'select_account';
            } else if (true === Options_Service::get_global_boolean_var('add_create_account_prompt')) {
                $params['prompt'] = 'create';
            }

            if (true === $multi_tenanted) {
                $directory_id = 'common';
                $multi_tenanted_api_permissions = Options_Service::get_global_list_var('multi_tenanted_api_permissions');

                foreach ($multi_tenanted_api_permissions as $key => $permission) {

                    $permission = strtolower(trim($permission));

                    if (!empty($permission)) {
                        $params['scope'] = $params['scope'] . " $permission";
                    }
                }
            }

            $tld = !empty($tld = Options_Service::get_global_string_var('tld')) ? $tld : '.com';
            $auth_url = sprintf(
                'https://login.microsoftonline%s/%s/oauth2/v2.0/authorize?%s',
                $tld,
                $directory_id,
                http_build_query($params, '', '&')
            );

            Log_Service::write_log('DEBUG', __METHOD__ . " -> Open ID Connect URL: $auth_url");

            return $auth_url;
        }

        /**
         * Processes the ID token and caches it for the current request. If an authorization code is sent
         * along, it will be saved so the it can be used when requesting access tokens for the current
         * user (if integration is configured).
         * 
         * @return  void
         */
        public static function process_openidconnect_token($force_goodbye = true)
        {
            Log_Service::write_log('DEBUG', '##### -> ' . __METHOD__);

            // Decode the id_token
            $id_token = self::decode_id_token();

            // Handle if token could not be processed
            if ($id_token === false) {

                if (true === $force_goodbye) {
                    Log_Service::write_log('ERROR', __METHOD__ . ' -> ID token could not be processed and user will be redirected to default Wordpress login.');
                    Authentication_Service::goodbye(Error_Service::ID_TOKEN_ERROR);
                    exit();
                }

                return;
            }

            // Handle if nonce is invalid 
            if (!Options_Service::get_global_boolean_var('skip_nonce_verification')) {

                if (!Nonce_Service::verify_nonce($id_token->nonce)) {
                    Log_Service::write_log('WARN', __METHOD__ . ' -> Could not successfully validate oidc nonce with value ' . $id_token->nonce);
                }
            }

            // Log id token if configured
            if (true === Options_Service::get_global_boolean_var('debug_log_id_token')) {
                Log_Service::write_log('DEBUG', $id_token);
            }

            $request_service = Request_Service::get_instance();
            $request = $request_service->get_request($GLOBALS['WPO_CONFIG']['request_id']);
            $request->set_item('id_token', $id_token);

            if (property_exists($id_token, 'tfp')) {
                $request->set_item('tfp', $id_token->tfp);
            } elseif (property_exists($id_token, 'acr')) {
                $request->set_item('tfp', $id_token->acr);
            }
        }

        /**
         * Helper to process the authorization code which is then used to request an ID and access token.
         * 
         * @since   18.0
         * 
         * @return void 
         */
        public static function process_openidconnect_code($scope = '', $force_goodbye = true)
        {
            Log_Service::write_log('DEBUG', '##### -> ' . __METHOD__);

            $tld = !empty($tld = Options_Service::get_global_string_var('tld')) ? $tld : '.com';
            $scope = str_replace('.com', $tld, $scope);

            $request_service = Request_Service::get_instance();
            $request = $request_service->get_request($GLOBALS['WPO_CONFIG']['request_id']);

            $code = Access_Token_Service::get_authorization_code();
            $mode = $request->get_item('mode');

            if (empty($code)) {
                Log_Service::write_log('ERROR', sprintf('%s -> Authorization code not found', __METHOD__));
                return;
            }

            $use_mail_config = $mode == 'mailAuthorize';

            $directory_id = $use_mail_config ? Options_Service::get_mail_option('mail_tenant_id') : Options_Service::get_aad_option('tenant_id');
            $application_id = $use_mail_config ? Options_Service::get_mail_option('mail_application_id') : Options_Service::get_aad_option('application_id');
            $application_secret = $use_mail_config ? Options_Service::get_mail_option('mail_application_secret') : Options_Service::get_aad_option('application_secret');
            $multi_tenanted = Options_Service::get_global_boolean_var('multi_tenanted') && !$use_mail_config && !Options_Service::get_global_boolean_var('use_b2c');

            /**
             * @since 24.0 Filters the AAD Redirect URI e.g. to set it dynamically to the current host.
             */

            if ($use_mail_config) {
                $redirect_uri = Options_Service::get_mail_option('mail_redirect_url');
            } else {
                $redirect_uri = Options_Service::get_aad_option('redirect_url');
                $redirect_uri = apply_filters('wpo365/aad/redirect_uri', $redirect_uri);
            }

            if (true === $multi_tenanted) {
                $directory_id = 'common';
            }

            $params = array(
                'client_id'     => $application_id,
                'response_type' => 'token',
                'redirect_uri'  => $redirect_uri,
                'response_mode' => 'form_post',
                'grant_type'    => 'authorization_code',
                'scope'         => 'openid email profile offline_access' . (empty($scope) ? '' : (' ' . $scope)),
                'code'          => $code,
                'client_secret' => $application_secret,
            );

            if (Options_Service::get_global_boolean_var('use_pkce') && class_exists('\Wpo\Services\Pkce_Service')) {
                $pkce_code_verifier = \Wpo\Services\Pkce_Service::get_personal_pkce_code_verifier();

                if (!empty($pkce_code_verifier)) {
                    $params['code_verifier'] = $pkce_code_verifier;
                } else {
                    $warning = 'Cannot retrieve an (ID) token because the Administrator 
                        has configured the use of a Proof Key for Code Exchange but a code verifier for the current
                        user cannot be found. See the <a href="https://docs.wpo365.com/article/149-require-proof-key-for-code-exchange-pkce" target="_blank">online documentation</a> 
                        for detailed step-by-step instructions on how to configure the WPO365 | LOGIN plugin to use a Proof Key for Code Exchange.';
                    Log_Service::write_log('ERROR', __METHOD__ . " -> $warning");

                    $access_token_errors = $request->get_item('access_token_errors') ?: array();
                    $access_token_errors[] = $warning;
                    $request->set_item('access_token_errors', $access_token_errors);

                    return;
                }
            }

            $skip_ssl_verify = !Options_Service::get_global_boolean_var('skip_host_verification');

            $tld = !empty($tld = Options_Service::get_global_string_var('tld')) ? $tld : '.com';
            $token_url = sprintf(
                'https://login.microsoftonline%s/%s/oauth2/v2.0/token',
                $tld,
                $directory_id
            );

            /**
             * @since 33.x  Filters the params e.g. to support SNI based authentication.
             */
            $params = apply_filters('wpo365/aad/params', $params, $application_id, $token_url);

            $response = wp_remote_post($token_url, array(
                'sslverify' => $skip_ssl_verify,
                'body' => $params,
                'headers' => array('Expect' => ''),
            ));

            if (is_wp_error($response)) {
                Log_Service::write_log('ERROR', sprintf('%s -> Error occured whilst fetching from %s: %s', __METHOD__, $token_url, $response->get_error_message()));
                return;
            }

            $body = json_decode(wp_remote_retrieve_body($response));

            if (empty($body)) {
                Log_Service::write_log('ERROR', sprintf('%s -> Error occured whilst fetching from %s: See next line for details.', __METHOD__, $token_url));
                Log_Service::write_log('ERROR', $response);
                return;
            }

            if (property_exists($body, 'error')) {
                $message = property_exists($body, 'error_description') ? $body->error_description : $body->error;
                Log_Service::write_log('ERROR', sprintf('%s -> Error occured whilst fetching from %s: %s', __METHOD__, $token_url, $message));
                return;
            }

            if (property_exists($body, 'access_token')) {
                $access_token = new \stdClass();
                $access_token->access_token = $body->access_token;

                if (property_exists($body, 'expires_in')) {
                    $access_token->expiry = time() + intval($body->expires_in);
                }

                if (property_exists($body, 'scope')) {
                    $access_token->scope = $body->scope;
                }

                $access_tokens = $request->get_item('access_tokens');

                if (empty($access_tokens)) {
                    $access_tokens = array();
                }

                // Save access token as request variable -> will be saved on shutdown
                $access_tokens[] = $access_token;
                $request->set_item('access_tokens', $access_tokens);
            }

            if (property_exists($body, 'refresh_token')) {
                $refresh_token = new \stdClass();
                $refresh_token->refresh_token = $body->refresh_token;

                if (property_exists($body, 'scope')) {
                    $refresh_token->scope = $body->scope;
                }

                $request->set_item('refresh_token', $refresh_token);
            }

            if ($mode == 'mailAuthorize' && Options_Service::get_global_boolean_var('mail_skip_all_checks')) {
                return;
            }

            if (property_exists($body, 'id_token')) {
                $request->set_item('encoded_id_token', $body->id_token);
                self::process_openidconnect_token($force_goodbye);
                return;
            }

            Log_Service::write_log('ERROR', sprintf('%s -> ID token not found in data retrieved from token endpoint [see next line for response body]', __METHOD__));
            Log_Service::write_log('DEBUG', $body);
        }

        /**
         * Unraffles the incoming JWT id_token with the help of Firebase\JWT and the tenant specific public keys available from Microsoft.
         * 
         * @since   1.0
         *
         * @return  object|boolean 
         */
        public static function decode_id_token()
        {
            Log_Service::write_log('DEBUG', '##### -> ' . __METHOD__);

            $request_service = Request_Service::get_instance();
            $request = $request_service->get_request($GLOBALS['WPO_CONFIG']['request_id']);
            $id_token = $request->get_item('encoded_id_token');

            // Get the token and get it's header for a first analysis
            if (empty($id_token)) {
                Log_Service::write_log('ERROR', __METHOD__ . ' -> ID token not found in posted data.');
                return false;
            }

            $claims = Jwt_Token_Service::validate_signature($id_token);

            if (is_wp_error($claims)) {
                Log_Service::write_log('ERROR', $claims->get_error_message());
                return false;
            }

            return $claims;
        }

        /**
         * Helper to check if the ID token was issued by the "home" tenant and whether the ID token
         * was indeed isssued for the requesting application.
         * 
         * @since   21.x    Initially as part of decode_id_token
         * @since   23.0    Moved into its own function
         * 
         * @param   mixed   $id_token 
         * 
         * @return  bool 
         */
        public static function check_audience($id_token)
        {
            $request_service = Request_Service::get_instance();
            $request = $request_service->get_request($GLOBALS['WPO_CONFIG']['request_id']);

            if ((!($multi_tenanted = Options_Service::get_global_boolean_var('multi_tenanted')) || ($multi_tenanted && !empty($allowed_tenants = Options_Service::get_global_list_var('allowed_tenants')))) && !Options_Service::get_global_boolean_var('skip_id_token_verification')) {

                /**
                 * @since 23.0  Either let request bypass WPO365 logic (= exit) if the audience check 
                 *              fails or send user with error to login / error page.
                 */
                $on_error = function () use ($request) {

                    if (!Options_Service::get_global_boolean_var('exit_on_audience_error')) {
                        Authentication_Service::goodbye(Error_Service::ID_TOKEN_AUD);
                        exit();
                    }

                    $request->set_item('skip_authentication', true);
                    return false;
                };

                $token_arr = explode('.', $id_token);

                // Token should explored in three segments header, body, signature
                if (sizeof($token_arr) != 3) {
                    return $on_error(); // Either exit or return false
                }

                // Payload (claims)
                $claims_enc = $token_arr[1];
                $claims = \json_decode(WordPress_Helpers::base64_url_decode($claims_enc));

                if (!empty($claims->iss)) {
                    $tenant_id = $request->get_item('mode') == 'mailAuthorize'
                        ? Options_Service::get_mail_option('mail_tenant_id')
                        : Options_Service::get_aad_option('tenant_id');

                    $user_name = !empty($claims->unique_name)
                        ? $claims->unique_name
                        : (!empty($claims->preferred_username)
                            ? $claims->preferred_username
                            : '???'
                        );

                    // At this point we already verified that the list of allowed tenants is not empty
                    if ($multi_tenanted) {
                        $allowed_tenants[] = $tenant_id;

                        foreach ($allowed_tenants as $allowed_tenant) {

                            if (false !== WordPress_Helpers::stripos($claims->iss, $allowed_tenant)) {
                                return true;
                            }
                        }

                        $error_message = sprintf(
                            '%s -> The ID token that has been received for [%s] has been issued by a tenant [%s] that has not been allow-listed on the plugin\'s "User registration" configuration page.',
                            __METHOD__,
                            $user_name,
                            $claims->iss
                        );
                        Log_Service::write_log('ERROR', $error_message);
                        return $on_error(); // Either exit or return false
                    } elseif (empty($tenant_id) || false === WordPress_Helpers::stripos($claims->iss, $tenant_id)) {
                        $error_message = sprintf(
                            '%s -> The ID token that has been received for [%s] has been issued by another tenant [%s] (vs. your tenant [%s]). If you believe this error to be a false-positive, then you can check the option to <em>Skip the ID token verification</em> on the plugin\'s <em>Miscellaneous</em> configuration page.',
                            __METHOD__,
                            $user_name,
                            $claims->iss,
                            $tenant_id
                        );
                        Log_Service::write_log('ERROR', $error_message);
                        return $on_error(); // Either exit or return false
                    }
                }

                if (!empty($claims->aud)) {
                    $application_id = $request->get_item('mode') == 'mailAuthorize'
                        ? Options_Service::get_mail_option('mail_application_id')
                        : Options_Service::get_aad_option('application_id');

                    if (false === WordPress_Helpers::stripos($claims->aud, $application_id)) {
                        $error_message = sprintf(
                            '%s -> The ID token that has been received is intended for another audience [%s] (vs. your registered application [%s]). If you believe this error to be a false-positive, then you can check the option to <em>Skip the ID token verification</em> on the plugin\'s <em>Miscellaneous</em> configuration page.',
                            __METHOD__,
                            $application_id,
                            $claims->aud
                        );
                        Log_Service::write_log('ERROR', $error_message);
                        return $on_error(); // Either exit or return false
                    }
                }
            }

            return true;
        }
    }
}

Youez - 2016 - github.com/yon3zu
LinuXploit