You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@vcl.apache.org by jf...@apache.org on 2018/05/07 18:45:59 UTC

[2/3] vcl git commit: VCL-1087 - VCL CAS SSO

VCL-1087 - VCL CAS SSO

initial commit of code to support CAS authentication contributed by [~junaid.ali]

authentication.php: modified selectAuth: added elseif to cover type 'cas'

conf-default.php: added CAS example section to $authMechs array

utils.php:
-modified getCryptKeyID: added $casauthreg and cooresponding preg_replace
because this function ends up getting called from casauth/index.php which
would have a different path than normal
-added curlDoSSLWebRequest needed by authmethods/casauth.php
-added vclAutoLoader and registered it with spl_autoload_register because
CAS.php ends up calling spl_autoload_register which prevends the existing
__autoload function from being used

added authmethods/casauth.php

added casauth/index.php


Project: http://git-wip-us.apache.org/repos/asf/vcl/repo
Commit: http://git-wip-us.apache.org/repos/asf/vcl/commit/075c2c44
Tree: http://git-wip-us.apache.org/repos/asf/vcl/tree/075c2c44
Diff: http://git-wip-us.apache.org/repos/asf/vcl/diff/075c2c44

Branch: refs/heads/VCL-1087_VCL_CAS_SSO
Commit: 075c2c4461a05849f4f525cd8ca39730ed33c200
Parents: 92391b8
Author: Josh Thompson <jf...@ncsu.edu>
Authored: Tue May 1 16:02:49 2018 -0400
Committer: Josh Thompson <jf...@ncsu.edu>
Committed: Tue May 1 16:02:49 2018 -0400

----------------------------------------------------------------------
 web/.ht-inc/authentication.php      |   5 +
 web/.ht-inc/authmethods/casauth.php | 194 +++++++++++++++++++++++
 web/.ht-inc/conf-default.php        |  13 ++
 web/.ht-inc/utils.php               | 258 ++++++++++++++++++++++---------
 web/casauth/index.php               | 133 ++++++++++++++++
 5 files changed, 530 insertions(+), 73 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/vcl/blob/075c2c44/web/.ht-inc/authentication.php
----------------------------------------------------------------------
diff --git a/web/.ht-inc/authentication.php b/web/.ht-inc/authentication.php
index 5c933aa..b28e175 100644
--- a/web/.ht-inc/authentication.php
+++ b/web/.ht-inc/authentication.php
@@ -149,6 +149,11 @@ function selectAuth() {
 			printLoginPageWithSkin($authtype);
 			return;
 		}
+		elseif($authMechs[$authtype]['type'] == 'cas') {
+		    validateCASUser($authtype);
+		    dbDisconnect();
+		    return;
+		}
 	}
 	require_once("themes/$skin/page.php");
 	$HTMLheader = getHeader(0);

http://git-wip-us.apache.org/repos/asf/vcl/blob/075c2c44/web/.ht-inc/authmethods/casauth.php
----------------------------------------------------------------------
diff --git a/web/.ht-inc/authmethods/casauth.php b/web/.ht-inc/authmethods/casauth.php
new file mode 100644
index 0000000..1acd599
--- /dev/null
+++ b/web/.ht-inc/authmethods/casauth.php
@@ -0,0 +1,194 @@
+<?php
+/*
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+/**
+ * \file
+ */
+
+require_once 'CAS.php';
+
+// Enable debugging
+phpCAS::setDebug();
+// Enable verbose error messages. Disable in production!
+phpCAS::setVerbose(FALSE);
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn validateCASUser($type, $loginid)
+///
+/// \param $type - an array from the $authMechs table
+///
+/// \return 1 user redirectied to CAS server, 0 if not, -1 on CAS error
+///
+/// \brief forces CAS authentication
+///
+////////////////////////////////////////////////////////////////////////////////
+function validateCASUser($type) {
+    global $authMechs;
+    $auth = $authMechs[$type];
+    $callbackURL = BASEURL . "/casauth/index.php?authtype=" . $type;
+    $casversion = ($auth['version'] == 2 ? CAS_VERSION_2_0 : CAS_VERSION_3_0);
+    
+    if ($auth['cacertpath'] != null)
+        if (file_exists($auth['cacertpath']))
+            phpCAS::setCasServerCACert($auth['cacertpath']);
+
+    phpCAS::client($casversion, $auth['host'], $auth['port'], $auth['context']);
+    
+    // Set the service URL to use custom casauth directly within the VCL website
+    phpCAS::setFixedServiceURL($callbackURL);
+    if ( $auth['validatecassslcerts'] != true )
+        phpCAS::setNoCasServerValidation();
+    
+    phpCAS::forceAuthentication();
+    
+    # TODO - Check if server is available. 
+}
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn checkCASUserInDatabase($userid)
+///
+/// \param $type - an array from the $authMechs table
+/// \param $userid - a userid without the affiliation part
+///
+/// \return true if the user exists in the database, else false
+///
+/// \brief looks up $userid in VCL database
+///
+////////////////////////////////////////////////////////////////////////////////
+function checkCASUserInDatabase($type, $userid) {
+    global $authMechs, $mysql_link_vcl;
+    $loweruserid = strtolower($userid);
+    $loweruserid = mysql_real_escape_string($loweruserid);
+    $query = "SELECT id "
+           . "FROM user "
+           . "WHERE unityid = '$userid' AND affiliationid = {$authMechs[$type]['affiliationid']}";
+    $qh = doQuery($query, 101);
+    if ($row = mysql_fetch_assoc($qh)) {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn addCASUser($authtype, $userid)
+///
+/// \param $userinfo - an array with user information
+///
+/// \return id from the user table or NULL on failure
+///
+/// \brief looks up $userid in CAS according to info in $authMechs array, adds
+/// the user to the user table, and returns the new id from the table
+///
+////////////////////////////////////////////////////////////////////////////////
+function addCASUser($userinfo) {
+    global $authMechs, $mysql_link_vcl;
+    $now = unixToDatetime(time());
+    
+    $query = "INSERT INTO user (unityid, affiliationid";
+    if(array_key_exists('firstname', $userinfo))
+        $query .= ", firstname";
+    if(array_key_exists('lastname', $userinfo))
+        $query .= ", lastname";
+    if(array_key_exists('preferredname', $userinfo))
+        $query .= ", preferredname";
+    if(array_key_exists('email', $userinfo))
+        $query .= ", email";
+    $query .= ", lastupdated) VALUES ( '{$userinfo['unityid']}', {$userinfo['affiliationid']}";
+    if(array_key_exists('firstname', $userinfo))
+        $query .= ",'{$userinfo['firstname']}'";
+    if(array_key_exists('lastname', $userinfo))
+        $query .= ",'{$userinfo['lastname']}'";
+    if(array_key_exists('preferredname', $userinfo))
+        $query .= ",'{$userinfo['preferredname']}'";
+    if(array_key_exists('email', $userinfo))
+        $query .= ",'{$userinfo['email']}'";
+        $query .= ",'{$now}')";
+    
+    doQuery($query, 101, 'vcl', 1);
+    if(mysql_affected_rows($mysql_link_vcl)) {
+        $qh = doQuery("SELECT LAST_INSERT_ID() FROM user", 101);
+        if(! $row = mysql_fetch_row($qh)) {
+            abort(101);
+        }
+        
+        // Add to default group
+        if ($userinfo['defaultgroup'] != null) {
+            $usergroups = array();
+            array_push($usergroups, getUserGroupID($userinfo['defaultgroup'], $userinfo['affiliationid']));
+            updateGroups($usergroups, $row[0]);
+        }
+            
+        return $row[0];
+    }
+    return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn updateCASUser($authtype, $userid)
+///
+/// \param $userinfo - an array with user information
+///
+/// \return FALSE if update failed, else TRUE
+///
+/// \brief pulls the user's information from CAS, updates it in the db, and
+/// returns an array of the information
+///
+////////////////////////////////////////////////////////////////////////////////
+function updateCASUser($userinfo) {
+    global $mysql_link_vcl;
+    $now = unixToDatetime(time());
+    $esc_userid = mysql_real_escape_string($userinfo['unityid']);
+    $query = "UPDATE user SET unityid = '{$userinfo['unityid']}', lastupdated = '{$now}'";
+    if(array_key_exists('firstname', $userinfo))
+        $query .= ", firstname = '{$userinfo['firstname']}' ";
+    if(array_key_exists('lastname', $userinfo))
+        $query .= ", lastname = '{$userinfo['lastname']}' ";
+    if(array_key_exists('preferredname', $userinfo))
+        $query .= ", preferredname = '{$userinfo['preferredname']}' ";
+    if(array_key_exists('email', $userinfo))
+        $query .= ", email = '{$userinfo['email']}' ";
+    $query .= "WHERE unityid = '{$esc_userid}' AND affiliationid = {$userinfo['affiliationid']}";
+    doQuery($query, 256, 'vcl', 1);
+    if (mysql_affected_rows($mysql_link_vcl) == -1) {
+        error_log(mysql_error($mysql_link_vcl));
+        error_log($query);
+        return FALSE;
+    }
+    
+    // get id of current user
+    $query = "SELECT id FROM user WHERE unityid = '{$esc_userid}' AND affiliationid = {$userinfo['affiliationid']}";
+    $qh = doQuery($query, 255);
+    if ($user = mysql_fetch_assoc($qh)) {
+        // Add to default group
+        if ($userinfo['defaultgroup'] != null) {
+            $usergroups = array();
+            $newgroupid = getUserGroupID($userinfo['defaultgroup'], $userinfo['affiliationid']);
+            array_push($usergroups, $newgroupid);
+            $usergroups = array_unique($usergroups);
+            if (! empty($usergroups))
+                updateGroups($usergroups, $user["id"]);
+        }
+    }
+        
+    return TRUE;    
+}
+?>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/vcl/blob/075c2c44/web/.ht-inc/conf-default.php
----------------------------------------------------------------------
diff --git a/web/.ht-inc/conf-default.php b/web/.ht-inc/conf-default.php
index 255991b..99e323e 100644
--- a/web/.ht-inc/conf-default.php
+++ b/web/.ht-inc/conf-default.php
@@ -158,6 +158,18 @@ $authMechs = array(
 	                                                             #   for the user.  Typically either 'cn', 'uid', or 'samaccountname'
 	                           "help" => "Use EXAMPLE1 LDAP if you are using an EXAMPLE1 account"), # message to be displayed on login page about when
 	                                                                                                #   to use this login mechanism*/
+    /*"CAS (Central Authentication Service)" => array("type" => "cas",
+     *                                                "affiliationid" => 3,                      # id from affiliation id this login method is associated with
+     *                                                "version" => 3,                            # this denotes the CAS protocol version used. currently supported values is 3. this value is maintained to track furture updates to the protocol
+     *                                                "host" => "cas.example.edu",               # the CAS server DNS name
+     *                                                "port" => "8443",                          # the CAS Server port
+     *                                                "context" => "/cas",                       # the CAS context
+     *                                                "validatecassslcerts" => true,             # validates the SSL certificates used by CAS server. strictly set to true for production (like) environments
+     *                                                "cacertpath" => "/etc/cas/cachain.pem",    # if using self signed certificates on the CAS server set this to the path where the CA chain is stored. Set to '' if using publicly trusted certificates
+     *                                                "attributemap" => array("sn" => "lastname", "givenName" => "firstname", "cn" => "preferredname", "mail" => "email"), # a list of CAS user attributes mapped to VCL user attributes
+     *                                                "defaultgroup" => "global",   # the default group name (excluding the affiliation name) that each CAS user should be added. make sure this group is pre-created
+     *                                                "help" => "Use CAS authentication to use your university CAS environment"),  # message to be displayed on login page about when to use this login mechanism
+     */
 );
 
 $affilValFunc = array();
@@ -187,4 +199,5 @@ $findAffilFuncs = array("testGeneralAffiliation");
 #require_once(".ht-inc/authmethods/itecsauth.php");
 #require_once(".ht-inc/authmethods/ldapauth.php");
 #require_once(".ht-inc/authmethods/shibauth.php");
+#require_once(".ht-inc/authmethods/casauth.php");
 ?>

http://git-wip-us.apache.org/repos/asf/vcl/blob/075c2c44/web/.ht-inc/utils.php
----------------------------------------------------------------------
diff --git a/web/.ht-inc/utils.php b/web/.ht-inc/utils.php
index feaabef..596c811 100644
--- a/web/.ht-inc/utils.php
+++ b/web/.ht-inc/utils.php
@@ -448,7 +448,7 @@ function checkAccess() {
 						exit;
 					}
 					$search = ldap_search($ds,
-					                      $auth['binddn'], 
+					                      $auth['binddn'],
 					                      "{$auth['lookupuserfield']}={$user['unityid']}",
 					                      array('dn'), 0, 3, 15);
 					if($search) {
@@ -498,7 +498,7 @@ function checkAccess() {
 			elseif($authMechs[$authtype]['type'] == 'redirect') {
 				$affilid = $authMechs[$authtype]['affiliationid'];
 				if(!(isset($apiValidateFunc) && is_array($apiValidateFunc) &&
-				   array_key_exists($affilid, $apiValidateFunc) && 
+				   array_key_exists($affilid, $apiValidateFunc) &&
 				   $apiValidateFunc[$affilid]($xmluser, $xmlpass))) {
 					printXMLRPCerror(3);    # access denied
 					dbDisconnect();
@@ -636,7 +636,7 @@ function checkCryptkey() {
 		$id = fread($fh, 50);
 		fclose($fh);
 		$_id = mysql_real_escape_string($id);
-	
+
 		$query = "SELECT id "
 		       . "FROM cryptkey  "
 		       . "WHERE id = '$_id'";
@@ -745,7 +745,7 @@ function maintenanceCheck() {
 		doQuery($query, 101, 'vcl', 1);
 		dbDisconnect();
 		return;
-	}  
+	}
 	$inmaintenance = 0;
 	$skin = '';
 	foreach($files as $file) {
@@ -1104,7 +1104,7 @@ function validateUserid($loginid) {
 	global $affilValFuncArgs, $affilValFunc;
 	if(empty($loginid))
 		return 0;
-	
+
 	$rc = getAffilidAndLogin($loginid, $affilid);
 	if($rc == -1)
 		return 0;
@@ -1122,15 +1122,15 @@ function validateUserid($loginid) {
 		return 1;
 
 	if($rc == 0 &&
-	   ALLOWADDSHIBUSERS == 1 && 
+	   ALLOWADDSHIBUSERS == 1 &&
 	   strpos($loginid, '@')) {
 		$query = "SELECT shibonly "
 		       . "FROM affiliation "
 		       . "WHERE id = " . DEFAULT_AFFILID;
-		$qh = doQuery($query); 
+		$qh = doQuery($query);
 		$row = mysql_fetch_assoc($qh);
 		if($row['shibonly'] == 1)
-			return 0;           
+			return 0;
 	}
 
 	$valfunc = $affilValFunc[$affilid];
@@ -1270,7 +1270,7 @@ function dbDisconnect() {
 function doQuery($query, $errcode=101, $db="vcl", $nolog=0) {
 	global $mysql_link_vcl, $mysql_link_acct, $user, $mode, $ENABLE_ITECSAUTH;
 	if($db == "vcl") {
-		if(QUERYLOGGING != 0 && (! $nolog) && 
+		if(QUERYLOGGING != 0 && (! $nolog) &&
 		   preg_match('/^(UPDATE|INSERT|DELETE)/', $query) &&
 		   strpos($query, 'UPDATE continuations SET expiretime = ') === FALSE) {
 			$logquery = str_replace("'", "\'", $query);
@@ -1373,7 +1373,7 @@ function getOSList() {
 ///                  checked out\n
 /// \b maxinitialtime - maximum time (in minutes) to be shown when requesting
 ///                     a reservation that the image can reserved for\n
-/// \b imagemetaid - NULL or corresponding id from imagemeta table and the 
+/// \b imagemetaid - NULL or corresponding id from imagemeta table and the
 /// following additional information:\n
 /// \b checkuser - whether or not vcld should check for a logged in user\n
 /// \b sysprep - whether or not to use sysprep on creation of the image\n
@@ -1990,7 +1990,7 @@ function getProductionRevisionid($imageid, $nostatic=0) {
 			return '';
 	$query = "SELECT id, "
 	       .        "imageid "
-	       . "FROM imagerevision  " 
+	       . "FROM imagerevision  "
 	       . "WHERE production = 1";
 	$qh = doQuery($query, 101);
 	while($row = mysql_fetch_assoc($qh))
@@ -2190,7 +2190,7 @@ function getUserResources($userprivs, $resourceprivs=array("available"),
 
 	$resources = array();
 	foreach(array_keys($resourcegroups) as $type) {
-		$resources[$type] = 
+		$resources[$type] =
 		   getResourcesFromGroups($resourcegroups[$type], $type, $includedeleted);
 	}
 	if(! $bygroup)
@@ -2220,7 +2220,7 @@ function getUserResources($userprivs, $resourceprivs=array("available"),
 /// \brief adds resource privileges to $nodeprivs for the parents of $nodeid
 ///
 ////////////////////////////////////////////////////////////////////////////////
-function getUserResourcesUp(&$nodeprivs, $nodeid, $userid, 
+function getUserResourcesUp(&$nodeprivs, $nodeid, $userid,
                             $resourceprivs, $privdataset) {
 	# build list of parent nodes
 	# starting at top, get images available at that node and user privs there and
@@ -2257,7 +2257,7 @@ function getUserResourcesUp(&$nodeprivs, $nodeid, $userid,
 /// of $nodeid
 ///
 ////////////////////////////////////////////////////////////////////////////////
-function getUserResourcesDown(&$nodeprivs, $nodeid, $userid, 
+function getUserResourcesDown(&$nodeprivs, $nodeid, $userid,
                               $resourceprivs, $privdataset) {
 	# FIXME can we check for cascading and if not there, don't descend?
 	$children = getChildNodes($nodeid);
@@ -2283,11 +2283,11 @@ function getUserResourcesDown(&$nodeprivs, $nodeid, $userid,
 ///
 /// \return modifies $nodeprivs, but doesn't return anything
 ///
-/// \brief for $id, gets privileges and cascaded privileges the user and any 
+/// \brief for $id, gets privileges and cascaded privileges the user and any
 /// groups the user is and adds them to $nodeprivs
 ///
 ////////////////////////////////////////////////////////////////////////////////
-function addNodeUserResourcePrivs(&$nodeprivs, $id, $lastid, $userid, 
+function addNodeUserResourcePrivs(&$nodeprivs, $id, $lastid, $userid,
                                   $resourceprivs, $privdataset) {
 	$nodeprivs[$id]["user"] = array("cascade" => 0);
 	foreach($resourceprivs as $priv) {
@@ -2358,9 +2358,9 @@ function addNodeUserResourcePrivs(&$nodeprivs, $id, $lastid, $userid,
 			if($noprivs)
 				$nodeprivs[$id][$groupid]["cascade"] = 0;
 		}
-		// if group not blocking at this node, and group had cascade at previous 
+		// if group not blocking at this node, and group had cascade at previous
 		# node
-		if($lastid && ! $nodeprivs[$id][$groupid]["block"] && 
+		if($lastid && ! $nodeprivs[$id][$groupid]["block"] &&
 		   isset($nodeprivs[$lastid][$groupid]) &&
 		   $nodeprivs[$lastid][$groupid]["cascade"]) {
 			# set cascade = 1
@@ -2725,7 +2725,7 @@ function encryptData($data, $cryptkey, $algo, $option, $keylength) {
 	$cryptdata = $iv . $cryptdata;
 	return trim(base64_encode($cryptdata));
 }
- 
+
 ////////////////////////////////////////////////////////////////////////////////
 ///
 /// \fn decryptData($data, $cryptkey, $algo, $option, $keylength)
@@ -2969,7 +2969,9 @@ function deleteSecretKeys($secretid) {
 ////////////////////////////////////////////////////////////////////////////////
 function getCryptKeyID() {
 	$reg = "|" . SCRIPT . "$|";
+	$casauthreg = "|/casauth$|";
 	$filebase = preg_replace($reg, '', $_SERVER['SCRIPT_FILENAME']);
+	$filebase = preg_replace($casauthreg, '', $filebase);
 	$filebase .= "/.ht-inc/cryptkey";
 	$idfile = "$filebase/cryptkeyid";
 
@@ -3392,7 +3394,7 @@ function getUserEditGroups($id) {
 		       . "FROM `usergroup` u, "
 		       .      "`usergroupmembers` m "
 		       . "WHERE u.editusergroupid = m.usergroupid AND "
-		       .       "(u.ownerid = $id OR m.userid = $id) AND " 
+		       .       "(u.ownerid = $id OR m.userid = $id) AND "
 		       .       "u.affiliationid = {$user['affiliationid']} "
 		       . "ORDER BY name";
 	}
@@ -3714,7 +3716,7 @@ function addUserGroupMember($loginid, $groupid) {
 		return;
 
 	$query = "INSERT INTO usergroupmembers "
-	       .        "(userid, " 
+	       .        "(userid, "
 	       .        "usergroupid) "
 	       . "VALUES "
 	       .        "($userid, "
@@ -3966,7 +3968,7 @@ function processInputVar($vartag, $type, $defaultvalue=NULL, $stripwhitespace=0)
 	   strncmp("{$_POST[$vartag]}", "0", 1) == 0 &&
 	   $type == ARG_NUMERIC &&
 		strncmp("{$_POST[$vartag]}", "0x0", 3) != 0) ||
-	   (array_key_exists($vartag, $_GET) && 
+	   (array_key_exists($vartag, $_GET) &&
 	   ! is_array($_GET[$vartag]) &&
 	   strncmp("{$_GET[$vartag]}", "0", 1) == 0 &&
 	   $type == ARG_NUMERIC &&
@@ -4556,7 +4558,7 @@ function updateUserPrefs($userid, $preferredname, $width, $height, $bpp, $audio,
 ///
 /// \param $userid - an id from the user table
 ///
-/// \return an array of privileges types that the user has somewhere in the 
+/// \return an array of privileges types that the user has somewhere in the
 /// privilege tree
 ///
 /// \brief get the privilege types that the user has somewhere in the
@@ -4761,7 +4763,7 @@ function isAvailable($images, $imageid, $imagerevisionid, $start, $end,
 
 	foreach($requestInfo["images"] as $key => $imageid) {
 		# check for max concurrent usage of image
-		if(! $skipconcurrentcheck && 
+		if(! $skipconcurrentcheck &&
 		   $images[$imageid]['maxconcurrent'] != NULL) {
 			if($userid == 0)
 				$usersgroups = $user['groups'];
@@ -5576,7 +5578,7 @@ function getPossibleRecentFailures($userid, $imageid) {
 ///
 /// \return an array of resource ids of type $resourcetype2
 ///
-/// \brief gets a list of resources of type $resourcetype2 that $resourcesubid 
+/// \brief gets a list of resources of type $resourcetype2 that $resourcesubid
 /// of type $resourcetype1 maps to based on the resourcemap table
 ///
 ////////////////////////////////////////////////////////////////////////////////
@@ -5894,7 +5896,7 @@ function addRequest($forimaging=0, $revisionid=array(), $checkuser=1) {
 	       .        "computerid, "
 	       .        "imageid, "
 	       .        "imagerevisionid, "
-	       .        "managementnodeid " 
+	       .        "managementnodeid "
 	       . "FROM semaphore "
 	       . "WHERE expires > NOW() AND "
 	       .       "procid = '$uniqid'";
@@ -6117,7 +6119,7 @@ function getRequestInfo($id, $returnNULL=0) {
 		if($returnNULL)
 			return NULL;
 		# FIXME handle XMLRPC cases
-		if(! $printedHTMLheader) 
+		if(! $printedHTMLheader)
 			print $HTMLheader;
 		print "<h1>" . i("OOPS! - Reservation Has Expired") . "</h1>\n";
 		$h = i("The selected reservation is no longer available. Go to <a>Reservations</a> to request a new reservation or select another one that is available.");
@@ -6204,7 +6206,7 @@ function getRequestInfo($id, $returnNULL=0) {
 /// \fn updateRequest($requestid, $nowfuture)
 ///
 /// \param $requestid - the id of the request to be updated
-/// \param $nowfuture (optional) - "now" or "future"; whether the 
+/// \param $nowfuture (optional) - "now" or "future"; whether the
 ///
 /// \brief updates an entry to the request and reservation tables
 ///
@@ -6256,7 +6258,7 @@ function updateRequest($requestid, $nowfuture="now") {
 		                    # could be updated, which would end up setting both
 		                    # rows to the same computer
 		doQuery($query, 147);
-		addChangeLogEntry($logid, NULL, $endstamp, $startstamp, $computerid, NULL, 
+		addChangeLogEntry($logid, NULL, $endstamp, $startstamp, $computerid, NULL,
 		                  1);
 		$query = "UPDATE sublog "
 		       . "SET computerid = $computerid "
@@ -6430,7 +6432,7 @@ function moveReservationsOffComputer($compid=0, $count=0) {
 	# a reservation is reassigned to meets the same restrictions
 	foreach($resInfo as $res) {
 		// pass forimaging = 1 so that isAvailable only looks at one computer
-		$rc = isAvailable($images, $res["imageid"], $res['imagerevisionid'], 
+		$rc = isAvailable($images, $res["imageid"], $res['imagerevisionid'],
 		      datetimeToUnix($res["start"]), datetimeToUnix($res["end"]), 0,
 		      0, $res["userid"], 0, 1);
 		if($rc < 1) {
@@ -6442,7 +6444,7 @@ function moveReservationsOffComputer($compid=0, $count=0) {
 		return 0;
 	foreach($resInfo as $res) {
 		$rc = isAvailable($images, $res["imageid"], $res['imagerevisionid'],
-		      datetimeToUnix($res["start"]), datetimeToUnix($res["end"]), 1, 
+		      datetimeToUnix($res["start"]), datetimeToUnix($res["end"]), 1,
 		      0, $res["userid"], 0, 1);
 		if($rc > 0) {
 			$newcompid = array_shift($requestInfo["computers"]);
@@ -6894,7 +6896,7 @@ function getUserRequests($type, $id=0) {
 			}
 			else {
 				$data[$count]['serverowner'] = 0;
-				if(! empty($row['serveradmingroupid']) && 
+				if(! empty($row['serveradmingroupid']) &&
 				   array_key_exists($row['serveradmingroupid'], $user['groups']))
 					$data[$count]['serveradmin'] = 1;
 				else
@@ -7182,7 +7184,7 @@ function getDepartmentName($id) {
 ///
 /// \fn getImageId($image)
 ///
-/// \param $image - name of an image (must match name (not prettyname) in the 
+/// \param $image - name of an image (must match name (not prettyname) in the
 /// image table)
 ///
 /// \return the id of matching $image in the image table or 0 if lookup fails
@@ -7519,7 +7521,7 @@ function getManagementNodes($alive="neither", $includedeleted=0, $id=0) {
 			$return[$mn_id]['timeservers'] = $timeservers;
 		}
 	}
-	
+
 	return $return;
 }
 
@@ -7660,7 +7662,7 @@ function getPredictiveModules() {
 /// \return array of free/used timeslotes
 ///
 /// \brief generates an array of availability for computers where index is a
-/// computerid with a value that is an array whose indexes are unix timestamps 
+/// computerid with a value that is an array whose indexes are unix timestamps
 /// that increment by 15 minutes with a value that is an array with 2 indexes:
 /// 'scheduleclosed' and 'available' that tell if the computer's schedule is
 /// closed at that moment and if the computer is available at that moment\n
@@ -7855,7 +7857,7 @@ function getTimeSlots($compids, $end=0, $start=0) {
 				continue;
 			}
 			//if between a start and end time
-			if($current >= $times[$id][$count]["start"] && 
+			if($current >= $times[$id][$count]["start"] &&
 			   $current <  $times[$id][$count]["end"]) {
 				if($first) {
 					# set the previous 15 minute block to show as busy to allow for load time
@@ -7874,7 +7876,7 @@ function getTimeSlots($compids, $end=0, $start=0) {
 				continue;
 			}
 			//if after previous end but before this start
-			if($current >= $times[$id][$count - 1]["end"] && 
+			if($current >= $times[$id][$count - 1]["end"] &&
 			   $current <  $times[$id][$count]["start"]) {
 				$reserveInfo[$id][$current]["available"] = 1;
 				continue;
@@ -8304,7 +8306,7 @@ function showTimeTable($links) {
 /// \param $ip - (optional, default='') desired IP address
 /// \param $mac - (optional, default='') desired MAC address
 ///
-/// \return an array where each key is a unix timestamp for the start time of 
+/// \return an array where each key is a unix timestamp for the start time of
 /// the available slot and each element is an array with these items:\n
 /// \b start - start of slot in datetime format\n
 /// \b startts - start of slot in unix timestamp format\n
@@ -8993,7 +8995,7 @@ function getUserComputerMetaData() {
 	if(isset($_SESSION['usersessiondata'][$key]))
 		return $_SESSION['usersessiondata'][$key];
 	$computers = getComputers();
-	$resources = getUserResources(array("computerAdmin"), 
+	$resources = getUserResources(array("computerAdmin"),
 	                              array("administer", "manageGroup"), 0, 1);
 	$return = array("platforms" => array(),
 	                "schedules" => array());
@@ -9026,7 +9028,7 @@ function getUserComputerMetaData() {
 /// they occur\n
 /// \b nextstates - array where each key is a computerloadstate id and its value
 /// is that state's following state; the last state has a NULL value\n
-/// \b totaltime - estimated time (in seconds) it takes for all states to 
+/// \b totaltime - estimated time (in seconds) it takes for all states to
 /// complete\n
 /// \b data - array where each key is is a computerloadstate id and each value
 /// is an array with these elements:\n
@@ -9440,8 +9442,8 @@ function getNAThosts($id=0, $sort=0) {
 function getNATports($resid) {
 	$ports = array();
 	$query = "SELECT n.publicport, "
-	       .        "n.connectmethodportid, " 
-	       .        "c.port AS privateport, " 
+	       .        "n.connectmethodportid, "
+	       .        "c.port AS privateport, "
 	       .        "c.protocol, "
 	       .        "c.connectmethodid "
 	       . "FROM natport n, "
@@ -9648,7 +9650,7 @@ function isImageBlockTimeActive($imageid) {
 /// \param $extra - (optional) any extra attributes that need to be set
 ///
 /// \brief prints out a select input part of a form\n
-/// it is assumed that if $selectedid is left off, we assume $dataArr has no 
+/// it is assumed that if $selectedid is left off, we assume $dataArr has no
 /// index '-1'\n
 /// each OPTION's value is the index of that element of the array
 ///
@@ -9707,7 +9709,7 @@ function selectInputAutoDijitHTML($name, $dataArr, $domid='', $extra='',
 /// multiple tag set
 ///
 /// \brief generates HTML for select input
-/// it is assumed that if $selectedid is left off, we assume $dataArr has no 
+/// it is assumed that if $selectedid is left off, we assume $dataArr has no
 /// index '-1'\n
 /// each OPTION's value is the index of that element of the array
 ///
@@ -9941,12 +9943,12 @@ function dijitButton($id, $label, $onclick='', $wraprightdiv=0) {
 ///
 /// \fn requestIsReady($request)
 ///
-/// \param $request - a request element from the array returned by 
+/// \param $request - a request element from the array returned by
 /// getUserRequests
 ///
 /// \return 1 if request is ready for a user to connect, 0 if not
 ///
-/// \brief checks to see if a request is 
+/// \brief checks to see if a request is
 ///
 ////////////////////////////////////////////////////////////////////////////////
 function requestIsReady($request) {
@@ -9954,7 +9956,7 @@ function requestIsReady($request) {
 		if($res["computerstateid"] != 3 && $res["computerstateid"] != 8)
 			return 0;
 	}
-	if(($request["currstateid"] == 14 &&      // request current state pending 
+	if(($request["currstateid"] == 14 &&      // request current state pending
 	   $request["laststateid"] == 3 &&        //   and last state reserved and
 	   $request["computerstateid"] == 3) ||   //   computer reserved
 	   ($request["currstateid"] == 8 &&       // request current state inuse
@@ -10171,7 +10173,7 @@ function addLoadTime($imageid, $start, $loadtime) {
 ///
 /// \return 1 if schedule is closed at $timestamp, 0 if it is open
 ///
-/// \brief checks to see if the computer's schedule is open or closed at 
+/// \brief checks to see if the computer's schedule is open or closed at
 /// $timestamp
 ///
 ////////////////////////////////////////////////////////////////////////////////
@@ -10303,7 +10305,7 @@ function getUserGroupID($name, $affilid=DEFAULT_AFFILID, $noadd=0) {
 /// \fn getUserGroupName($id, $incAffil)
 ///
 /// \param $id - id of a user group
-/// \param $incAffil - 0 or 1 (optional, defaults to 0); include @ and 
+/// \param $incAffil - 0 or 1 (optional, defaults to 0); include @ and
 /// affiliation at the end
 ///
 /// \return name for $id from usergroup table or 0 if name not found
@@ -10454,7 +10456,7 @@ function getMaintItemsForTimeTable($start, $end) {
 ///
 ////////////////////////////////////////////////////////////////////////////////
 function unset_by_val($needle, &$haystack) {
-	while(($gotcha = array_search($needle,$haystack)) > -1) { 
+	while(($gotcha = array_search($needle,$haystack)) > -1) {
 		unset($haystack[$gotcha]);
 	}
 }
@@ -10468,13 +10470,14 @@ function unset_by_val($needle, &$haystack) {
 ////////////////////////////////////////////////////////////////////////////////
 function sendRDPfile() {
 	global $user;
-	# for more info on this file, see 
+	# for more info on this file, see
 	# http://dev.remotenetworktechnology.com/ts/rdpfile.htm
 	$requestid = getContinuationVar("requestid");
 	$resid = getContinuationVar("resid");
+
 	$request = getRequestInfo("$requestid");
 	if($request['stateid'] == 11 || $request['stateid'] == 12 ||
-	   ($request['stateid'] == 14 && 
+	   ($request['stateid'] == 14 &&
 	   ($request['laststateid'] == 11 || $request['laststateid'] == 12))) {
 		$cont = addContinuationsEntry('viewRequests');
 		header("Location: " . BASEURL . SCRIPT . "?continuation=$cont");
@@ -10542,15 +10545,15 @@ function sendRDPfile() {
 	print "desktopwidth:i:$width\r\n";
 	print "desktopheight:i:$height\r\n";
 	print "session bpp:i:$bpp\r\n";
-	
+
 	print "winposstr:s:0,1,0,0,5000,4000\r\n";
-	# 0: 
+	# 0:
 	# 1:    use coordinates for the window position, as opposed to 3 - maximized
 	# 0:    left position in client coordinates
 	# 0:    top position in client coordinates
 	# 5000: width in pixels - set large to avoid scrollbars
 	# 4000: height in pixels - set large to avoid scrollbars
-	
+
 	print "full address:s:$ipaddress$port\r\n";
 	print "compression:i:1\r\n";
 	print "keyboardhook:i:2\r\n";
@@ -10634,16 +10637,16 @@ function addLogEntry($nowfuture, $start, $end, $wasavailable, $imageid) {
 /// available; \b NOTE: pass -1 instead of NULL if you don't want this field
 /// to be updated
 ///
-/// \brief adds an entry to the changelog table and updates information in 
+/// \brief adds an entry to the changelog table and updates information in
 /// the log table
 ///
 ////////////////////////////////////////////////////////////////////////////////
-function addChangeLogEntry($logid, $remoteIP, $end=NULL, $start=NULL, 
+function addChangeLogEntry($logid, $remoteIP, $end=NULL, $start=NULL,
                            $computerid=NULL, $ending=NULL, $wasavailable=-1) {
 	if($logid == 0) {
 		return;
 	}
-	$query = "SELECT computerid, " 
+	$query = "SELECT computerid, "
 	       .        "start, "
 	       .        "initialend, "
 	       .        "remoteIP, "
@@ -10934,8 +10937,8 @@ function getUserMaxTimes($uid=0) {
 ///
 /// \param $max - max allowed length in minutes
 ///
-/// \return array of lengths up to $max starting with 30 minutes, 1 hour, 
-/// 2 hours, then increasing by 2 hours up to 47 hours, then 2 days, then 
+/// \return array of lengths up to $max starting with 30 minutes, 1 hour,
+/// 2 hours, then increasing by 2 hours up to 47 hours, then 2 days, then
 /// increasing by 1 day; indexes are the duration in minutes
 ///
 /// \brief generates an array of reservation lengths
@@ -11240,7 +11243,7 @@ function getMappedConfigs($imageid) {
 	       .      "user u, "
 	       .      "affiliation ua, "
 	       .      "configtype ct, "
-	       .      "configmaptype cmt, " 
+	       .      "configmaptype cmt, "
 	       .      "affiliation a, "
 	       .      "configstage cs "
 	       . "WHERE cm.configid = c.id AND "
@@ -11345,7 +11348,7 @@ function getMappedSubConfigs($mode, $arg1, $arg2, $rec=0) {
 	       .      "user u, "
 	       .      "affiliation ua, "
 	       .      "configtype ct, "
-	       .      "configmaptype cmt, " 
+	       .      "configmaptype cmt, "
 	       .      "affiliation a, "
 	       .      "configstage cs "
 	       . "WHERE cm.configid = c.id AND "
@@ -11749,7 +11752,7 @@ function sortKeepIndex($a, $b) {
 ///
 /// \return -1, 0, 1 if numerical parts of $a <, =, or > $b
 ///
-/// \brief compares $a and $b to determine which one should be ordered first; 
+/// \brief compares $a and $b to determine which one should be ordered first;
 /// has some understand of numerical order in strings
 ///
 ////////////////////////////////////////////////////////////////////////////////
@@ -11809,8 +11812,8 @@ function compareDashedNumbers($a, $b) {
 /// \param $resource2inlist - (optional) comma delimited list of resource groups
 /// to limit query to
 ///
-/// \return an array of $resourcetype1 group to $resourcetype2 group mappings 
-/// where each index is a group id from $resourcetype1 and each value is an 
+/// \return an array of $resourcetype1 group to $resourcetype2 group mappings
+/// where each index is a group id from $resourcetype1 and each value is an
 /// array of $resourcetype2 group ids
 ///
 /// \brief builds an array of $resourcetype2 group ids for each $resourcetype1
@@ -12024,7 +12027,7 @@ function generateString($length=8) {
 /// \param $id (optional) - a profile id; if specified, only data about this
 /// profile will be returned
 ///
-/// \return an array of profiles where each key is the profile id and each 
+/// \return an array of profiles where each key is the profile id and each
 /// element is an array with these keys:\n
 /// \b profilename - name of profile\n
 /// \b name - name of profile (so array can be passed to printSelectInput)\n
@@ -12117,7 +12120,7 @@ function getENUMvalues($table, $field) {
 /// \fn addContinuationsEntry($nextmode, $data, $duration, $deleteFromSelf,
 ///                           $multicall, $repeatProtect)
 ///
-/// \param $nextmode - next mode to go in to 
+/// \param $nextmode - next mode to go in to
 /// \param $data (optional, default=array())- array of data to make available
 /// in $nextmode
 /// \param $duration (optional, default=SECINWEEK)- how long this continuation
@@ -12451,7 +12454,7 @@ function getVariable($key, $default=NULL, $incparams=0) {
 ///
 /// \return array of values from variable table
 ///
-/// \brief gets data from the variable table for $pattern matches 'name' from 
+/// \brief gets data from the variable table for $pattern matches 'name' from
 /// table
 ///
 ////////////////////////////////////////////////////////////////////////////////
@@ -12521,7 +12524,7 @@ function setVariable($key, $data, $serialization='') {
 	}
 	if($update)
 		$query = "UPDATE variable "
-		       . "SET value = '$qdata', " 
+		       . "SET value = '$qdata', "
 		       .     "serialization = '$serialization', "
 		       .     "setby = 'webcode', "
 		       .     "timestamp = NOW() "
@@ -12729,13 +12732,13 @@ function xmlRPChandler($function, $args, $blah) {
 		if(! defined('XMLRPCLOGGING') || XMLRPCLOGGING != 0) {
 			$saveargs = mysql_real_escape_string(serialize($args));
 			$query = "INSERT INTO xmlrpcLog "
-			       .        "(xmlrpcKeyid, " 
+			       .        "(xmlrpcKeyid, "
 			       .        "timestamp, "
 			       .        "IPaddress, "
 			       .        "method, "
 			       .        "apiversion, "
 			       .        "comments) "
-			       . "VALUES " 
+			       . "VALUES "
 			       .        "($keyid, "
 			       .        "NOW(), "
 			       .        "'$remoteIP', "
@@ -13022,7 +13025,7 @@ function json_encode($a=false) {
 			 // Always use "." for floats.
 			 return floatval(str_replace(",", ".", strval($a)));
 		}
- 
+
 		if (is_string($a)) {
 			 static $jsonReplaces = array(array("\\", "/", "\n", "\t", "\r", "\b", "\f", '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'));
 			return '"' . str_replace($jsonReplaces[0], $jsonReplaces[1], $a) . '"';
@@ -14363,7 +14366,7 @@ function setVCLLocale() {
 		setcookie("VCLLOCALE", $_COOKIE['VCLLOCALE'], (time() + (86400 * 31)), "/", COOKIEDOMAIN);
 		$locale = $_COOKIE['VCLLOCALE'];
 	}
-	
+
 	#putenv('LC_ALL=' . $locale);
 	# use UTF8 encoding for any locales other than English (we may just be able
 	#   to always use UTF8)
@@ -14494,4 +14497,113 @@ function getFSlocales() {
 	$_SESSION['locales'] = $locales;
 	return $locales;
 }
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn curlDoSSLWebRequest()
+/// \param $url - the URL to fetch
+/// \param $validatecert - boolean value indicating if server certificates
+///                        should be validated
+///
+/// \return response - string returned by web request
+///
+/// \brief performs an HTTPS web request for given URL
+///
+////////////////////////////////////////////////////////////////////////////////
+function curlDoSSLWebRequest($url, $validatecert = TRUE) {
+    if (! function_exists ( 'curl_init' ) ) {
+        $message = "php cURL library is not configured.";
+        if(ONLINEDEBUG && checkUserHasPerm('View Debug Information')) {
+            print "<font color=red>" . $message . "</font><br>\n";
+        }
+        error_log('php cURL library is not configured.');
+        return;
+    }
+    
+    $ch = curl_init();
+    
+    curl_setopt($ch, CURLOPT_HEADER, false);
+    curl_setopt($ch, CURLOPT_URL, $url) ;
+    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
+    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
+    
+    if ($validatecert == TRUE) {
+        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
+    }
+    curl_setopt( $ch, CURLOPT_VERBOSE, true );
+    
+    $response = curl_exec( $ch );
+    
+    if( curl_errno( $ch ) )	{
+        $info = curl_getinfo( $ch );
+        if(ONLINEDEBUG && checkUserHasPerm('View Debug Information')) {
+            print "<font color=red>" . curl_error( $ch ) . print_r( $info, TRUE ) . "</font><br>\n";
+        }
+        print "ERROR(curl_errno( $ch )): " . $ERRORS[$info] . "<BR>\n";
+        error_log("===========================================================================");
+        error_log("ERROR(curl_errno( $ch )): " . $ERRORS[$info]);
+        $backtrace = getBacktraceString(FALSE);
+        print "<pre>\n";
+        print $backtrace;
+        print "</pre>\n";
+        error_log($backtrace);
+    }
+    curl_close( $ch );
+    return $response;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn vclAutoLoader()
+///
+/// \brief autoload function for VCL classes
+///
+////////////////////////////////////////////////////////////////////////////////
+function vclAutoLoader($class) {
+    $siteconfigclasses = array(
+        'TimeVariable' => '',
+        'connectedUserCheck' => '',
+        'acknowledge' => '',
+        'initialconnecttimeout' => '',
+        'reconnecttimeout' => '',
+        'generalInuse' => '',
+        'serverInuse' => '',
+        'clusterInuse' => '',
+        'generalEndNotice1' => '',
+        'generalEndNotice2' => '',
+        'AffilTextVariable' => '',
+        'AffilHelpAddress' => '',
+        'AffilWebAddress' => '',
+        'AffilKMSserver' => '',
+        'AffilTheme' => '',
+        'AffilShibOnly' => '',
+        'AffilShibName' => '',
+        'GlobalSingleVariable' => '',
+        'userPasswordLength' => '',
+        'userPasswordSpecialChar' => '',
+        'NATportRange' => '',
+        'GlobalMultiVariable' => '',
+        'NFSmounts' => '',
+        'Affiliations' => '',
+        'Messages' => ''
+    );
+    if (file_exists('.ht-inc/'.strtolower($class).'.php')) {
+        require('.ht-inc/'.strtolower($class).'.php');
+    }
+    elseif (array_key_exists($class, $siteconfigclasses)) {
+        require('.ht-inc/siteconfig.php');
+    }
+    else {
+        throw new Exception("Unable to load $class.");
+    }
+}
+
+/**
+ * \autoload function
+ */
+if (function_exists('spl_autoload_register')) {
+    spl_autoload_register('vclAutoLoader');
+}
 ?>

http://git-wip-us.apache.org/repos/asf/vcl/blob/075c2c44/web/casauth/index.php
----------------------------------------------------------------------
diff --git a/web/casauth/index.php b/web/casauth/index.php
new file mode 100644
index 0000000..8bc50df
--- /dev/null
+++ b/web/casauth/index.php
@@ -0,0 +1,133 @@
+<?php
+
+chdir("..");
+require_once('.ht-inc/conf.php');
+require_once('.ht-inc/utils.php');
+require_once('.ht-inc/errors.php');
+
+global $authMechs;
+global $keys;
+
+function getFooter() {}
+$noHTMLwrappers = array();
+
+dbConnect();
+
+// Validate the Ticket
+if (array_key_exists('ticket', $_GET)) {
+    $serviceticket = $_GET['ticket'];
+    if (array_key_exists('authtype', $_GET)) {
+        $authtype = $_GET['authtype'];
+        $auth = $authMechs[$authtype];
+        $casversion = ($auth['version'] == 2 ? CAS_VERSION_2_0 : CAS_VERSION_3_0);
+        $cashost = $auth['host'];
+        $casport = $auth['port'];
+        $cascontext = $auth['context'];
+        $validatecassslcerts = $auth['validatecassslcerts'];
+        $attributemap = $auth['attributemap'];
+        
+        if ($auth['cacertpath'] != null)
+            if (file_exists($auth['cacertpath']))
+                phpCAS::setCasServerCACert($auth['cacertpath']);
+            
+        $serviceurl = BASEURL . '/casauth/index.php?authtype=' . $_GET['authtype'];
+        if ($casversion == CAS_VERSION_2_0)
+            $servicevalidateurl = 'https://' . $cashost . ':' . $casport . $cascontext . '/serviceValidate' . '?' . 'service=' . urlencode($serviceurl) . '&' . 'ticket=' . $serviceticket;
+        else 
+            $servicevalidateurl = 'https://' . $cashost . ':' . $casport . $cascontext . '/p3/serviceValidate' . '?' . 'service=' . urlencode($serviceurl) . '&' . 'ticket=' . $serviceticket;
+        
+        $response = curlDoSSLWebRequest($servicevalidateurl, $validatecassslcerts);
+
+        // check for authentication success
+        $xmldata = new DOMDocument();
+        $xmldata->loadXML($response);
+        $xpath = new DOMXPath($xmldata);
+        $authresults = $xpath->query('//cas:serviceResponse/cas:authenticationSuccess/cas:user');
+        $userid = '';
+        $userinfo = array();
+        $vcluser = array();
+        foreach ($authresults as $authresult) {
+            $userid = $authresult->nodeValue;
+            $vcluser['unityid'] = $userid;
+            $vcluser['affiliationid'] = $auth['affiliationid'];
+            if ($auth['defaultgroup'] != null)
+                $vcluser['defaultgroup'] = $auth['defaultgroup'];
+        }
+        
+        // extract user attributes provided by CAS
+        $attributeresults = $xpath->query('//cas:serviceResponse/cas:authenticationSuccess/cas:attributes');
+        if ($attributeresults->length > 0) {
+            $userattributeitems = $attributeresults->item(0);
+            foreach ($userattributeitems->childNodes as $userattributeitem) {
+                $attributename = preg_replace('#^cas:#', '', $userattributeitem->nodeName);
+                $userinfo[$attributename] = $userattributeitem->nodeValue;
+            }
+        }
+        // convert CAS attributes to VCL user attributes
+        foreach (array_keys($userinfo) as $attribute) {
+            if (array_key_exists($attribute, $attributemap)) {
+                $vcluser[$attributemap[$attribute]] = $userinfo[$attribute];
+            }
+        }        
+        
+        unset($xmldata);
+        unset($xpath);
+        
+        if ($userid != '') {
+            // read keys
+            $fp = fopen(".ht-inc/keys.pem", "r");
+            $key = fread($fp, 8192);
+            fclose($fp);
+            $keys["private"] = openssl_pkey_get_private($key, $pemkey);
+            if(! $keys['private'])
+                abort(6);
+            $fp = fopen(".ht-inc/pubkey.pem", "r");
+            $key = fread($fp, 8192);
+            fclose($fp);
+            $keys["public"] = openssl_pkey_get_public($key);
+            if(! $keys['public'])
+                abort(7);
+            
+            // valid user returned, login if user exists
+            if (checkCASUserInDatabase($authtype, $userid) == TRUE) {
+                updateCASUser($vcluser);
+                # get cookie data
+                $cookie = getAuthCookieData("$userid@" . getAffiliationName($auth['affiliationid']));
+                if ($cookie != "Failed to encrypt cookie data") {
+                    # set cookie
+                    if(version_compare(PHP_VERSION, "5.2", ">=") == true)
+                        setcookie("VCLAUTH", "{$cookie['data']}", 0, "/", COOKIEDOMAIN, 0, 1);
+                    else
+                        setcookie("VCLAUTH", "{$cookie['data']}", 0, "/", COOKIEDOMAIN);
+                    
+                    addLoginLog($userid, $authtype, $auth['affiliationid'], 1);
+                }
+            }
+            else {
+                // user does not exists in VCL database, so add user
+                if (addCASUser($vcluser) != NULL) {
+                    # get cookie data
+                    $cookie = getAuthCookieData("$userid@" . getAffiliationName($auth['affiliationid']));
+                    if ($cookie != "Failed to encrypt cookie data") {
+                        # set cookie
+                        if(version_compare(PHP_VERSION, "5.2", ">=") == true)
+                            setcookie("VCLAUTH", "{$cookie['data']}", 0, "/", COOKIEDOMAIN, 0, 1);
+                        else
+                            setcookie("VCLAUTH", "{$cookie['data']}", 0, "/", COOKIEDOMAIN);
+                        
+                        addLoginLog($userid, $authtype, $auth['affiliationid'], 1);
+                    }
+                }
+            }
+            // Set theme
+            $theme = getAffiliationTheme($auth['affiliationid']);
+            setcookie("VCLSKIN", $theme, (time() + 2678400), "/", COOKIEDOMAIN);
+        }
+    }            
+}
+
+// Redirect to homepage
+header("Location: " . BASEURL . "/");
+dbDisconnect();
+
+?>
\ No newline at end of file