<?php
/*
 * consentAdmin - Consent administration module
 *
 * This module enables the user to add and remove consents given for a given
 * Service Provider.
 *
 * The module relies on methods and functions from the Consent module and can
 * not be user without it.
 *
 * Author: Mads Freen - WAYF, Jacob Christiansen - WAYF
 */

/*
 * Runs the processingchain and ignores all filter which have user 
 * interaction.
 */
function driveProcessingChain($idp_metadata, $source, $sp_metadata, $sp_entityid, $attributes, $userid) {

	/* 
	 * Create a new processing chain 
	 */
	$pc = new SimpleSAML_Auth_ProcessingChain($idp_metadata, $sp_metadata, 'idp');

	/* 
	 * Construct the state.
	 * REMEMBER: Do not set Return URL if you are calling processStatePassive
	 */
	$authProcState = array(
		'Attributes' => $attributes,
		'Destination' => $sp_metadata,
		'Source' => $idp_metadata,
		'isPassive' => TRUE,
	);

	/* 
	 * Call processStatePAssive.
	 * We are not interested in any user interaction, only modifications to the attributes
	 */
	$pc->processStatePassive($authProcState);

	$attributes = $authProcState['Attributes'];

	/*
	 * Generate identifiers and hashes
	 */
	$destination = $sp_metadata['metadata-set'] . '|' . $sp_entityid;

	$targeted_id    = sspmod_consent_Auth_Process_Consent::getTargetedID($userid, $source, $destination);
	$attribute_hash = sspmod_consent_Auth_Process_Consent::getAttributeHash($attributes, false);

	SimpleSAML_Logger::info('consentAdmin: user: ' . $hashed_user_id);
	SimpleSAML_Logger::info('consentAdmin: target: ' . $targeted_id);
	SimpleSAML_Logger::info('consentAdmin: attribute: ' . $attribute_hash);

	/* Return values */
	return array($targeted_id, $attribute_hash, $attributes);
}

// Get config object
$config = SimpleSAML_Configuration::getInstance();

// Get session object
$session = SimpleSAML_Session::getInstance();

/* Check if valid local session exists */
if (!isset($session) || !$session->isValid('saml2') ) {
	// Set idpentity to force a specific IdP
	SimpleSAML_Utilities::redirect('/saml2/sp/initSSO.php',
		array('RelayState'  => SimpleSAML_Utilities::selfURL())
	);
}

// Get user ID
$userid_attributename = $config->getValue('consent_userid', 'eduPersonPrincipalName');
$userids = ($session->getAttribute($userid_attributename));
		
if (empty($userids)) {
	throw new Exception('Could not generate useridentifier for storing consent. Attribute [' .
		$userid_attributename . '] was not available.');
}

$userid = $userids[0];

// Get metadata storage handler
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();

// Get all SP metadata
$all_sp_metadata = $metadata->getList('saml20-sp-remote');

// Get released attributes
$attributes = $session->getAttributes();

// Parse action, if any
$action = null;
$sp_entityid = null;
if (!empty($_GET['cv'])) {
	$sp_entityid=$_GET['cv'];
}
if (!empty($_GET['action'])) {
	$action=$_GET["action"];
}

SimpleSAML_Logger::critical('consentAdmin: sp: ' .$sp_entityid.' action: '.$action);

/*
 * Get IdP id and metadata
 */
if($session->getIdP() != null) {
	/*
	 * From a remote idp (as bridge)
 	 */
	$idp_entityid = $session->getIdP();
	$idp_metadata = $metadata->getMetaData($idp_entityid, 'saml20-idp-remote');
} else {
	/*
	 * from the local idp
	 */
	$idp_entityid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
	$idp_metadata = $metadata->getMetaData($idp_entityid, 'saml20-idp-hosted');
}
 
SimpleSAML_Logger::info('consentAdmin: '.$idp_entityid);

// Calc correct source
$source = $idp_metadata['metadata-set'] . '|' . $idp_entityid;

// Parse consent config
$consent_storage = sspmod_consent_Store::parseStoreConfig($config->getValue('consentadmin'));

// Calc correct user ID hash
$hashed_user_id = sspmod_consent_Auth_Process_Consent::getHashedUserID($userid, $source);

// If a checkbox have been clicked
if ($action != null && $sp_entityid != null) {
	// Get SP metadata
	$sp_metadata = $metadata->getMetaData($sp_entityid, 'saml20-sp-remote');

	// Run AuthProc filters
	list($targeted_id, $attribute_hash, $attributes_new) = driveProcessingChain($idp_metadata, $source, $sp_metadata, $sp_entityid, $attributes, $userid);

	// Add a consent (or update if attributes have changed and old consent for SP and IdP exists)
	if($action == 'true') {
		$isStored = $consent_storage->saveConsent($hashed_user_id, $targeted_id, $attribute_hash);
		if($isStored) {
			$res =  "added";
		} else {
			$res = "updated";
		}
	// Remove consent
	} else if($action == 'false') {
		// Got consent, so this is a request to remove it
		$rowcount = $consent_storage->deleteConsent($hashed_user_id, $targeted_id, $attribute_hash);
		if($rowcount > 0) {
			$res = "removed";
		}
	// Unknown action (should not happen)
	} else {
		SimpleSAML_Logger::info('consentAdmin: unknown action');
		$res = "unknown";
	}
	/*
	 * Init template to enable translation of status messages 
 	 */
	$et = new SimpleSAML_XHTML_Template($config, 'consentAdmin:consentadminajax.php', 'consentAdmin:consentadmin');
	$et->data['res'] = $res;
	$et->show();
	exit;
}

// Get all consents for user
$user_consent_list = $consent_storage->getConsents($hashed_user_id);

// Parse list of consents
$user_consent = array();
foreach ($user_consent_list as $c) {
	$user_consent[$c[0]]=$c[1];
}

$sp_empty_name = array(
	'en' => '(name not specified)',
	'no' => '(namn ikke spesifisert)',
	'nn' => '(name not specified)',
	'da' => '(navn ikke angivet)',
	'en' => '(name not specified)',
	'fr' => '(name not specified)',
	'de' => '(name nicht definiert)',
	'nl' => '(name not specified)',
	'lu' => '(name not specified)',
	'sl' => '(name not specified)',
); // TODO: Should be moved to language file
$sp_empty_description = array(
	'en' => '(no description)',
	'no' => '(ingen beskrivelse)',
	'nn' => '(no description)',
	'da' => '(ingen beskrivelse)',
	'es' => '(no description)',
	'fr' => '(no description)',
	'de' => '(no description)',
	'nl' => '(no description)',
	'lu' => '(no description)',
	'sl' => '(no description)',
); // TODO: Should be moved to language file

$template_sp_content = array();

// Process consents for all SP
foreach ($all_sp_metadata as $sp_entityid => $sp_values) {
	// Get metadata for SP
	$sp_metadata = $metadata->getMetaData($sp_entityid, 'saml20-sp-remote');

	// Run attribute filters
	list($targeted_id, $attribute_hash, $attributes_new) = driveProcessingChain($idp_metadata, $source, $sp_metadata, $sp_entityid, $attributes, $userid);

	// Check if consent exists
	if (array_key_exists($targeted_id, $user_consent)) {
		$sp_status = "changed";
		SimpleSAML_Logger::info('consentAdmin: changed');
		// Check if consent is valid. (Possible that attributes has changed)
		if ($user_consent[$targeted_id] == $attribute_hash) {
			SimpleSAML_Logger::info('consentAdmin: ok');
			$sp_status = "ok";
		}
	// Consent does not exists
	} else {
		SimpleSAML_Logger::info('consentAdmin: none');
		$sp_status = "none";
	}

	// Set name of SP
	if(empty($sp_values['name']) || !is_array($sp_values['name'])) {
		$sp_name = $sp_empty_name;
	} else {
		$sp_name = $sp_metadata['name'];
	}

	// Set description of SP
	if(empty($sp_metadata['description']) || !is_array($sp_metadata['description'])) {
		$sp_description = $sp_empty_description;
	} else {
		$sp_description = $sp_metadata['description'];
	}

	// Fill out array for the template
	$sp_list[$sp_entityid] = array(
		'spentityid' => $sp_entityid,
		'name' =>  $sp_name,
		'description' =>  $sp_description,
		'consentStatus' => $sp_status,
		'consentValue' => $sp_entityid,
		'attributes_by_sp' => $attributes_new,
	);
}

// Init template
$et = new SimpleSAML_XHTML_Template($config, 'consentAdmin:consentadmin.php', 'consentAdmin:consentadmin');
$et->data['header'] = 'Consent Administration';
$et->data['logout'] = '<p>[ <a href="/' . $config->getValue('baseurlpath') . 'saml2/sp/initSLO.php?RelayState=https://www.wayf.dk">Logout</a> ]'; // TODO: Fix RelayState. Should be set in config
$et->data['spList'] = $sp_list;
$et->show();
?>
