mirror of
https://github.com/retspen/webvirtcloud
synced 2024-10-31 19:44:16 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
296081d1e3
18 changed files with 167 additions and 240 deletions
82
README.md
82
README.md
|
@ -385,55 +385,73 @@ python manage.py test
|
||||||
|
|
||||||
## LDAP Configuration
|
## LDAP Configuration
|
||||||
|
|
||||||
The example settings are based on an OpenLDAP server with groups defined as "cn" of class "groupOfUniqueNames"
|
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).
|
||||||
|
|
||||||
Enable LDAP
|
Enable LDAP
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo sed -i "s/LDAP_ENABLED = False/LDAP_ENABLED = True/g"" /srv/webvirtcloud/webvirtcloud/settings.py
|
sudo sed -i "s~#\"django_auth_ldap.backend.LDAPBackend\",~\"django_auth_ldap.backend.LDAPBackend\",~g" /srv/webvirtcloud/webvirtcloud/settings.py
|
||||||
```
|
```
|
||||||
|
|
||||||
Set the LDAP server name and root DN
|
Set the LDAP server name and bind DN
|
||||||
|
|
||||||
```bash
|
```python
|
||||||
sudo sed -i "s/LDAP_URL = ''/LDAP_URL = 'myldap.server.com'/g"" /srv/webvirtcloud/webvirtcloud/settings.py
|
# Active Directory
|
||||||
sudo sed -i "s/LDAP_ROOT_DN = ''/LDAP_ROOT_DN = 'dc=server,dc=com'/g"" /srv/webvirtcloud/webvirtcloud/settings.py
|
AUTH_LDAP_SERVER_URI = "ldap://example.com"
|
||||||
|
AUTH_LDAP_BIND_DN = "username@example.com"
|
||||||
|
AUTH_LDAP_BIND_PASSWORD = "password"
|
||||||
|
|
||||||
|
# OpenLDAP
|
||||||
|
AUTH_LDAP_SERVER_URI = "ldap://example.com"
|
||||||
|
AUTH_LDAP_BIND_DN = "CN=username,CN=Users,OU=example,OU=com"
|
||||||
|
AUTH_LDAP_BIND_PASSWORD = "password"
|
||||||
```
|
```
|
||||||
|
|
||||||
Set the passphrase to decrypt the password
|
Set the user filter and user and group search base and filter
|
||||||
```bash
|
|
||||||
sudo sed -i "s/pass:MYPASSPHRASE/pass:MYTRUEPASSPHRASE/g" /srv/webvirtcloud/webvirtcloud/.dec_ldap_pwd.sh
|
```python
|
||||||
|
# Active Directory
|
||||||
|
AUTH_LDAP_USER_SEARCH = LDAPSearch(
|
||||||
|
"CN=Users,DC=example,DC=com", ldap.SCOPE_SUBTREE, "(sAMAccountName=%(user)s)"
|
||||||
|
)
|
||||||
|
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
|
||||||
|
"CN=Users,DC=example,DC=com", ldap.SCOPE_SUBTREE, "(objectClass=group)"
|
||||||
|
)
|
||||||
|
AUTH_LDAP_GROUP_TYPE = NestedActiveDirectoryGroupType()
|
||||||
|
|
||||||
|
# OpenLDAP
|
||||||
|
AUTH_LDAP_USER_SEARCH = LDAPSearch(
|
||||||
|
"CN=Users,DC=example,DC=com", ldap.SCOPE_SUBTREE, "(cn=%(user)s)"
|
||||||
|
)
|
||||||
|
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
|
||||||
|
"CN=Users,DC=example,DC=com", ldap.SCOPE_SUBTREE, "(objectClass=groupOfUniqueNames)"
|
||||||
|
)
|
||||||
|
AUTH_LDAP_GROUP_TYPE = GroupOfUniqueNamesType() # import needs to be changed at the top of settings.py
|
||||||
```
|
```
|
||||||
|
|
||||||
Encrypt the password
|
Set group which is required to access WebVirtCloud. You may set this to `False` to disable this filter.
|
||||||
```bash
|
|
||||||
echo MYPASSWORD | openssl enc -pbkdf2 -salt -pass pass:MYTRUEPASSPHRASE | base64
|
```python
|
||||||
|
AUTH_LDAP_REQUIRE_GROUP = "CN=WebVirtCloud Access,CN=Users,DC=example,DC=com"
|
||||||
```
|
```
|
||||||
|
|
||||||
Set the user that has browse access to LDAP and its password encrypted
|
Populate user fields with values from LDAP
|
||||||
|
|
||||||
```bash
|
```python
|
||||||
sudo sed -i "s/LDAP_MASTER_DN = ''/LDAP_MASTER_DN = 'cn=admin,ou=users,dc=kendar,dc=org'/g"" /srv/webvirtcloud/webvirtcloud/settings.py
|
AUTH_LDAP_USER_FLAGS_BY_GROUP = {
|
||||||
sudo sed -i "s/LDAP_MASTER_PW_ENC = ''/LDAP_MASTER_PW_ENC = 'MYPASSWORDENCRYPTED'/g"" /srv/webvirtcloud/webvirtcloud/settings.py
|
"is_staff": "CN=WebVirtCloud Staff,CN=Users,DC=example,DC=com",
|
||||||
|
"is_superuser": "CN=WebVirtCloud Admins,CN=Users,DC=example,DC=com",
|
||||||
|
}
|
||||||
|
AUTH_LDAP_USER_ATTR_MAP = {
|
||||||
|
"first_name": "givenName",
|
||||||
|
"last_name": "sn",
|
||||||
|
"email": "mail",
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Set the attribute that will be used to find the username, i usually use the cn
|
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.
|
||||||
|
|
||||||
```bash
|
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.
|
||||||
sudo sed -i "s/LDAP_USER_UID_PREFIX = ''/LDAP_USER_UID_PREFIX = 'cn'/g"" /srv/webvirtcloud/webvirtcloud/settings.py
|
|
||||||
```
|
|
||||||
|
|
||||||
You can now create the filters to retrieve the users for the various group. This will be used during the user creation only
|
|
||||||
|
|
||||||
```bash
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
## REST API / BETA
|
## REST API / BETA
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends "base_auth.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{% trans "WebVirtCloud" %} - {% trans "Sign Out"%}
|
{% trans "WebVirtCloud" %} - {% trans "Sign Out"%}
|
||||||
|
|
|
@ -117,7 +117,7 @@ def user_create(request):
|
||||||
@superuser_only
|
@superuser_only
|
||||||
def user_update(request, pk):
|
def user_update(request, pk):
|
||||||
user = get_object_or_404(User, pk=pk)
|
user = get_object_or_404(User, pk=pk)
|
||||||
attributes = UserAttributes.objects.get(user=user)
|
attributes, attributes_created = UserAttributes.objects.get_or_create(user=user)
|
||||||
user_form = forms.UserForm(request.POST or None, instance=user)
|
user_form = forms.UserForm(request.POST or None, instance=user)
|
||||||
attributes_form = forms.UserAttributesForm(
|
attributes_form = forms.UserAttributesForm(
|
||||||
request.POST or None, instance=attributes
|
request.POST or None, instance=attributes
|
||||||
|
|
18
appsettings/migrations/0009_alter_appsettings_id.py
Normal file
18
appsettings/migrations/0009_alter_appsettings_id.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 4.2.5 on 2023-10-30 17:00
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('appsettings', '0008_auto_20220905_1459'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='appsettings',
|
||||||
|
name='id',
|
||||||
|
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||||
|
),
|
||||||
|
]
|
28
appsettings/migrations/0010_auto_20231030_1305.py
Normal file
28
appsettings/migrations/0010_auto_20231030_1305.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# Generated by Django 4.2.5 on 2023-10-30 17:05
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
def add_default_settings(apps, schema_editor):
|
||||||
|
setting = apps.get_model("appsettings", "AppSettings")
|
||||||
|
db_alias = schema_editor.connection.alias
|
||||||
|
setting.objects.using(db_alias).bulk_create([
|
||||||
|
setting(35, _("VM NIC Type"), "INSTANCE_NIC_DEFAULT_TYPE", "default", "default,e1000,e1000e,rt18139,virtio", _("Change instance default NIC type"))
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def del_default_settings(apps, schema_editor):
|
||||||
|
setting = apps.get_model("appsettings", "AppSettings")
|
||||||
|
db_alias = schema_editor.connection.alias
|
||||||
|
setting.objects.using(db_alias).filter(key="INSTANCE_NIC_DEFAULT_TYPE").delete()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('appsettings', '0009_alter_appsettings_id')
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(add_default_settings,del_default_settings)
|
||||||
|
]
|
|
@ -14,7 +14,7 @@ server {
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-for $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-for $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header Host $host:$server_port;
|
proxy_set_header Host $host:$server_port;
|
||||||
proxy_set_header X-Forwarded-Proto $remote_addr;
|
proxy_set_header X-Forwarded-Proto http;
|
||||||
proxy_set_header X-Forwarded-Ssl off;
|
proxy_set_header X-Forwarded-Ssl off;
|
||||||
proxy_connect_timeout 1800;
|
proxy_connect_timeout 1800;
|
||||||
proxy_read_timeout 1800;
|
proxy_read_timeout 1800;
|
||||||
|
@ -34,6 +34,12 @@ server {
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection "upgrade";
|
proxy_set_header Connection "upgrade";
|
||||||
}
|
}
|
||||||
|
location /websockify {
|
||||||
|
proxy_pass http://wsnovncd;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
upstream wsnovncd {
|
upstream wsnovncd {
|
||||||
|
|
|
@ -4,6 +4,7 @@ django-bootstrap-icons==0.8.6
|
||||||
django-login-required-middleware==0.9.0
|
django-login-required-middleware==0.9.0
|
||||||
django-otp==1.3.0
|
django-otp==1.3.0
|
||||||
django-qr-code==3.1.1
|
django-qr-code==3.1.1
|
||||||
|
django-auth-ldap==4.5.0
|
||||||
gunicorn==21.2.0
|
gunicorn==21.2.0
|
||||||
libsass==0.22.0
|
libsass==0.22.0
|
||||||
libvirt-python==9.8.0
|
libvirt-python==9.8.0
|
||||||
|
|
|
@ -176,7 +176,7 @@ def connect(sid, environ):
|
||||||
if child_pid:
|
if child_pid:
|
||||||
# already started child process, don't start another
|
# already started child process, don't start another
|
||||||
# write a new line so that when a client refresh the shell prompt is printed
|
# write a new line so that when a client refresh the shell prompt is printed
|
||||||
fd.write("\n")
|
os.write(fd, str.encode("\n"))
|
||||||
return
|
return
|
||||||
|
|
||||||
# create child process attached to a pty we can read from and write to
|
# create child process attached to a pty we can read from and write to
|
||||||
|
@ -200,8 +200,13 @@ def disconnect(sid):
|
||||||
global child_pid
|
global child_pid
|
||||||
|
|
||||||
# kill pty process
|
# kill pty process
|
||||||
os.kill(child_pid, signal.SIGKILL)
|
try:
|
||||||
os.wait()
|
os.kill(child_pid, signal.SIGKILL)
|
||||||
|
os.wait()
|
||||||
|
except ProcessLookupError:
|
||||||
|
pass
|
||||||
|
except ChildProcessError:
|
||||||
|
pass
|
||||||
|
|
||||||
# reset the variables
|
# reset the variables
|
||||||
fd = None
|
fd = None
|
||||||
|
|
|
@ -200,7 +200,7 @@
|
||||||
<div class="col-sm-7">
|
<div class="col-sm-7">
|
||||||
<select class="form-select" name="net_model">
|
<select class="form-select" name="net_model">
|
||||||
{% for model in net_models_host %}
|
{% for model in net_models_host %}
|
||||||
<option value="{{ model }}" {% if model == 'default' %} selected {% endif %}>{{ model }}</option>
|
<option value="{{ model }}" {% if model == default_nic_type %} selected {% endif %}>{{ model }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
@ -476,7 +476,7 @@
|
||||||
<div class="col-sm-7">
|
<div class="col-sm-7">
|
||||||
<select class="form-select" name="net_model">
|
<select class="form-select" name="net_model">
|
||||||
{% for model in net_models_host %}
|
{% for model in net_models_host %}
|
||||||
<option value="{{ model }}" {% if model == 'default' %} selected {% endif %}>{{ model }}</option>
|
<option value="{{ model }}" {% if model == default_nic_type %} selected {% endif %}>{{ model }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
@ -728,7 +728,7 @@
|
||||||
<div class="col-sm-7">
|
<div class="col-sm-7">
|
||||||
<select class="form-select" name="net_model">
|
<select class="form-select" name="net_model">
|
||||||
{% for model in net_models_host %}
|
{% for model in net_models_host %}
|
||||||
<option value="{{ model }}" {% if model == 'default' %} selected {% endif %}>{{ model }}</option>
|
<option value="{{ model }}" {% if model == default_nic_type %} selected {% endif %}>{{ model }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import os
|
||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
|
|
||||||
from accounts.models import UserInstance
|
from accounts.models import UserInstance, UserAttributes
|
||||||
from appsettings.settings import app_settings
|
from appsettings.settings import app_settings
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
@ -26,7 +26,7 @@ def get_clone_free_names(size=10):
|
||||||
|
|
||||||
|
|
||||||
def check_user_quota(user, instance, cpu, memory, disk_size):
|
def check_user_quota(user, instance, cpu, memory, disk_size):
|
||||||
ua = user.userattributes
|
ua, attributes_created = UserAttributes.objects.get_or_create(user=user)
|
||||||
msg = ""
|
msg = ""
|
||||||
|
|
||||||
if user.is_superuser:
|
if user.is_superuser:
|
||||||
|
@ -196,7 +196,7 @@ def get_dhcp_mac_address(vname):
|
||||||
|
|
||||||
|
|
||||||
def get_random_mac_address():
|
def get_random_mac_address():
|
||||||
mac = "52:54:00:%02x:%02x:%02x" % (
|
mac = settings.MAC_OUI + ":%02x:%02x:%02x" % (
|
||||||
random.randint(0x00, 0xFF),
|
random.randint(0x00, 0xFF),
|
||||||
random.randint(0x00, 0xFF),
|
random.randint(0x00, 0xFF),
|
||||||
random.randint(0x00, 0xFF),
|
random.randint(0x00, 0xFF),
|
||||||
|
|
|
@ -1692,6 +1692,7 @@ def create_instance(request, compute_id, arch, machine):
|
||||||
networks = sorted(conn.get_networks())
|
networks = sorted(conn.get_networks())
|
||||||
nwfilters = conn.get_nwfilters()
|
nwfilters = conn.get_nwfilters()
|
||||||
net_models_host = conn.get_network_models()
|
net_models_host = conn.get_network_models()
|
||||||
|
default_nic_type = app_settings.INSTANCE_NIC_DEFAULT_TYPE
|
||||||
storages = sorted(conn.get_storages(only_actives=True))
|
storages = sorted(conn.get_storages(only_actives=True))
|
||||||
default_graphics = app_settings.QEMU_CONSOLE_DEFAULT_TYPE
|
default_graphics = app_settings.QEMU_CONSOLE_DEFAULT_TYPE
|
||||||
default_cdrom = app_settings.INSTANCE_CDROM_ADD
|
default_cdrom = app_settings.INSTANCE_CDROM_ADD
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends "base_auth.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% block title %}{% trans "403" %}{% endblock %}
|
{% block title %}{% trans "403" %}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% extends "base_auth.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% block title %}{% trans "404" %}{% endblock %}
|
{% block title %}{% trans "404" %}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
@ -6,6 +6,8 @@ import string
|
||||||
import libvirt
|
import libvirt
|
||||||
import lxml.etree as etree
|
import lxml.etree as etree
|
||||||
|
|
||||||
|
from django.conf import UserSettingsHolder, settings
|
||||||
|
|
||||||
|
|
||||||
def is_kvm_available(xml):
|
def is_kvm_available(xml):
|
||||||
kvm_domains = get_xml_path(xml, "//domain/@type='kvm'")
|
kvm_domains = get_xml_path(xml, "//domain/@type='kvm'")
|
||||||
|
@ -15,10 +17,12 @@ def is_kvm_available(xml):
|
||||||
def randomMAC():
|
def randomMAC():
|
||||||
"""Generate a random MAC address."""
|
"""Generate a random MAC address."""
|
||||||
# qemu MAC
|
# qemu MAC
|
||||||
oui = [0x52, 0x54, 0x00]
|
mac = settings.MAC_OUI + ":%02x:%02x:%02x" % (
|
||||||
|
random.randint(0x00, 0xFF),
|
||||||
mac = oui + [random.randint(0x00, 0xFF), random.randint(0x00, 0xFF), random.randint(0x00, 0xFF)]
|
random.randint(0x00, 0xFF),
|
||||||
return ":".join(map(lambda x: "%02x" % x, mac))
|
random.randint(0x00, 0xFF),
|
||||||
|
)
|
||||||
|
return mac
|
||||||
|
|
||||||
|
|
||||||
def randomUUID():
|
def randomUUID():
|
||||||
|
|
|
@ -174,7 +174,7 @@ configure_nginx () {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
novncd_port_escape="$(echo -n "$novncd_port"|sed -e 's/[](){}<>=:\!\?\+\|\/\&$*.^[]/\\&/g')"
|
novncd_port_escape="$(echo -n "$novncd_port"|sed -e 's/[](){}<>=:\!\?\+\|\/\&$*.^[]/\\&/g')"
|
||||||
sed -i "s|\\(server 127.0.0.1:\\).*|\\1$novncd_port_escape;|" "$nginxfile"
|
sed -i "s|server 127.0.0.1:6080;|server 127.0.0.1:$novncd_port_escape;|" "$nginxfile"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,9 +424,15 @@ until [[ $setupfqdn == "yes" ]] || [[ $setupfqdn == "no" ]]; do
|
||||||
|
|
||||||
case $setupfqdn in
|
case $setupfqdn in
|
||||||
[yY] | [yY][Ee][Ss] )
|
[yY] | [yY][Ee][Ss] )
|
||||||
echo -n " Q. What is the FQDN of your server? ($(hostname --fqdn)): "
|
fqdn=$(hostname --fqdn)
|
||||||
read -r fqdn
|
echo -n " Q. What is the FQDN of your server? ($fqdn): "
|
||||||
|
read -r fqdn_from_user
|
||||||
setupfqdn="yes"
|
setupfqdn="yes"
|
||||||
|
|
||||||
|
if [ ! -z $fqdn_from_user ]; then
|
||||||
|
fqdn=$fqdn_from_user
|
||||||
|
fi
|
||||||
|
|
||||||
echo " Setting to $fqdn"
|
echo " Setting to $fqdn"
|
||||||
echo ""
|
echo ""
|
||||||
;;
|
;;
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
#####
|
|
||||||
|
|
||||||
#
|
|
||||||
|
|
||||||
# LDAP PASSWORD DECRYPTION SCRIPT
|
|
||||||
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
|
||||||
|
|
||||||
#####
|
|
||||||
|
|
||||||
ENC_PASSWD=$1
|
|
||||||
|
|
||||||
echo $(echo $ENC_PASSWD | base64 -d | openssl enc -pbkdf2 -salt -d -pass pass:MYPASSPHRASE )
|
|
||||||
|
|
|
@ -1,142 +0,0 @@
|
||||||
from django.contrib.auth.backends import ModelBackend
|
|
||||||
from django.contrib.auth.models import User, Group
|
|
||||||
from django.conf import settings
|
|
||||||
from accounts.models import UserAttributes, UserInstance, UserSSHKey
|
|
||||||
from django.contrib.auth.models import Permission
|
|
||||||
from logs.models import Logs
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
try:
|
|
||||||
from ldap3 import Server, Connection, ALL
|
|
||||||
#/srv/webvirtcloud/ldap/ldapbackend.py
|
|
||||||
class LdapAuthenticationBackend(ModelBackend):
|
|
||||||
|
|
||||||
def get_LDAP_user(self, username, password, filterString):
|
|
||||||
print('get_LDAP_user {}'.format(username))
|
|
||||||
try:
|
|
||||||
server = Server(settings.LDAP_URL, port=settings.LDAP_PORT,
|
|
||||||
use_ssl=settings.USE_SSL,get_info=ALL)
|
|
||||||
connection = Connection(server,
|
|
||||||
settings.LDAP_MASTER_DN,
|
|
||||||
settings.LDAP_MASTER_PW, auto_bind=True)
|
|
||||||
connection.search(settings.LDAP_ROOT_DN,
|
|
||||||
'(&({attr}={login})({filter}))'.format(
|
|
||||||
attr=settings.LDAP_USER_UID_PREFIX,
|
|
||||||
login=username,
|
|
||||||
filter=filterString), attributes=['*'])
|
|
||||||
|
|
||||||
if len(connection.response) == 0:
|
|
||||||
print('get_LDAP_user-no response')
|
|
||||||
return None
|
|
||||||
specificUser = connection.response[0]
|
|
||||||
userDn = str(specificUser.get('raw_dn'),'utf-8')
|
|
||||||
userGivenName = connection.entries[0].givenName
|
|
||||||
userSn = connection.entries[0].sn
|
|
||||||
userMail = connection.entries[0].mail
|
|
||||||
with Connection(server, userDn, password) as con:
|
|
||||||
return username, userGivenName, userSn, userMail
|
|
||||||
except Exception as e:
|
|
||||||
print("LDAP Exception: {}".format(e))
|
|
||||||
return None
|
|
||||||
return None
|
|
||||||
|
|
||||||
def authenticate(self, request, username=None, password=None, **kwargs):
|
|
||||||
if not settings.LDAP_ENABLED:
|
|
||||||
return None
|
|
||||||
print("authenticate_ldap")
|
|
||||||
# Get the user information from the LDAP if he can be authenticated
|
|
||||||
isAdmin = False
|
|
||||||
isStaff = False
|
|
||||||
isTechnician = False
|
|
||||||
|
|
||||||
requeteLdap = self.get_LDAP_user(username, password, settings.LDAP_SEARCH_GROUP_FILTER_ADMINS)
|
|
||||||
isAdmin = requeteLdap is not None
|
|
||||||
isStaff = requeteLdap is not None
|
|
||||||
|
|
||||||
if requeteLdap is None:
|
|
||||||
requeteLdap = self.get_LDAP_user(username, password, settings.LDAP_SEARCH_GROUP_FILTER_STAFF)
|
|
||||||
isStaff = requeteLdap is not None
|
|
||||||
|
|
||||||
if requeteLdap is None:
|
|
||||||
requeteLdap = self.get_LDAP_user(username, password, settings.LDAP_SEARCH_GROUP_FILTER_TECHNICIANS)
|
|
||||||
isTechnician = requeteLdap is not None
|
|
||||||
|
|
||||||
if requeteLdap is None:
|
|
||||||
requeteLdap = self.get_LDAP_user(username, password, settings.LDAP_SEARCH_GROUP_FILTER_USERS)
|
|
||||||
|
|
||||||
if requeteLdap is None:
|
|
||||||
print("User does not belong to any search group. Check LDAP_SEARCH_GROUP_FILTER in settings.")
|
|
||||||
return None
|
|
||||||
|
|
||||||
techniciansGroup = Group.objects.get(name='Technicians')
|
|
||||||
|
|
||||||
try:
|
|
||||||
user = User.objects.get(username=username)
|
|
||||||
attributes = UserAttributes.objects.get(user=user)
|
|
||||||
user.is_staff = isStaff
|
|
||||||
user.is_superuser = isAdmin
|
|
||||||
if not isTechnician and user.groups.filter(name='Technicians').exists():
|
|
||||||
user.groups.remove(techniciansGroup)
|
|
||||||
elif isTechnician and not user.groups.filter(name='Technicians').exists():
|
|
||||||
user.groups.add(techniciansGroup)
|
|
||||||
else:
|
|
||||||
print("The user is already in the Technicians group")
|
|
||||||
user.save()
|
|
||||||
# TODO VERIFY
|
|
||||||
except User.DoesNotExist:
|
|
||||||
print(f"authenticate-create new user: {username}")
|
|
||||||
user = User(username=username)
|
|
||||||
user.first_name = requeteLdap[1]
|
|
||||||
user.last_name = requeteLdap[2]
|
|
||||||
user.email = requeteLdap[3]
|
|
||||||
user.is_active = True
|
|
||||||
user.is_staff = isStaff
|
|
||||||
user.is_superuser = isAdmin
|
|
||||||
user.set_password(uuid.uuid4().hex)
|
|
||||||
user.save()
|
|
||||||
if isTechnician:
|
|
||||||
user.groups.add(techniciansGroup)
|
|
||||||
maxInstances = 1
|
|
||||||
maxCpus = 1
|
|
||||||
maxMemory = 128
|
|
||||||
maxDiskSize = 1
|
|
||||||
if isStaff:
|
|
||||||
maxMemory = 2048
|
|
||||||
maxDiskSize = 20
|
|
||||||
permission = Permission.objects.get(codename='clone_instances')
|
|
||||||
user.user_permissions.add(permission)
|
|
||||||
if isAdmin:
|
|
||||||
maxInstances = -1
|
|
||||||
maxCpus = -1
|
|
||||||
maxMemory = -1
|
|
||||||
maxDiskSize = -1
|
|
||||||
permission = Permission.objects.get(codename='clone_instances')
|
|
||||||
user.user_permissions.add(permission)
|
|
||||||
user.save()
|
|
||||||
UserAttributes.objects.create(
|
|
||||||
user=user,
|
|
||||||
max_instances=maxInstances,
|
|
||||||
max_cpus=maxCpus,
|
|
||||||
max_memory=maxMemory,
|
|
||||||
max_disk_size=maxDiskSize,
|
|
||||||
)
|
|
||||||
user.save()
|
|
||||||
|
|
||||||
print("authenticate-user created")
|
|
||||||
return user
|
|
||||||
|
|
||||||
def get_user(self, user_id):
|
|
||||||
if not settings.LDAP_ENABLED:
|
|
||||||
return None
|
|
||||||
print("get_user_ldap")
|
|
||||||
try:
|
|
||||||
return User.objects.get(pk=user_id)
|
|
||||||
except User.DoesNotExist:
|
|
||||||
print("get_user-user not found")
|
|
||||||
return None
|
|
||||||
except:
|
|
||||||
class LdapAuthenticationBackend(ModelBackend):
|
|
||||||
def authenticate(self, request, username=None, password=None, **kwargs):
|
|
||||||
return None
|
|
||||||
def get_user(self, user_id):
|
|
||||||
return None
|
|
|
@ -3,7 +3,9 @@ Django settings for webvirtcloud project.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import ldap
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from django_auth_ldap.config import LDAPSearch, NestedActiveDirectoryGroupType
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
|
@ -13,6 +15,8 @@ SECRET_KEY = ""
|
||||||
|
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
|
|
||||||
|
MAC_OUI = '52:54:10'
|
||||||
|
|
||||||
ALLOWED_HOSTS = ["*"]
|
ALLOWED_HOSTS = ["*"]
|
||||||
|
|
||||||
CSRF_TRUSTED_ORIGINS = ['http://localhost',]
|
CSRF_TRUSTED_ORIGINS = ['http://localhost',]
|
||||||
|
@ -102,7 +106,7 @@ DATABASES = {
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = [
|
AUTHENTICATION_BACKENDS = [
|
||||||
"django.contrib.auth.backends.ModelBackend",
|
"django.contrib.auth.backends.ModelBackend",
|
||||||
"webvirtcloud.ldapbackend.LdapAuthenticationBackend",
|
#"django_auth_ldap.backend.LDAPBackend",
|
||||||
]
|
]
|
||||||
|
|
||||||
LOGIN_URL = "/accounts/login/"
|
LOGIN_URL = "/accounts/login/"
|
||||||
|
@ -196,7 +200,7 @@ WS_PUBLIC_PATH = "/novncd/"
|
||||||
WS_CERT = None
|
WS_CERT = None
|
||||||
|
|
||||||
SOCKETIO_PORT = 6081
|
SOCKETIO_PORT = 6081
|
||||||
SOCKETIO_HOST = '0.0.0.0'
|
SOCKETIO_HOST = "0.0.0.0"
|
||||||
|
|
||||||
# Socketio public host
|
# Socketio public host
|
||||||
SOCKETIO_PUBLIC_HOST = None
|
SOCKETIO_PUBLIC_HOST = None
|
||||||
|
@ -277,27 +281,23 @@ EMAIL_HOST_PASSWORD = ''
|
||||||
# LDAP Config
|
# LDAP Config
|
||||||
#
|
#
|
||||||
|
|
||||||
LDAP_ENABLED = False
|
AUTH_LDAP_SERVER_URI = "ldap://example.com"
|
||||||
LDAP_URL = ''
|
AUTH_LDAP_BIND_DN = "username@example.com"
|
||||||
LDAP_PORT = 389
|
AUTH_LDAP_BIND_PASSWORD = "password"
|
||||||
USE_SSL = False
|
AUTH_LDAP_USER_SEARCH = LDAPSearch(
|
||||||
## The user with search rights on ldap. (e.g cn=admin,dc=kendar,dc=org)
|
"CN=Users,DC=example,DC=com", ldap.SCOPE_SUBTREE, "(sAMAccountName=%(user)s)"
|
||||||
LDAP_MASTER_DN = ''
|
)
|
||||||
LDAP_MASTER_PW_ENC = ''
|
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
|
||||||
LDAP_MASTER_PW = subprocess.Popen(["bash", str(BASE_DIR) + "/webvirtcloud/.dec_ldap_pwd.sh", LDAP_MASTER_PW_ENC],stdout=subprocess.PIPE, encoding='utf8').stdout.read().strip('\n')
|
"CN=Users,DC=example,DC=com", ldap.SCOPE_SUBTREE, "(objectClass=group)"
|
||||||
## The root dn (e.g. dc=kendar,dc=org)
|
)
|
||||||
LDAP_ROOT_DN = ''
|
AUTH_LDAP_GROUP_TYPE = NestedActiveDirectoryGroupType()
|
||||||
## Queries to identify the users, i use groupOfUniqueNames on openldap
|
AUTH_LDAP_REQUIRE_GROUP = "CN=WebVirtCloud Access,CN=Users,DC=example,DC=com"
|
||||||
|
AUTH_LDAP_USER_FLAGS_BY_GROUP = {
|
||||||
### PLEASE BE SURE memberOf overlay is activated on slapd
|
"is_staff": "CN=WebVirtCloud Staff,CN=Users,DC=example,DC=com",
|
||||||
## e.g. memberOf=cn=admins,cn=staff,cn=technicians,cn=webvirtcloud,ou=groups,dc=kendar,dc=org
|
"is_superuser": "CN=WebVirtCloud Admins,CN=Users,DC=example,DC=com",
|
||||||
LDAP_SEARCH_GROUP_FILTER_ADMINS = ''
|
}
|
||||||
## e.g. memberOf=cn=staff,cn=technicians,cn=webvirtcloud,ou=groups,dc=kendar,dc=org
|
AUTH_LDAP_USER_ATTR_MAP = {
|
||||||
LDAP_SEARCH_GROUP_FILTER_STAFF = ''
|
"first_name": "givenName",
|
||||||
## e.g. memberOf=cn=technicians,cn=webvirtcloud,ou=groups,dc=kendar,dc=org
|
"last_name": "sn",
|
||||||
LDAP_SEARCH_GROUP_FILTER_TECHNICIANS = ''
|
"email": "mail",
|
||||||
## e.g. memberOf=cn=webvirtcloud,ou=groups,dc=kendar,dc=org
|
}
|
||||||
LDAP_SEARCH_GROUP_FILTER_USERS = ''
|
|
||||||
|
|
||||||
## The user name prefix to identify the user name (e.g. cn)
|
|
||||||
LDAP_USER_UID_PREFIX = ''
|
|
||||||
|
|
Loading…
Reference in a new issue