<?php
/**
 * @package    HybridAuth
 * @author     HybridAuth authors / Joomla! integration by Abhishek Das
 * @copyright  Copyright (c) 2009-2019 hybridAuth authors.
 * @license    HybridAuth is released under dual licence MIT and GPL. see http://hybridauth.sourceforge.net/licenses.html
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 * @link       http://hybridauth.sourceforge.net | http://github.com/hybridauth/hybridauth
 */
defined('_JEXEC') or die;

/**
 * To implement an OpenID based service provider, Hybrid_Provider_Model_OpenID
 * can be used to save the hassle of the authentication flow.
 *
 * Each class that inherit from Hybrid_Provider_Model_OAuth2 have only to define
 * the provider identifier : <code>public $openidIdentifier = ""; </code>
 *
 * Hybrid_Provider_Model_OpenID use LightOpenID lib which can be found on
 * Hybrid/thirdparty/OpenID/LightOpenID.php
 */
class Hybrid_Provider_Model_OpenID extends Hybrid_Provider_Model {

	/**
	 * Provider API client
	 * @var LightOpenID
	 */
	public $api = null;

	/**
	 * Openid provider identifier
	 * @var string
	 */
	public $openidIdentifier = "";

	/**
	 * {@inheritdoc}
	 */
	function initialize() {
		if (isset($this->params["openid_identifier"])) {
			$this->openidIdentifier = $this->params["openid_identifier"];
		}

		// include LightOpenID lib
		require_once Hybrid_Auth::$config["path_libraries"] . "OpenID/LightOpenID.php";

		// An error was occurring when proxy wasn't set. Not sure where proxy was meant to be set/initialized.
		Hybrid_Auth::$config['proxy'] = isset(Hybrid_Auth::$config['proxy']) ? Hybrid_Auth::$config['proxy'] : '';

		$hostPort = parse_url(Hybrid_Auth::$config["base_url"], PHP_URL_PORT);
		$hostUrl = parse_url(Hybrid_Auth::$config["base_url"], PHP_URL_HOST);

		// Check for port on url
		if ($hostPort) {
			$hostUrl .= ':' . $hostPort;
		}

		$this->api = new LightOpenID($hostUrl, Hybrid_Auth::$config["proxy"]);
	}

	/**
	 * {@inheritdoc}
	 */
	function loginBegin() {
		if (empty($this->openidIdentifier)) {
			throw new Exception("OpenID adapter require the identity provider identifier 'openid_identifier' as an extra parameter.", 4);
		}

		$this->api->identity = $this->openidIdentifier;
		$this->api->returnUrl = $this->endpoint;
		$this->api->required = array(
			'namePerson/first',
			'namePerson/last',
			'namePerson/friendly',
			'namePerson',
			'contact/email',
			'birthDate',
			'birthDate/birthDay',
			'birthDate/birthMonth',
			'birthDate/birthYear',
			'person/gender',
			'pref/language',
			'contact/postalCode/home',
			'contact/city/home',
			'contact/country/home',
			'media/image/default',
		);

		# redirect the user to the provider authentication url
		Hybrid_Auth::redirect($this->api->authUrl());
	}

	/**
	 * {@inheritdoc}
	 */
	function loginFinish() {
		# if user don't grant access of their data to your site, halt with an Exception
		if ($this->api->mode == 'cancel') {
			throw new Exception("Authentication failed! User has canceled authentication!", 5);
		}

		# if something goes wrong
		if (!$this->api->validate()) {
			throw new Exception("Authentication failed. Invalid request received!", 5);
		}

		# fetch received user data
		$response = $this->api->getAttributes();

		# store the user profile
		$this->user->profile->identifier = $this->api->identity;

		$this->user->profile->firstName = (array_key_exists("namePerson/first", $response)) ? $response["namePerson/first"] : "";
		$this->user->profile->lastName = (array_key_exists("namePerson/last", $response)) ? $response["namePerson/last"] : "";
		$this->user->profile->displayName = (array_key_exists("namePerson", $response)) ? $response["namePerson"] : "";
		$this->user->profile->email = (array_key_exists("contact/email", $response)) ? $response["contact/email"] : "";
		$this->user->profile->language = (array_key_exists("pref/language", $response)) ? $response["pref/language"] : "";
		$this->user->profile->country = (array_key_exists("contact/country/home", $response)) ? $response["contact/country/home"] : "";
		$this->user->profile->zip = (array_key_exists("contact/postalCode/home", $response)) ? $response["contact/postalCode/home"] : "";
		$this->user->profile->gender = (array_key_exists("person/gender", $response)) ? $response["person/gender"] : "";
		$this->user->profile->photoURL = (array_key_exists("media/image/default", $response)) ? $response["media/image/default"] : "";

		$this->user->profile->birthDay = (array_key_exists("birthDate/birthDay", $response)) ? $response["birthDate/birthDay"] : "";
		$this->user->profile->birthMonth = (array_key_exists("birthDate/birthMonth", $response)) ? $response["birthDate/birthMonth"] : "";
		$this->user->profile->birthYear = (array_key_exists("birthDate/birthDate", $response)) ? $response["birthDate/birthDate"] : "";

		if (isset($response['namePerson/friendly']) && !empty($response['namePerson/friendly']) && !$this->user->profile->displayName) {
			$this->user->profile->displayName = $response["namePerson/friendly"];
		}

		if (isset($response['birthDate']) && !empty($response['birthDate']) && !$this->user->profile->birthDay) {
			list( $birthday_year, $birthday_month, $birthday_day ) = $response['birthDate'];

			$this->user->profile->birthDay = (int) $birthday_day;
			$this->user->profile->birthMonth = (int) $birthday_month;
			$this->user->profile->birthYear = (int) $birthday_year;
		}

		if (!$this->user->profile->displayName) {
			$this->user->profile->displayName = trim($this->user->profile->firstName . " " . $this->user->profile->lastName);
		}

		if ($this->user->profile->gender == "f") {
			$this->user->profile->gender = "female";
		}

		if ($this->user->profile->gender == "m") {
			$this->user->profile->gender = "male";
		}

		// set user as logged in
		$this->setUserConnected();

		// with openid providers we get the user profile only once, so store it
		Hybrid_Auth::storage()->set("hauth_session.{$this->providerId}.user", $this->user);
	}

	/**
	 * {@inheritdoc}
	 */
	function getUserProfile() {
		// try to get the user profile from stored data
		$this->user = Hybrid_Auth::storage()->get("hauth_session.{$this->providerId}.user");

		// if not found
		if (!is_object($this->user)) {
			throw new Exception("User profile request failed! User is not connected to {$this->providerId} or his session has expired.", 6);
		}

		return $this->user->profile;
	}

}
