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 <jftho...@ncsu.edu> Authored: Tue May 1 16:02:49 2018 -0400 Committer: Josh Thompson <jftho...@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