<?php

class API_LDAP extends API
{

	function constructUserDetailsMapping () {
		$allowUpdateDetails = '0';
		if (isset($GLOBALS['ldapAllowUserUpdateDetails']) && $GLOBALS['ldapAllowUserUpdateDetails']) {
			$allowUpdateDetails = '1';
		}
		$GLOBALS['ldapUserDetailsMapping'] = "firstname;{$GLOBALS['ldapFirstnameMapto']};$allowUpdateDetails|lastname;{$GLOBALS['ldapLastnameMapto']};$allowUpdateDetails|email;{$GLOBALS['ldapEmailMapto']};0";
	}

	/**
		* GetUserType
		*
		* @return string
		*/
	function isLdapUser ($var) {
		if ($var == '@LDAP') {
			return true;
		} else {
			return false;
		}
	}

	/**
		* explodeLdapUserDetailsMapping
		* Check if we have the correct format of the ldap user mapping details and return the exploded
		* details as an array.
		* 
		* @param string $var A string that stores all the ldap user mapping details
		* @return array The exploded of the ldap user mapping details
		* 
		* 
		*/
	function explodeLdapUserDetailsMapping($var)
	{
		$explodedMappedDetails = array();
		if (!isset($GLOBALS['ldapUserDetailsMapping']) || $GLOBALS['ldapUserDetailsMapping'] == '') {
			return $explodedMappedDetails;
		}
		$detailsTokens = explode('|', $GLOBALS['ldapUserDetailsMapping']);

		foreach ($detailsTokens as $detailsToken) {
			$attributesTokens = split(';', $detailsToken);
			$explodedMappedDetails[$attributesTokens[0]]['mapto'] = $attributesTokens[1];
			$explodedMappedDetails[$attributesTokens[0]]['allowUpdate'] = $attributesTokens[2];
		}
		return $explodedMappedDetails;
	}

	function explodeGroupMapping ($groupMappings)
	{
		$results = array();
		$firstExplodes = explode(';', $groupMappings);
		foreach ($firstExplodes as $firstExplode) {
			$secondExplodes = explode(':_:', $firstExplode);
			$lastExplodes = explode(',', $secondExplodes[1]);
			foreach ($lastExplodes as $lastExplode) {
				$results[$secondExplodes[0]][] = $lastExplode;
			}
		}
		return $results;
	}

	function constructSearchString($username)
	{
		$constructedString = '('.str_replace('[login]', $username, $GLOBALS['ldapSearchString']).')';
		return $constructedString;
	}

	function authenticate($username, $password, $userId) {
		// if binding using the authorized user's account failed.
		if(!$GLOBALS['AKB_LDAP']->bind()) {
			return false;
		}

		// get the all ldap sync attributes mapping
		$explodedUserDetails = API_LDAP::explodeLdapUserDetailsMapping($GLOBALS['ldapUserDetailsMapping']);
		if (!sizeof($explodedUserDetails)) {
			return false;
		}

		// prepare for the search entries.
		$mapAttributes = array();
		while (list($k, $v) = each($explodedUserDetails)) {
			$mapAttributes[$k] = $explodedUserDetails[$k]['mapto'];
		}
		reset($explodedUserDetails);
		
		// generate the search string
		$GLOBALS['constructedSearchString'] = API_LDAP::constructSearchString($username);

		// get the login user's details regarding to the mapping details
		$userData = $GLOBALS['AKB_LDAP']->search($GLOBALS['constructedSearchString'], array_values($mapAttributes));

		// if the result isn't unique, return false
		if (sizeof($userData) != 1 || !$userData) {
			return false;
		}
		
		// get the first result of the results.
		$userData = $userData[0];

		$dn = $userData['dn'];

		// Get the status of the user's status in LDAP
		$userStatus = $GLOBALS['AKB_LDAP']->getAccountStatus($GLOBALS['constructedSearchString']);

		// Bind as the login user
		if (!$GLOBALS['AKB_LDAP']->bind($dn, $password)) {
			return false;
		}
		
		// Verify Account Status in AD, they are not allowed to login if the are disabled in LDAP
		if (is_array($userStatus) && sizeof($userStatus) == 1) {
			// Sync the inactive status with LDAP server
			$statusAttb = $GLOBALS['AKB_LDAP']->getAccountStatusAttribute();
			$status = $userStatus[0][$statusAttb][0];
			$isAccountEnabled = $GLOBALS['AKB_LDAP']->isStatusEnable($status);

			if (!$isAccountEnabled) {
				if (API_LDAP::isLdapUser($_SESSION['user']->pass)) {
					$_SESSION['user']->updateField('status', 0);
				}
				return false;
			}
		}

		// if this is an existing LDAP user
		if (API_LDAP::isLdapUser($_SESSION['user']->pass)) {

			// update the user's details in AD, if the flag is set.
			// Perform the LDAP operation to save details.
			if (isset($GLOBALS['ldapUserDetailsMapping'])) {
				foreach ($_SESSION['user']->fields as $field) {
					if (isset($explodedUserDetails[$field]['allowUpdate']) && $explodedUserDetails[$field]['allowUpdate']) {
						$_SESSION['user']->$field=$userData[$explodedUserDetails[$field]['mapto']][0];
						$_SESSION['user']->updateField($field, $_SESSION['user']->$field);
					}
				}
			}
			
			// Set the user's status to enable if the status in LDAP isn't disabled
			if (is_array($userStatus) && sizeof($userStatus) == 1) {
				$_SESSION['user']->updateField('status', 1);
			// else if the user's status is disable in AKB
			} elseif ($_SESSION['user']->status == 0) {
				return false;
			}
		}
		// else if this is a first time logged in LDAP user
		elseif (!$userId) {

			$userLdapGroups = array();
			$systemLdapGroups = array();

			// Perform the group mapping between LDAP and IKM
			if (isset($GLOBALS['ldapEnableGroupMapping']) && $GLOBALS['ldapEnableGroupMapping']) {
				// Get the user's groups
				$groupFilter = "({$GLOBALS['ldapGroupMemberAttb']}=$dn)";
				$userLdapGroups = $GLOBALS['AKB_LDAP'] -> search($groupFilter, array('dn'));

				// Decode the group mapping setting
				$systemLdapMapping = API_LDAP::explodeGroupMapping($GLOBALS['ldapGroupMapping']);
				$systemLdapGroups = array();
				if (sizeof($systemLdapMapping)) {
					$systemLdapGroups = array_keys($systemLdapMapping);
				}

				// if the user has at least on group assigned
				$tmpUserLdapGroup = array();
				if (is_array($userLdapGroups) && sizeof($userLdapGroups)) {
					foreach ($userLdapGroups as $userLdapGroup) {
						$tmpUserLdapGroup[] = $userLdapGroup['dn'];
					}
					$userLdapGroups = $tmpUserLdapGroup;
				} else {
					$userLdapGroups = array();
				}
			}
			
			
			// check if user's is in the group mapping
			$userGroupMapped = array_intersect($userLdapGroups, $systemLdapGroups);

			// if s/he is not in the group mapping and the default condition is to disable the login
			if (!sizeof($userGroupMapped) && $GLOBALS['ldapDefaultAction'] == '-1') {
				return false;
			}

			// if everything is cool, start creating new user
			$_SESSION['user']->username = $username;
			$_SESSION['user']->pass = '@LDAP';
			$_SESSION['user']->status = 1;
			$_SESSION['user']->forgotpasscode = '';
			$_SESSION['user']->sessionid = session_id();
			$_SESSION['user']->tokencode = generateTokenCode($username);

			foreach ($_SESSION['user']->fields as $field) {
				if (isset($explodedUserDetails[$field]['mapto'])) {
					if (isset($userData[$explodedUserDetails[$field]['mapto']][0])) {
						$_SESSION['user']->$field=$userData[$explodedUserDetails[$field]['mapto']][0];
					}
				}
			}
			$_SESSION['user']->usePostVars = false;
			$_SESSION['user']->userid = $_SESSION['user']->create();
			$_SESSION['user']->usePostVars = true;

			// Assign the user's to the group according to the group mapping
			if ($_SESSION['user']->userid) {
				if (sizeof($userGroupMapped)) {
					$groupAdded = false;
					while (list($k, $v) = each($userGroupMapped)) {
						if (isset($systemLdapMapping[$v]) && is_array($systemLdapMapping[$v]) && sizeof($systemLdapMapping[$v])) {
							foreach ($systemLdapMapping[$v] as $eachSystemMapped) {
								$_SESSION['user']->join ((int) $eachSystemMapped);
								$groupAdded = true;
							}
						}
					}
					if ($groupAdded) {
						$_SESSION['user']->loadPerms();
					}
					// if the default condition is to join a specific group
				} elseif ($GLOBALS['ldapDefaultAction'] > 0) {
					$_SESSION['user']->join ((int) $GLOBALS['ldapDefaultAction']);
					$_SESSION['user']->loadPerms();
				}
			}
		}
		// if everything is cool, return the user id
		return $_SESSION['user']->userid;
	}

	function updateUserDetails ($username, $newValue) {
		// if binding using the authorized user's account failed.
		if(!$GLOBALS['AKB_LDAP']->bind()) {
			return false;
		}

		$explodedUserDetails = API_LDAP::explodeLdapUserDetailsMapping($GLOBALS['ldapUserDetailsMapping']);

		// generate the search string
		$GLOBALS['constructedSearchString'] = API_LDAP::constructSearchString($username);

		$dn = $GLOBALS['AKB_LDAP'] -> search($GLOBALS['constructedSearchString'], array('dn'));

		if (is_array($dn) && sizeof($dn)) {
			$dn=$dn[0]['dn'];

			// Get the status of the user's status in LDAP
			$userStatus = $GLOBALS['AKB_LDAP']->getAccountStatus($GLOBALS['constructedSearchString']);

			// if we could the current status
			if (is_array($userStatus) && sizeof($userStatus) == 1) {
				// Sync the inactive status with LDAP server
				$statusAttb = $GLOBALS['AKB_LDAP']->getAccountStatusAttribute();
				$status = $userStatus[0][$statusAttb][0];
				if(!$GLOBALS['AKB_LDAP']->setAccountStatus($dn, $newValue['status'], $status)) {
					return false;
				}
			}
			while (list($k, $v) = each($explodedUserDetails)) {
				if (isset($explodedUserDetails[$k]['allowUpdate']) && $explodedUserDetails[$k]['allowUpdate']) {
					if (isset($newValue[$k])) {
						$val = $newValue[$k];
						$attribute = $explodedUserDetails[$k]['mapto'];
						$entry = array("$attribute" => "$val");
						if (method_exists($this, 'validate_'.$k)
						&& !call_user_func(array($this, 'validate_'.$k), $val)) {
							$this->error = sprintf(GetLang('apiValidateFailedFor'), $k);
							return false;
						}
						if(!$GLOBALS['AKB_LDAP'] -> modify ($dn, $entry)) {
							return false;
						}
					}
				}
			}
		} else {
			return false;
		}
		$GLOBALS['AKB_LDAP'] -> close();
		return true;
	}
}