Current Path : /home/theafprt/conviviality360.com/wp-content/mu-plugins/ionos-sso/inc/ |
Current File : /home/theafprt/conviviality360.com/wp-content/mu-plugins/ionos-sso/inc/class-manager.php |
<?php /* Plugin Name: IONOS SSO Plugin URI: https://www.ionos.com Description: SSO for WordPress Version: License: GPLv2 or later Author: IONOS Author URI: https://www.ionos.com Text Domain: ionos-sso @package ionos-sso */ namespace Ionos\SSO; // Do not allow direct access! if ( ! defined( 'ABSPATH' ) ) { die(); } /** * Manager class */ class Manager { const JUMP_HOST_DOMAIN = 'webapps-sso.hosting.ionos.com'; const WP_PSS_API = 'https://cisapi.hosting.ionos.com/%s/managed-wordpress/provisionings?domain-binding=%s'; const DEFAULT_OAUTH_ERROR = 'The login process via SSO failed'; const TRANSIENT_PREFIX = 'ionos_sso_'; /** * SSO constructor. */ public function __construct() { add_action( 'init', array( $this, 'oauth' ) ); add_action( 'wp_logout', array( $this, 'cleanup_after_logout' ) ); } /** * Handle oauth process. */ public function oauth() { global $pagenow; if ( '1' !== get_option( 'ionos_oauth_enabled' ) || strpos( wp_login_url(), $pagenow ) === false || ! is_ssl() ) { return null; } $this->single_sign_on(); if ( Helper::compare_action( 'ionos_oauth_register' ) ) { $this->register_domain(); $this->oauth_authenticate(); } elseif ( Helper::compare_action( 'ionos_oauth_authenticate' ) ) { if ( ! isset( $_GET['access_token'] ) || ! isset( $_GET['state'] ) || $_GET['state'] !== get_transient(self::TRANSIENT_PREFIX . 'state') ) { return $this->login_error( __( self::DEFAULT_OAUTH_ERROR, 'ionos-sso' ) ); } // decrypt access token. $decoded_access_token = $this->decrypt_access_token( $_GET['access_token'], get_transient(self::TRANSIENT_PREFIX . 'iv'), get_transient(self::TRANSIENT_PREFIX . 'secret') ); if ( $decoded_access_token === false ) { return $this->login_error( __( self::DEFAULT_OAUTH_ERROR, 'ionos-sso' ) ); } // validate access token by wordpress-pss. $is_valid_access_token = $this->check_customer_access_authorization( $decoded_access_token ); if ( $is_valid_access_token === true ) { // add user information to transient. delete_transient( self::TRANSIENT_PREFIX . 'state' ); delete_transient( self::TRANSIENT_PREFIX . 'secret' ); delete_transient( self::TRANSIENT_PREFIX . 'iv' ); set_transient( self::TRANSIENT_PREFIX . 'access_token', base64_encode( $decoded_access_token ), 60 * 60 * 2 ); add_filter( 'authenticate', array( $this, 'login_admin_user' ), 1 ); } else { return $this->login_error( __( self::DEFAULT_OAUTH_ERROR, 'ionos-sso' ) ); } } } /** * try to log in via Single Sign-On, if the conditions are given */ private function single_sign_on() { $referer_host = $this->get_referer_host(); if ( '1' === get_option( 'ionos_oauth_enabled' ) && true === Helper::is_ionos_host( $referer_host ) && Helper::is_blacklisted_ionos_domain( $referer_host ) === false && ! isset($_GET['action']) ) { $this->register_domain(); $this->oauth_authenticate(); } } /** * Returns hostname of the referer * * @return string */ private function get_referer_host() { $referer_host = null; if ( ( $referer = filter_var( wp_get_raw_referer(), FILTER_VALIDATE_URL ) ) !== false ) { $referer_host = parse_url( $referer, PHP_URL_HOST ); } return $referer_host; } /** * Register Domain to JumpHost and store keys into the session. * The keys are needed to encrypt access_token */ private function register_domain() { $oauth_register_result = $this->oauth_register(); set_transient(self::TRANSIENT_PREFIX . 'state', $oauth_register_result['state'], 7200); set_transient(self::TRANSIENT_PREFIX . 'secret', $oauth_register_result['secret'], 600); set_transient(self::TRANSIENT_PREFIX . 'iv', $oauth_register_result['iv'], 600); } /** * Redirect to IONOS OAuth login form. * * @return mixed [ $state, $iv, $secret ] */ private function oauth_register() { try { $response = wp_remote_post( 'https://' . self::JUMP_HOST_DOMAIN . '/api/wordpress/register', array( 'method' => 'POST', 'body' => array( 'wp_callback' => wp_login_url() . '?action=ionos_oauth_authenticate', 'market' => get_option( 'ionos_assistant_market', 'US' ), ), ) ); } catch ( Exception $e ) { return $this->login_error( __( self::DEFAULT_OAUTH_ERROR, 'ionos-sso' ) ); } if ( is_array( $response ) && isset( $response['response'] ) && isset( $response['response']['code'] ) && 200 === $response['response']['code'] && is_array( $response_decoded = json_decode( $response['body'], true ) ) && isset( $response_decoded['state'], $response_decoded['secret'], $response_decoded['iv'] ) ) { return $response_decoded; } else { return $this->login_error( __( self::DEFAULT_OAUTH_ERROR, 'ionos-sso' ) ); } } /** * Throw error message. * * @param string $text // Error message. * * @return WP_ERROR */ private function login_error( $text = '' ) { $this->error_message = $text; return add_filter( 'wp_login_errors', function ( $errors ) { $msg = '<strong>Error</strong>: ' . $this->error_message; $errors->add( 'ionos_oauth_error', $msg ); return $errors; } ); } /** * Redirect to jumphost. */ private function oauth_authenticate() { $param = [ 'state' => get_transient(self::TRANSIENT_PREFIX . 'state'), 'action' => 'ionos_oauth_authenticate', ]; wp_redirect( 'https://' . self::JUMP_HOST_DOMAIN . '/wordpress/login?' . http_build_query( $param ) ); } /** * Decrypt the access token. * * @param string $string // String that have to decrypted. * @param string $iv // Individual value needed for decrypting. * @param string $secret // needed for decrypting. * * @return string|false */ private function decrypt_access_token( $string, $iv, $secret ) { return openssl_decrypt( $string, 'AES-256-CBC', $secret, 0, $iv ); } /** * Validate access token via WP_PSS_API * * @param string $access_token // Decrypted access token. * * @return bool */ private function check_customer_access_authorization( string $access_token = null ) { if ( is_null( $access_token ) ) { return false; } $customer_domain = parse_url( filter_var( get_home_url(), FILTER_VALIDATE_URL ), PHP_URL_HOST ); $response = wp_remote_get( sprintf( self::WP_PSS_API, self::JUMP_HOST_DOMAIN, $customer_domain ), array( 'headers' => array( 'Authorization' => 'Bearer ' . $access_token, ), ) ); if ( isset( $response['response']['code'] ) && 200 === $response['response']['code'] ) { $provisions = json_decode( $response['body'], true ); return $this->validate_provisioning( $provisions, $customer_domain ); } return false; } private function validate_provisioning( array $provisions = [], string $customer_domain = null ) { if ( empty( $provisions ) || is_null( $customer_domain ) ) { return false; } foreach ( $provisions as $provisioning ) { if ( isset( $provisioning['projects'] ) ) { foreach ( $provisioning['projects'] as $project ) { if ( isset( $project['domain_binding'] ) && $project['domain_binding'] === $customer_domain ) { return true; } } } } return false; } /** * Remove session parameter and revoke access token by jumphost. * * @return void */ public function cleanup_after_logout() { $access_token = get_transient(self::TRANSIENT_PREFIX . 'access_token'); wp_remote_post( 'https://' . self::JUMP_HOST_DOMAIN . '/api/wordpress/revoke', array( 'headers' => array( 'Authorization' => 'Bearer ' . $access_token, ), ) ); delete_transient(self::TRANSIENT_PREFIX . 'state'); delete_transient(self::TRANSIENT_PREFIX . 'secret'); delete_transient(self::TRANSIENT_PREFIX . 'iv'); } /** * Login first admin user */ public function login_admin_user() { foreach ( get_users() as $user ) { if ( user_can( $user->ID, 'administrator' ) ) { return $user; } } return $this->login_error( __( self::DEFAULT_OAUTH_ERROR, 'ionos-sso' ) ); } }