1<?php
2/*
3 * consentAdmin - Consent administration module
4 *
5 * This module enables the user to add and remove consents given for a given
6 * Service Provider.
7 *
8 * The module relies on methods and functions from the Consent module and can
9 * not be user without it.
10 *
11 * Author: Mads Freek <freek@ruc.dk>, Jacob Christiansen <jach@wayf.dk>
12 */
13
14/*
15 * Runs the processing chain and ignores all filter which have user
16 * interaction.
17 */
18function driveProcessingChain(
19    $idp_metadata,
20    $source,
21    $sp_metadata,
22    $sp_entityid,
23    $attributes,
24    $userid,
25    $hashAttributes = false,
26    $excludeAttributes = array()
27) {
28
29    /*
30     * Create a new processing chain
31     */
32    $pc = new SimpleSAML_Auth_ProcessingChain($idp_metadata, $sp_metadata, 'idp');
33
34    /*
35     * Construct the state.
36     * REMEMBER: Do not set Return URL if you are calling processStatePassive
37     */
38    $authProcState = array(
39        'Attributes'  => $attributes,
40        'Destination' => $sp_metadata,
41        'SPMetadata'  => $sp_metadata,
42        'Source'      => $idp_metadata,
43        'IdPMetadata' => $idp_metadata,
44        'isPassive'   => true,
45    );
46    /* we're being bridged, so add that info to the state */
47    if (strpos($source, '-idp-remote|') !== false) {
48        $authProcState['saml:sp:IdP'] = substr($source, strpos($source, '|') + 1);
49    }
50
51    /*
52     * Call processStatePAssive.
53     * We are not interested in any user interaction, only modifications to the attributes
54     */
55    $pc->processStatePassive($authProcState);
56
57    $attributes = $authProcState['Attributes'];
58    // Remove attributes that do not require consent/should be excluded
59    foreach ($attributes as $attrkey => $attrval) {
60        if (in_array($attrkey, $excludeAttributes)) {
61            unset($attributes[$attrkey]);
62        }
63    }
64
65    /*
66     * Generate identifiers and hashes
67     */
68    $destination = $sp_metadata['metadata-set'].'|'.$sp_entityid;
69
70    $targeted_id = sspmod_consent_Auth_Process_Consent::getTargetedID($userid, $source, $destination);
71    $attribute_hash = sspmod_consent_Auth_Process_Consent::getAttributeHash($attributes, $hashAttributes);
72
73    SimpleSAML\Logger::info('consentAdmin: user: '.$userid);
74    SimpleSAML\Logger::info('consentAdmin: target: '.$targeted_id);
75    SimpleSAML\Logger::info('consentAdmin: attribute: '.$attribute_hash);
76
77    // Return values
78    return array($targeted_id, $attribute_hash, $attributes);
79}
80
81// Get config object
82$config = SimpleSAML_Configuration::getInstance();
83$cA_config = SimpleSAML_Configuration::getConfig('module_consentAdmin.php');
84$authority = $cA_config->getValue('authority');
85
86$as = new \SimpleSAML\Auth\Simple($authority);
87
88// If request is a logout request
89if (array_key_exists('logout', $_REQUEST)) {
90    $returnURL = $cA_config->getValue('returnURL');
91    $as->logout($returnURL);
92}
93
94$hashAttributes = $cA_config->getValue('attributes.hash');
95
96$excludeAttributes = $cA_config->getValue('attributes.exclude', array());
97
98// Check if valid local session exists
99$as->requireAuth();
100
101// Get released attributes
102$attributes = $as->getAttributes();
103
104// Get metadata storage handler
105$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
106
107/*
108 * Get IdP id and metadata
109 */
110
111
112$idp_entityid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
113$idp_metadata = $metadata->getMetaData($idp_entityid, 'saml20-idp-hosted');
114
115// Calc correct source
116if ($as->getAuthData('saml:sp:IdP') !== null) {
117    // from a remote idp (as bridge)
118    $source = 'saml20-idp-remote|'.$as->getAuthData('saml:sp:IdP');
119} else {
120    // from the local idp
121    $source = $idp_metadata['metadata-set'].'|'.$idp_entityid;
122}
123
124// Get user ID
125$userid_attributename = (isset($idp_metadata['userid.attribute']) && is_string($idp_metadata['userid.attribute'])) ? $idp_metadata['userid.attribute'] : 'eduPersonPrincipalName';
126
127$userids = $attributes[$userid_attributename];
128
129if (empty($userids)) {
130    throw new Exception('Could not generate useridentifier for storing consent. Attribute ['.
131        $userid_attributename.'] was not available.');
132}
133
134$userid = $userids[0];
135
136// Get all SP metadata
137$all_sp_metadata = $metadata->getList('saml20-sp-remote');
138
139// Parse action, if any
140$action = null;
141$sp_entityid = null;
142if (!empty($_GET['cv'])) {
143    $sp_entityid = $_GET['cv'];
144}
145if (!empty($_GET['action'])) {
146    $action = $_GET["action"];
147}
148
149SimpleSAML\Logger::critical('consentAdmin: sp: '.$sp_entityid.' action: '.$action);
150
151// Remove services, whitch have consent disabled
152if (isset($idp_metadata['consent.disable'])) {
153    foreach ($idp_metadata['consent.disable'] AS $disable) {
154        if (array_key_exists($disable, $all_sp_metadata)) {
155            unset($all_sp_metadata[$disable]);
156        }
157    }
158}
159
160SimpleSAML\Logger::info('consentAdmin: '.$idp_entityid);
161
162// Parse consent config
163$consent_storage = sspmod_consent_Store::parseStoreConfig($cA_config->getValue('consentadmin'));
164
165// Calc correct user ID hash
166$hashed_user_id = sspmod_consent_Auth_Process_Consent::getHashedUserID($userid, $source);
167
168// If a checkbox have been clicked
169if ($action !== null && $sp_entityid !== null) {
170    // Get SP metadata
171    $sp_metadata = $metadata->getMetaData($sp_entityid, 'saml20-sp-remote');
172
173    // Run AuthProc filters
174    list($targeted_id, $attribute_hash, $attributes_new) = driveProcessingChain($idp_metadata, $source, $sp_metadata,
175        $sp_entityid, $attributes, $userid, $hashAttributes, $excludeAttributes);
176
177    // Add a consent (or update if attributes have changed and old consent for SP and IdP exists)
178    if ($action == 'true') {
179        $isStored = $consent_storage->saveConsent($hashed_user_id, $targeted_id, $attribute_hash);
180        if ($isStored) {
181            $res = "added";
182        } else {
183            $res = "updated";
184        }
185        // Remove consent
186    } else {
187        if ($action == 'false') {
188            // Got consent, so this is a request to remove it
189            $rowcount = $consent_storage->deleteConsent($hashed_user_id, $targeted_id);
190            if ($rowcount > 0) {
191                $res = "removed";
192            }
193            // Unknown action (should not happen)
194        } else {
195            SimpleSAML\Logger::info('consentAdmin: unknown action');
196            $res = "unknown";
197        }
198    }
199    // init template to enable translation of status messages
200    $template = new SimpleSAML_XHTML_Template($config, 'consentAdmin:consentadminajax.php', 'consentAdmin:consentadmin');
201    $template->data['res'] = $res;
202    $template->show();
203    exit;
204}
205
206// Get all consents for user
207$user_consent_list = $consent_storage->getConsents($hashed_user_id);
208
209// Parse list of consents
210$user_consent = array();
211foreach ($user_consent_list as $c) {
212    $user_consent[$c[0]] = $c[1];
213}
214
215$template_sp_content = array();
216
217// Init template
218$template = new SimpleSAML_XHTML_Template($config, 'consentAdmin:consentadmin.php', 'consentAdmin:consentadmin');
219$translator = $template->getTranslator();
220$translator->includeLanguageFile('attributes'); // attribute listings translated by this dictionary
221$sp_empty_name = $translator->getTag('sp_empty_name');
222$sp_empty_description = $translator->getTag('sp_empty_description');
223
224// Process consents for all SP
225foreach ($all_sp_metadata as $sp_entityid => $sp_values) {
226    // Get metadata for SP
227    $sp_metadata = $metadata->getMetaData($sp_entityid, 'saml20-sp-remote');
228
229    // Run attribute filters
230    list($targeted_id, $attribute_hash, $attributes_new) = driveProcessingChain($idp_metadata, $source, $sp_metadata,
231        $sp_entityid, $attributes, $userid, $hashAttributes, $excludeAttributes);
232
233    // Check if consent exists
234    if (array_key_exists($targeted_id, $user_consent)) {
235        $sp_status = "changed";
236        SimpleSAML\Logger::info('consentAdmin: changed');
237        // Check if consent is valid. (Possible that attributes has changed)
238        if ($user_consent[$targeted_id] == $attribute_hash) {
239            SimpleSAML\Logger::info('consentAdmin: ok');
240            $sp_status = "ok";
241        }
242        // Consent does not exists
243    } else {
244        SimpleSAML\Logger::info('consentAdmin: none');
245        $sp_status = "none";
246    }
247
248    // Set name of SP
249    if (isset($sp_values['name']) && is_array($sp_values['name'])) {
250        $sp_name = $sp_metadata['name'];
251    } else {
252        if (isset($sp_values['name']) && is_string($sp_values['name'])) {
253            $sp_name = $sp_metadata['name'];
254        } elseif (isset($sp_values['OrganizationDisplayName']) && is_array($sp_values['OrganizationDisplayName'])) {
255            $sp_name = $sp_metadata['OrganizationDisplayName'];
256        } else {
257            $sp_name = $sp_empty_name;
258        }
259    }
260
261    // Set description of SP
262    if (empty($sp_metadata['description']) || !is_array($sp_metadata['description'])) {
263        $sp_description = $sp_empty_description;
264    } else {
265        $sp_description = $sp_metadata['description'];
266    }
267
268    // Add a URL to the service if present in metadata
269    $sp_service_url = isset($sp_metadata['ServiceURL']) ? $sp_metadata['ServiceURL'] : null;
270
271    // Fill out array for the template
272    $sp_list[$sp_entityid] = array(
273        'spentityid'       => $sp_entityid,
274        'name'             => $sp_name,
275        'description'      => $sp_description,
276        'consentStatus'    => $sp_status,
277        'consentValue'     => $sp_entityid,
278        'attributes_by_sp' => $attributes_new,
279        'serviceurl'       => $sp_service_url,
280    );
281}
282
283$template->data['header'] = 'Consent Administration';
284$template->data['spList'] = $sp_list;
285$template->data['showDescription'] = $cA_config->getValue('showDescription');
286$template->show();
287