Skip to content

Commit 296081d

Browse files
authored
Merge branch 'master' into master
2 parents e324a19 + 6c0cc3c commit 296081d

File tree

18 files changed

+163
-236
lines changed

18 files changed

+163
-236
lines changed

README.md

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -385,55 +385,73 @@ python manage.py test
385385

386386
## LDAP Configuration
387387

388-
The example settings are based on an OpenLDAP server with groups defined as "cn" of class "groupOfUniqueNames"
388+
The config options below can be changed in `webvirtcloud/settings.py` file. Variants for Active Directory and OpenLDAP are shown. This is a minimal config to get LDAP running, for further info read the [django-auth-ldap documentation](https://django-auth-ldap.readthedocs.io).
389389

390390
Enable LDAP
391391

392392
```bash
393-
sudo sed -i "s/LDAP_ENABLED = False/LDAP_ENABLED = True/g"" /srv/webvirtcloud/webvirtcloud/settings.py
393+
sudo sed -i "s~#\"django_auth_ldap.backend.LDAPBackend\",~\"django_auth_ldap.backend.LDAPBackend\",~g" /srv/webvirtcloud/webvirtcloud/settings.py
394394
```
395395

396-
Set the LDAP server name and root DN
396+
Set the LDAP server name and bind DN
397397

398-
```bash
399-
sudo sed -i "s/LDAP_URL = ''/LDAP_URL = 'myldap.server.com'/g"" /srv/webvirtcloud/webvirtcloud/settings.py
400-
sudo sed -i "s/LDAP_ROOT_DN = ''/LDAP_ROOT_DN = 'dc=server,dc=com'/g"" /srv/webvirtcloud/webvirtcloud/settings.py
401-
```
398+
```python
399+
# Active Directory
400+
AUTH_LDAP_SERVER_URI = "ldap://example.com"
401+
AUTH_LDAP_BIND_DN = "[email protected]"
402+
AUTH_LDAP_BIND_PASSWORD = "password"
402403

403-
Set the passphrase to decrypt the password
404-
```bash
405-
sudo sed -i "s/pass:MYPASSPHRASE/pass:MYTRUEPASSPHRASE/g" /srv/webvirtcloud/webvirtcloud/.dec_ldap_pwd.sh
404+
# OpenLDAP
405+
AUTH_LDAP_SERVER_URI = "ldap://example.com"
406+
AUTH_LDAP_BIND_DN = "CN=username,CN=Users,OU=example,OU=com"
407+
AUTH_LDAP_BIND_PASSWORD = "password"
406408
```
407409

408-
Encrypt the password
409-
```bash
410-
echo MYPASSWORD | openssl enc -pbkdf2 -salt -pass pass:MYTRUEPASSPHRASE | base64
411-
```
410+
Set the user filter and user and group search base and filter
412411

413-
Set the user that has browse access to LDAP and its password encrypted
412+
```python
413+
# Active Directory
414+
AUTH_LDAP_USER_SEARCH = LDAPSearch(
415+
"CN=Users,DC=example,DC=com", ldap.SCOPE_SUBTREE, "(sAMAccountName=%(user)s)"
416+
)
417+
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
418+
"CN=Users,DC=example,DC=com", ldap.SCOPE_SUBTREE, "(objectClass=group)"
419+
)
420+
AUTH_LDAP_GROUP_TYPE = NestedActiveDirectoryGroupType()
414421

415-
```bash
416-
sudo sed -i "s/LDAP_MASTER_DN = ''/LDAP_MASTER_DN = 'cn=admin,ou=users,dc=kendar,dc=org'/g"" /srv/webvirtcloud/webvirtcloud/settings.py
417-
sudo sed -i "s/LDAP_MASTER_PW_ENC = ''/LDAP_MASTER_PW_ENC = 'MYPASSWORDENCRYPTED'/g"" /srv/webvirtcloud/webvirtcloud/settings.py
422+
# OpenLDAP
423+
AUTH_LDAP_USER_SEARCH = LDAPSearch(
424+
"CN=Users,DC=example,DC=com", ldap.SCOPE_SUBTREE, "(cn=%(user)s)"
425+
)
426+
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
427+
"CN=Users,DC=example,DC=com", ldap.SCOPE_SUBTREE, "(objectClass=groupOfUniqueNames)"
428+
)
429+
AUTH_LDAP_GROUP_TYPE = GroupOfUniqueNamesType() # import needs to be changed at the top of settings.py
418430
```
419431

420-
Set the attribute that will be used to find the username, i usually use the cn
432+
Set group which is required to access WebVirtCloud. You may set this to `False` to disable this filter.
421433

422-
```bash
423-
sudo sed -i "s/LDAP_USER_UID_PREFIX = ''/LDAP_USER_UID_PREFIX = 'cn'/g"" /srv/webvirtcloud/webvirtcloud/settings.py
434+
```python
435+
AUTH_LDAP_REQUIRE_GROUP = "CN=WebVirtCloud Access,CN=Users,DC=example,DC=com"
424436
```
425437

426-
You can now create the filters to retrieve the users for the various group. This will be used during the user creation only
438+
Populate user fields with values from LDAP
427439

428-
```bash
429-
sudo sed -i "s/LDAP_SEARCH_GROUP_FILTER_ADMINS = ''/LDAP_SEARCH_GROUP_FILTER_ADMINS = 'memberOf=cn=admins,dc=kendar,dc=org'/g"" /srv/webvirtcloud/webvirtcloud/settings.py
430-
sudo sed -i "s/LDAP_SEARCH_GROUP_FILTER_STAFF = ''/LDAP_SEARCH_GROUP_FILTER_STAFF = 'memberOf=cn=staff,dc=kendar,dc=org'/g"" /srv/webvirtcloud/webvirtcloud/settings.py
431-
sudo sed -i "s/LDAP_SEARCH_GROUP_FILTER_USERS = ''/LDAP_SEARCH_GROUP_FILTER_USERS = 'memberOf=cn=users,dc=kendar,dc=org'/g"" /srv/webvirtcloud/webvirtcloud/settings.py
440+
```python
441+
AUTH_LDAP_USER_FLAGS_BY_GROUP = {
442+
"is_staff": "CN=WebVirtCloud Staff,CN=Users,DC=example,DC=com",
443+
"is_superuser": "CN=WebVirtCloud Admins,CN=Users,DC=example,DC=com",
444+
}
445+
AUTH_LDAP_USER_ATTR_MAP = {
446+
"first_name": "givenName",
447+
"last_name": "sn",
448+
"email": "mail",
449+
}
432450
```
433451

434-
Now when you login with an LDAP user it will be assigned the rights defined. The user will be authenticated then with ldap and authorized through the WebVirtCloud permissions.
452+
Now when you login with an LDAP user it will be assigned the rights defined. The user will be authenticated then with LDAP and authorized through the WebVirtCloud permissions.
435453

436-
If you'd like to move a user from ldap to WebVirtCloud, just change its password from the UI and (eventually) remove from the group in ldap
454+
If you'd like to move a user from ldap to WebVirtCloud, just change its password from the UI and (eventually) remove from the group in LDAP.
437455

438456

439457
## REST API / BETA

accounts/templates/logout.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{% extends "base_auth.html" %}
1+
{% extends "base.html" %}
22
{% load i18n %}
33
{% block title %}
44
{% trans "WebVirtCloud" %} - {% trans "Sign Out"%}
@@ -14,4 +14,4 @@ <h2>{% trans "Successful log out" %}</h2>
1414
</div>
1515
</div>
1616
</div>
17-
{% endblock %}
17+
{% endblock %}

admin/views.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def user_create(request):
117117
@superuser_only
118118
def user_update(request, pk):
119119
user = get_object_or_404(User, pk=pk)
120-
attributes = UserAttributes.objects.get(user=user)
120+
attributes, attributes_created = UserAttributes.objects.get_or_create(user=user)
121121
user_form = forms.UserForm(request.POST or None, instance=user)
122122
attributes_form = forms.UserAttributesForm(
123123
request.POST or None, instance=attributes
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 4.2.5 on 2023-10-30 17:00
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('appsettings', '0008_auto_20220905_1459'),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name='appsettings',
15+
name='id',
16+
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
17+
),
18+
]
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Generated by Django 4.2.5 on 2023-10-30 17:05
2+
3+
from django.db import migrations
4+
from django.utils.translation import gettext_lazy as _
5+
6+
def add_default_settings(apps, schema_editor):
7+
setting = apps.get_model("appsettings", "AppSettings")
8+
db_alias = schema_editor.connection.alias
9+
setting.objects.using(db_alias).bulk_create([
10+
setting(35, _("VM NIC Type"), "INSTANCE_NIC_DEFAULT_TYPE", "default", "default,e1000,e1000e,rt18139,virtio", _("Change instance default NIC type"))
11+
])
12+
13+
14+
def del_default_settings(apps, schema_editor):
15+
setting = apps.get_model("appsettings", "AppSettings")
16+
db_alias = schema_editor.connection.alias
17+
setting.objects.using(db_alias).filter(key="INSTANCE_NIC_DEFAULT_TYPE").delete()
18+
19+
20+
class Migration(migrations.Migration):
21+
22+
dependencies = [
23+
('appsettings', '0009_alter_appsettings_id')
24+
]
25+
26+
operations = [
27+
migrations.RunPython(add_default_settings,del_default_settings)
28+
]

conf/nginx/webvirtcloud.conf

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ server {
1414
proxy_set_header X-Real-IP $remote_addr;
1515
proxy_set_header X-Forwarded-for $proxy_add_x_forwarded_for;
1616
proxy_set_header Host $host:$server_port;
17-
proxy_set_header X-Forwarded-Proto $remote_addr;
17+
proxy_set_header X-Forwarded-Proto http;
1818
proxy_set_header X-Forwarded-Ssl off;
1919
proxy_connect_timeout 1800;
2020
proxy_read_timeout 1800;
@@ -34,6 +34,12 @@ server {
3434
proxy_set_header Upgrade $http_upgrade;
3535
proxy_set_header Connection "upgrade";
3636
}
37+
location /websockify {
38+
proxy_pass http://wsnovncd;
39+
proxy_http_version 1.1;
40+
proxy_set_header Upgrade $http_upgrade;
41+
proxy_set_header Connection "upgrade";
42+
}
3743
}
3844

3945
upstream wsnovncd {

conf/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ django-bootstrap-icons==0.8.6
44
django-login-required-middleware==0.9.0
55
django-otp==1.3.0
66
django-qr-code==3.1.1
7+
django-auth-ldap==4.5.0
78
gunicorn==21.2.0
89
libsass==0.22.0
910
libvirt-python==9.8.0

console/socketiod

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ def connect(sid, environ):
176176
if child_pid:
177177
# already started child process, don't start another
178178
# write a new line so that when a client refresh the shell prompt is printed
179-
fd.write("\n")
179+
os.write(fd, str.encode("\n"))
180180
return
181181

182182
# create child process attached to a pty we can read from and write to
@@ -200,8 +200,13 @@ def disconnect(sid):
200200
global child_pid
201201

202202
# kill pty process
203-
os.kill(child_pid, signal.SIGKILL)
204-
os.wait()
203+
try:
204+
os.kill(child_pid, signal.SIGKILL)
205+
os.wait()
206+
except ProcessLookupError:
207+
pass
208+
except ChildProcessError:
209+
pass
205210

206211
# reset the variables
207212
fd = None

instances/templates/create_instance_w2.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ <h5 class="modal-title">{% trans "Create Virtual Machine" %} ({{ flavor.label }}
200200
<div class="col-sm-7">
201201
<select class="form-select" name="net_model">
202202
{% for model in net_models_host %}
203-
<option value="{{ model }}" {% if model == 'default' %} selected {% endif %}>{{ model }}</option>
203+
<option value="{{ model }}" {% if model == default_nic_type %} selected {% endif %}>{{ model }}</option>
204204
{% endfor %}
205205
</select>
206206
</div>
@@ -476,7 +476,7 @@ <h5 class="modal-title">{% trans "Create Virtual Machine" %} ({{ flavor.label }}
476476
<div class="col-sm-7">
477477
<select class="form-select" name="net_model">
478478
{% for model in net_models_host %}
479-
<option value="{{ model }}" {% if model == 'default' %} selected {% endif %}>{{ model }}</option>
479+
<option value="{{ model }}" {% if model == default_nic_type %} selected {% endif %}>{{ model }}</option>
480480
{% endfor %}
481481
</select>
482482
</div>
@@ -728,7 +728,7 @@ <h5 class="modal-title">{% trans "Create Virtual Machine" %} ({{ flavor.label }}
728728
<div class="col-sm-7">
729729
<select class="form-select" name="net_model">
730730
{% for model in net_models_host %}
731-
<option value="{{ model }}" {% if model == 'default' %} selected {% endif %}>{{ model }}</option>
731+
<option value="{{ model }}" {% if model == default_nic_type %} selected {% endif %}>{{ model }}</option>
732732
{% endfor %}
733733
</select>
734734
</div>

instances/utils.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import random
33
import string
44

5-
from accounts.models import UserInstance
5+
from accounts.models import UserInstance, UserAttributes
66
from appsettings.settings import app_settings
77
from django.conf import settings
88
from django.utils.translation import gettext_lazy as _
@@ -26,7 +26,7 @@ def get_clone_free_names(size=10):
2626

2727

2828
def check_user_quota(user, instance, cpu, memory, disk_size):
29-
ua = user.userattributes
29+
ua, attributes_created = UserAttributes.objects.get_or_create(user=user)
3030
msg = ""
3131

3232
if user.is_superuser:
@@ -196,7 +196,7 @@ def get_dhcp_mac_address(vname):
196196

197197

198198
def get_random_mac_address():
199-
mac = "52:54:00:%02x:%02x:%02x" % (
199+
mac = settings.MAC_OUI + ":%02x:%02x:%02x" % (
200200
random.randint(0x00, 0xFF),
201201
random.randint(0x00, 0xFF),
202202
random.randint(0x00, 0xFF),

instances/views.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,6 +1692,7 @@ def create_instance(request, compute_id, arch, machine):
16921692
networks = sorted(conn.get_networks())
16931693
nwfilters = conn.get_nwfilters()
16941694
net_models_host = conn.get_network_models()
1695+
default_nic_type = app_settings.INSTANCE_NIC_DEFAULT_TYPE
16951696
storages = sorted(conn.get_storages(only_actives=True))
16961697
default_graphics = app_settings.QEMU_CONSOLE_DEFAULT_TYPE
16971698
default_cdrom = app_settings.INSTANCE_CDROM_ADD

templates/403.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{% extends "base_auth.html" %}
1+
{% extends "base.html" %}
22
{% load i18n %}
33
{% block title %}{% trans "403" %}{% endblock %}
44
{% block content %}

templates/404.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{% extends "base_auth.html" %}
1+
{% extends "base.html" %}
22
{% load i18n %}
33
{% block title %}{% trans "404" %}{% endblock %}
44
{% block content %}

vrtManager/util.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import libvirt
77
import lxml.etree as etree
88

9+
from django.conf import UserSettingsHolder, settings
10+
911

1012
def is_kvm_available(xml):
1113
kvm_domains = get_xml_path(xml, "//domain/@type='kvm'")
@@ -15,10 +17,12 @@ def is_kvm_available(xml):
1517
def randomMAC():
1618
"""Generate a random MAC address."""
1719
# qemu MAC
18-
oui = [0x52, 0x54, 0x00]
19-
20-
mac = oui + [random.randint(0x00, 0xFF), random.randint(0x00, 0xFF), random.randint(0x00, 0xFF)]
21-
return ":".join(map(lambda x: "%02x" % x, mac))
20+
mac = settings.MAC_OUI + ":%02x:%02x:%02x" % (
21+
random.randint(0x00, 0xFF),
22+
random.randint(0x00, 0xFF),
23+
random.randint(0x00, 0xFF),
24+
)
25+
return mac
2226

2327

2428
def randomUUID():

webvirtcloud.sh

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ configure_nginx () {
174174
fi
175175

176176
novncd_port_escape="$(echo -n "$novncd_port"|sed -e 's/[](){}<>=:\!\?\+\|\/\&$*.^[]/\\&/g')"
177-
sed -i "s|\\(server 127.0.0.1:\\).*|\\1$novncd_port_escape;|" "$nginxfile"
177+
sed -i "s|server 127.0.0.1:6080;|server 127.0.0.1:$novncd_port_escape;|" "$nginxfile"
178178

179179
}
180180

@@ -424,9 +424,15 @@ until [[ $setupfqdn == "yes" ]] || [[ $setupfqdn == "no" ]]; do
424424

425425
case $setupfqdn in
426426
[yY] | [yY][Ee][Ss] )
427-
echo -n " Q. What is the FQDN of your server? ($(hostname --fqdn)): "
428-
read -r fqdn
427+
fqdn=$(hostname --fqdn)
428+
echo -n " Q. What is the FQDN of your server? ($fqdn): "
429+
read -r fqdn_from_user
429430
setupfqdn="yes"
431+
432+
if [ ! -z $fqdn_from_user ]; then
433+
fqdn=$fqdn_from_user
434+
fi
435+
430436
echo " Setting to $fqdn"
431437
echo ""
432438
;;

webvirtcloud/.dec_ldap_pwd.sh

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)