mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-09 03:36:48 +00:00
The REST API took only the login session, so a script could not use it without a browser. A user now makes API tokens on the profile page (API Tokens tab): a name, and an expiry of 30, 90 or 365 days or none. The token is shown once, on a page that is not cached, and then kept only as a SHA-512 digest; the list shows its name, first characters, creation and expiry, and a token is deleted there. Tools send it as "Authorization: Token wvc_...", and act as its user, with that user's permissions. Making and deleting a token is logged, without the token. A password alone (HTTP Basic) still does not reach the API, as it would skip the OTP second factor: a token is made in a session that passed the login and its OTP. The token class comes first, so a refused request gets 401 with its challenge instead of 403. django-rest-knox 5.1.0 provides the tokens (accounts.ApiToken adds the name); settings.py takes "knox", KNOX_TOKEN_MODEL and REST_KNOX from the template.
93 lines
2.8 KiB
Python
93 lines
2.8 KiB
Python
from django.contrib.auth.models import User
|
|
from django.core.validators import MinValueValidator
|
|
from django.db import models
|
|
from django.utils.translation import gettext_lazy as _
|
|
from instances.models import Instance
|
|
from knox.models import AbstractAuthToken
|
|
|
|
|
|
class UserInstanceManager(models.Manager):
|
|
def get_queryset(self):
|
|
return super().get_queryset().select_related("instance", "user")
|
|
|
|
|
|
class UserInstance(models.Model):
|
|
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
|
instance = models.ForeignKey(Instance, on_delete=models.CASCADE)
|
|
is_change = models.BooleanField(default=False)
|
|
is_delete = models.BooleanField(default=False)
|
|
is_vnc = models.BooleanField(default=False)
|
|
|
|
objects = UserInstanceManager()
|
|
|
|
def __str__(self):
|
|
return _('Instance "%(inst)s" of user %(user)s') % {
|
|
"inst": self.instance,
|
|
"user": self.user,
|
|
}
|
|
|
|
class Meta:
|
|
unique_together = ["user", "instance"]
|
|
|
|
|
|
class UserSSHKey(models.Model):
|
|
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
|
keyname = models.CharField(_("key name"), max_length=25)
|
|
keypublic = models.TextField(_("public key"), max_length=16384)
|
|
|
|
def __str__(self):
|
|
return self.keyname
|
|
|
|
|
|
class UserAttributes(models.Model):
|
|
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
|
can_clone_instances = models.BooleanField(default=True)
|
|
must_change_password = models.BooleanField(default=False)
|
|
max_instances = models.IntegerField(
|
|
_("max instances"),
|
|
default=2,
|
|
help_text=_("-1 for unlimited. Any integer value"),
|
|
validators=[MinValueValidator(-1)],
|
|
)
|
|
max_cpus = models.IntegerField(
|
|
_("max CPUs"),
|
|
default=2,
|
|
help_text=_("-1 for unlimited. Any integer value"),
|
|
validators=[MinValueValidator(-1)],
|
|
)
|
|
max_memory = models.IntegerField(
|
|
_("max memory"),
|
|
default=2048,
|
|
help_text=_("-1 for unlimited. Any integer value"),
|
|
validators=[MinValueValidator(-1)],
|
|
)
|
|
max_disk_size = models.IntegerField(
|
|
_("max disk size"),
|
|
default=20,
|
|
help_text=_("-1 for unlimited. Any integer value"),
|
|
validators=[MinValueValidator(-1)],
|
|
)
|
|
|
|
def __str__(self):
|
|
return self.user.username
|
|
|
|
|
|
class PermissionSet(models.Model):
|
|
"""
|
|
Dummy model for holding set of permissions we need to be automatically added by Django
|
|
"""
|
|
|
|
class Meta:
|
|
default_permissions = ()
|
|
permissions = (("change_password", _("Can change password")),)
|
|
|
|
managed = False
|
|
|
|
|
|
class ApiToken(AbstractAuthToken):
|
|
"""A token for the REST API, kept as a digest (django-rest-knox); the
|
|
name says what uses it."""
|
|
name = models.CharField(_("name"), max_length=64)
|
|
|
|
class Meta:
|
|
ordering = ["-created"]
|