Initial checkin of plewww single sign on functionality
Tony Mack [Wed, 31 Oct 2012 00:41:21 +0000 (20:41 -0400)]
planetlab/common/login_sso.php [new file with mode: 0644]
planetlab/includes/plc_session_sso.php [new file with mode: 0644]

diff --git a/planetlab/common/login_sso.php b/planetlab/common/login_sso.php
new file mode 100644 (file)
index 0000000..3144e2c
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+//
+// Login form
+//
+//
+// $Id$ $
+//
+
+// Get session and API handles
+require_once 'plc_session.php';
+require_once 'plc_session_sso.php';
+global $plc, $api;
+
+// Print header
+require_once 'plc_drupal.php';
+drupal_set_title('Login');
+include 'plc_header.php';
+
+if (!empty($_REQUEST['email']) &&
+    !empty($_REQUEST['password'])) {
+  $plc_sso = new PLCSessionSSO($_REQUEST['email'], $_REQUEST['password']);
+  $plc = new PLCSession($_REQUEST['email'], $_REQUEST['password']);
+
+  if ($plc->person) {
+    // Login admins to Drupal as the superuser
+    if (in_array('admin', $plc->person['roles']) &&
+       function_exists('user_load')) {
+      global $user;
+      $user = user_load(array('uid' => 1));
+    }
+
+    if (empty($_REQUEST['url'])) {
+      // XXX Redirect to default home page
+      header("Location: /");
+      exit();
+    } else {
+      // Make sure that redirections are always local
+      $url = urldecode($_REQUEST['url']);
+      if ($url[0] != "/") {
+       $url = "/$url";
+      }
+      header("Location: $url");
+      exit();
+    }
+  } else {
+    // XXX Use our own stylesheet instead of drupal.css
+    print '<div class="messages error">Sorry. Unrecognized username or password.</div>';
+  }
+}
+
+$self = $_SERVER['PHP_SELF'];
+if (!empty($_SERVER['QUERY_STRING'])) {
+  $self .= "?" . $_SERVER['QUERY_STRING'];
+}
+
+$url = htmlspecialchars($_REQUEST['url']);
+
+// XXX Use our own stylesheet instead of drupal.css
+print <<<EOF
+<div class="content">
+<form action="$self" method="post">
+
+<table border="0" cellpadding="0" cellspacing="0">
+  <tr>
+    <td>
+      <div class="form-item">
+        <label for="edit-name">E-mail: <span class="form-required" title="This field is required.">*</span></label>
+       <input type="text" maxlength="60" name="email" id="edit-name" size="30" value="" class="form-text required" />
+      </div>
+      <div class="form-item">
+       <label for="edit-password">Password: <span class="form-required" title="This field is required.">*</span></label>
+       <input type="password" maxlength="" name="password" id="edit-password" size="30" class="form-text required" />
+      </div>
+      <input type="submit" name="op" value="Log in"  class="form-submit" />
+      <p><p><a href="/db/persons/reset_password.php">Forgot your password?</a></p>
+      <p><a href="/db/persons/register.php">Create an account</a></p>
+      <p><a href="/db/sites/register.php">File a site registration</a></p>
+      <input type="hidden" name="url" value="$url" />
+    </td>
+  </tr>
+</table>
+
+</form>
+</div>
+
+EOF;
+
+include 'plc_footer.php';
+
+?>
diff --git a/planetlab/includes/plc_session_sso.php b/planetlab/includes/plc_session_sso.php
new file mode 100644 (file)
index 0000000..54c18c8
--- /dev/null
@@ -0,0 +1,190 @@
+<?php
+//
+// PlanetLab Single Sign On session handling. Responsible for syncing Remote account details 
+// with local account. 
+//
+// person: If logged in, the user's GetPersons() details
+// api: If logged in, the user's API handle
+//
+//
+// $Id$ $
+//
+
+// Usually in /etc/planetlab/php
+require_once 'plc_config.php';
+
+// Usually in /usr/share/plc_api/php
+require_once 'plc_api.php';
+global $adm;
+
+require_once 'plc_functions.php';
+
+
+$cwd = getcwd();
+chdir($_SERVER['DOCUMENT_ROOT']);
+$included = include_once('./includes/bootstrap.inc');
+if ($included === TRUE) {
+  // Already included, no need to bootstrap
+} elseif ($included) {
+  // Not already included, initialize Drupal session handling
+  drupal_bootstrap(DRUPAL_BOOTSTRAP_SESSION);
+} else {
+  // Drupal not available, use regular PHP session handling
+  session_start();
+}
+chdir($cwd);
+
+class PLCSessionSSO
+{
+  var $api;
+  var $person;
+
+  function PLCSessionSSO($name = NULL, $pass = NULL)
+  {
+    $name= strtolower( $name );
+    // User PlanetLab API access
+    if ($name && $pass) {
+      $server = "planet-lab.org";
+      $path = "/PLCAPI/";
+      $port = 443;
+      $cainfo = NULL;  
+      $api = new PLCAPI(array('AuthMethod' => "password",
+                             'Username' => $name,
+                             'AuthString' => $pass),
+                  $server = $server, 
+                  $port = $port, 
+                  $path = $path, 
+                  $cainfo = $cainfo);
+      // Authenticate user and get session key
+      $session = $api->GetSession();
+      if (!$session) {
+          return NULL;
+      }
+      // Change GetSession() at some point to return expires as well
+      $api->auth = array('AuthMethod' => "session", 'session' => $session);
+      $this->api = $api;
+
+      // Get account details
+      list($person) = $api->GetPersons(array('email'=>$name,'peer_id'=>NULL));
+      $this->person = $person;
+
+      //         
+      // TODO
+      // Sync planetlab account. Ensure user record,  keys and slices             
+      // exists locally.
+      $local_person = $this->person;
+      $local_person['password'] = $pass;         
+      $this->SyncAccount($local_person);  
+      // Save session variables
+      $_SESSION['plc_sso'] = array('auth' => $api->auth,
+                                              'person' => $person,
+                                          'expires' => $expires);
+     } 
+    }
+
+    function SyncAccount($person) {   
+        # Sync the user record, slices and keys
+        
+        global $adm;
+        $api = $this->api;    
+        list($local_person) = $adm->GetPersons(array('email'=>$person['email'], 'peer_id'=>NULL));
+        if ($local_person) 
+        {
+            // Update existing account details
+            $adm->UpdatePerson($local_person['person_id'], $person);
+        }
+        else
+        {
+            // Add new account
+            $adm->AddPerson($person);
+            $adm->UpdatePerson($person['email'], array('enabled' => true));
+            $adm->AddRoleToPerson('user', $person['email']);       
+            $remote_sites = $api->GetSites($person['site_ids']);
+            foreach ($remote_sites as $remote_site) {
+                $adm->AddPersonToSite($person['email'], $remote_site['login_base']);
+            }
+        }
+
+        # Sync keys
+        # compare local user keys to user's keys at authortative host. Add any keys that
+        # don't exist locally
+        $remote_keys = $api->GetKeys(array('person_id'=>$person['person_id']));
+        $r_keys = array();
+        foreach ($remote_keys as $remote_key){
+            $r_keys[] = $remote_key['key'];
+        }
+        $local_keys = $adm->GetKeys(array('person_id'=>$local_person['person_id']));
+        $l_keys  = array();
+        foreach ($local_keys as $local_key) {
+            $l_keys[] = $local_key['key'];
+        } 
+        $added_keys = array_diff($r_keys, $l_keys);
+        foreach ($added_keys as $added_key) {
+            $adm->AddPersonKey($local_person['email'], array('key_type'=>'ssh',
+                                                             'key'=>$added_key));     
+        }
+        # Sync slices
+        # compare local slices to user's slices at authortative host. Add any slices that
+        # don't exist locally.
+        $slices = $api->GetSlices(array('slice_id'=>$person['slice_ids']));
+        $slice_names = array();
+        $slices_dict = array();
+        foreach ($slices as $slice){
+            $new_slice = array ('url' => $slice['url'],
+                                'description' => $slice['description'],
+                                'name' => $slice['name']); 
+            $slice_names[] = $new_slice['name'];
+            $slices_dict[$new_slice['name']] = $new_slice;
+        }
+        $local_slices = $adm->GetSlices(array('name'=>$slice_names));
+        $local_slice_names = array();
+        $local_slices_dict = array();
+        foreach ($local_slices as $local_slice) {
+            $local_slice_names[] = $local_slice['name']; 
+            $local_slices_dict[$local_slice['name']] = $local_slice;
+        }
+        $new_slice_names = array_diff($slice_names, $local_slice_names);
+        foreach($slices as $slice) {
+            if (in_array($slice['name'], $new_slice_names)) {
+                # add new slices and associate user
+                $adm->AddSlice($slices_dict[$slice['name']]);
+                $adm->AddPersonToSlice($person['email'], $slice['name']);
+            }
+            else {
+                # assoicate user with existing slice
+                $adm->AddPersonToSlice($person['email'], $slice['name']);
+            }
+        }  
+    }
+}    
+
+/*
+global $plc, $api;
+
+$plc = new PLCSession();
+
+if (!empty($_SESSION['plc'])) {
+  if ($_SESSION['plc']['expires'] > time()) {
+    $plc->person = $_SESSION['plc']['person'];
+    $plc->api = new PLCAPI($_SESSION['plc']['auth']);
+    if (array_key_exists('alt_person',$_SESSION['plc']))
+      $plc->alt_person = $_SESSION['plc']['alt_person'];
+    if (array_key_exists('alt_auth',$_SESSION['plc']))
+      $plc->alt_auth = $_SESSION['plc']['alt_auth'];
+  } else {
+    // Destroy PHP session
+    session_destroy();
+  }
+}
+
+// For convenience
+$api = $plc->api;
+
+if ($api && $api->AuthCheck() != 1) {
+  $current_pagename = basename($_SERVER['PHP_SELF']);
+  if ($current_pagename != basename(l_logout())) {
+    plc_redirect(l_logout());
+  }
+}
+*/
+?>