Merge branch 'develop' into VCL-1087_VCL_CAS_SSO
diff --git a/web/.ht-inc/authentication.php b/web/.ht-inc/authentication.php
index cb72534..b2a3a80 100644
--- a/web/.ht-inc/authentication.php
+++ b/web/.ht-inc/authentication.php
@@ -212,6 +212,11 @@
 			printLoginPageWithSkin($authtype);
 			return;
 		}
+		elseif($authMechs[$authtype]['type'] == 'cas') {
+		    validateCASUser($authtype);
+		    dbDisconnect();
+		    return;
+		}
 	}
 	require_once("themes/$skin/page.php");
 	$HTMLheader = getHeader(0);
diff --git a/web/.ht-inc/authmethods/casauth.php b/web/.ht-inc/authmethods/casauth.php
new file mode 100644
index 0000000..31325ac
--- /dev/null
+++ b/web/.ht-inc/authmethods/casauth.php
@@ -0,0 +1,206 @@
+<?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());
+	if(array_key_exists('firstname', $userinfo))
+		$esc_firstname = mysql_real_escape_string($userinfo['firstname']);
+	if(array_key_exists('lastname', $userinfo))
+		$esc_lastname = mysql_real_escape_string($userinfo['lastname']);
+	if(array_key_exists('preferredname', $userinfo))
+		$esc_preferredname = mysql_real_escape_string($userinfo['preferredname']);
+	$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 .= ",'{$esc_firstname}'";
+	if(array_key_exists('lastname', $userinfo))
+		$query .= ",'{$esc_lastname}'";
+	if(array_key_exists('preferredname', $userinfo))
+		$query .= ",'{$esc_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']);
+	if(array_key_exists('firstname', $userinfo))
+		$esc_firstname = mysql_real_escape_string($userinfo['firstname']);
+	if(array_key_exists('lastname', $userinfo))
+		$esc_lastname = mysql_real_escape_string($userinfo['lastname']);
+	if(array_key_exists('preferredname', $userinfo))
+		$esc_preferredname = mysql_real_escape_string($userinfo['preferredname']);
+	$query = "UPDATE user SET unityid = '{$userinfo['unityid']}', lastupdated = '{$now}'";
+	if(array_key_exists('firstname', $userinfo))
+		$query .= ", firstname = '{$esc_firstname}' ";
+	if(array_key_exists('lastname', $userinfo))
+		$query .= ", lastname = '{$esc_lastname}' ";
+	if(array_key_exists('preferredname', $userinfo))
+		$query .= ", preferredname = '{$esc_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;
+}
+?>
diff --git a/web/.ht-inc/conf-default.php b/web/.ht-inc/conf-default.php
index 50f204b..6993ee2 100644
--- a/web/.ht-inc/conf-default.php
+++ b/web/.ht-inc/conf-default.php
@@ -165,6 +165,17 @@
 	                                                             #   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();
@@ -182,7 +193,7 @@
 		$updateUserFunc[$item['affiliationid']] = 'updateLDAPUser';
 		$updateUserFuncArgs[$item['affiliationid']] = $key;
 	}
-	elseif($item['type'] == 'local') {
+	elseif($item['type'] == 'local' || $item['type'] == 'cas') {
 		$affilValFunc[$item['affiliationid']] = create_function('', 'return 0;');
 		$addUserFunc[$item['affiliationid']] = create_function('', 'return NULL;');
 		$updateUserFunc[$item['affiliationid']] = create_function('', 'return NULL;');
@@ -194,4 +205,5 @@
 #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");
 ?>
diff --git a/web/.ht-inc/utils.php b/web/.ht-inc/utils.php
index 662ab77..a9928eb 100644
--- a/web/.ht-inc/utils.php
+++ b/web/.ht-inc/utils.php
@@ -363,13 +363,19 @@
 ////////////////////////////////////////////////////////////////////////////////
 function __autoload($class) {
 	global $actions;
-	$class = strtolower($class);
-	if(array_key_exists($class, $actions['classmapping'])) {
-		require_once(".ht-inc/{$actions['classmapping'][$class]}.php");
-		return;
+	$_class = strtolower($class);
+	if(array_key_exists($_class, $actions['classmapping'])) {
+		require_once(".ht-inc/{$actions['classmapping'][$_class]}.php");
 	}
-	require_once(".ht-inc/resource.php");
-	require_once(".ht-inc/$class.php");
+	elseif(file_exists(".ht-inc/{$_class}.php")) {
+		require_once(".ht-inc/{$_class}.php");
+		if(get_parent_class($class) == 'Resource')
+			require_once(".ht-inc/resource.php");
+	}
+}
+// register autoload function in case CAS or something else has used spl_autoload_register
+if(function_exists('spl_autoload_register')) {
+	spl_autoload_register('__autoload');
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -1508,7 +1514,7 @@
 	       .       "u.affiliationid = a.id ";
 	if(! $includedeleted)
 		$query .= "AND i.deleted = 0 ";
-   $query .= "ORDER BY i.prettyname";
+	$query .= "ORDER BY i.prettyname";
 	$qh = doQuery($query, 120);
 	while($row = mysqli_fetch_assoc($qh)) {
 		if(is_null($row['maxconcurrent']))
@@ -1534,8 +1540,8 @@
 				$imagelist[$includedeleted][$row["id"]]["subimages"] = array();
 				if($allmetadata[$metaid]["subimages"]) {
 					$query2 = "SELECT imageid "
-				        . "FROM subimages "
-				        . "WHERE imagemetaid = $metaid";
+					        . "FROM subimages "
+					        . "WHERE imagemetaid = $metaid";
 					$qh2 = doQuery($query2, 101);
 					while($row2 = mysqli_fetch_assoc($qh2))
 						$imagelist[$includedeleted][$row["id"]]["subimages"][] =  $row2["imageid"];
@@ -2993,11 +2999,10 @@
 ///
 ////////////////////////////////////////////////////////////////////////////////
 function getCryptKeyID() {
-	$reg = "|" . SCRIPT . "$|";
-	$filebase = preg_replace($reg, '', $_SERVER['SCRIPT_FILENAME']);
-	$filebase = preg_replace('|/shibauth|', '', $filebase);
-	$filebase .= "/.ht-inc/cryptkey";
-	$idfile = "$filebase/cryptkeyid";
+	$me = new ReflectionFunction('getCryptKeyID');
+	$myfile = $me->getFileName();
+	$path = dirname($myfile);
+	$idfile = "$path/cryptkey/cryptkeyid";
 
 	static $create = 1; # set flag so that recursion only goes one level deep
 
@@ -3991,12 +3996,12 @@
 	   ! is_array($_POST[$vartag]) &&
 	   strncmp("{$_POST[$vartag]}", "0", 1) == 0 &&
 	   $type == ARG_NUMERIC &&
-		strncmp("{$_POST[$vartag]}", "0x0", 3) != 0) ||
+	   strncmp("{$_POST[$vartag]}", "0x0", 3) != 0) ||
 	   (array_key_exists($vartag, $_GET) &&
 	   ! is_array($_GET[$vartag]) &&
 	   strncmp("{$_GET[$vartag]}", "0", 1) == 0 &&
 	   $type == ARG_NUMERIC &&
-		strncmp("{$_GET[$vartag]}", "0x0", 3) != 0)) {
+	   strncmp("{$_GET[$vartag]}", "0x0", 3) != 0)) {
 		$_POST[$vartag] = "zero";
 	}
 	if(!empty($_POST[$vartag])) {
@@ -4140,7 +4145,7 @@
 function processInputData($data, $type, $addslashes=0, $defaultvalue=NULL) {
 	if(strncmp("$data", "0", 1) == 0 &&
 	   $type == ARG_NUMERIC &&
-		strncmp("$data", "0x0", 3) != 0) {
+	   strncmp("$data", "0x0", 3) != 0) {
 		$data = "zero";
 	}
 	if(!empty($data))
@@ -6407,7 +6412,7 @@
 	$checkstart = unixToDatetime(time() + 180);
 	if($compid == 0) {
 		$resources = getUserResources(array("imageAdmin", "imageCheckOut"),
-			                           array("available"), 0, 0);
+		                              array("available"), 0, 0);
 		$computers = implode("','", array_keys($resources["computer"]));
 		$computers = "'$computers'";
 		$query = "SELECT DISTINCT COUNT(rs.id) AS reservations, "
@@ -7535,7 +7540,7 @@
 	}
 
 	# Get items from variable table for specific management node id
-	foreach ($return as $mn_id => $value ) {
+	foreach($return as $mn_id => $value) {
 		if(array_key_exists("hostname", $value)) {
 			$mn_hostname = $value['hostname'];
 			$timeservers = getVariable('timesource|'.$mn_hostname);
@@ -8074,9 +8079,9 @@
 			# or aren't mapped in resourcemap
 			if($computer_platformids[$id] != $platformid ||
 			   ($computerData[$id]["stateid"] != 2 &&
-				$computerData[$id]["stateid"] != 3 &&
-				$computerData[$id]["stateid"] != 6 &&
-				$computerData[$id]["stateid"] != 8) ||
+			   $computerData[$id]["stateid"] != 3 &&
+			   $computerData[$id]["stateid"] != 6 &&
+			   $computerData[$id]["stateid"] != 8) ||
 			   $computerData[$id]["ram"] < $imageData[$imageid]["minram"] ||
 			   $computerData[$id]["procnumber"] < $imageData[$imageid]["minprocnumber"] ||
 			   $computerData[$id]["procspeed"] < $imageData[$imageid]["minprocspeed"] ||
@@ -8189,7 +8194,7 @@
 				continue;
 			}
 			if($links && ($computer_platformids[$id] != $platformid ||
-				$computerData[$id]["stateid"] == 10 ||
+			   $computerData[$id]["stateid"] == 10 ||
 			   $computerData[$id]["stateid"] == 5)) {
 				continue;
 			}
@@ -8212,7 +8217,7 @@
 			elseif($timeslots[$id][$stamp]['blockAllocation'] &&
 			   ($timeslots[$id][$stamp]['blockInfo']['imageid'] != $imageid ||  # this line threw an error at one point, but we couldn't recreate it later
 			   (! in_array($timeslots[$id][$stamp]['blockInfo']['groupid'], array_keys($user['groups'])))) &&
-				$timeslots[$id][$stamp]['available']) {
+			   $timeslots[$id][$stamp]['available']) {
 				if($links) {
 					print "          <TD bgcolor=\"#ff0000\"><img src=images/red.jpg ";
 					print "alt=blockallocation border=0></TD>\n";
@@ -10846,7 +10851,7 @@
 	       .        "imagerevisionid, "
 	       .        "computerid, "
 	       .        "managementnodeid, "
-			 .        "predictivemoduleid, ";
+	       .        "predictivemoduleid, ";
 	if($fromblock) {
 		$query .=    "blockRequestid, "
 		       .     "blockStart, "
@@ -11387,7 +11392,7 @@
 	       .       "cm.affiliationid = a.id AND "
 	       .       "(cm.affiliationid = {$user['affiliationid']} OR "
 	       .        "a.name = 'Global') AND "
-			 .       "cm.configstageid = cs.id AND ";
+	       .       "cm.configstageid = cs.id AND ";
 	if($mode) {
 	$query .=      "cmt.name = 'config' AND "
 	       .       " cm.subid IN ($inlist)";
@@ -11591,7 +11596,7 @@
 	       .      "configmaptype cmt, "
 	       .      "configsubimage csi, "
 	       .      "image i, "
-	       .      "OS o,  "
+	       .      "OS o, "
 	       .      "OStype ot, "
 	       .      "affiliation a "
 	       . "WHERE ct.name = 'cluster' AND "
@@ -12613,7 +12618,7 @@
 ///
 /// \fn validateHostname($name)
 ///
-/// \param $name  the hostname to validate
+/// \param $name - the hostname to validate
 ///
 /// \return 1 if valid hostname else 0
 ///
@@ -13049,28 +13054,28 @@
 	if($a === true)
 		return 'true';
 	if(is_scalar($a)) {
-		if (is_float($a)) {
-			 // Always use "." for floats.
-			 return floatval(str_replace(",", ".", strval($a)));
+		if(is_float($a)) {
+			// 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', '\"'));
+		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) . '"';
 		}
 		else
 			return $a;
 	}
 	$isList = true;
-	for ($i = 0, reset($a); $i < count($a); $i++, next($a)) {
-		if (key($a) !== $i) {
+	for($i = 0, reset($a); $i < count($a); $i++, next($a)) {
+		if(key($a) !== $i) {
 			$isList = false;
 			break;
 		}
 	}
 	$result = array();
-	if ($isList) {
-		foreach ($a as $v) $result[] = json_encode($v);
+	if($isList) {
+		foreach($a as $v) $result[] = json_encode($v);
 		return '[' . join(',', $result) . ']';
 	}
 	else {
@@ -13181,8 +13186,8 @@
 			if(! array_key_exists('ownergroup', $data))
 				$data['ownergroup'] = processInputVar('ownergroup', ARG_NUMERIC, 0);
 			$ownergroupids = explode(',', $data['ownergroupids']);
-		   if(in_array($data['ownergroup'], $ownergroupids) &&
-		      array_key_exists($data['ownergroup'], $user['groups'])) {
+			if(in_array($data['ownergroup'], $ownergroupids) &&
+			   array_key_exists($data['ownergroup'], $user['groups'])) {
 				$expire = time() + 31536000; //expire in 1 year
 				setcookie("VCLOWNERGROUPID", $data['ownergroup'], $expire, "/", COOKIEDOMAIN);
 			}
@@ -13241,7 +13246,7 @@
 		$HTMLheader .= getHeader($refresh);
 
 	if(! in_array($mode, $noHTMLwrappers) &&
-		(! is_array($contdata) ||
+	   (! is_array($contdata) ||
 	    ! array_key_exists('noHTMLwrappers', $contdata) ||
 	    $contdata['noHTMLwrappers'] == 0)) {
 		print $HTMLheader;
@@ -13514,7 +13519,7 @@
 	global $NOAUTH_HOMENAV;
 	$rt = '';
 	foreach($NOAUTH_HOMENAV as $name => $url)
-		$rt .= "<li><a href=\"$url\">" .  i($name) . "</a></li>\n";
+		$rt .= "<li><a href=\"$url\">" . i($name) . "</a></li>\n";
 	return $rt;
 }
 
@@ -14343,9 +14348,9 @@
 	# use UTF8 encoding for any locales other than English (we may just be able
 	#   to always use UTF8)
 	if(preg_match('/^en/', $locale))
-		setlocale(LC_ALL,  $locale);
+		setlocale(LC_ALL, $locale);
 	else
-		setlocale(LC_ALL,  $locale . '.UTF8');
+		setlocale(LC_ALL, $locale . '.UTF8');
 	bindtextdomain('vcl', './locale');
 	textdomain('vcl');
 	bind_textdomain_codeset('vcl', 'UTF-8');
@@ -14375,7 +14380,7 @@
 	if(! is_array($user))
 		$user['id'] = 0;
 
-	$rt  = "<form name=\"localeform\" class=\"localeform\" action=\"" . BASEURL . SCRIPT . "\" method=post>\n";
+	$rt = "<form name=\"localeform\" class=\"localeform\" action=\"" . BASEURL . SCRIPT . "\" method=post>\n";
 	if($authed) {
 		$rt .= "<select name=\"continuation\" onChange=\"this.form.submit();\" autocomplete=\"off\">\n";
 		$cdata = array('IP' => $remoteIP, 'oldmode' => $mode);
@@ -14469,4 +14474,60 @@
 	$_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;
+}
 ?>
diff --git a/web/casauth/index.php b/web/casauth/index.php
new file mode 100644
index 0000000..df95bfd
--- /dev/null
+++ b/web/casauth/index.php
@@ -0,0 +1,137 @@
+<?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();
+
+?>