Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
saml_account_manager.inc
1 <?php
16 require_once SQ_PACKAGES_PATH.'/cms/page_templates/page_asset_builder/page_asset_builder.inc';
17 require_once SQ_INCLUDE_PATH.'/asset.inc';
18 require_once SQ_DATA_PATH.'/private/conf/tools.inc';
19 
32 {
33 
34 
35  var $saml_auth_manager;
36  var $idp_entityid;
37 
45  function __construct($assetid=0)
46  {
47  parent::__construct($assetid);
48  if($this->isSimplesamlphpInstalled()) {
49  require_once SQ_TOOL_SIMPLESAMLPHP_PATH.'/lib/_autoload.php';
50  require_once SQ_PACKAGES_PATH.'/saml/lib/saml_auth_manager.inc';
51  }
52 
53  }//end constructor
54 
55 
64  function __wakeup()
65  {
66  // don't cache any config
67  $this->saml_auth_manager = null;
68  $this->idp_entityid = null;
69 
70  }//end __wakeup()
71 
78  protected function _getAuthManager()
79  {
80  require_once SQ_PACKAGES_PATH.'/saml/lib/saml_auth_manager.inc';
81  if($this->saml_auth_manager) return $this->saml_auth_manager;
82  $this->saml_auth_manager = new SAML_Auth_Manager($this->attr('auth_source'));
83  return $this->saml_auth_manager;
84  }//end _getAuthManager()
85 
92  protected function _getEntityid()
93  {
94  if($this->idp_entityid) return $this->idp_entityid;
95  require SQ_TOOL_SIMPLESAMLPHP_PATH.'/config/authsources.php';
96  $authConfig = array_get_index($config, $this->attr('auth_source'));
97  $this->idp_entityid = array_get_index($authConfig, 'idp');
98  return $this->idp_entityid;
99  }//end _getEntityid()
100 
101 
108  protected function _getAuthenticatedSamlUserid()
109  {
110  $saml_auth_manager = $this->_getAuthManager();
111  $authData = $saml_auth_manager->getAuthDataArray();
112 
113  $location = $this->attr('saml_userid_location');
114  if($location == 'nameid') {
115  // use nameid as saml user id
116  $nameid_array = array_get_index($authData, 'saml:sp:NameID');
117  return (array_get_index($nameid_array, 'Value'));
118  }
119  else {
120  // use attribute value as saml user id
121  $attribute = $this->attr('saml_userid_attribute');
122  $attributes_array = array_get_index($authData, 'Attributes');
123  return (array_get_index(array_get_index($attributes_array, $attribute), 0));
124  }
125 
126  }// end _getAuthenticatedSamlUserid()
127 
128 
129 
136  public function isSimplesamlphpInstalled()
137  {
138  return (SQ_TOOL_SIMPLESAMLPHP_PATH && file_exists(SQ_TOOL_SIMPLESAMLPHP_PATH.'/lib/_autoload.php'));
139  }
140 
148  public function create(Array &$link)
149  {
150  return parent::create($link);
151 
152  }//end constructor
153 
164  function _createAdditional(&$link)
165  {
166 
167  if (!parent::_createAdditional($link)) return FALSE;
168 
169  // add bodycopies to this page when creating
170  $GLOBALS['SQ_SYSTEM']->am->includeAsset('saml2_acs');
171  $GLOBALS['SQ_SYSTEM']->am->includeAsset('saml2_sls');
172 
173  $sub_assets= Array(
174  'saml2_assertion_consumer_service' => 'saml2_acs',
175  'saml2_single_logout_service' => 'saml2_sls',
176  );
177 
178  foreach ($sub_assets as $name => $type) {
179  $asset = new $type();
180  $copy_link = Array('asset' => &$this, 'value' => $name ,'link_type' => SQ_LINK_TYPE_2, 'is_dependant' => 1, 'is_exclusive' => 1);
181 
182  $asset->setAttrValue('name', ucwords(str_replace('_',' ', $name)));
183  if (!$asset->create($copy_link)) return FALSE;
184  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($asset);
185  unset($asset);
186  }
187 
188  return TRUE;
189 
190  }//end _createAdditional()
191 
192 
193 
201  function _getAllowedLinks()
202  {
203  $page_links = parent::_getAllowedLinks();
204  $page_links[SQ_LINK_TYPE_2]['saml2_acs'] = Array('card' => 'M', 'exclusive' => TRUE);
205  $page_links[SQ_LINK_TYPE_2]['saml2_sls'] = Array('card' => 'M', 'exclusive' => TRUE);
206  return $page_links;
207 
208  }//end _getAllowedLinks()
209 
210 
217  function printFrontend()
218  {
219 
220  // require library installed
221  if(!$this->isSimplesamlphpInstalled()) {
222  trigger_error('Simplesamlphp library is not installed');
223  return FALSE;
224  }
225  require_once SQ_TOOL_SIMPLESAMLPHP_PATH.'/lib/_autoload.php';
226  require_once SQ_PACKAGES_PATH.'/saml/lib/saml_auth_manager.inc';
227 
228  $saml_auth_manager = $this->_getAuthManager();
229 
230  // set global redirect URL
231  if(!isset($_SESSION['sq_saml_account_manager_current_state_redirect_url'])) {
232  $redirect_url = $this->_getRedirectURL();
233  if(!empty($redirect_url))
234  $_SESSION['sq_saml_account_manager_current_state_redirect_url'] = $redirect_url;
235  }
236 
237 
238 
239  /*
240  * SAML special actions
241  */
242 
243  // print SP metadata file
244  if(isset($_GET['showMetadata'])) {
245  // get ACS URL
246  $acs_asset = $GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_TYPE_2, 'saml2_acs', TRUE, 'saml2_assertion_consumer_service', 'major', '1');
247  $acs_url = array_get_index( $GLOBALS['SQ_SYSTEM']->am->getAssetURL(Array($acs_asset['minorid'])), $acs_asset['minorid']);
248 
249  // get SLS URL
250  $sls_asset = $GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_TYPE_2, 'saml2_sls', TRUE, 'saml2_single_logout_service', 'major', '1');
251  $sls_url = array_get_index( $GLOBALS['SQ_SYSTEM']->am->getAssetURL(Array($sls_asset['minorid'])), $sls_asset['minorid']);
252 
253  $xml = $saml_auth_manager->printSPMetadataXML($acs_url, $sls_url);
254  header('Content-Type: application/samlmetadata+xml');
255  echo($xml);
256  exit();
257  }
258 
259  // link current matrix user to the authenticated SAML acount
260  if(isset($_GET['linkAccounts'])) {
261  $allow_create_link = $this->attr('allow_link');
262  // logged in saml user
263  if($allow_create_link && $saml_auth_manager->isAuthenticated()) {
264  $samlUserid = $this->_getAuthenticatedSamlUserid();
265  if($samlUserid) {
266  $current_user = $GLOBALS['SQ_SYSTEM']->user;
267  // logged in matrix user
268  if($current_user && !($current_user instanceof Public_User)) {
269  // link those 2 accounts
270  $this->_linkMatrixUserWithSAML($current_user->id, $samlUserid);
271 
272  // redirect after linking
273  if($this->attr('redirect_after_link')) {
274  if(isset($_SESSION['sq_saml_account_manager_current_state_redirect_url']) && $_SESSION['sq_saml_account_manager_current_state_redirect_url']) {
275  $redirect_url = $_SESSION['sq_saml_account_manager_current_state_redirect_url'];
276  unset($_SESSION['sq_saml_account_manager_current_state_redirect_url']);
277  do_redirect($redirect_url);
278  }
279  }
280  // stop further redirects
281  unset($_SESSION['sq_saml_account_manager_current_state_redirect_url']);
282  }
283  }
284  }
285  }
286 
287  /*
288  * probably we don't really need this function because allow user to unlink itself to be able to create new local users could be pointless and annoying
289  * it's rare to run into this situation and probaly best to inform sysadmin to unlink in backend.
290  *
291  // unlink current matrix user to the authenticated SAML account
292  if(isset($_GET['unlinkAccounts'])) {
293  // logged in saml user
294  if($saml_auth_manager->isAuthenticated()) {
295  $saml_userid = $this->_getAuthenticatedSamlUserid();
296  if($saml_userid) {
297  $linked_matrix_userid = $this->_searchLinkedMatrixUser($saml_userid);
298  $current_user = $GLOBALS['SQ_SYSTEM']->user;
299  // logged in matrix user is linked to the samlid
300  if($current_user && !($current_user instanceof Public_User) && ($current_user->id == $linked_matrix_userid)) {
301  // unlink those 2 accounts
302  $this->_unlinkMatrixUserWithSAML($linked_matrix_userid, $saml_userid);
303  // logout of Matrix and saml, and start a new session
304  $this->_logoutUser();
305  do_redirect($this->getURL());
306  return;
307  }
308  }
309  }
310  }
311  */
312 
313  // single logout user
314  if(isset($_GET['logout'])) {
315  // log out of matrix first
316  $this->_logoutUser(FALSE);
317 
318  // start single logout of saml
319  if($saml_auth_manager->isAuthenticated()) {
320  $options = Array();
321  $return_url = $this->_getRedirectURL();
322  if($return_url) {
323  $options['ReturnTo'] = $return_url;
324  }
325  $saml_auth_manager->logout($options);
326  }
327 
328  }
329 
330 
331  // move on....
332  parent::printFrontend();
333 
334  }//end printFrontend()
335 
336 
337 
344  function printBody()
345  {
346 
347  $saml_auth_manager = $this->_getAuthManager();
348 
349  if (isset($_POST['AB_'.$this->id.'_ASSET_BUILDER_ACTION'])) {
350  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
351  }
352 
353  $this->_current_state = '';
354  $current_user = $GLOBALS['SQ_SYSTEM']->user;
355  set_error_handler(Array(&$this, '_errorHandler'));
356  $success = $this->_processGlobalActions();
357  restore_error_handler();
358 
359  // create a friendly error message on error
360  if (isset($_POST['AB_'.$this->id.'_ASSET_BUILDER_ACTION']) && !$success) {
361  $this->_replacements[strtolower($_POST['AB_'.$this->id.'_ASSET_BUILDER_ACTION']).'_error'] = $this->attr(strtolower($_POST['AB_'.$this->id.'_ASSET_BUILDER_ACTION']).'_error');
362 
363  if (!empty($this->_errors)) {
364  $errors = '';
365  foreach ($this->_errors as $text) {
366  $errors .= '<li>'.$text.'</li>';
367  }
368  $this->_replacements[strtolower($_POST['AB_'.$this->id.'_ASSET_BUILDER_ACTION']).'_error'] .= '<ul>'.$errors.'</ul>';
369  }
370  }
371  if(isset($_SESSION['sq_saml_account_manager_auth_error'])) {
372  $this->_replacements['auth_error'] = $_SESSION['sq_saml_account_manager_auth_error'];
373  $this->_current_state = 'auth_fail';
374  unset($_SESSION['sq_saml_account_manager_auth_error']);
375  }
376 
377  // start performance mode timer
378  $GLOBALS['SQ_SYSTEM']->pm->startTimer($this, 'printBody');
379 
380  // if a new asset is created, it will be stored in the tmp vars for use by other asset types
381  // that extend this one, but we wont need it any more - so chuck it out, but first, load up
382  // some replacements for the newly created asset
383  if (isset($this->_tmp['created_asset'])) {
384  $this->_loadAssetReplacements();
385  unset($this->_tmp['created_asset']);
386  }
387 
388  // If we don't allow linking saml user to existing Matrix user
389  // and if user already logged in, just do nothing
390  $allow_create_link = $this->attr('allow_link');
391  if(empty($this->_current_state) && !$allow_create_link) {
392  if(!is_null($current_user) && !($current_user instanceof Public_User))
393  $this->_current_state = 'logged_in';
394  }
395 
396  if (empty($this->_current_state)) {
397  /*
398  * SAML authentication starts here
399  */
400 
401  if(!$saml_auth_manager->isAuthenticated()) {
402 
403  $options = Array();
404  // add saml extensions to request message
405  if($this->attr('use_extensions')) {
406  $extensions = $this->attr('extensions');
407  $ext = Array();
408  if(!empty($extensions)) {
409  $dom = new DOMDocument();
410  $dom->loadXML($extensions);
411  $extension_node = $dom->getElementsByTagName('Extensions')->item(0);
412  $child_nodes = $extension_node->childNodes;
413  foreach ($child_nodes as $node) {
414  $ext[] = new SAML2_XML_Chunk($node);
415  }
416  }
417  if(!empty($ext)) {
418  $options['saml:Extensions'] = $ext;
419  }
420  }
421 
422  // add ACS URL
423  $acs_asset = $GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_TYPE_2, 'saml2_acs', TRUE, 'saml2_assertion_consumer_service', 'major', '1');
424  $acs_url = array_get_index( $GLOBALS['SQ_SYSTEM']->am->getAssetURL(Array($acs_asset['minorid'])), $acs_asset['minorid']);
425  $options['acs_url'] = $acs_url;
426 
427  // add other options
428  $protocol_binding = $this->attr('protocol_binding');
429  $nameid_policy = $this->attr('nameid_policy');
430  $authn_context_class_ref = $this->attr('authn_context_class_ref');
431 
432  if(!empty($protocol_binding)) {
433  $options['ProtocolBinding'] = $protocol_binding;
434  }
435  if(!empty($nameid_policy)) {
436  $options['saml:NameIDPolicy'] = $nameid_policy;
437  }
438  if(!empty($authn_context_class_ref)) {
439  $options['saml:AuthnContextClassRef'] = $authn_context_class_ref;
440  }
441 
442  // remove all buffered content, so it won't interrupt the SAML redirect
443  while (ob_get_level() > SQ_INIT_OB_LEVEL) {
444  ob_end_clean();
445  }
446 
447  // login saml, start the dance
448  $saml_auth_manager->login($options);
449  exit();
450  }
451 
452 
453  // SAML user should have been already authenticated at this point
454 
455 
456  // try find linked Matrix user
457  $samlUserid = $this->_getAuthenticatedSamlUserid();
458  $matrixUserid = $this->_searchLinkedMatrixUser($samlUserid);
459 
460 
461  // Log in as the linked Matrix user
462  if ((is_null($current_user) || ($current_user instanceof Public_User)) && $matrixUserid) {
463  $this->_loginUser($matrixUserid);
464  $current_user = $GLOBALS['SQ_SYSTEM']->user;
465  }
466 
467 
468 
469  // can't find a linked matrix user for the authenticated saml user, create a new matrix user
470  if (is_null($current_user) || ($current_user instanceof Public_User)) {
471  $auto_create = $this->attr('auto_create');
472  // automatically create the user asset, skipping the create user form, randomly generates username and password
473  if($auto_create) {
474  $create_type = $this->attr('create_type');
475  $create_type = array_pop(array_keys($create_type));
476  $this->_createUser($create_type);
477  }
478  else {
479  $this->_current_state = 'create_user';
480  $this->_replacements['login_invite'] = $this->getKeywordReplacement('login_invite');
481  $this->_replacements['login_form'] = $this->getKeywordReplacement('login_form');
482  }
483 
484  } else {
485  // if logged in as both Matrix user and SAML user
486  if($GLOBALS['SQ_SYSTEM']->currentUserId() == $matrixUserid) {
487  // the saml user is correctly linked to current matrix user
488  $this->_current_state = 'logged_in';
489  }
490  else {
491  // the saml user is not linked to current logged in matrix user, create a link?
492  $this->_current_state = 'create_link';
493  }
494 
495 
496  }
497  }
498 
499 
500  // instead of displaying logged in body, do redirect
501  if( $this->_current_state == 'logged_in' && $this->attr('redirect_after_login') && isset($_SESSION['sq_saml_account_manager_current_state_redirect_url']) && $_SESSION['sq_saml_account_manager_current_state_redirect_url']) {
502  $redirect_url = $_SESSION['sq_saml_account_manager_current_state_redirect_url'];
503  unset($_SESSION['sq_saml_account_manager_current_state_redirect_url']);
504  do_redirect($redirect_url);
505  }
506 
507 
508  $fn = '_load'.$this->_default_state.'Replacements';
509  $this->_loadcreateReplacements();
510  $this->$fn();
511 
512 
513 
514  if($saml_auth_manager->isAuthenticated()) {
515  $auth_data = $saml_auth_manager->getAuthDataArray();
516  $attributes_array = array_get_index($auth_data, 'Attributes');
517 
518  // replace user attribute keyword
519  if(!empty($attributes_array)) {
520  // get the bodycopy attached to us
521  $bodycopy_data = $GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_TYPE_2, 'bodycopy', TRUE, $this->_current_state, 'major', '1');
522  if(!empty($bodycopy_data)) {
523  $bodycopy = $GLOBALS['SQ_SYSTEM']->am->getAsset($bodycopy_data['minorid'], $bodycopy_data['minor_type_code']);
524  $keywords = $bodycopy->getKeywords();
525  foreach($keywords as $word) {
526  $keyword = parse_keyword($word, $modifiers);
527  if($keyword === 'user_attributes_xml') {
528  // replace it with xml version of user's attributes, also enable modifier like xpath.
529  $xml = new SimpleXMLElement('<root/>');
530  arrayToXml($attributes_array, $xml);
531  $replacement = $xml->asXML();
532  apply_keyword_modifiers($replacement, $modifiers);
533  $this->_replacements[$word] = $replacement;
534 
535  }
536  }
537  }
538  }
539 
540  // replace saml id keyword
541  $this->_replacements['user_saml_id'] = $this->_getAuthenticatedSamlUserid();
542  }
543 
544 
545  $this->_printBody();
546 
547  // stop performance mode timer
548  $GLOBALS['SQ_SYSTEM']->pm->stopTimer($this, 'printBody');
549 
550  if (isset($_POST['AB_'.$this->id.'_ASSET_BUILDER_ACTION'])) {
551  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
552  }
553 
554  }//end printBody()
555 
556 
557 
558 
559 
571  {
572 
573  // set to live status once created
574  $this->vars['create_status']['value'] = SQ_STATUS_LIVE;
575 
576  $success = parent::_processGlobalActions();
577  if (!$success) return FALSE;
578 
579  /*
580  * Log in the just created local user
581  */
582  if($this->_current_state === 'created' && !empty($this->_tmp['created_asset'])) {
583  // link the created user with this saml account
584  $samlUserid = $this->_getAuthenticatedSamlUserid();
585  if(!empty($samlUserid))
586  $this->_linkMatrixUserWithSAML($this->_tmp['created_asset']->id, $samlUserid);
587 
588  $this->_loginUser($this->_tmp['created_asset']->id);
589 
590  $this->_current_state = 'logged_in';
591  }
592 
593 
594  return TRUE;
595 
596  }//end _processGlobalActions()
597 
598 
599 
600 
609  protected function _searchLinkedMatrixUser ($samlUserid)
610  {
611  if (empty($samlUserid))
612  return NULL;
613 
614  // DAL query
615  $bind_vars = Array(
616  'samlid' => $samlUserid,
617  'entityid' => $this->_getEntityid(),
618  );
619  $result = MatrixDAL::executeAll('saml_package', 'getUserid', $bind_vars);
620  if(empty($result)) return NULL;
621 
622  return ($result[0]['assetid']);
623  }//end _searchLinkedMatrixUser()
624 
625 
635  protected function _linkMatrixUserWithSAML ($matrixUserid, $samlUserid)
636  {
637  if (empty($matrixUserid) || empty($samlUserid) )
638  return NULL;
639 
640  // already linked?
641  $existingMatrixUserid = $this->_searchLinkedMatrixUser($samlUserid);
642  if($existingMatrixUserid) {
643  $bind_vars = Array(
644  'assetid' => $matrixUserid,
645  'samlid' => $samlUserid,
646  'entityid' => $this->_getEntityid(),
647  'updated' => ts_iso8601(time()),
648  );
649  $result = MatrixDAL::executeQuery('saml_package', 'updateUserid', $bind_vars);
650  return $result;
651  }
652 
653  // insert new entry
654  $linkid = MatrixDAL::executeOne('core', 'seqNextVal', Array('seqName' => 'sq_saml_lnk_seq'));
655  $bind_vars = Array(
656  'linkid' => $linkid,
657  'assetid' => $matrixUserid,
658  'samlid' => $samlUserid,
659  'entityid' => $this->_getEntityid(),
660  'created' => ts_iso8601(time()),
661  'updated' => ts_iso8601(time()),
662  );
663  $result = MatrixDAL::executeQuery('saml_package', 'addLink', $bind_vars);
664  return $result;
665  }//end _linkMatrixUserWithSAML()
666 
667 
677  protected function _unlinkMatrixUserWithSAML ($matrixUserid, $samlUserid)
678  {
679  if (empty($matrixUserid) || empty($samlUserid) )
680  return NULL;
681 
682  // delete entry
683  $bind_vars = Array(
684  'assetid' => $matrixUserid,
685  'samlid' => $samlUserid,
686  'entityid' => $this->_getEntityid(),
687  );
688  $result = MatrixDAL::executeQuery('saml_package', 'deleteLink', $bind_vars);
689  return $result;
690  }//end _linkMatrixUserWithSAML()
691 
692 
693 
694 
701  function &getRedirectAsset()
702  {
703  $res = NULL;
704  if ($this->useSystemVersion()) {
705  $notice_links = unserialize(file_to_string($this->data_path.'/.sq_notice_links'));
706  foreach ($notice_links as $link) {
707  if ($link['value'] == 'redirect_asset') {
708  $redirect_link = $link;
709  break;
710  }
711  }
712  } else {
713  if (!empty($this->id)) {
714  $link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_NOTICE, '', TRUE, 'redirect_asset');
715  }
716  }
717  if (!empty($link)) {
718  $res = $GLOBALS['SQ_SYSTEM']->am->getAsset($link['minorid'], $link['minor_type_code']);
719  }
720 
721  return $res;
722 
723  }//end getRedirectAsset()
724 
725 
734  function setRedirectAsset(&$asset)
735  {
736  $old_link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_NOTICE, '', TRUE, 'redirect_asset');
737  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
738  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
739  if (empty($old_link)) {
740  // if there is not existing asset, and we aren't setting on, we are done here
741  if (is_null($asset)) {
742  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
743  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
744  return TRUE;
745  }
746 
747  // else if there is a link, and we are about to set an asset, but it is the same as we already have
748  } else if (!is_null($asset) && $old_link['minorid'] == $asset->id) {
749  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
750  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
751  return TRUE;
752 
753  // else something different, delete the old link
754  } else {
755  if (!$this->deleteLink($old_link['linkid'])) {
756  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
757  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
758  return FALSE;
759  }
760  }
761 
762  if (!is_null($asset)) {
763  if (!$this->createLink($asset, SQ_LINK_NOTICE, 'redirect_asset')) {
764  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
765  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
766  return FALSE;
767  }
768  }
769 
770  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
771  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
772 
773  return TRUE;
774 
775  }//end setRedirectAsset()
776 
777 
778 
785  function _getRedirectURL()
786  {
787  // See if we are given a query string value to look at
788  $qrystr_param = $this->attr('use_querystring_parameter');
789  $url = trim($this->attr('redirect_url'));
790  if ($qrystr_param && isset($_GET[$qrystr_param]) && trim($_GET[$qrystr_param]) != '') {
791  $url = trim($_GET[$qrystr_param]);
792 
793  // See if there is a URL entered manually in the redirect_url attribute field
794  } else if ($url != '') {
795  // Replace global keywords
796  replace_global_keywords($url);
797 
798  // if there is no url, see if we have an asset selected
799  } else {
800  $redirect_asset = $this->getRedirectAsset();
801  if (!is_null($redirect_asset)) {
802  if (($url = $redirect_asset->getURL()) == '') {
803  $url = current_url().'?a='.$redirect_asset->id;
804  }
805  }
806  }//end if
807 
808  if ($url == '') {
809  return '';
810  }
811 
812 
813  // Strip newlines (and other dodgy characters) from the $url that may have
814  // been inadvertently added by keywords or modifiers. They're not allowed in
815  // the 'Location' header and will cause an error.
816  $stripchars = array();
817  for ($i = 0; $i < 32; $stripchars[] = chr($i), $i++);
818  $url = str_replace($stripchars, '', $url);
819 
820  return $url;
821 
822  }//end _getRedirectURL()
823 
824 
825 
826 
837  function onRequestKeywords(&$broadcaster, $vars=Array())
838  {
839 
840  if (!isset($vars['keywords'])) return;
841 
842  // get type-code
843  $parents = $GLOBALS['SQ_SYSTEM']->am->getParents($broadcaster->id, 'bodycopy', TRUE);
844  $type_links = $GLOBALS['SQ_SYSTEM']->am->getLinks($this->id, SQ_LINK_TYPE_2, 'bodycopy');
845  $bodycopy_type = '';
846  foreach ($type_links as $link_info) {
847  if (isset($parents[$link_info['minorid']])) {
848  $bodycopy_type = $link_info['value'];
849  }
850  }
851 
852  switch ($bodycopy_type) {
853  case 'create_user' :
854  $vars['keywords'] = array_merge($vars['keywords'], $this->_getNotLoggedInKeywords());
855  break;
856  case 'auth_fail' :
857  $vars['keywords'] = array_merge($vars['keywords'], Array('auth_error' => translate('saml_account_manager_auth_error')));
858  break;
859 
860  }
861 
862  $vars['keywords'] = array_merge($vars['keywords'], Array('user_attributes_xml' => translate('saml_account_manager_user_attributes_xml')));
863  $vars['keywords'] = array_merge($vars['keywords'], Array('user_saml_id' => translate('saml_account_manager_user_saml_id')));
864 
865  }//end onRequestKeywords()
866 
867 
868 
869 
870 
871 
878  function _getBodycopies()
879  {
880  $res = Array();
881  $res['create_user']= Array(
882  'name' => translate('saml_account_manager_create_user'),
883  'content' => '%create_error% %login_error% %login_invite% %login_form% %create_form%',
884  );
885  $res['create_link']= Array(
886  'name' => translate('saml_account_manager_create_link'),
887  'content' => 'SAML account is not linked to current Matrix user. <a href="?linkAccounts">Link them now</a>.',
888  );
889  $res['logged_in']= Array(
890  'name' => translate('logged_in'),
891  'content' => 'logged in as %globals_user_name%',
892  );
893  $res['auth_fail']= Array(
894  'name' => translate('saml_account_manager_auth_fail'),
895  'content' => '%auth_error%',
896  );
897  return $res;
898 
899  }//end _getBodycopies()
900 
909  protected function _loginUser($userid)
910  {
911  $user = $GLOBALS['SQ_SYSTEM']->am->getAsset($userid);
912  if($user && $user->canLogin()) {
913  unset($_SESSION['SQ_RETURN_TO_HTTP']);
914  $GLOBALS['SQ_SYSTEM']->loginUser($user);
915  // redirect after login
916  if($this->attr('redirect_after_login')) {
917  if(isset($_SESSION['sq_saml_account_manager_current_state_redirect_url']) && $_SESSION['sq_saml_account_manager_current_state_redirect_url']) {
918  $redirect_url = $_SESSION['sq_saml_account_manager_current_state_redirect_url'];
919  unset($_SESSION['sq_saml_account_manager_current_state_redirect_url']);
920  do_redirect($redirect_url);
921  }
922  }
923  // stop further redirects
924  unset($_SESSION['sq_saml_account_manager_current_state_redirect_url']);
925  }
926  }// end _loginUser
927 
928 
936  protected function _logoutUser($clear_saml_session = TRUE)
937  {
938  $for_real = ( $GLOBALS['SQ_SYSTEM']->user && !($GLOBALS['SQ_SYSTEM']->user instanceof Public_User));
939  $old_user = &$GLOBALS['SQ_SYSTEM']->user;
940  if ($for_real) {
941  $GLOBALS['SQ_SYSTEM']->broadcastTriggerEvent('trigger_event_before_user_logout', $old_user, NULL);
942  }
943  foreach (array_keys($_SESSION) as $key) {
944  if ($key == 'SQ_RETURN_TO_HTTP') continue;
945  // do not reset the unsuccessful attempt,
946  // do not reset current saml session
947  if ($key == 'user_login_attempts') continue;
948 
949  if( !$clear_saml_session && $key == 'SimpleSAMLphp_SESSION') continue;
950 
951  unset($_SESSION[$key]);
952  }
953  if ($for_real) {
954  $GLOBALS['SQ_SYSTEM']->broadcastTriggerEvent('trigger_event_user_logout', $old_user, NULL);
955  }
956  $GLOBALS['SQ_SYSTEM']->loginPublicUser();
957  $GLOBALS['SQ_SYSTEM']->generateLoginKey(TRUE);
958 
959  if($clear_saml_session) {
960  $this->saml_auth_manager = null;
961  }
962  }//end _logoutUser
963 
964 
973  protected function _createUser($create_type)
974  {
975  $_POST['AB_'.$this->id.'_ASSET_BUILDER_ACTION'] = 'create';
976  $_POST['AB_'.$this->id.'_ASSET_BUILDER_CREATE_TYPE'] = $create_type;
977 
978  $GLOBALS['SQ_SYSTEM']->am->includeAsset($create_type);
979  $new_user = new $create_type();
980  $prefix = $new_user->getPrefix();
981  $username_attr = $new_user->getAttribute('username', TRUE);
982  $password_attr = $new_user->getAttribute('password', TRUE);
983  $GLOBALS['SQ_SYSTEM']->am->includeAsset('user');
984  $user = new User();
985  // username unique value is stored as owning type user
986  $user_username_attr = $user->getAttribute('username', TRUE);
987  $_POST['asset_action'] = 'create';
988  $_REQUEST['asset_action'] = 'create';
989 
990  // generate username from samlid, and make up a random password
991  $samlid = $this->_getAuthenticatedSamlUserid();
992  $valid_username = $new_user->getValidUsername($user_username_attr->id, $samlid);
993  $valid_password = random_user_password(Array($valid_username));
994 
995  $_REQUEST[$prefix.'_'.$username_attr->id] = $valid_username;
996  $_REQUEST[$prefix.'_'.$password_attr->id.'_one'] = $valid_password;
997  $_REQUEST[$prefix.'_'.$password_attr->id.'_two'] = $valid_password;
998 
999  $this->_processGlobalActions();
1000 
1001  } // end _createUser
1002 
1003 
1004 
1005 }//end class
1006 ?>