From 85db11d8588b69ed6e56cd952df43ade5d511c59 Mon Sep 17 00:00:00 2001 From: "Ramón M. Gómez" Date: Thu, 16 May 2019 08:12:13 +0200 Subject: #761 New Vagrantfile to deploy an OpenGnsys 3 virtual laboratory. --- installer/vagrant/Vagrantfile-webconsole3-vbox | 171 +++++++++++++++++++++++++ server/bin/setserveraddr | 83 ++---------- 2 files changed, 181 insertions(+), 73 deletions(-) create mode 100644 installer/vagrant/Vagrantfile-webconsole3-vbox diff --git a/installer/vagrant/Vagrantfile-webconsole3-vbox b/installer/vagrant/Vagrantfile-webconsole3-vbox new file mode 100644 index 00000000..6cf4f037 --- /dev/null +++ b/installer/vagrant/Vagrantfile-webconsole3-vbox @@ -0,0 +1,171 @@ +# Vagrantfile to prepare virtual environment using VirtualBox provider to develop new AngularJS-based web interface. + +VAGRANTFILE_API_VERSION = "2" +ENV['VAGRANT_DEFAULT_PROVIDER'] = "virtualbox" +LANGUAGE = "es_ES" +ENV['LC_ALL'] = LANGUAGE + ".UTF-8" +SERVERMEM = 2048 +SERVERCPUS = 2 +CLIENTMEM = 512 +NCLIENTS = 4 +REPODISK = "repo.vdi" +REPOSIZE = 50 +MACPREFIX = "08:00:27:0e:65" +NETPREFIX = "192.168.2" +SERVERIP = "#{NETPREFIX}.10" +LOCALWEBPORT = 8443 + + +# OpenGnsys Server provisioning script. +SCRIPT = < /etc/default/locale +echo "LANG=\"$LANG\"" >> /etc/environment +echo "LANGUAGE=\"$LANG\"" >> /etc/environment +echo "LC_ALL=\"$LANG\"" >> /etc/environment +echo "LC_CTYPE=\"$LANG\"" >> /etc/environment +locale-gen --lang #{LANGUAGE} +sed -i "s/XKBLAYOUT=.*/XKBLAYOUT=\"${LANG%_*}\"/" /etc/default/keyboard +dpkg-reconfigure -fnoninteractive console-setup +# Exit if OpenGnsys is installed. +[ -f /opt/opengnsys/doc/VERSION.json ] && echo "Cannot provision, OpenGnsys is alread +y installed." && exit 1 +# Create repository disk using LVM, if necesary. +if [ -z "$(blkid /dev/mapper/og-images | grep ext4)" ]; then + pvcreate /dev/sdb + vgcreate og /dev/sdb + vgchange -ay + lvcreate -ay -n images -l 100%VG og + mkfs -t ext4 /dev/mapper/og-images + mkdir -p /opt/opengnsys/images + echo "/dev/mapper/og-images /opt/opengnsys/images ext4 defaults 0 0" >> /etc/fstab + mount -a +fi +# Update repositories. +add-apt-repository -y ppa:webupd8team/atom +apt-get update +# Install main dependencies. +apt-get install -y xfce4 gnome-icon-theme-full tango-icon-theme linux-headers-$(uname -r) firefox atom virtualbox-guest-dkms virtualbox-guest-utils virtualbox-guest-x11 +echo "allowed_users=anybody" > /etc/X11/Xwrapper.config +# Install OpenGnsys Server +tar xpvzf /vagrant/opengnsys3.tar.gz -C /tmp +/tmp/opengnsys/installer/opengnsys_installer.sh +echo y | /opt/opengnsys/bin/setserveraddr eth1 +# Configure the virtual lab. +read -e APIID APISECRET <<<$(/opt/opengnsys/www3/backend/app/console doctrine:query:sql "SELECT random_id, secret FROM og_core__clients WHERE id=1;" | awk -F\\" '$2~/^(random_id|secret)$/ {getline; printf("%s ", $2)}') +rm -fr /opt/opengnsys/www3/backend/var/cache/* +REQ=$(curl -sk 'https://localhost/opengnsys3/backend/web/app_dev.php/oauth/v2/token?client_id=1_'"$APIID"'&client_secret='"$APISECRET"'&grant_type=password&username=admin&password=admin') +TOKEN="$(echo $REQ | jq -r .access_token)" +REQ=$(curl -sk -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"name":"Repositorio virtual", "ip":"#{SERVERIP}", "password":"'$(php -r 'echo md5(uniqid(rand(), true));')'", "configurationpath":"/", "adminpath":"/", "pxepath":"/", "port":0 }' https://localhost/opengnsys3/backend/web/app_dev.php/api/private/repositories) +REPOID=$(echo $REQ | jq -r .id) +REQ=$(curl -sk -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"name":"Aula virtual", "description":"Despliegue virtual con Vagrant.", "networkSettings":{"mcastMode":"full-duplex", "mcastIp":"239.194.2.11", "mcastPort":9000, "mcastPort":9000, "mcastSpeed":100, "netmask":"#{NETPREFIX}.0", "router":"#{NETPREFIX}.1", "p2pMode":"peer", "p2pTime":60} }' https://localhost/opengnsys3/backend/web/app_dev.php/api/private/organizationalunits) +OUID=$(echo $REQ | jq -r .id) +for ((i=11; i<=10+#{NCLIENTS}; i++)); do + sed -i "/^}$/ i host pc${i} { hardware ethernet #{MACPREFIX}:${i}; fixed-address #{NETPREFIX}.${i}; }" /etc/dhcp/dhcpd.conf + [ $i == 11 ] && BOOTID=5 || BOOTID=6 + REQ=$(curl -sk -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"name":"pc'$i'", "ip":"#{NETPREFIX}.'$i'", "mac":"#{MACPREFIX}:'$i'", "serialno":"", "netiface":"eth0", "netdriver":"generic", "netboot":'"$BOOTID"', "organizationalUnit":'"$OUID"', "repository":'"$REPOID"'}' https://localhost/opengnsys3/backend/web/app_dev.php/api/private/clients) +done +systemctl restart isc-dhcp-server +#/opt/opengnsys/bin/setclientmode ogLiveAdmin pc11 PERM +#for ((i=12; i<=#{NCLIENTS+10}; i++)); do +# /opt/opengnsys/bin/setclientmode ogLive pc$i PERM +#done +sed -i "s,\(url = 'https://\)[^/]*,\1localhost:#{LOCALWEBPORT}," /opt/opengnsys/www3/frontend/main.js +sed -i "s,\(url = 'https://\)[^/]*,\1localhost:#{LOCALWEBPORT}," /opt/opengnsys/www3/frontend/main.js.map +echo "Notes:" +echo "- New OpenGnsys Server URL: https://localhost:#{LOCALWEBPORT}/opengnsys3/frontend/" +EOT + +# Client 1 OS provisioning script. +OGAGENTPKG = "ogagent_1.1.1_all.deb" +MODELSCRIPT = <&2 - exit 2 - fi - # Updating configuration variables (if URLs does not contain "localhost"). - sed -e "s,ServidorAdm=.*,ServidorAdm=$SERVERIP," \ - -e "s,IPlocal=.*,IPlocal=$SERVERIP," \ - -e "s,UrlMenu=https?://\([^/]*\)/\(.*\),UrlMenu=https://$SERVERIP/\2," \ - -e '/localhost/!s,https\?://[^/]*/\(.*\),https://'$SERVERIP'/\1,' $f >$tmpfile - file="${f/./-$SERVERDEV.}" - # Copying updated file, if needed. - if [ ! $f -ef $file ] || ! diff -q $tmpfile $file &>/dev/null; then - cp $tmpfile $file - ln -f $file $f - CHANGE=1 - fi - done - - # Processing when something has changed. - if [ $CHANGE == 1 ]; then - # Restart OpenGnsys services. - /etc/init.d/opengnsys restart - # If Repository is active, generating a new API token. - source $DEFAULTFILE - if [ "$RUN_OGADMREPO" == "yes" ]; then - REPOKEY=$(php -r 'echo md5(uniqid(rand(), true));') - sed -i -e "s/ApiToken=.*/ApiToken=$REPOKEY/" $OPENGNSYS/etc/ogAdmRepo.cfg - fi - # If OpenGnsys Server is active, updating the database. - if [ "$RUN_OGADMSERVER" == "yes" ]; then - source $OPENGNSYS/etc/ogAdmServer.cfg - # Creating credentials file. - cat << EOT > $MYCNF -[client] -user=$USUARIO -password=$PASSWORD -EOT - # Updating OpenGnsys Server IP address. - mysql --defaults-extra-file=$MYCNF -D "$CATALOG" -e \ - "UPDATE entornos - SET ipserveradm='$SERVERIP' - WHERE identorno=1" - # If OpenGnsys Repository is active, updating IP address and API token. - if [ "$RUN_OGADMREPO" == "yes" ]; then - mysql --defaults-extra-file=$MYCNF -D "$CATALOG" -e \ - "UPDATE repositorios - SET ip='$SERVERIP', apikey='$REPOKEY' - WHERE ip='$OLDSERVERIP'" - unset REPOKEY - fi - # Updating all menu URLs. - mysql --defaults-extra-file=$MYCNF -D "$CATALOG" -e \ - "UPDATE menus - SET htmlmenupub = REPLACE(htmlmenupub, '$OLDSERVERIP', '$SERVERIP'), - htmlmenupri = REPLACE(htmlmenupri, '$OLDSERVERIP', '$SERVERIP');" - # Updating all PXE files. - find $PXEDIR -name "01-*" -exec sed -i -e "s/$OLDSERVERIP/$SERVERIP/g" {} \; - fi - + OLDSERVERIP=$(jq -r .server.ip $CONFIGFILE) + if [ "$SERVERIP" != "$OLDSERVERIP" ]; then + # Updating configuration file. + jq ".server.ip=\"$SERVERIP\"" $CONFIGFILE | sponge $CONFIGFILE + # Updating all PXE files. + find $PXEDIR -name "01-*" -exec sed -i -e "s/$OLDSERVERIP/$SERVERIP/g" {} \; # Showing manual task to do after execution. cat << EOT Default server interface set to: $SERVERDEV ($SERVERIP) @@ -161,7 +99,6 @@ Manual tasks: - Check PXE files. - Log-in as Web Console user: - Check menu URLs. -${REPOKEY:+" - Update repository API token"} EOT else # Showing message if nothing changes. @@ -173,6 +110,6 @@ else exit 1 fi -# Removing temporary files. -rm -f $tmpfile $MYCNF +# Removing temporary file. +rm -f $tmpfile -- cgit v1.2.3-18-g5258 From e848ab462bf599171a87e24e10f365fa7fe9d643 Mon Sep 17 00:00:00 2001 From: "Ramón M. Gómez" Date: Thu, 16 May 2019 08:14:14 +0200 Subject: #908: OGAgent uses a new Python decorator to check the REST access token. --- .../opengnsys/modules/server/OpenGnSys/__init__.py | 104 ++++++++++++++------- 1 file changed, 70 insertions(+), 34 deletions(-) diff --git a/admin/Sources/Clients/ogagent/src/opengnsys/modules/server/OpenGnSys/__init__.py b/admin/Sources/Clients/ogagent/src/opengnsys/modules/server/OpenGnSys/__init__.py index 04c7ebc5..6e729046 100644 --- a/admin/Sources/Clients/ogagent/src/opengnsys/modules/server/OpenGnSys/__init__.py +++ b/admin/Sources/Clients/ogagent/src/opengnsys/modules/server/OpenGnSys/__init__.py @@ -47,6 +47,25 @@ from opengnsys.workers import ServerWorker from six.moves.urllib import parse +# Check authorization header decorator +def check_secret(fnc): + """ + Decorator to check for received secret key and raise exception if it isn't valid. + """ + def wrapper(*args, **kwargs): + try: + this, path, get_params, post_params, server = args # @UnusedVariable + if this.random == server.headers['Authorization']: + fnc(*args, **kwargs) + else: + raise Exception('Unauthorized operation') + except Exception as e: + logger.error(e) + raise Exception(e) + + return wrapper + + # Error handler decorator. def catch_background_error(fnc): def wrapper(*args, **kwargs): @@ -93,7 +112,6 @@ class OpenGnSysWorker(ServerWorker): interface = None # Bound interface for OpenGnsys REST = None # REST object loggedin = False # User session flag - locked = {} # Locked partitions browser = {} # Browser info commands = [] # Running commands random = None # Random string for secure connections @@ -101,17 +119,6 @@ class OpenGnSysWorker(ServerWorker): access_token = refresh_token = None # Server authorization tokens grant_type = 'http://opengnsys.es/grants/og_client' - def _check_secret(self, server): - """ - Checks for received secret key and raise exception if it isn't valid. - """ - try: - if self.random != server.headers['Authorization']: - raise Exception('Unauthorized operation') - except Exception as e: - logger.error(e) - raise Exception(e) - def _launch_browser(self, url): """ Launchs the Browser with specified URL @@ -238,7 +245,7 @@ class OpenGnSysWorker(ServerWorker): -

Initializing...

+

OpenGnsys 3

""" f = open('/tmp/init.html', 'w') @@ -319,7 +326,12 @@ class OpenGnSysWorker(ServerWorker): def process_status(self, path, get_params, post_params, server): """ - Returns client status (OS type and login status). + Returns client status (OS type or execution status) and login status. + :param path: + :param get_params: + :param post_params: + :param server: + :return: JSON object {"status": "status_code", "loggedin": boolean} """ res = {'loggedin': self.loggedin} try: @@ -327,32 +339,42 @@ class OpenGnSysWorker(ServerWorker): except KeyError: res['status'] = '' # Check if OpenGnsys Client is busy - if res['status'] == 'oglive' and self.locked: + if res['status'] == 'oglive' and len(self.commands) > 0: res['status'] = 'busy' return res + @check_secret def process_reboot(self, path, get_params, post_params, server): """ Launches a system reboot operation. + :param path: + :param get_params: + :param post_params: + :param server: authorization header + :return: JSON object {"op": "launched"} """ logger.debug('Received reboot operation') - self._check_secret(server) - # Rebooting thread. + # Rebooting thread def rebt(): operations.reboot() threading.Thread(target=rebt).start() return {'op': 'launched'} + @check_secret def process_poweroff(self, path, get_params, post_params, server): """ Launches a system power off operation. + :param path: + :param get_params: + :param post_params: + :param server: authorization header + :return: JSON object {"op": "launched"} """ logger.debug('Received poweroff operation') - self._check_secret(server) - # Powering off thread. + # Powering off thread def pwoff(): time.sleep(2) operations.poweroff() @@ -360,18 +382,23 @@ class OpenGnSysWorker(ServerWorker): threading.Thread(target=pwoff).start() return {'op': 'launched'} + @check_secret def process_script(self, path, get_params, post_params, server): """ Processes an script execution (script should be encoded in base64) + :param path: + :param get_params: + :param post_params: JSON object {"redirect_uri, "uri", "script": "commands", "id": trace_id} + :param server: authorization header + :return: JSON object {"op": "launched"} or {"error": "message"} """ logger.debug('Processing script request') - self._check_secret(server) # Processing data try: script = urllib.unquote(post_params.get('script').decode('base64')).decode('utf8') op_id = post_params.get('id') route = post_params.get('redirect_uri') - # Checking if the thread id. exists + # Check if the thread id. exists for c in self.commands: if c.getName() == str(op_id): raise Exception('Task id. already exists: {}'.format(op_id)) @@ -388,43 +415,43 @@ class OpenGnSysWorker(ServerWorker): return {'error': e} return {'op': 'launched'} + @check_secret def process_logoff(self, path, get_params, post_params, server): """ Closes user session. """ logger.debug('Received logoff operation') - self._check_secret(server) - # Sending log off message to OGAgent client. + # Send log off message to OGAgent client. self.sendClientMessage('logoff', {}) return {'op': 'sent to client'} + @check_secret def process_popup(self, path, get_params, post_params, server): """ Shows a message popup on the user's session. """ logger.debug('Received message operation') - self._check_secret(server) - # Sending popup message to OGAgent client. + # Send popup message to OGAgent client. self.sendClientMessage('popup', post_params) return {'op': 'launched'} def process_client_popup(self, params): self.REST.sendMessage('popup_done', params) + @check_secret def process_config(self, path, get_params, post_params, server): """ Returns client configuration :param path: :param get_params: :param post_params: - :param server: - :return: object + :param server: authorization header + :return: JSON object """ serialno = '' # Serial number storage = [] # Storage configuration warnings = 0 # Number of warnings logger.debug('Received getconfig operation') - # self._check_secret(server) # Processing data for row in operations.get_configuration().split(';'): cols = row.split(':') @@ -450,33 +477,42 @@ class OpenGnSysWorker(ServerWorker): logger.warn('Configuration parameter error: {}'.format(cols)) warnings += 1 else: - # Logging warnings + # Log warnings logger.warn('Configuration data error: {}'.format(cols)) warnings += 1 # Return configuration data and count of warnings return {'serialno': serialno, 'storage': storage, 'warnings': warnings} + @check_secret def process_execinfo(self, path, get_params, post_params, server): """ Returns running commands information :param path: :param get_params: :param post_params: - :param server: - :return: object + :param server: authorization header + :return: JSON array: [["callback_url", "commands", trace_id], ...] """ data = [] logger.debug('Received execinfo operation') - self._check_secret(server) - # Returning the arguments of all running threads + # Return the arguments of all running threads for c in self.commands: if c.is_alive(): data.append(c.__dict__['_Thread__args']) return data + @check_secret def process_stopcmd(self, path, get_params, post_params, server): + """ + Stops a running process identified by its trace id. + :param path: + :param get_params: + :param post_params: JSON object {"trace": trace_id} + :param server: authorization header + :return: JSON object: {"stopped": trace_id} + """ logger.debug('Received stopcmd operation with params {}:'.format(post_params)) - self._check_secret(server) + # Find operation id. and stop the thread op_id = post_params.get('trace') for c in self.commands: if c.is_alive() and c.getName() == str(op_id): -- cgit v1.2.3-18-g5258