/**
  * @since 1.0.0
  */
 public function verify_configuration_callback()
 {
     if (isset($_REQUEST['nonce']) && $this->wp_facade->wp_verify_nonce($_REQUEST['nonce'], static::VERIFIER_NONCE_KEY)) {
         $user = $this->wp_facade->wp_get_current_user();
         $response = array('nonce' => $this->wp_facade->wp_create_nonce(static::VERIFIER_NONCE_KEY));
         if (stripos($_SERVER['REQUEST_METHOD'], 'POST') !== false && isset($_POST['verify_action']) && 'pair' === $_POST['verify_action']) {
             try {
                 $white_label_user = $this->launchkey_client->whiteLabel()->createUser($user->user_login);
                 $response['qrcode_url'] = $white_label_user->getQrCodeUrl();
                 $response['manual_code'] = $white_label_user->getCode();
             } catch (Exception $e) {
                 $response['error'] = $e->getCode();
             }
         } elseif (stripos($_SERVER['REQUEST_METHOD'], 'POST') !== false) {
             $response['completed'] = false;
             try {
                 $username = empty($_POST['username']) ? $user->user_login : $_POST['username'];
                 $auth_request = $this->launchkey_client->auth()->authorize($username);
                 $this->wp_facade->update_user_meta($user->ID, 'launchkey_username', $username);
                 $this->wp_facade->update_user_meta($user->ID, 'launchkey_auth', $auth_request->getAuthRequestId());
                 $this->wp_facade->update_user_meta($user->ID, 'launchkey_authorized', null);
             } catch (Exception $e) {
                 $response['error'] = $e->getCode();
             }
         } else {
             $db = $this->wp_facade->get_wpdb();
             $value = $db->get_var($db->prepare("SELECT meta_value FROM {$db->usermeta} WHERE user_id = %s AND meta_key = 'launchkey_authorized' LIMIT 1", $user->ID));
             $response['completed'] = !empty($value);
         }
         $this->wp_facade->wp_send_json($response);
     }
 }
 /**
  * Callback handler to process white label pairing via AJAX
  *
  * @since 1.0.0
  */
 public function white_label_pair_callback()
 {
     if (isset($_POST['nonce'])) {
         // If there is no nonce, ignore the request
         if ($this->wp_facade->wp_verify_nonce($_POST['nonce'], LaunchKey_WP_User_Profile::NONCE_KEY)) {
             // If there is a valid nonce
             if ($user = $this->wp_facade->wp_get_current_user()) {
                 // and a current logged in user
                 try {
                     // Create a LaunchKey White Label user with the WordPress username as the unique identifer
                     $pair_response = $this->launchkey_client->whiteLabel()->createUser($user->user_login);
                     // Set the WordPress username as the LaunchKey username for subsequent login attempts
                     $this->wp_facade->update_user_meta($user->ID, 'launchkey_username', $user->user_login);
                     // Set up the response with the QR Code URL and manual pairing codes
                     $response = array('qrcode' => $pair_response->getQrCodeUrl(), 'code' => $pair_response->getCode());
                 } catch (\LaunchKey\SDK\Service\Exception\CommunicationError $e) {
                     // Communication error response
                     $response = array('error' => 'There was a communication error encountered during the pairing process.  Please try again later');
                 } catch (\LaunchKey\SDK\Service\Exception\InvalidCredentialsError $e) {
                     // Invalid credentials response
                     $response = array('error' => 'There was an error encountered during the pairing process caused by a misconfiguration.  Please contact the administrator.');
                 } catch (\Exception $e) {
                     // General error response
                     $response = array('error' => 'There was an error encountered during the pairing process.  Please contact the administrator.');
                 }
                 // Add a new nonce to the response to allow another request
                 $response['nonce'] = $this->wp_facade->wp_create_nonce(LaunchKey_WP_User_Profile::NONCE_KEY);
                 // Set the headers for the AJAX response
                 $this->wp_facade->wp_send_json($response);
             }
         }
     }
 }
 /**
  * @param $user_id
  * @param $launchkey_username
  *
  * @return null|WP_Error
  */
 private function authenticate_user($user_id, $launchkey_username)
 {
     // reset user authentication
     $this->reset_auth($user_id);
     // Get the auth client from the SDK
     $auth = $this->launchkey_client->auth();
     try {
         // Authenticate and get the request ID
         $auth_request = $auth->authenticate($launchkey_username)->getAuthRequestId();
         // Set the auth request ID in the user metadata to be available to the server side event
         $this->wp_facade->update_user_meta($user_id, 'launchkey_auth', $auth_request);
         // Loop until a response has been recorded by the SSE callback
         do {
             // Sleep before checking for the response to not kill the server
             sleep(1);
             // See if the user has authorized
             $auth = $this->get_user_authorized($user_id);
         } while (null === $auth);
         // If the response is null, continue the loop
         if ($auth) {
             // If the user accepted, return true
             $response = true;
         } else {
             // Otherwise, return an error
             $response = new WP_Error('launchkey_authentication_denied', $this->wp_facade->__('Authentication denied!', $this->language_domain));
         }
     } catch (Exception $e) {
         // Process exceptions appropriately
         $response = new WP_Error();
         if ($e instanceof \LaunchKey\SDK\Service\Exception\NoPairedDevicesError) {
             $response->add('launchkey_authentication_denied', $this->wp_facade->__('No Paired Devices!', $this->language_domain));
         } elseif ($e instanceof \LaunchKey\SDK\Service\Exception\NoSuchUserError) {
             $response->add('launchkey_authentication_denied', $this->wp_facade->__('Authentication denied!', $this->language_domain));
         } elseif ($e instanceof \LaunchKey\SDK\Service\Exception\RateLimitExceededError) {
             $response->add('launchkey_authentication_denied', $this->wp_facade->__('Authentication denied!', $this->language_domain));
         } elseif ($e instanceof \LaunchKey\SDK\Service\Exception\ExpiredAuthRequestError) {
             $response->add('launchkey_authentication_timeout', $this->wp_facade->__('Authentication denied!', $this->language_domain));
         } else {
             if ($this->wp_facade->is_debug_log()) {
                 $this->wp_facade->error_log('Error authenticating user with Launchkey: ' . $e->getMessage());
             }
             $response->add('launchkey_authentication_error', $this->wp_facade->__('Authentication error!  Please try again later', $this->language_domain));
         }
     }
     return $response;
 }
/**
 * Initialize LaunchKey WordPress Plugin
 *
 * This function will perform the entire initialization for the plugin.  The initialization is encapsulated into
 * a funciton to protect against global variable collision.
 *
 * @since 1.0.0
 * Enclose plug-in initialization to protect against global variable corruption
 */
function launchkey_plugin_init()
{
    global $wpdb;
    /**
     * Register activation hooks for the plugin
     * @since 1.1.0
     */
    register_activation_hook(__FILE__, 'launchkey_create_tables');
    /**
     * Remove the scheduled cron
     * @since 1.1.0
     */
    register_deactivation_hook(__FILE__, 'launchkey_cron_remove');
    /**
     * @since 1.1.0
     * Add the cron hook and schedule if not scheduled
     */
    add_action('launchkey_cron_hook', 'launchkey_cron');
    if (!wp_next_scheduled('launchkey_cron_hook')) {
        wp_schedule_event(time(), 'hourly', 'launchkey_cron_hook');
    }
    /**
     * Language domain for the plugin
     */
    $language_domain = 'launchkey';
    /**
     * Register plugin text domain with language files
     *
     * @see load_plugin_textdomain
     * @link https://developer.wordpress.org/reference/hooks/plugins_loaded/
     */
    add_action('plugins_loaded', function () use($language_domain) {
        load_plugin_textdomain($language_domain, false, plugin_basename(__FILE__) . '/languages/');
    });
    /**
     * Create an AES encryption class for encryption/decryption of the secret options
     * @link https://docs.launchkey.com/glossary.html#term-aes
     */
    $crypt_aes = new \phpseclib\Crypt\AES();
    /**
     * Use an MD5 hash of the auth key as the crypto key.  The crypto key is used as it would normally affect all auth
     * procedures as it is used as a salt for passwords.  An md5 hash is used as it will be a constant value based on
     * the AUTH_KEY but guaranteed to be exactly thirty-two (32) characters as is needed by AES encryption.
     */
    $crypt_aes->setKey(md5(AUTH_KEY));
    // Create an options handler that will encrypt and decrypt the plugin options as necessary
    $options_handler = new LaunchKey_WP_Options($crypt_aes);
    /**
     * The pre_update_option_launchkey filter will process the "launchkey" option directly
     * before updating the data in the database.
     *
     * @since 1.0.0
     * @link https://developer.wordpress.org/reference/hooks/pre_update_option_option/
     * @see LaunchKey_WP_Options::pre_update_option_filter
     */
    add_filter('pre_update_option_launchkey', array($options_handler, 'pre_update_option_filter'));
    add_filter('pre_update_site_option_launchkey', array($options_handler, 'pre_update_option_filter'));
    /**
     * The pre_update_option_filter filter will process the "launchkey" option directly
     * before adding the data in the database.
     *
     * @since 1.0.0
     * @link https://developer.wordpress.org/reference/hooks/pre_update_option_option/
     * @see LaunchKey_WP_Options::pre_update_option_filter
     */
    add_filter('pre_add_option_launchkey', array($options_handler, 'pre_update_option_filter'));
    add_filter('pre_add_site_option_launchkey', array($options_handler, 'pre_update_option_filter'));
    /**
     * The option_launchkey filter will process the "launchkey" option directly
     * after retrieving the data from the database.
     *
     * @since 1.0.0
     * @link https://developer.wordpress.org/reference/hooks/option_option/
     * @see LaunchKey_WP_Options::post_get_option_filter
     */
    add_filter('option_launchkey', array($options_handler, 'post_get_option_filter'));
    add_filter('site_option_launchkey', array($options_handler, 'post_get_option_filter'));
    $is_multi_site = is_multisite() && is_plugin_active_for_network(plugin_basename(__FILE__));
    $options = $is_multi_site ? get_site_option(LaunchKey_WP_Admin::OPTION_KEY) : get_option(LaunchKey_WP_Admin::OPTION_KEY);
    /**
     * Handle upgrades if in the admin and not the latest version
     */
    if (is_admin() && launchkey_is_activated() && $options && $options[LaunchKey_WP_Options::OPTION_VERSION] < 1.1) {
        launchkey_create_tables();
    }
    /**
     * If the pre-1.0.0 option style was already used, create a 1.0.0 option and remove the old options.  They are
     * removed as the secret_key was stored plain text in the database.
     *
     * @since 1.0.0
     */
    if (get_option('launchkey_app_key') || get_option('launchkey_secret_key')) {
        $launchkey_options[LaunchKey_WP_Options::OPTION_ROCKET_KEY] = get_option('launchkey_app_key');
        $launchkey_options[LaunchKey_WP_Options::OPTION_SECRET_KEY] = get_option('launchkey_secret_key');
        $launchkey_options[LaunchKey_WP_Options::OPTION_SSL_VERIFY] = defined('LAUNCHKEY_SSLVERIFY') && LAUNCHKEY_SSLVERIFY || true;
        $launchkey_options[LaunchKey_WP_Options::OPTION_IMPLEMENTATION_TYPE] = LaunchKey_WP_Implementation_Type::OAUTH;
        $launchkey_options[LaunchKey_WP_Options::OPTION_LEGACY_OAUTH] = true;
        $updated = $is_multi_site ? update_network_option(LaunchKey_WP_Admin::OPTION_KEY, $launchkey_options) : update_option(LaunchKey_WP_Admin::OPTION_KEY, $launchkey_options);
        if ($updated) {
            delete_option('launchkey_app_key');
            delete_option('launchkey_secret_key');
        } else {
            throw new RuntimeException('Unable to upgrade LaunchKey meta-data.  Failed to save setting ' . LaunchKey_WP_Admin::OPTION_KEY);
        }
    } elseif (!$options) {
        $is_multi_site ? add_site_option(LaunchKey_WP_Admin::OPTION_KEY, array()) : add_option(LaunchKey_WP_Admin::OPTION_KEY, array());
        $options = $is_multi_site ? get_site_option(LaunchKey_WP_Admin::OPTION_KEY) : get_option(LaunchKey_WP_Admin::OPTION_KEY);
    }
    /**
     * Get the WP global facade
     * @see LaunchKey_WP_Global_Facade
     */
    $facade = new LaunchKey_WP_Global_Facade();
    /**
     * Create a templating object and point it at the correct directory for template files.
     *
     * @see LaunchKey_WP_Template
     */
    $template = new LaunchKey_WP_Template(__DIR__ . '/templates', $facade, $language_domain);
    // Prevent XXE Processing Vulnerability
    libxml_disable_entity_loader(true);
    // Get the plugin options to determine which authentication implementation should be utilized
    $logger = new LaunchKey_WP_Logger($facade);
    $launchkey_client = null;
    $client = null;
    // Only register the pieces that need to interact with LaunchKey if it's been configured
    if (LaunchKey_WP_Implementation_Type::SSO === $options[LaunchKey_WP_Options::OPTION_IMPLEMENTATION_TYPE] && !empty($options[LaunchKey_WP_Options::OPTION_SSO_ENTITY_ID])) {
        $container = new LaunchKey_WP_SAML2_Container($logger);
        SAML2_Compat_ContainerSingleton::setContainer($container);
        $securityKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public'));
        $securityKey->loadKey($options[LaunchKey_WP_Options::OPTION_SSO_CERTIFICATE], false, true);
        $saml_response_service = new LaunchKey_WP_SAML2_Response_Service($securityKey, $facade);
        $saml_request_service = new LaunchKey_WP_SAML2_Request_Service($securityKey);
        $client = new LaunchKey_WP_SSO_Client($facade, $template, $options[LaunchKey_WP_Options::OPTION_SSO_ENTITY_ID], $saml_response_service, $saml_request_service, $wpdb, $options[LaunchKey_WP_Options::OPTION_SSO_LOGIN_URL], $options[LaunchKey_WP_Options::OPTION_SSO_LOGOUT_URL], $options[LaunchKey_WP_Options::OPTION_SSO_ERROR_URL], $is_multi_site);
    } elseif (LaunchKey_WP_Implementation_Type::OAUTH === $options[LaunchKey_WP_Options::OPTION_IMPLEMENTATION_TYPE] && !empty($options[LaunchKey_WP_Options::OPTION_SECRET_KEY])) {
        /**
         * If the implementation type is OAuth, use the OAuth client
         * @see LaunchKey_WP_OAuth_Client
         */
        $client = new LaunchKey_WP_OAuth_Client($facade, $template, $is_multi_site);
    } elseif (!empty($options[LaunchKey_WP_Options::OPTION_SECRET_KEY])) {
        $launchkey_client = \LaunchKey\SDK\Client::wpFactory($options[LaunchKey_WP_Options::OPTION_ROCKET_KEY], $options[LaunchKey_WP_Options::OPTION_SECRET_KEY], $options[LaunchKey_WP_Options::OPTION_PRIVATE_KEY], $options[LaunchKey_WP_Options::OPTION_SSL_VERIFY]);
        $client = new LaunchKey_WP_Native_Client($launchkey_client, $facade, $template, $language_domain, $is_multi_site);
        add_filter('init', function () use($facade) {
            wp_enqueue_script('launchkey-script', plugins_url('/public/launchkey-login.js', __FILE__), array('jquery'), '1.1.1', true);
        });
    }
    if ($client) {
        /**
         * Register the non-admin actions for authentication client.  These actions will handle all of the
         * authentication work for the plugin.
         *
         * @see LaunchKey_WP_Client::register_actions
         * @see LaunchKey_WP_OAuth_Client::register_actions
         * @see LaunchKey_WP_Native_Client::register_actions
         */
        $client->register_actions();
        /**
         * Create the a user profile object and register its actions.  These actions will handle all functionality
         * related to a user customizing their authentication related options.
         *
         * @see LaunchKey_WP_User_Profile
         */
        $profile = new LaunchKey_WP_User_Profile($facade, $template, $language_domain, $is_multi_site);
        $profile->register_actions();
        /**
         * Hideous workaround for the wp-login.php page not printing styles in the header like it should.
         *
         * @since 1.0.0
         */
        if (!has_action('login_enqueue_scripts', 'wp_print_styles')) {
            add_action('login_enqueue_scripts', 'wp_print_styles', 11);
        }
    }
    if (is_admin() || $is_multi_site && is_network_admin()) {
        /**
         * If we are in the admin, create an admin object and register its actions.  These actions
         * will manage setting of options and user management for the plugin.
         *
         * @see is_admin
         * @see LaunchKey_WP_Admin
         */
        $launchkey_admin = new LaunchKey_WP_Admin($facade, $template, $language_domain, $is_multi_site);
        $launchkey_admin->register_actions();
        $config_wizard = new LaunchKey_WP_Configuration_Wizard($facade, $launchkey_admin, $is_multi_site, $launchkey_client);
        $config_wizard->register_actions();
    }
    /**
     * Add a filter to enqueue styles for the plugin
     *
     * @since 1.0.0
     *
     * @see add_filter
     * @see wp_enqueue_style
     * @link https://developer.wordpress.org/reference/functions/add_filter/
     * @link https://developer.wordpress.org/reference/functions/wp_enqueue_style/
     */
    add_filter('init', function () use($facade) {
        wp_enqueue_style('launchkey-style', plugins_url('/public/launchkey.css', __FILE__), array(), '1.0.1', false);
    });
    /**
     * Handle activation when a "must use" plugin
     */
    if (launchkey_is_mu_plugin()) {
        $mu_activated_option = "launchkey_activated";
        if (!get_option($mu_activated_option)) {
            do_action("activate_" . plugin_basename(__FILE__));
            add_option($mu_activated_option, true);
        }
    }
}
 public function wizard_easy_setup_callback()
 {
     $headers = array();
     array_walk($_SERVER, function ($value, $key) use(&$headers) {
         if (preg_match('/^HTTP\\_(.+)$/', $key, $matches)) {
             $headers[str_replace('_', '-', $matches[1])] = $value;
         }
     });
     preg_match('/^[^\\/]+\\/(.*)$/', $_SERVER['SERVER_PROTOCOL'], $matches);
     $protocol_version = $matches ? $matches[1] : null;
     $request = new Request($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'], $headers, $this->wp_facade->fopen('php://input', 'rb'), $protocol_version);
     $http_response = new Response();
     if ($request->hasHeader('signature')) {
         try {
             // Have the SDK client handle the callback
             $response = $this->launchkey_client->serverSentEvent()->handleEvent($request, $http_response);
             if ($response instanceof \LaunchKey\SDK\Domain\RocketCreated) {
                 $config = $this->get_option(LaunchKey_WP_Configuration_Wizard::EASY_SETUP_OPTION);
                 if (empty($config['nonce']) || !$config['nonce'] instanceof \LaunchKey\SDK\Domain\NonceResponse) {
                     throw new \LaunchKey\SDK\Service\Exception\InvalidRequestError(sprintf('Easy config request with no valid "nonce" in option "%s"', LaunchKey_WP_Configuration_Wizard::EASY_SETUP_OPTION));
                 }
                 // Delete the option, valid or not.
                 $this->wp_facade->delete_option(LaunchKey_WP_Configuration_Wizard::EASY_SETUP_OPTION);
                 // Check for expiration of the nonce
                 $expires = $config['nonce']->getExpiration();
                 if ($expires <= new DateTime("now", new DateTimeZone("UTC"))) {
                     throw new \LaunchKey\SDK\Service\Exception\InvalidRequestError('Easy config "nonce" has expired');
                 }
                 $rocketConfig = $response->getRocketConfig($this->crypt_service, $config['nonce']->getNonce());
                 $expected_callback_url = $this->wp_facade->admin_url('admin-ajax.php?action=' . LaunchKey_WP_Native_Client::CALLBACK_AJAX_ACTION);
                 // Verify the callback URL before attempting to decrypt the data
                 $actual_callback_url = $rocketConfig->getCallbackURL();
                 if ($actual_callback_url !== $expected_callback_url) {
                     throw new \LaunchKey\SDK\Service\Exception\InvalidRequestError(sprintf('Easy config is not for this site based on callback. Expected: %s, Actual: %s.', $expected_callback_url, $actual_callback_url));
                 }
                 $options = $this->get_option(LaunchKey_WP_Admin::OPTION_KEY);
                 $rocket_type = $rocketConfig->isWhiteLabel() ? LaunchKey_WP_Implementation_Type::WHITE_LABEL : LaunchKey_WP_Implementation_Type::NATIVE;
                 // Update options from server sent event service response
                 $options[LaunchKey_WP_Options::OPTION_IMPLEMENTATION_TYPE] = $rocket_type;
                 $options[LaunchKey_WP_Options::OPTION_ROCKET_KEY] = $rocketConfig->getKey();
                 $options[LaunchKey_WP_Options::OPTION_SECRET_KEY] = $rocketConfig->getSecret();
                 $options[LaunchKey_WP_Options::OPTION_PRIVATE_KEY] = $rocketConfig->getPrivateKey();
                 $this->update_option(LaunchKey_WP_Admin::OPTION_KEY, $options);
                 $response_string = "";
                 $body = $http_response->getBody();
                 $body->rewind();
                 while ($segment = $body->read(256)) {
                     $response_string .= $segment;
                 }
                 $this->wp_facade->header("Content-Type: text/plain", true, $http_response->getStatusCode());
                 $this->wp_facade->wp_die($response_string);
             }
         } catch (\Exception $e) {
             if ($this->wp_facade->is_debug_log()) {
                 $this->wp_facade->error_log('Callback Exception: ' . $e->getMessage());
             }
             if ($e instanceof \LaunchKey\SDK\Service\Exception\InvalidRequestError) {
                 $this->wp_facade->http_response_code(400);
                 $this->wp_facade->wp_die('Invalid Request');
             } else {
                 $this->wp_facade->http_response_code(500);
                 $this->wp_facade->wp_die('Server Error');
             }
         }
     }
 }
Ejemplo n.º 6
0
 protected function setUp()
 {
     $this->client = Client::factory("APP_KEY", "SECRET_KEY", $this->getPrivateKey());
     $this->wpClient = Client::wpFactory("APP_KEY", "SECRET_KEY", $this->getPrivateKey());
 }