diff --git a/test-python-ssh/docker-compose.yml b/test-python-ssh/docker-compose.yml index acdd2c3..9d4c272 100644 --- a/test-python-ssh/docker-compose.yml +++ b/test-python-ssh/docker-compose.yml @@ -3,5 +3,6 @@ services: app: build: . volumes: - - ./users.txt:/usr/share/app/users.txt + - ./data:/usr/share/app/data + - ./production_eleves:/usr/share/app/python_app/modules network_mode: "host" diff --git a/test-python-ssh/entrypoint.sh b/test-python-ssh/entrypoint.sh index 82afa80..dd9aa22 100755 --- a/test-python-ssh/entrypoint.sh +++ b/test-python-ssh/entrypoint.sh @@ -2,33 +2,59 @@ HOME_BASE="/usr/share/app/python_app/modules" - -# Check we got users -if [ ! -f 'users.txt' ] ; then - echo "Missing file users.txt" - exit 1 -fi +USERS_LIST="/usr/share/app/data/users.txt" +PASSWD_LIST="/usr/share/app/data/passwords.txt" +CUSTOM_SCRIPT="/usr/share/app/data/init.sh" # Must be ascii for cut separator="=" +forbidden_chars=". /" + +# Check we got users +if [ ! -f "$USERS_LIST" ] && [ ! -f "$PASSWD_LIST" ] ; then + echo "Les fichiers des utilisateurs ou des passwords n’ont pas étés trouvées." + exit 1 +fi + +for c in $forbidden_chars ; do + for file in "$USERS_LIST" "$PASSWD_LIST" ; do + if [ -n "$(cat "$USERS_LIST" | grep -F $c)" ] ; then + echo "Le fichier « $file » ne doit pas contenir le caractère « $c » !" + exit 1 + fi + done +done # Generate passwords if not done yet genPassowrd () { tr -dc A-Za-z0-9 > passwords.txt +if [ ! -f $PASSWD_LIST ] ; then + for user in $(cat "$USERS_LIST") ; do + echo "$user$separator$(genPassowrd 10)" >> $PASSWD_LIST done fi # Create users -for line in $(cat passwords.txt) ; do +for line in $(cat $PASSWD_LIST) ; do name="$(echo "$line" | cut -d "$separator" -f 1)" pass="$(echo "$line" | cut -d "$separator" -f 2)" - echo "$pass\n$pass" | useradd --home-dir "$HOME_BASE/$name" --create-home --no-user-group -G eleve "$name" + home="$HOME_BASE/$name" + mkdir -p "$home" + #useradd --home-dir "$home" --no-user-group -G eleve --shell /bin/bash --root "$home" "$name" + useradd --home-dir "$home" --no-user-group -G eleve --shell /bin/bash "$name" + echo "$pass\n$pass" | passwd "$name" &> /dev/null + chown "$name":eleve "$home" done +# Custom script +if [ -f "$CUSTOM_SCRIPT" ] ; then + if [ ! -x "$CUSTOM_SCRIPT" ] ; then + chmod +x "$CUSTOM_SCRIPT" + fi + "$CUSTOM_SCRIPT" +fi + # Nginx nginx -c '/etc/nginx/nginx.conf' diff --git a/test-python-ssh/python_app/main.py b/test-python-ssh/python_app/main.py index 013a3b7..1a60e92 100644 --- a/test-python-ssh/python_app/main.py +++ b/test-python-ssh/python_app/main.py @@ -4,6 +4,9 @@ import importlib # Get function args import inspect +# check file properties +import os + # The directory where student work will be # not a real path, do not use ./ or stuff like this BASE_MODULE_PATH = 'python_app/modules' @@ -13,60 +16,58 @@ if BASE_MODULE_PATH != '': def application(env, start_response): """ Cette fonction est appellée à chaque requête HTTP et doit exécuter le bon code python. """ - # Find which python module and function will be called - # And remove empty elements - elements = tuple(e for e in env['PATH_INFO'].split('/') if e != '') - print(env) - - #m = importlib.import_module('python_app.modules.main') - #f = getattr(m,'index') - #if env['REQUEST_URI'] == '/': - # return htmlresp(200, f(), start_response) - - # Defaults - path = '' - module = 'main' - function = 'index' - - # Get from url path - if len(elements) == 1: - module = elements[0] - elif len(elements) == 2: - module = elements[0] - function = elements[1] - elif len(elements) > 2: - path = '/'.join(elements[0:-2]) - module = elements[-2] - function = elements[-1] + path = env['PATH_INFO'][1:] # removing first slash # slash stuff - if path != '': - path += '/' + if path.endswith('/'): + path = path[:-1] + path_elements = tuple(d for d in path.split('/') if d != '') + path_minus_one = '/'.join(path_elements[:-1]) + + # Find which python module and function will be called + if os.path.isfile(BASE_MODULE_PATH + path_minus_one): + path = path_minus_one + function = path_elements[-1] + elif os.path.isfile(BASE_MODULE_PATH + path): + function = 'index' + elif os.path.isdir(BASE_MODULE_PATH + path): + path += '/main' + function = 'index' + else: + return htmlresp(404, 'Le dossier {} n’a pas été trouvé.'.format(path), start_response) + + # Module full path - module_path = BASE_MODULE_PATH + path + module + module_path = BASE_MODULE_PATH + path module_path = module_path.replace('/', '.') # Import the function try: m = importlib.import_module(module_path) except ModuleNotFoundError: - print('Le fichier {} n’a pas été trouvé. {}'.format(module_path, str(elements))) - return htmlresp(404, 'Le fichier {} n’a pas été trouvé.'.format(path + module), start_response) + #print('Le fichier {} n’a pas été trouvé. {}'.format(module_path, str(path_elements))) + return htmlresp(404, 'Le fichier {} n’a pas été trouvé.'.format(path), start_response) # Find which parameters the function needs try: f = getattr(m,function) # Call the function with the rigth attributes except AttributeError: - return htmlresp(404, 'La fonction {} n’a pas été trouvée.'.format(function), start_response) + return htmlresp(404, 'La fonction {} n’a pas été trouvée dans {}'.format(function, module_path), start_response) # Pass url parameters to the function try: - params = {p:'' for p in list(inspect.getargspec(f).args)} + #print(inspect.getargspec(f)) + #params = {p:(d if d is not None else '') for p,d in zip(inspect.getargspec(f).args, inspect.getargspec(f).defaults)} + expected_params = inspect.getargspec(f).args + params = {} + # TODO POST params? for item in env['QUERY_STRING'].split('&'): + if item == '': + continue k,v = tuple(item.split('=')) - if k in params: + if k in expected_params: params[k] = v except Exception: return htmlresp(400, 'La fonction {} demande les arguments suivants : {}. On a uniquement {}.'.format(function, params, ), start_response) @@ -77,8 +78,8 @@ def application(env, start_response): return htmlresp(response[0], str(response[1]), start_response, False) else: return htmlresp(200, str(response), start_response, False) - except Exception: - return htmlresp(400, 'Erreur à l’exécution de la fonction {}.'.format(function), start_response) + except Exception as e: + return htmlresp(400, 'Erreur à l’exécution de la fonction {}.
{}'.format(function, e), start_response) def htmlresp(code, message, start_response, squelette=True): diff --git a/test-python-ssh/sshd/sshd_config b/test-python-ssh/sshd/sshd_config deleted file mode 100644 index 50c9fa6..0000000 --- a/test-python-ssh/sshd/sshd_config +++ /dev/null @@ -1,116 +0,0 @@ -# $OpenBSD: sshd_config,v 1.103 2018/04/09 20:41:22 tj Exp $ - -# This is the sshd server system-wide configuration file. See -# sshd_config(5) for more information. - -# This sshd was compiled with PATH=/usr/local/sbin:/usr/local/bin:/usr/bin - -# The strategy used for options in the default sshd_config shipped with -# OpenSSH is to specify options with their default value where -# possible, but leave them commented. Uncommented options override the -# default value. - -#Port 22 -#AddressFamily any -#ListenAddress 0.0.0.0 -#ListenAddress :: - -#HostKey /etc/ssh/ssh_host_rsa_key -#HostKey /etc/ssh/ssh_host_ecdsa_key -#HostKey /etc/ssh/ssh_host_ed25519_key - -# Ciphers and keying -#RekeyLimit default none - -# Logging -#SyslogFacility AUTH -#LogLevel INFO - -# Authentication: - -#LoginGraceTime 2m -#PermitRootLogin prohibit-password -#StrictModes yes -#MaxAuthTries 6 -#MaxSessions 10 - -#PubkeyAuthentication yes - -# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 -# but this is overridden so installations will only check .ssh/authorized_keys -AuthorizedKeysFile .ssh/authorized_keys - -#AuthorizedPrincipalsFile none - -#AuthorizedKeysCommand none -#AuthorizedKeysCommandUser nobody - -# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts -#HostbasedAuthentication no -# Change to yes if you don't trust ~/.ssh/known_hosts for -# HostbasedAuthentication -#IgnoreUserKnownHosts no -# Don't read the user's ~/.rhosts and ~/.shosts files -#IgnoreRhosts yes - -# To disable tunneled clear text passwords, change to no here! -#PasswordAuthentication yes -#PermitEmptyPasswords no - -# Change to no to disable s/key passwords -ChallengeResponseAuthentication no - -# Kerberos options -#KerberosAuthentication no -#KerberosOrLocalPasswd yes -#KerberosTicketCleanup yes -#KerberosGetAFSToken no - -# GSSAPI options -#GSSAPIAuthentication no -#GSSAPICleanupCredentials yes - -# Set this to 'yes' to enable PAM authentication, account processing, -# and session processing. If this is enabled, PAM authentication will -# be allowed through the ChallengeResponseAuthentication and -# PasswordAuthentication. Depending on your PAM configuration, -# PAM authentication via ChallengeResponseAuthentication may bypass -# the setting of "PermitRootLogin without-password". -# If you just want the PAM account and session checks to run without -# PAM authentication, then enable this but set PasswordAuthentication -# and ChallengeResponseAuthentication to 'no'. -UsePAM yes - -#AllowAgentForwarding yes -#AllowTcpForwarding yes -#GatewayPorts no -#X11Forwarding no -#X11DisplayOffset 10 -#X11UseLocalhost yes -#PermitTTY yes -PrintMotd no # pam does that -#PrintLastLog yes -#TCPKeepAlive yes -#PermitUserEnvironment no -#Compression delayed -#ClientAliveInterval 0 -#ClientAliveCountMax 3 -#UseDNS no -#PidFile /run/sshd.pid -#MaxStartups 10:30:100 -#PermitTunnel no -#ChrootDirectory none -#VersionAddendum none - -# no default banner path -#Banner none - -# override default of no subsystems -Subsystem sftp /usr/lib/ssh/sftp-server - -# Example of overriding settings on a per-user basis -#Match User anoncvs -# X11Forwarding no -# AllowTcpForwarding no -# PermitTTY no -# ForceCommand cvs server diff --git a/test-python-ssh/users.txt b/test-python-ssh/users.txt deleted file mode 100644 index 15bf471..0000000 --- a/test-python-ssh/users.txt +++ /dev/null @@ -1,2 +0,0 @@ -218.amine -218.chems