Skip to content
Snippets Groups Projects
Commit 64977def authored by Stefano Alberto Russo's avatar Stefano Alberto Russo
Browse files

Added the power user status and restricted options for standard users when...

Added the power user status and restricted options for standard users when adding containers and running taks. Fixed bug in proxy auth.
parent dff2b416
Branches
Tags
No related merge requests found
# Generated by Django 2.2.1 on 2021-11-05 11:23
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core_app', '0009_auto_20211103_2256'),
]
operations = [
migrations.AddField(
model_name='profile',
name='is_power_user',
field=models.BooleanField(default=False, verbose_name='Power user status'),
),
]
......@@ -45,6 +45,7 @@ class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
timezone = models.CharField('User Timezone', max_length=36, default='UTC')
authtoken = models.CharField('User auth token', max_length=36, blank=True, null=True)
is_power_user = models.BooleanField('Power user status', default=False)
def save(self, *args, **kwargs):
......@@ -116,7 +117,7 @@ class Container(models.Model):
@ property
def color(self):
string_int_hash = hash_string_to_int(self.registry + self.image + self.tag)
string_int_hash = hash_string_to_int(self.image + self.tag + self.registry)
color_map_index = string_int_hash % len(color_map)
return color_map[color_map_index]
......
......@@ -72,7 +72,14 @@
<tr>
<td><b>Interface protocol</b></td>
<td>
{% if request.user.profile.is_power_user %}
<input type="text" value="http" name="container_interface_protocol" size="5" />
{% else %}
<select name="container_interface_protocol" >
<option value="http" selected>http</option>
<option value="https" selected>https</option>
</select>
{% endif %}
</td>
</tr>
</table>
......
......@@ -70,7 +70,7 @@
<div style="width:300px; background:#ffffff; margin-left:10px; margin-right:10px; margin-top:10px; margin-bottom:0px">
<h4>Details and confirm</h4>
<div style="width:640px; float:left; border: #e0e0e0 solid 0px; margin:10px; ; margin-bottom:15px">
<div style="width:620px; float:left; border: #e0e0e0 solid 0px; margin-top:10px; ; margin-bottom:15px">
<form action="/create_task/" method="POST">
......@@ -81,7 +81,7 @@
<input type="hidden" name="task_container_uuid" value="{{ data.task_container.uuid }}" />
<input type="hidden" name="task_computing_uuid" value="{{ data.task_computing.uuid }}" />
<table class="dashboard" style="max-width:700px; margin-bottom:20px">
<table class="dashboard" style="max-width:640px; margin-bottom:20px">
<tr><td colspan="2"></td></tr>
<tr>
......@@ -93,11 +93,17 @@
<td valign="top"><b>Task&nbsp;password</b></td>
<td>
<input type="text" name="task_auth_password" placeholder="{{data.task_auth_token}}" size="37" style="-webkit-text-security: disc;" /><br>
<input type="hidden" name="task_auth_token" value="{{data.task_auth_token}}">
<!-- <font size=-1>A one-time task password. By default set to a randomly generated token, and automatically handled by Rosetta. Can be also set to a custom one, which in this case will be required to be entered manually when connecting to the task (as it will not be stored by Rosetta). Six characters minimum.</font> -->
<font size=-1>A one-time task password. By default set to a randomly generated token, and automatically handled by Rosetta. Six chars min.</font>
{% if request.user.profile.is_power_user %}
<input type="text" name="task_auth_password" placeholder="{{data.task_auth_token}}" size="37" style="-webkit-text-security: disc;" /><br>
<font size=-1>
A one-time task password. By default set to a randomly generated token, and usually automatically handled by Rosetta. Six chars min.
</font>
{% else %}
<input type="text" name="task_auth_password_disabled" value="{{data.task_auth_token}}" size="37" readonly/><br>
<font size=-1>A randomly generated token to be used as task password. Usually automatically handled by Rosetta when loggin-in to the task.</font>
{% endif %}
</td>
</tr>
......@@ -113,15 +119,26 @@
{% endif %}
-->
{% if request.user.profile.is_power_user %}
<tr>
<td><b>Access method</b></td><td>
<select name="access_method" >
<option value="direct_tunnel" selected>Direct tunnel</option>
<option value="auto" selected>Auto</option>
<option value="direct_tunnel">Direct tunnel</option>
<option value="https_proxy">HTTPS proxy</option>
<option value="None">None</option>
</select>
</td>
</tr>
{% else %}
<tr>
<td><b>Access method</b></td><td>
<select name="access_method" >
<option value="auto" selected>Auto</option>
</select>
</td>
</tr>
{% endif %}
<tr>
<td><b>Container runtime</b></td><td>
......@@ -165,8 +182,8 @@
</p></div>
{% endif %} -->
<table><tr><td style="border: 1px solid lightgray;" >
I understand that files saved or modified in this container, if not explicitly saved to a persistent storage, will be LOST upon task completition.
<table style="max-width:620px;"><tr><td style="border: 1px solid lightgray;" >
I understand that files saved or modified in the task, if not explicitly saved to a persistent storage, will be LOST upon task completition.
</td><td style="border: 1px solid lightgray;" >
<input class="form-check-input" type="checkbox" value="" id="invalidCheck" required>
</td></table>
......
......@@ -510,6 +510,8 @@ def create_task(request):
# Add auth
task_auth_password = request.POST.get('task_auth_password', None)
if task_auth_password and not request.user.profile.is_power_user:
raise ErrorMessage('Sorry, only power users can set a custom task password.')
task_auth_token = request.POST.get('task_auth_token', None)
if task_auth_password:
if task_auth_password != task_auth_token: # Just an extra check probably not much useful
......@@ -527,14 +529,23 @@ def create_task(request):
# Task access method
access_method = request.POST.get('access_method', None)
if access_method == 'direct_tunnel':
if access_method and access_method != 'auto' and not request.user.profile.is_power_user:
raise ErrorMessage('Sorry, only power users can set a task access method other than \'auto\'.')
if access_method == 'auto':
if task.container.interface_protocol in ['http','https']:
task.requires_proxy = True
task.requires_proxy_auth = True
else:
task.requires_proxy = False
task.requires_proxy_auth = False
elif access_method == 'direct_tunnel':
task.requires_proxy = False
task.requires_proxy_auth = False
elif access_method == 'https_proxy':
task.requires_proxy = True
task.requires_proxy_auth = True
else:
raise ErrorMessage('Unknow access method "{}"'.format(access_method))
raise ErrorMessage('Unknown access method "{}"'.format(access_method))
# Computing options # TODO: This is hardcoded thinking about Slurm and Singularity
computing_cpus = request.POST.get('computing_cpus', None)
......@@ -578,6 +589,10 @@ def create_task(request):
# ..and re-raise
raise
# Ensure proxy conf directory exists
if not os.path.exists('/shared/etc_apache2_sites_enabled'):
os.makedirs('/shared/etc_apache2_sites_enabled')
# Add here proxy auth file as we have the password
if task.requires_proxy_auth:
out = os_shell('ssh -o StrictHostKeyChecking=no proxy "cd /shared/etc_apache2_sites_enabled/ && htpasswd -bc {}.htpasswd {} {}"'.format(task.uuid, task.user.email, task.password), capture=True)
......@@ -759,16 +774,21 @@ def add_container(request):
container_interface_port = request.POST.get('container_interface_port', None)
if container_interface_port:
try:
int(container_interface_port)
container_interface_port = int(container_interface_port)
except:
raise ErrorMessage('Invalid container port "{}"')
else:
container_interface_port = None
# Container interface protocol
container_interface_protocol = request.POST.get('container_interface_protocol')
container_interface_protocol = request.POST.get('container_interface_protocol', None)
if container_interface_protocol and not container_interface_protocol in ['http','https']:
raise ErrorMessage('Sorry, only power users can add custom software containers with interface protocols other than \'http\' or \'https\'.')
# Container interface transport
container_interface_transport = request.POST.get('container_interface_transport')
logger.critical('Creating with desc={}, transp={}'.format(container_description, container_interface_transport))
# Capabilities
container_supports_custom_interface_port = request.POST.get('container_supports_custom_interface_port', None)
if container_supports_custom_interface_port and container_supports_custom_interface_port == 'True':
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment