Author: jfthomps Date: Fri Sep 30 16:56:45 2016 New Revision: 1762935 URL: http://svn.apache.org/viewvc?rev=1762935&view=rev Log: VCL-277 - Add support for images to join Active Directory domains VCL-867 - Active Directory Authentication for Windows VM's
incorporated patches from Junaid Ali attached to VCL-867; the VCL resource code has been largely rewritten since the patches were generated, so that part needed to be rewritten as well; shortened some of the names of fields and tables addomain.php: initial add; definition of ADdomain class which inherits from Resource class image.php: -modified fieldWidth: added os, addomain, baseOU, adauthenabled -modified fieldDisplayName: added adauthenabled, addomain, baseOU -modified addEditDialogHTML: added fieldset and fields for AD authentication; added tooltip for baseOU -modified AJsaveResource: added section that inserts/deletes/updates imageaddomain table as appropriate -modified addResource: added section to insert into imageaddomain table as appropriate -modified validateResourceData: added array keys and validation for adauthendabled, addomainid, baseou resource.php: -modified resource: added case statement for addomain -modified viewResources and fieldWidth: added conditional for Edge browser for setting widths (unrelated to these JIRAs) -added checkExistingField states.php: -added addomain to $actions["entry"] -added addomain to $actions['mode'], $actions['args'], and $actions['pages'] utils.php: -modified initGlobals: added case for addomain in section that require_once's resource.php -modified getImages: added addomainid, addomain, and baseOU to query and returned data; added adauthenabled to returned data -modified getResourceGroupMembers: added conditional for $type == addomain; added addomain to $names, $joins, and $orders -added getADdomains -modified labeledFormItem: added case for password to go along with text case; changed hard coded 'text' for input type to be $type so it matches the passed in type to be either text or password -added validateHostname -modified getNavMenuData: added AD Domains menu entry for users with addomainAdmin -modified getDojoHTML: added addomain case statement to include addomain.js to switch statement in groupMapHTML, viewResources, and editConfigMap case statements image.js: -modified Image.prototype.colformatter: added adauthenabled for true/false part; added addomain and baseOU to (unset) part -modified inlineEditResourceCB: added showing/hiding of imageadauthbox; added setting of adauthenable, addomainid, and baseou -modified resetEditResource: added resets for adauthenable, addomainid, and baseou -modified saveResource: added for validation of baseou; added adauthenabled, addomainid, and baseou to submitted data -modified saveResourceCB: added setting for adauthenabled, addomainid, addomain, and baseOU fields in store object -modified startImageCB: added resetting of adauthenable, addomainid, and baseou and showing/hiding of imageauthbox based on OS type -added toggleADauth vcl.css: -added: #addomaindlgcontent label #addomaindlgcontent .labeledform dropdownmenus/css/theme.css: -added: #renameDialog tbody tr:hover td #renameDialog tbody tr td div.dijitDialog h2 div.dijitDialog h3 #confdelcontent h3 #groupbyresourcediv table.dojoxGridRowTable tbody tr:hover td #groupbyresourcediv div.dojoxGridRowSelected table.dojoxGridRowTable tbody tr td #imageadauthbox label #imageadauthbox .labeledform Added: vcl/trunk/web/.ht-inc/addomain.php vcl/trunk/web/js/resources/addomain.js Modified: vcl/trunk/web/.ht-inc/image.php vcl/trunk/web/.ht-inc/resource.php vcl/trunk/web/.ht-inc/states.php vcl/trunk/web/.ht-inc/utils.php vcl/trunk/web/css/vcl.css vcl/trunk/web/js/resources/image.js vcl/trunk/web/themes/dropdownmenus/css/theme.css Added: vcl/trunk/web/.ht-inc/addomain.php URL: http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/addomain.php?rev=1762935&view=auto ============================================================================== --- vcl/trunk/web/.ht-inc/addomain.php (added) +++ vcl/trunk/web/.ht-inc/addomain.php Fri Sep 30 16:56:45 2016 @@ -0,0 +1,653 @@ +<?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. +*/ + +//////////////////////////////////////////////////////////////////////////////// +/// +/// \class ADdomain +/// +/// \brief extends Resource class to add things specific to resources of the +/// addomain type +/// +//////////////////////////////////////////////////////////////////////////////// +class ADdomain extends Resource { + ///////////////////////////////////////////////////////////////////////////// + /// + /// \fn __construct() + /// + /// \brief calls parent constructor; initializes things for Schedule class + /// + ///////////////////////////////////////////////////////////////////////////// + function __construct() { + parent::__construct(); + $this->restype = 'addomain'; + $this->restypename = 'AD Domain'; + $this->namefield = 'name'; + $this->basecdata['obj'] = $this; + $this->deletable = 1; + $this->deletetoggled = 0; + $this->defaultGetDataArgs = array('rscid' => 0); + } + + ///////////////////////////////////////////////////////////////////////////// + /// + /// \fn getData($args) + /// + /// \param $args - array of arguments that determine what data gets returned; + /// must include:\n + /// \b rscid - only return data for resource with this id; pass 0 for all + /// (from addomain table) + /// + /// \return array of data as returned from getADdomains + /// + /// \brief wrapper for calling getADdomains + /// + ///////////////////////////////////////////////////////////////////////////// + function getData($args) { + return getADdomains($args['rscid']); + } + + ///////////////////////////////////////////////////////////////////////////// + /// + /// \fn fieldWidth($field) + /// + /// \param $field - name of a resource field + /// + /// \return string for setting width of field (includes width= part) + /// + /// \brief generates the required width for the field; can return an empty + /// string if field should default to auto width + /// + ///////////////////////////////////////////////////////////////////////////// + function fieldWidth($field) { + switch($field) { + case 'name': + $w = 17; + break; + case 'owner': + $w = 11; + break; + case 'domaindnsname': + $w = 12; + break; + case 'domainnetbiosname': + $w = 12; + break; + case 'username': + $w = 9; + break; + case 'dnsservers': + $w = 12; + break; + case 'domaincontrollers': + $w = 17; + break; + case 'logindescription': + $w = 12; + break; + default: + return ''; + } + if(preg_match('/MSIE/i', $_SERVER['HTTP_USER_AGENT']) || + preg_match('/Trident/i', $_SERVER['HTTP_USER_AGENT']) || + preg_match('/Edge/i', $_SERVER['HTTP_USER_AGENT'])) + $w = round($w * 11.5) . 'px'; + else + $w = "{$w}em"; + return "width=\"$w\""; + } + + ///////////////////////////////////////////////////////////////////////////// + /// + /// \fn fieldDisplayName($field) + /// + /// \param $field - name of a resource field + /// + /// \return display value for $field + /// + /// \brief generates the display value for $field + /// + ///////////////////////////////////////////////////////////////////////////// + function fieldDisplayName($field) { + switch($field) { + case 'domaindnsname': + return 'Domain DNS Name'; + case 'domainnetbiosname': + return 'Domain NetBIOS Name'; + case 'dnsservers': + return 'DNS Server(s)'; + case 'domaincontrollers': + return 'Domain Controller(s)'; + case 'logindescription': + return 'Login Description'; + } + return ucfirst($field); + } + + ///////////////////////////////////////////////////////////////////////////// + /// + /// \fn AJsaveResource() + /// + /// \brief saves changes to a resource; must be implemented by inheriting + /// class + /// + ///////////////////////////////////////////////////////////////////////////// + function AJsaveResource() { + global $user; + $add = getContinuationVar('add', 0); + $data = $this->validateResourceData(); + if($data['error']) { + $ret = array('status' => 'error', 'msg' => $data['errormsg']); + sendJSON($ret); + return; + } + + if($add) { + $esc_name = mysql_real_escape_string($data['name']); + $query = "SELECT id FROM addomain WHERE name = '$esc_name'"; + $qh = doQuery($query); + if($row = mysql_fetch_assoc($qh)) { + sendJSON(array('status' => 'adderror', + 'errormsg' => wordwrap(i('An AD Domain with this name already exists.'), 75, '<br>'))); + return; + } + if(! $data['rscid'] = $this->addResource($data)) { + sendJSON(array('status' => 'adderror', + 'errormsg' => wordwrap(i('Error encountered while trying to create new AD domain. Please contact an admin for assistance.'), 75, '<br>'))); + return; + } + } + else { + $olddata = getContinuationVar('olddata'); + $updates = array(); + # name + if($data['name'] != $olddata['name']) + $updates[] = "name = '{$data['name']}'"; + # ownerid + $ownerid = getUserlistID($data['owner']); + if($ownerid != $olddata['ownerid']) + $updates[] = "ownerid = $ownerid"; + # domaindnsname + if($data['domaindnsname'] != $olddata['domaindnsname']) + $updates[] = "domainDNSName = '{$data['domaindnsname']}'"; + # domainnetbiosname + if($data['domainnetbiosname'] != $olddata['domainnetbiosname']) + $updates[] = "domainNetBIOSName = '{$data['domainnetbiosname']}'"; + # username + if($data['username'] != $olddata['username']) + $updates[] = "username = '{$data['username']}'"; + # password + if(strlen($data['password'])) { + $esc_pass = mysql_real_escape_string($data['password']); + $updates[] = "password = '$esc_pass'"; + } + # dnsservers + if($data['dnsservers'] != $olddata['dnsservers']) + $updates[] = "dnsServers = '{$data['dnsservers']}'"; + # domaincontrollers + if($data['domaincontrollers'] != $olddata['domaincontrollers']) + $updates[] = "domainControllers = '{$data['domaincontrollers']}'"; + # logindescription + if($data['logindescription'] != $olddata['logindescription']) { + $esc_desc = mysql_real_escape_string($data['logindescription']); + $updates[] = "logindescription = '$esc_desc'"; + } + if(count($updates)) { + $query = "UPDATE addomain SET " + . implode(', ', $updates) + . " WHERE id = {$data['rscid']}"; + doQuery($query); + } + } + + # clear user resource cache for this type + $key = getKey(array(array($this->restype . "Admin"), array("administer"), 0, 1, 0, 0)); + unset($_SESSION['userresources'][$key]); + $key = getKey(array(array($this->restype . "Admin"), array("administer"), 0, 0, 0, 0)); + unset($_SESSION['userresources'][$key]); + $key = getKey(array(array($this->restype . "Admin"), array("manageGroup"), 0, 1, 0, 0)); + unset($_SESSION['userresources'][$key]); + $key = getKey(array(array($this->restype . "Admin"), array("manageGroup"), 0, 0, 0, 0)); + unset($_SESSION['userresources'][$key]); + + $tmp = $this->getData(array('rscid' => $data['rscid'])); + $data = $tmp[$data['rscid']]; + $arr = array('status' => 'success'); + $arr['data'] = $data; + if($add) { + $arr['action'] = 'add'; + $arr['nogroups'] = 0; + $groups = getUserResources(array($this->restype . 'Admin'), array('manageGroup'), 1); + if(count($groups[$this->restype])) + $arr['groupingHTML'] = $this->groupByResourceHTML(); + else + $arr['nogroups'] = 1; + } + else + $arr['action'] = 'edit'; + sendJSON($arr); + } + + ///////////////////////////////////////////////////////////////////////////// + /// + /// \fn AJeditResource() + /// + /// \brief sends data for editing a resource + /// + ///////////////////////////////////////////////////////////////////////////// + function AJeditResource() { + $rscid = processInputVar('rscid', ARG_NUMERIC); + $resources = getUserResources(array($this->restype . 'Admin'), array('administer'), 0, 1); + if(! array_key_exists($rscid, $resources[$this->restype])) { + $ret = array('status' => 'noaccess'); + sendJSON($ret); + return; + } + $args = $this->defaultGetDataArgs; + $args['rscid'] = $rscid; + $tmp = $this->getData($args); + $data = $tmp[$rscid]; + $login = preg_replace("/<br>/", "\n", $data['logindescription']); + $data['logindescription'] = htmlspecialchars_decode($login); + $cdata = $this->basecdata; + $cdata['rscid'] = $rscid; + $cdata['olddata'] = $data; + + # save continuation + $cont = addContinuationsEntry('AJsaveResource', $cdata); + + $ret = $this->jsondata; + $ret['title'] = "Edit {$this->restypename}"; + $ret['cont'] = $cont; + $ret['resid'] = $rscid; + $ret['data'] = $data; + $ret['status'] = 'success'; + sendJSON($ret); + } + + ///////////////////////////////////////////////////////////////////////////// + /// + /// \fn addResource($data) + /// + /// \param $data - array of needed data for adding a new resource + /// + /// \return id of new resource + /// + /// \brief handles all parts of adding a new resource to the database; should + /// be implemented by inheriting class, but not required since it is only + /// called by functions in the inheriting class (nothing in this base class + /// calls it directly) + /// + ///////////////////////////////////////////////////////////////////////////// + function addResource($data) { + global $user; + + $ownerid = getUserlistID($data['owner']); + $esc_pass = mysql_real_escape_string($data['password']); + $esc_desc = mysql_real_escape_string($data['logindescription']); + + $query = "INSERT INTO addomain" + . "(name," + . "ownerid," + . "domainDNSName," + . "domainNetBIOSName," + . "username," + . "password," + . "dnsServers," + . "domainControllers," + . "logindescription)" + . "VALUES ('{$data['name']}'," + . "$ownerid," + . "'{$data['domaindnsname']}'," + . "'{$data['domainnetbiosname']}'," + . "'{$data['username']}'," + . "'$esc_pass'," + . "'{$data['dnsservers']}'," + . "'{$data['domaincontrollers']}'," + . "'$esc_desc')"; + doQuery($query); + + $rscid = dbLastInsertID(); + if($rscid == 0) { + return 0; + } + // add entry in resource table + $query = "INSERT INTO resource " + . "(resourcetypeid, " + . "subid) " + . "VALUES (19, " + . "$rscid)"; + doQuery($query); + return $rscid; + } + + ///////////////////////////////////////////////////////////////////////////// + /// + /// \fn addEditDialogHTML($add) + /// + /// \param $add - unused for this class + /// + /// \brief handles generating HTML for dialog used to edit resource + /// + ///////////////////////////////////////////////////////////////////////////// + function addEditDialogHTML($add=0) { + global $user, $days; + # dialog for on page editing + $h = ''; + $h .= "<div dojoType=dijit.Dialog\n"; + $h .= " id=\"addeditdlg\"\n"; + $h .= " title=\"Edit {$this->restypename}\"\n"; + $h .= " duration=250\n"; + #$h .= " style=\"width: 70%;\"\n"; + $h .= " draggable=true>\n"; + $h .= "<div id=\"addeditdlgcontent\">\n"; + $h .= "<div id=\"addomaindlgcontent\">\n"; + # id + $h .= "<input type=\"hidden\" id=\"editresid\">\n"; + + # todo consider adding help icons with popups + + $h .= "<div style=\"text-align: center;\">\n"; + # name + $errmsg = i("Name cannot contain single (') or double (") quotes, less than (<), or greater than (>) and can be from 2 to 30 characters long"); + $h .= labeledFormItem('name', i('Name'), 'text', '^([A-Za-z0-9-!@#$%^&\*\(\)_=\+\[\]{}\\\|:;,\./\?~` ]){2,30}$', + 1, '', $errmsg, '', '', '200px'); + # owner + $extra = array('onKeyPress' => 'setOwnerChecking'); + $h .= labeledFormItem('owner', i('Owner'), 'text', '', 1, + "{$user['unityid']}@{$user['affiliation']}", i('Unknown user'), + 'checkOwner', $extra, '200px'); + $cont = addContinuationsEntry('AJvalidateUserid'); + $h .= "<input type=\"hidden\" id=\"valuseridcont\" value=\"$cont\">\n"; + # domain dns name + $hostbase = '([A-Za-z0-9]{1,63})(\.[A-Za-z0-9-_]+)*(\.?[A-Za-z0-9])'; + $errmsg = i("Domain DNS Name should be in the format domain.tld and can only contain letters, numbers, dashes(-), periods(.), and underscores(_) (e.g. myuniversity.edu)"); + $h .= labeledFormItem('domaindnsname', i('Domain DNS Name'), 'text', "^$hostbase$", + 1, '', $errmsg, '', '', '200px'); + # domain netbios name + $errmsg = i("Domain NetBIOS Name can only contain letters, numbers, dashes(-), periods(.), and underscores(_) and can be up to 15 characters long"); + $h .= labeledFormItem('domainnetbiosname', i('Domain NetBIOS Name'), 'text', '^[a-zA-Z0-9_][-a-zA-Z0-9_\.]{0,14}$', + 1, '', $errmsg, '', '', '200px'); + $h .= "<br>\n"; + # username + $errmsg = i("Username cannot contain single (') or double (") quotes, less than (<), or greater than (>) and can be from 2 to 64 characters long"); + $h .= labeledFormItem('username', i('Username'), 'text', '^([A-Za-z0-9-!@#$%^&\*\(\)_=\+\[\]{}\\\|:;,\./\?~` ]){2,30}$', + 1, '', $errmsg, '', '', '200px'); + # password + # todo make required for adding + $errmsg = i("Password must be at least 4 characters long"); + $h .= labeledFormItem('password', i('Password'), 'password', '^.{4,256}$', 0, '', $errmsg, '', '', '200px'); + # confirm password + $h .= labeledFormItem('password2', i('Confirm Password'), 'password', '', 0, '', '', '', '', '200px'); + $h .= "<br>\n"; + # dns server list + $ipreg = '(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'; + $reg = "^($ipreg,)*($ipreg)$"; + $errmsg = i("Invalid IP address specified - must be a valid IPV4 address"); + $h .= labeledFormItem('dnsservers', i('DNS Server(s)'), 'text', $reg, 0, '', $errmsg, + '', '', '300px'); + # domain controllers list + $reg = "$hostbase(,$hostbase){0,4}"; + $errmsg = i("Invalid Domain Controller specified. Must be comma delimited list of hostnames or IP addresses, with up to 5 allowed"); + $h .= labeledFormItem('domaincontrollers', i('Domain Controller(s)'), 'text', $reg, 0, '', $errmsg, + '', '', '300px'); + # login description + $h .= labeledFormItem('logindescription', i('Login Description'), 'textarea', '', + 1, '', '', '', '', '300px'); + + $h .= "</div>\n"; # center + $h .= "</div>\n"; # addomaindlgcontent + $h .= "</div>\n"; # addeditdlgcontent + + $h .= "<div id=\"addeditdlgerrmsg\" class=\"nperrormsg\"></div>\n"; + $h .= "<div id=\"editdlgbtns\" align=\"center\">\n"; + $h .= dijitButton('addeditbtn', "Confirm", "saveResource();"); + $h .= dijitButton('', "Cancel", "dijit.byId('addeditdlg').hide();"); + $h .= "</div>\n"; # editdlgbtns + $h .= "</div>\n"; # addeditdlg + + $h .= "<div dojoType=dijit.Dialog\n"; + $h .= " id=\"groupingnote\"\n"; + $h .= " title=\"AD Domain Grouping\"\n"; + $h .= " duration=250\n"; + $h .= " draggable=true>\n"; + $msg = i("Each AD Domain should be a member of an AD Domain resource group. The following dialog will allow you to add the new AD Domain to a group."); + $h .= wordwrap($msg, 75, '<br>'); + $h .= "<br><br>\n"; + $h .= "<div align=\"center\">\n"; + $h .= dijitButton('', "Close", "dijit.byId('groupingnote').hide();"); + $h .= "</div>\n"; # btn div + $h .= "</div>\n"; # groupingnote + + $h .= "<div dojoType=dijit.Dialog\n"; + $h .= " id=\"groupdlg\"\n"; + $h .= " title=\"AD Domain Grouping\"\n"; + $h .= " duration=250\n"; + $h .= " draggable=true>\n"; + $h .= "<div id=\"groupdlgcontent\"></div>\n"; + $h .= "<div align=\"center\">\n"; + $script = " dijit.byId('groupdlg').hide();\n"; + $script .= " checkFirstAdd();\n"; + $h .= dijitButton('', "Close", $script); + $h .= "</div>\n"; # btn div + $h .= "</div>\n"; # groupdlg + + return $h; + } + + ///////////////////////////////////////////////////////////////////////////// + /// + /// \fn validateResourceData() + /// + /// \return array with these fields:\n + /// \b rscid - id of resource (from addomain table)\n + /// \b name\n + /// \b owner\n + /// \b times - array of arrays, each having 2 keys: start and end, each in + /// unix timestamp format\n + /// \b error - 0 if submitted data validates; 1 if anything is invalid\n + /// \b errormsg - if error = 1; string of error messages separated by html + /// break tags + /// + /// \brief validates form input from editing or adding an AD domain + /// + ///////////////////////////////////////////////////////////////////////////// + function validateResourceData() { + global $user; + + $return = array('error' => 0); + $errormsg = array(); + + $return['rscid'] = getContinuationVar('rscid', 0); + $return["name"] = processInputVar("name", ARG_STRING); + $return["owner"] = processInputVar("owner", ARG_STRING, "{$user["unityid"]}@{$user['affiliation']}"); + $return["domaindnsname"] = processInputVar("domaindnsname", ARG_STRING); + $return["domainnetbiosname"] = processInputVar("domainnetbiosname", ARG_STRING); + $return["username"] = processInputVar("username", ARG_STRING); + $return["password"] = processInputVar("password", ARG_STRING); + $return["password2"] = processInputVar("password2", ARG_STRING); + $return["dnsservers"] = processInputVar("dnsservers", ARG_STRING); + $return["domaincontrollers"] = processInputVar("domaincontrollers", ARG_STRING); + $return["logindescription"] = processInputVar("logindescription", ARG_STRING); + + $return['logindescription'] = preg_replace("/[\n\s]*$/", '', $return['logindescription']); + $return['logindescription'] = preg_replace("/\r/", '', $return['logindescription']); + $return['logindescription'] = htmlspecialchars($return['logindescription']); + $return['logindescription'] = preg_replace("/\n/", '<br>', $return['logindescription']); + + if(! preg_match("/^([A-Za-z0-9-!@#$%^&\*\(\)_=\+\[\]{}\\\|:;,\.\/\?~` ]){2,30}$/", $return['name'])) { + $return['error'] = 1; + $errormsg[] = i("Name cannot contain single (') or double (") quotes, less than (<), or greater than (>) and can be from 2 to 30 characters long"); + } + elseif($this->checkExistingField('name', $return['name'], $return['rscid'])) { + $return['error'] = 1; + $errormsg[] = i("An AD domain already exists with this name."); + } + if(! validateUserid($return['owner'])) { + $return['error'] = 1; + $errormsg[] = i("Submitted owner is not valid"); + } + + if(! preg_match('/^([A-Za-z0-9]{1,63})(\.[A-Za-z0-9-_]+)*(\.?[A-Za-z0-9])$/', $return['domaindnsname'])) { + $return['error'] = 1; + $errormsg[] = i("Domain DNS Name should be in the format domain.tld and can only contain letters, numbers, dashes(-), periods(.), and underscores(_) (e.g. myuniversity.edu)"); + } + if(! preg_match('/^[a-zA-Z0-9_][-a-zA-Z0-9_\.]{0,14}$/', $return['domainnetbiosname'])) { + $return['error'] = 1; + $errormsg[] = i("Domain NetBIOS Name can only contain letters, numbers, dashes(-), periods(.), and underscores(_) and can be up to 15 characters long"); + } + + if(! preg_match('/^([A-Za-z0-9-!@#$%^&\*\(\)_=\+\[\]{}\\\|:;,\.\/\?~` ]){2,30}$/', $return['username'])) { + $return['error'] = 1; + $errormsg[] = i("Username cannot contain single (') or double (") quotes, less than (<), or greater than (>) and can be from 2 to 64 characters long"); + } + + if((! empty($return['password']) || + ! empty($return['password2'])) && + ! preg_match('/^.{4,256}$/', $return['password'])) { + $return['error'] = 1; + $errormsg[] = i("Password must be at least 4 characters long"); + } + elseif($return['password'] != $return['password2']) { + $return['error'] = 1; + $errormsg[] = i("Passwords do not match"); + } + + $ips = explode(',', $return['dnsservers']); + foreach($ips as $ip) { + if(! validateIPv4addr($ip)) { + $return['error'] = 1; + $errormsg[] = i("Invalid IP address specified for DNS Server - must be a valid IPV4 address"); + break; + } + } + + $dcs = explode(',', $return['domaincontrollers']); + if(count($dcs) > 5) { + $return['error'] = 1; + $errormsg[] = i("Too many Domain Controllers specified, up to 5 are allowed"); + } + else { + foreach($dcs as $dc) { + if(! validateHostname($dc) && ! validateIPv4addr($dc)) { + $return['error'] = 1; + $errormsg[] = i("Invalid Domain Controller specified. Must be comman delimited list of hostnames or IP addresses, with up to 5 allowed"); + } + } + } + + /*if(! preg_match('/^$/', $return['logindescription'])) { + $return['error'] = 1; + $errormsg[] = i(""); + }*/ + + if($return['error']) + $return['errormsg'] = implode('<br>', $errormsg); + + return $return; + } + + ///////////////////////////////////////////////////////////////////////////// + /// + /// \fn checkResourceInUse($rscid) + /// + /// \param $rscid - id of AD domain + /// + /// \return empty string if not being used; string of where resource is + /// being used if being used + /// + /// \brief checks to see if AD domain is being used + /// + ///////////////////////////////////////////////////////////////////////////// + function checkResourceInUse($rscid) { + $msg = ''; + + $query = "SELECT i.prettyname " + . "FROM imageaddomain ia, " + . "image i " + . "WHERE ia.addomainid = $rscid AND " + . "ia.imageid = i.id"; + $qh = doQuery($query); + $images = array(); + while($row = mysql_fetch_assoc($qh)) + $images[] = $row['prettyname']; + if(count($images)) + $msg = "This AD Domain cannot be deleted because the following <strong>images</strong> are using it:<br><br>\n" . implode("<br>\n", $images); + + return $msg; + } + + ///////////////////////////////////////////////////////////////////////////// + /// + /// \fn checkResourceInUse($rscid) + /// + /// \param $rscid - id of resource + /// + /// \return empty string if not being used; string of where resource is + /// being used if being used + /// + /// \brief checks to see if resource is being used + /// + ///////////////////////////////////////////////////////////////////////////// + function checkResourceInUse($rscid) { + $msgs = array(); + + /* + # check reservations + $query = "SELECT rq.end " + . "FROM request rq, " + . "reservation rs " + . "WHERE rs.requestid = rq.id AND " + . "rs.imageid = $rscid AND " + . "rq.stateid NOT IN (1, 12) AND " + . "rq.end > NOW() " + . "ORDER BY rq.end DESC " + . "LIMIT 1"; + $qh = doQuery($query); + if($row = mysql_fetch_assoc($qh)) + $msgs[] = sprintf(i("There is at least one <strong>reservation</strong> for this image. The latest end time is %s."), prettyDatetime($row['end'], 1));; + + # check blockComputers + $query = "SELECT br.name, " + . "bt.end " + . "FROM blockRequest br, " + . "blockTimes bt, " + . "blockComputers bc " + . "WHERE bc.imageid = $rscid AND " + . "bc.blockTimeid = bt.id AND " + . "bt.blockRequestid = br.id AND " + . "bt.end > NOW() AND " + . "bt.skip = 0 AND " + . "br.status = 'accepted' " + . "ORDER BY bt.end DESC " + . "LIMIT 1"; + $qh = doQuery($query); + if($row = mysql_fetch_assoc($qh)) + $msgs[] = sprintf(i("There is at least one <strong>Block Allocation</strong> with computers currently allocated with this image. Block Allocation %s has the latest end time which is %s."), $row['name'], prettyDatetime($row['end'], 1)); + + if(empty($msgs)) + return ''; + + $msg = i("The selected AD Domain is currently being used in the following ways and cannot be deleted at this time.") . "<br><br>\n"; + $msg .= implode("<br><br>\n", $msgs) . "<br><br>\n"; + return $msg; + */ + return ''; + } +} + +?> Modified: vcl/trunk/web/.ht-inc/image.php URL: http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/image.php?rev=1762935&r1=1762934&r2=1762935&view=diff ============================================================================== --- vcl/trunk/web/.ht-inc/image.php (original) +++ vcl/trunk/web/.ht-inc/image.php Fri Sep 30 16:56:45 2016 @@ -87,13 +87,23 @@ class Image extends Resource { $w = 12; break; case 'os': - $w = 7; + $w = 8; + break; + case 'addomain': + $w = 10; + break; + case 'baseOU': + $w = 12; + break; + case 'adauthenabled': + $w = 9; break; default: return ''; } if(preg_match('/MSIE/i', $_SERVER['HTTP_USER_AGENT']) || - preg_match('/Trident/i', $_SERVER['HTTP_USER_AGENT'])) + preg_match('/Trident/i', $_SERVER['HTTP_USER_AGENT']) || + preg_match('/Edge/i', $_SERVER['HTTP_USER_AGENT'])) $w = round($w * 11.5) . 'px'; else $w = "{$w}em"; @@ -143,6 +153,12 @@ class Image extends Resource { return i("Admin. Access"); case 'sethostname': return i("Set Hostname"); + case 'adauthenabled': + return i("Use AD Authentication"); + case 'addomain': + return i("AD Domain"); + case 'baseOU': + return i("Base OU"); } return i(ucfirst($field)); } @@ -434,6 +450,25 @@ class Image extends Resource { $h .= "id=\"connectmethodids\">\n"; } $h .= "</div>\n"; #labeledform + + # AD authentication + $h .= "<div class=\"boxedoptions hidden\" id=\"imageadauthbox\">\n"; + # enable toggle + $vals = getUserResources(array('addomainAdmin'), array("manageGroup")); + $extra = array(); + if(count($vals['addomain']) == 0) + $extra['disabled'] = 'true'; + $extra['onChange'] = 'toggleADauth();'; + $h .= labeledFormItem('adauthenable', i('Use AD Authentication'), 'check', '', '', '', '', '', $extra); + # AD domain + $disabled = array('disabled' => 'true'); + $h .= labeledFormItem('addomainid', i('AD Domain'), 'select', $vals['addomain'], '', '', '', '', $disabled); + # base OU + $reg = '^([Oo][Uu])=[^,]+(,([Oo][Uu])=[^,]+)*$'; + $errmsg = i("Invalid base OU; do not include DC components"); + $h .= labeledFormItem('baseou', i('Base OU'), 'text', $reg, 0, '', $errmsg, '', $disabled, '230px', helpIcon('baseouhelp')); + $h .= "</div>\n"; # boxedoptions + # subimages if(! $add) { $h .= "<br>\n"; @@ -488,6 +523,8 @@ class Image extends Resource { $h .= dijitButton('', i("Cancel"), $script); $h .= " </div>\n"; $h .= "</div>\n"; # autoconfirmdlg + + $h .= helpTooltip('baseouhelp', i('OU where nodes deployed with this image will be registered. Do not enter the domain component (ex OU=Computers,OU=VCL)')); return $h; } @@ -758,6 +795,41 @@ class Image extends Resource { . " WHERE id = {$data['imageid']}"; doQuery($query); } + + # ad authentication + if($olddata['ostype'] == 'windows') { + if($data['adauthenabled'] != $olddata['adauthenabled']) { + if($data['adauthenabled']) { + $esc_baseou = mysql_real_escape_string($data['baseou']); + $query = "INSERT INTO imageaddomain " + . "(imageid, " + . "addomainid, " + . "baseOU) " + . "VALUES " + . "({$data['imageid']}, " + . "{$data['addomainid']}, " + . "'$esc_baseou')"; + doQuery($query); + } + else { + $query = "DELETE FROM imageaddomain " + . "WHERE imageid = {$data['imageid']}"; + doQuery($query); + } + } + elseif($data['adauthenabled'] && + ($data['addomainid'] != $olddata['addomainid'] || + $data['baseou'] != $olddata['baseOU'])) { + $esc_baseou = mysql_real_escape_string($data['baseou']); + $query = "UPDATE imageaddomain " + . "SET addomainid = {$data['addomainid']}, " + . "baseOU = '$esc_baseou' " + . "WHERE imageid = {$data['imageid']}"; + doQuery($query); + } + } + + # imagemeta if(empty($olddata['imagemetaid']) && ($data['checkuser'] == 0 || $data['rootaccess'] == 0 || ($olddata['ostype'] == 'windows' && $data['sethostname'] == 1) || @@ -1148,6 +1220,20 @@ class Image extends Resource { . "{$data['basedoffrevisionid']})"; doQuery($query, 205); $imageid = dbLastInsertID(); + + # ad authentication + if($data['adauthenabled']) { + $esc_baseou = mysql_real_escape_string($data['baseou']); + $query = "INSERT INTO imageaddomain " + . "(imageid, " + . "addomainid, " + . "baseOU) " + . "VALUES " + . "($imageid, " + . "{$data['addomainid']}, " + . "'$esc_baseou')"; + doQuery($query); + } // possibly add entry to imagemeta table $imagemetaid = 0; @@ -1530,6 +1616,9 @@ class Image extends Resource { $return["sethostname"] = processInputVar("sethostname", ARG_NUMERIC); $return["sysprep"] = processInputVar("sysprep", ARG_NUMERIC); # only in add $return["connectmethodids"] = processInputVar("connectmethodids", ARG_STRING); # only in add + $return["adauthenabled"] = processInputVar("adauthenabled", ARG_NUMERIC); + $return["addomainid"] = processInputVar("addomainid", ARG_NUMERIC); + $return["baseou"] = processInputVar("baseou", ARG_STRING); $return['requestid'] = getContinuationVar('requestid'); # only in add $return["imageid"] = getContinuationVar('imageid'); @@ -1636,6 +1725,27 @@ class Image extends Resource { $return['error'] = 1; $errormsg[] = i("Use Sysprep must be Yes or No"); } + if($return['adauthenabled'] != 0 && $return['adauthenabled'] != 1) + $return['adauthenabled'] = 0; + if($return['adauthenabled'] == 1) { + $vals = getUserResources(array('addomainAdmin'), array("manageGroup")); + if(! array_key_exists($return['addomainid'], $vals['addomain'])) { + $return['error'] = 1; + $errormsg[] = i("Invalid AD Domain submitted"); + } + if(! preg_match('/^([Oo][Uu])=[^,]+(,([Oo][Uu])=[^,]+)*$/', $return['baseou'])) { + $return['error'] = 1; + $errormsg[] = i("Invalid Base OU submitted, must start with OU="); + } + if(preg_match('/DC=.+(,DC=.+)*$/', $return['baseou'])) { + $return['error'] = 1; + $errormsg[] = i("Base OU must not contain DC= components"); + } + } + else { + $return['addomainid'] = 0; + $return['baseou'] = NULL; + } if(empty($return['desc'])) { $return['error'] = 1; $errormsg[] = i("You must include a description of the image") . "<br>"; @@ -1659,6 +1769,7 @@ class Image extends Resource { $return['connectmethodids'] = implode(',', array_keys($ids)); } } + if($return['error']) $return['errormsg'] = implode('<br>', $errormsg); return $return; Modified: vcl/trunk/web/.ht-inc/resource.php URL: http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/resource.php?rev=1762935&r1=1762934&r2=1762935&view=diff ============================================================================== --- vcl/trunk/web/.ht-inc/resource.php (original) +++ vcl/trunk/web/.ht-inc/resource.php Fri Sep 30 16:56:45 2016 @@ -43,6 +43,9 @@ function resource($type) { case 'schedule': $obj = new Schedule(); break; + case 'addomain': + $obj = new ADdomain(); + break; } $html = $obj->selectionText(); @@ -69,7 +72,7 @@ class Resource { var $deletetoggled; var $errmsg; var $namefield; - var $noadd; + var $addable; var $jsondata; ///////////////////////////////////////////////////////////////////////////// @@ -288,7 +291,7 @@ class Resource { if($this->deletetoggled) { $h .= "<label for=\"showdeleted\"><strong>"; $h .= i("Include Deleted {$this->restypename}s:"); - $h .= "</strong>:</label>\n"; + $h .= "</strong></label>\n"; $h .= "<input type=\"checkbox\" dojoType=\"dijit.form.CheckBox\" "; $h .= "id=\"showdeleted\" onChange=\"resource.GridFilter();\">\n"; } @@ -306,7 +309,8 @@ class Resource { $h .= "<thead>\n"; $h .= "<tr>\n"; if(preg_match('/MSIE/i', $_SERVER['HTTP_USER_AGENT']) || - preg_match('/Trident/i', $_SERVER['HTTP_USER_AGENT'])) + preg_match('/Trident/i', $_SERVER['HTTP_USER_AGENT']) || + preg_match('/Edge/i', $_SERVER['HTTP_USER_AGENT'])) $w = array('64px', '38px', '200px'); else $w = array('5em', '3.5em', '17em'); @@ -442,7 +446,8 @@ class Resource { return ''; } if(preg_match('/MSIE/i', $_SERVER['HTTP_USER_AGENT']) || - preg_match('/Trident/i', $_SERVER['HTTP_USER_AGENT'])) + preg_match('/Trident/i', $_SERVER['HTTP_USER_AGENT']) || + preg_match('/Edge/i', $_SERVER['HTTP_USER_AGENT'])) $w = round($w * 11.5) . 'px'; else $w = "{$w}em"; @@ -1602,6 +1607,34 @@ class Resource { ///////////////////////////////////////////////////////////////////////////// /// + /// \fn checkExistingField($field, $value, $id=0) + /// + /// \param $field - database field name + /// \param $value - value for $field + /// \param $id - (optional, default=0) if nonzero, ignore resource with this + /// id + /// + /// \return 1 if existing resource with $field set to $value, 0 if not + /// + /// \brief checks to see if there is already a record in the database with + /// $field set to $value + /// + ///////////////////////////////////////////////////////////////////////////// + function checkExistingField($field, $value, $id=0) { + $query = "SELECT id FROM {$this->restype} " + . "WHERE `$field` = '$value'"; + if($this->deletetoggled) + $query .= " AND deleted = 0"; + if($id) + $query .= " AND id != $id"; + $qh = doQuery($query); + if(mysql_num_rows($qh)) + return 1; + return 0; + } + + ///////////////////////////////////////////////////////////////////////////// + /// /// \fn extraSelectAdminOptions() /// /// \return html @@ -1617,6 +1650,8 @@ class Resource { /// /// \fn checkResourceInUse($rscid) /// + /// \param $rscid - id of resource + /// /// \return empty string if not being used; string of where resource is /// being used if being used /// Modified: vcl/trunk/web/.ht-inc/states.php URL: http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/states.php?rev=1762935&r1=1762934&r2=1762935&view=diff ============================================================================== --- vcl/trunk/web/.ht-inc/states.php (original) +++ vcl/trunk/web/.ht-inc/states.php Fri Sep 30 16:56:45 2016 @@ -56,6 +56,7 @@ $actions["entry"] = array('main', 'computer', 'managementnode', 'schedule', + 'addomain', 'RESTresourceBasic', 'RESTresourceDetail', #'testDojoREST', @@ -596,6 +597,8 @@ $actions['mode']['managementnode'] = "re $actions['args']['managementnode'] = 'managementnode'; $actions['mode']['schedule'] = "resource"; $actions['args']['schedule'] = 'schedule'; +$actions['mode']['addomain'] = "resource"; +$actions['args']['addomain'] = 'addomain'; $actions['mode']['viewResources'] = "viewResources"; $actions['mode']['jsonResourceStore'] = "jsonResourceStore"; $actions['mode']['AJpromptToggleDeleteResource'] = "AJpromptToggleDeleteResource"; @@ -656,6 +659,7 @@ $actions['pages']['image'] = "image"; $actions['pages']['computer'] = "computer"; $actions['pages']['managementnode'] = "managementnode"; $actions['pages']['schedule'] = "schedule"; +$actions['pages']['addomain'] = "addomain"; $actions['pages']['viewResources'] = "resource"; $actions['pages']['jsonResourceStore'] = "resource"; $actions['pages']['AJpromptToggleDeleteResource'] = "resource"; Modified: vcl/trunk/web/.ht-inc/utils.php URL: http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/utils.php?rev=1762935&r1=1762934&r2=1762935&view=diff ============================================================================== --- vcl/trunk/web/.ht-inc/utils.php (original) +++ vcl/trunk/web/.ht-inc/utils.php Fri Sep 30 16:56:45 2016 @@ -300,6 +300,7 @@ function initGlobals() { case 'computer': case 'managementnode': case 'schedule': + case 'addomain': require_once(".ht-inc/resource.php"); break; case 'storebackend': @@ -1326,15 +1327,20 @@ function getImages($includedeleted=0, $i . "i.lastupdate, " . "i.forcheckout, " . "i.maxinitialtime, " - . "i.imagemetaid " - . "FROM image i, " - . "platform p, " + . "i.imagemetaid, " + . "ad.id AS addomainid, " + . "ad.name AS addomain, " + . "iadd.baseOU " + . "FROM platform p, " . "OS o, " . "OStype ot, " . "resource r, " . "resourcetype t, " . "user u, " - . "affiliation a " + . "affiliation a, " + . "image i " + . "LEFT JOIN imageaddomain iadd ON (i.id = iadd.imageid) " + . "LEFT JOIN addomain ad ON (iadd.addomainid = ad.id) " . "WHERE i.platformid = p.id AND " . "r.resourcetypeid = t.id AND " . "t.name = 'image' AND " @@ -1357,6 +1363,9 @@ function getImages($includedeleted=0, $i $imagelist[$includedeleted][$row['id']]['sethostname'] = 0; else $imagelist[$includedeleted][$row['id']]['sethostname'] = 1; + $imagelist[$includedeleted][$row['id']]['adauthenabled'] = 0; + if($row['addomainid'] != NULL) + $imagelist[$includedeleted][$row['id']]['adauthenabled'] = 1; if($row["imagemetaid"] != NULL) { if(array_key_exists($row['imagemetaid'], $allmetadata)) { $metaid = $row['imagemetaid']; @@ -2998,22 +3007,31 @@ function getResourceGroupMembers($type=" $orders = "m.hostname"; $types = "'managementnode'"; } + elseif($type == "addomain") { + $names = "ad.name AS addomain "; + $joins = "LEFT JOIN addomain ad ON (r.subid = ad.id AND r.resourcetypeid = 19) "; + $orders = "ad.name"; + $types = "'addomain'"; + } else { $names = "c.hostname AS computer, " . "c.deleted, " . "i.prettyname AS image, " . "i.deleted AS deleted2, " . "s.name AS schedule, " - . "m.hostname AS managementnode "; + . "m.hostname AS managementnode, " + . "ad.name AS addomain "; $joins = "LEFT JOIN computer c ON (r.subid = c.id AND r.resourcetypeid = 12) " . "LEFT JOIN image i ON (r.subid = i.id AND r.resourcetypeid = 13) " . "LEFT JOIN schedule s ON (r.subid = s.id AND r.resourcetypeid = 15) " - . "LEFT JOIN managementnode m ON (r.subid = m.id AND r.resourcetypeid = 16) "; + . "LEFT JOIN managementnode m ON (r.subid = m.id AND r.resourcetypeid = 16) " + . "LEFT JOIN addomain ad ON (r.subid = ad.id AND r.resourcetypeid = 19) "; $orders = "c.hostname, " . "i.prettyname, " . "s.name, " - . "m.hostname"; - $types = "'computer','image','schedule','managementnode'"; + . "m.hostname, " + . "ad.name"; + $types = "'computer','image','schedule','managementnode','addomain'"; } $query = "SELECT rgm.resourcegroupid, " @@ -8813,6 +8831,60 @@ function getNATports($resid) { //////////////////////////////////////////////////////////////////////////////// /// +/// \fn getADdomains($addomainid=0) +/// +/// \param $addomainid - (optional) id of an AD domain +/// +/// \return array of available AD domains with the following keys:\n +/// \b id\n +/// \b resourceid\n +/// \b name\n +/// \b ownerid\n +/// \b owner\n +/// \b domaindnsname\n +/// \b domainnetbiosname\n +/// \b username\n +/// \b dnsservers\n +/// \b domaincontrollers\n +/// \b logindescription +/// +/// \brief builds an array of AD domains +/// +//////////////////////////////////////////////////////////////////////////////// +function getADdomains($addomainid=0) { + $query = "SELECT ad.id, " + . "r.id AS resourceid, " + . "ad.name, " + . "ad.ownerid, " + . "CONCAT(u.unityid, '@', a.name) AS owner, " + . "ad.domainDNSName AS domaindnsname, " + . "ad.domainNetBIOSName AS domainnetbiosname, " + . "ad.username, " + . "ad.dnsServers AS dnsservers, " + . "ad.domainControllers AS domaincontrollers, " + . "ad.logindescription " + . "FROM addomain ad, " + . "affiliation a, " + . "user u, " + . "resource r, " + . "resourcetype rt " + . "WHERE ad.ownerid = u.id AND " + . "u.affiliationid = a.id AND " + . "r.subid = ad.id AND " + . "r.resourcetypeid = rt.id AND " + . "rt.name = 'addomain'"; + if($addomainid) + $query .= " AND ad.id = $addomainid"; + + $qh = doQuery($query); + $addomainlist = array(); + while($row = mysql_fetch_assoc($qh)) + $addomainlist[$row['id']] = $row; + return $addomainlist; +} + +//////////////////////////////////////////////////////////////////////////////// +/// /// \fn getBlockTimeData($start, $end) /// /// \param $start - (optional) start time of blockTimes to get in unix timestamp @@ -9098,11 +9170,12 @@ function labeledFormItem($id, $label, $t $required = 'false'; switch($type) { case 'text': + case 'password': if($width == '') $width = '300px'; $h .= "<label for=\"$id\">$label:</label>\n"; $h .= "<span class=\"labeledform\">\n"; - $h .= "<input type=\"text\" "; + $h .= "<input type=\"$type\" "; $h .= "dojoType=\"dijit.form.ValidationTextBox\" "; $h .= "required=\"$required\" "; if($constraints != '') @@ -11891,6 +11964,26 @@ function validateIPv4addr($ip) { //////////////////////////////////////////////////////////////////////////////// /// +/// \fn validateHostname($name) +/// +/// \param $name the hostname to validate +/// +/// \return 1 if valid hostname else 0 +/// +/// \brief validates a given hostname +/// +//////////////////////////////////////////////////////////////////////////////// +function validateHostname($name) { + if(strlen($name) > 255) + return 0; + // return 0 if dotted numbers only + if(preg_match('/^[0-9]+(\.[0-9]+){3}$/', $name)) + return 0; + return preg_match('/^([A-Za-z0-9]{1,63})(\.[A-Za-z0-9-_]+)*(\.?[A-Za-z0-9])$/', $name); +} + +//////////////////////////////////////////////////////////////////////////////// +/// /// \fn validateEmailAddress($addr) /// /// \param $addr - an email address @@ -12714,6 +12807,12 @@ function getNavMenuData($homeurl=HOMEURL $menudata['vm']['selected'] = checkMenuItemSelected('vm'); } + if(in_array("addomainAdmin", $user["privileges"])) { + $menudata['addomain']['url'] = BASEURL . SCRIPT . "?mode=addomain"; + $menudata['addomain']['title'] = i('AD Domains'); + $menudata['addomain']['selected'] = checkMenuItemSelected('addomain'); + } + if(checkUserHasPerm('Schedule Site Maintenance')) { $menudata['sitemaintenance']['url'] = BASEURL . SCRIPT . "?mode=siteMaintenance"; $menudata['sitemaintenance']['title'] = i('Site Maintenance'); @@ -13277,6 +13376,9 @@ function getDojoHTML($refresh) { case 'computer': $jsfile = 'resources/computer.js'; break; + case 'addomain': + $jsfile = 'resources/addomain.js'; + break; } if(isset($jsfile)) $rt .= "<script type=\"text/javascript\" src=\"js/$jsfile?v=$v\"></script>\n"; @@ -13366,6 +13468,9 @@ function getDojoHTML($refresh) { case 'computer': $jsfile = 'resources/computer.js'; break; + case 'addomain': + $jsfile = 'resources/addomain.js'; + break; } $rt .= "<script type=\"text/javascript\" src=\"js/resources.js?v=$v\"></script>\n"; if(isset($jsfile)) Modified: vcl/trunk/web/css/vcl.css URL: http://svn.apache.org/viewvc/vcl/trunk/web/css/vcl.css?rev=1762935&r1=1762934&r2=1762935&view=diff ============================================================================== --- vcl/trunk/web/css/vcl.css (original) +++ vcl/trunk/web/css/vcl.css Fri Sep 30 16:56:45 2016 @@ -591,6 +591,14 @@ body { width: 16.5em; } +#addomaindlgcontent label { + width: 14.5em; +} + +#addomaindlgcontent .labeledform { + margin-left: 15em; +} + #cfgvartypelbl { margin-top: 6px; } Added: vcl/trunk/web/js/resources/addomain.js URL: http://svn.apache.org/viewvc/vcl/trunk/web/js/resources/addomain.js?rev=1762935&view=auto ============================================================================== --- vcl/trunk/web/js/resources/addomain.js (added) +++ vcl/trunk/web/js/resources/addomain.js Fri Sep 30 16:56:45 2016 @@ -0,0 +1,145 @@ +/* +* 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. +*/ + +function ADdomain() { + Resource.apply(this, Array.prototype.slice.call(arguments)); + this.restype = 'addomain'; +} +ADdomain.prototype = new Resource(); + +ADdomain.prototype.colformatter = function(value, rowIndex, obj) { + if(obj.field == 'logindescription') { + var str = value.replace(/<br>/g, '<br>'); + str = str.replace(/&/g, '&'); + return str; + } + return value; +} + +var resource = new ADdomain(); + +function addNewResource(title) { + dijit.byId('addeditdlg').set('title', title); + dijit.byId('addeditbtn').set('label', title); + dojo.byId('editresid').value = 0; + resetEditResource(); + dijit.byId('addeditdlg').show(); +} + +function inlineEditResourceCB(data, ioArgs) { + if(data.items.status == 'success') { + dojo.byId('saveresourcecont').value = data.items.cont; + dijit.byId('addeditdlg').set('title', data.items.title); + dijit.byId('addeditbtn').set('label', 'Save Changes'); + dojo.byId('editresid').value = data.items.rscid; + dijit.byId('name').set('value', data.items.data.name); + dijit.byId('owner').set('value', data.items.data.owner); + + dijit.byId('domaindnsname').set('value', data.items.data.domaindnsname); + dijit.byId('domainnetbiosname').set('value', data.items.data.domainnetbiosname); + dijit.byId('username').set('value', data.items.data.username); + dijit.byId('dnsservers').set('value', data.items.data.dnsservers); + dijit.byId('domaincontrollers').set('value', data.items.data.domaincontrollers); + dijit.byId('logindescription').set('value', data.items.data.logindescription); + + dojo.byId('addeditdlgerrmsg').innerHTML = ''; + dijit.byId('addeditdlg').show(); + } + else if(data.items.status == 'noaccess') { + alert('Access denied to edit this item'); + } +} + +function resetEditResource() { + var fields = ['name', 'owner', 'domaindnsname', 'domainnetbiosname', 'username', 'password', 'password2', 'dnsservers', 'domaincontrollers', 'logindescription']; + for(var i = 0; i < fields.length; i++) { + dijit.byId(fields[i]).reset(); + } + dojo.byId('addeditdlgerrmsg').innerHTML = ''; +} + +function saveResource() { + var errobj = dojo.byId('addeditdlgerrmsg'); + var fields = ['name', 'owner', 'domaindnsname', 'domainnetbiosname', 'username', 'password', 'password2', 'dnsservers', 'domaincontrollers', 'logindescription']; + + if(dojo.byId('editresid').value == 0) + var data = {continuation: dojo.byId('addresourcecont').value}; + else + var data = {continuation: dojo.byId('saveresourcecont').value}; + + for(var i = 0; i < fields.length; i++) { + if(! checkValidatedObj(fields[i], errobj)) + return; + data[fields[i]] = dijit.byId(fields[i]).get('value'); + } + if(dijit.byId('password').get('value') != dijit.byId('password2').get('value')) { + dojo.byId('addeditdlgerrmsg').innerHTML = _('Passwords do not match'); + return; + } + + dijit.byId('addeditbtn').set('disabled', true); + RPCwrapper(data, saveResourceCB, 1); +} + +function saveResourceCB(data, ioArgs) { + if(data.items.status == 'error') { + dojo.byId('addeditdlgerrmsg').innerHTML = '<br>' + data.items.msg; + dijit.byId('addeditbtn').set('disabled', false); + return; + } + else if(data.items.status == 'adderror') { + alert(data.items.errormsg); + } + else if(data.items.status == 'success') { + if(data.items.action == 'add') { + if(typeof resourcegrid !== 'undefined') { + resourcegrid.store.newItem(data.items.data); + resourcegrid.sort(); + } + dojo.forEach(dijit.findWidgets(dojo.byId('groupdlgcontent')), function(w) { + w.destroyRecursive(); + }); + if(data.items.nogroups == 0) { + dojo.byId('groupdlgcontent').innerHTML = data.items.groupingHTML; + AJdojoCreate('groupdlgcontent'); + dojo.byId('resources').value = data.items.data.id; + populateLists('resources', 'ingroups', 'inresourcename', 'outresourcename', 'resgroupinggroupscont'); + dijit.byId('groupdlg').show(); + dijit.byId('groupingnote').show(); + } + } + else { + resourcegrid.store.fetch({ + query: {id: data.items.data.id}, + onItem: function(item) { + var fields = ['name', 'owner', 'domaindnsname', 'domainnetbiosname', 'username','dnsservers', 'domaincontrollers', 'logindescription']; + for(var i = 0; i < fields.length; i++) { + dijit.byId(fields[i]).reset(); + resourcegrid.store.setValue(item, fields[i], data.items.data[fields[i]]); + } + }, + onComplete: function(items, result) { + // when call resourcegrid.sort directly, the table contents disappear; not sure why + setTimeout(function() {resourcegrid.sort();}, 10); + } + }); + } + dijit.byId('addeditdlg').hide(); + resetEditResource(); + setTimeout(function() {dijit.byId('addeditbtn').set('disabled', false);}, 250); + } +} Modified: vcl/trunk/web/js/resources/image.js URL: http://svn.apache.org/viewvc/vcl/trunk/web/js/resources/image.js?rev=1762935&r1=1762934&r2=1762935&view=diff ============================================================================== --- vcl/trunk/web/js/resources/image.js (original) +++ vcl/trunk/web/js/resources/image.js Fri Sep 30 16:56:45 2016 @@ -29,13 +29,16 @@ Image.prototype.colformatter = function( obj.field == 'forcheckout' || obj.field == 'checkuser' || obj.field == 'rootaccess' || - obj.field == 'sethostname') { + obj.field == 'sethostname' || + obj.field == 'adauthenabled') { if(value == "0") return '<span class="rederrormsg">' + _('false') + '</span>'; if(value == "1") return '<span class="ready">' + _('true') + '</span>'; } - if(obj.field == 'maxinitialtime' && value == 0) + if((obj.field == 'maxinitialtime' && value == 0) || + (obj.field == 'addomain' && value == null) || + (obj.field == 'baseOU' && value == null)) return '(unset)'; return value; } @@ -70,6 +73,25 @@ function inlineEditResourceCB(data, ioAr dojo.addClass('sethostnamediv', 'hidden'); dojo.byId('connectmethodlist').innerHTML = data.items.data.connectmethods.join('<br>'); dijit.byId('connectmethodttd').set('href', data.items.data.connectmethodurl); + if(data.items.data.ostype == 'windows') { + dojo.removeClass('imageadauthbox', 'hidden'); + if(data.items.data.adauthenabled) { + dijit.byId('adauthenable').set('checked', true); + dijit.byId('addomainid').set('value', data.items.data.addomainid); + dijit.byId('baseou').set('value', data.items.data.baseOU); + } + else { + dijit.byId('adauthenable').set('checked', false); + dijit.byId('addomainid').reset(); + dijit.byId('baseou').reset(); + } + } + else { + dojo.addClass('imageadauthbox', 'hidden'); + dijit.byId('adauthenable').set('checked', false); + dijit.byId('addomainid').reset(); + dijit.byId('baseou').reset(); + } dijit.byId('subimagedlg').set('href', data.items.data.subimageurl); dojo.byId('revisiondiv').innerHTML = data.items.data.revisionHTML; dojo.byId('addeditdlgerrmsg').innerHTML = ''; @@ -111,6 +133,9 @@ function resetEditResource() { dijit.byId('advancedoptions').toggle(); dojo.byId('connectmethodlist').innerHTML = ''; dojo.byId('addeditdlgerrmsg').innerHTML = ''; + dijit.byId('adauthenable').reset(); + dijit.byId('addomainid').reset(); + dijit.byId('baseou').reset(); } function saveResource() { @@ -168,6 +193,12 @@ function saveResource() { setTimeout(function() {dijit.byId('reload').focus();}, 300); return; } + if(dijit.byId('adauthenable').checked && ! checkValidatedObj('baseou', errobj)) { + if(! dijit.byId('advancedoptions').open) + dijit.byId('advancedoptions').toggle(); + setTimeout(function() {dijit.byId('baseou').focus();}, 300); + return; + } if(dojo.byId('editresid').value == 0) var data = {continuation: dojo.byId('addresourcecont').value}; @@ -234,6 +265,16 @@ function saveResource() { data['cpuspeed'] = dijit.byId('cpuspeed').get('value'); if(dijit.byId('reload')) data['reload'] = dijit.byId('reload').get('value'); + if(dijit.byId('adauthenable').checked) { + data['adauthenabled'] = 1; + data['addomainid'] = dijit.byId('addomainid').get('value'); + data['baseou'] = dijit.byId('baseou').get('value'); + } + else { + data['adauthenabled'] = 0; + data['addomainid'] = 0; + data['baseou'] = ''; + } submitbtn.set('disabled', true); RPCwrapper(data, saveResourceCB, 1); @@ -287,6 +328,10 @@ function saveResourceCB(data, ioArgs) { resourcegrid.store.setValue(item, 'rootaccess', parseInt(data.items.data.rootaccess)); resourcegrid.store.setValue(item, 'sethostname', parseInt(data.items.data.sethostname)); resourcegrid.store.setValue(item, 'reloadtime', data.items.data.reloadtime); + resourcegrid.store.setValue(item, 'adauthenabled', data.items.data.adauthenabled); + resourcegrid.store.setValue(item, 'addomainid', data.items.data.addomainid); + resourcegrid.store.setValue(item, 'addomain', data.items.data.addomain); + resourcegrid.store.setValue(item, 'baseOU', data.items.data.baseOU); }, onComplete: function(items, result) { // when call resourcegrid.sort directly, the table contents disappear; not sure why @@ -663,10 +708,17 @@ function startImageCB(data, ioArgs) { } else dojo.addClass('sethostnamediv', 'hidden'); - if(data.items.ostype == 'windows') + dijit.byId('adauthenable').set('checked', false); + dijit.byId('addomainid').reset(); + dijit.byId('baseou').reset(); + if(data.items.ostype == 'windows') { dojo.removeClass('sysprepdiv', 'hidden'); - else + dojo.removeClass('imageadauthbox', 'hidden'); + } + else { dojo.addClass('sysprepdiv', 'hidden'); + dojo.addClass('imageadauthbox', 'hidden'); + } if(data.items.checkpoint) { dojo.addClass('imageendrescontent', 'hidden'); @@ -763,3 +815,14 @@ function submitUpdateImageClickthroughCB dijit.byId('clickthroughDlgBtn').set('disabled', false); resRefresh(); } + +function toggleADauth() { + if(dijit.byId('adauthenable').checked) { + dijit.byId('addomainid').set('disabled', false); + dijit.byId('baseou').set('disabled', false); + } + else { + dijit.byId('addomainid').set('disabled', true); + dijit.byId('baseou').set('disabled', true); + } +} Modified: vcl/trunk/web/themes/dropdownmenus/css/theme.css URL: http://svn.apache.org/viewvc/vcl/trunk/web/themes/dropdownmenus/css/theme.css?rev=1762935&r1=1762934&r2=1762935&view=diff ============================================================================== --- vcl/trunk/web/themes/dropdownmenus/css/theme.css (original) +++ vcl/trunk/web/themes/dropdownmenus/css/theme.css Fri Sep 30 16:56:45 2016 @@ -144,6 +144,27 @@ div.dijitDialog h3 { background-color: black; color: white; } +#renameDialog tbody tr:hover td, +#renameDialog tbody tr td { + background-color: transparent; + border-top: none; + padding: 0.2em; +} +div.dijitDialog h2, +div.dijitDialog h3 { + margin-top: 0.1em; +} +#confdelcontent h3 { + font-size: 1.4em; + font-weight: bold; +} +#groupbyresourcediv table.dojoxGridRowTable tbody tr:hover td { + background-color: transparent; +} +#groupbyresourcediv div.dojoxGridRowSelected table.dojoxGridRowTable tbody tr td { + background-color: black; + color: white; +} #addeditdlg tbody tr td.dijitButtonNode { border: 1px solid #c0c0c0; } @@ -416,6 +437,12 @@ h1.site-title { #advancedoptions .labeledform { margin-left: 21.5em; } +#imageadauthbox label { + width: 16em; +} +#imageadauthbox .labeledform { + margin-left: 16.5em; +} #mgmtnodedlgcontent label { width: 24.5em; }