mirror of https://github.com/jumpserver/jumpserver
[Update] 移动model
parent
1969fb79fe
commit
34040fcd59
|
@ -0,0 +1,2 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
|
@ -38,14 +38,4 @@ class Migration(migrations.Migration):
|
|||
('datetime', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserLoginLog',
|
||||
fields=[
|
||||
],
|
||||
options={
|
||||
'proxy': True,
|
||||
'indexes': [],
|
||||
},
|
||||
bases=('users.loginlog',),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# Generated by Django 2.1.7 on 2019-02-28 09:15
|
||||
|
||||
from django.db import migrations, models, connection
|
||||
import django.utils.timezone
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('audits', '0004_operatelog_passwordchangelog_userloginlog'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='UserLoginLog',
|
||||
fields=[
|
||||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||
('username', models.CharField(max_length=128, verbose_name='Username')),
|
||||
('type', models.CharField(choices=[('W', 'Web'), ('T', 'Terminal')], max_length=2, verbose_name='Login type')),
|
||||
('ip', models.GenericIPAddressField(verbose_name='Login ip')),
|
||||
('city', models.CharField(blank=True, max_length=254, null=True, verbose_name='Login city')),
|
||||
('user_agent', models.CharField(blank=True, max_length=254, null=True, verbose_name='User agent')),
|
||||
('mfa', models.SmallIntegerField(choices=[(0, 'Disabled'), (1, 'Enabled'), (2, '-')], default=2, verbose_name='MFA')),
|
||||
('reason', models.SmallIntegerField(choices=[(0, '-'), (1, 'Username/password check failed'), (2, 'MFA authentication failed'), (3, 'Username does not exist'), (4, 'Password expired')], default=0, verbose_name='Reason')),
|
||||
('status', models.BooleanField(choices=[(True, 'Success'), (False, 'Failed')], default=True, max_length=2, verbose_name='Status')),
|
||||
('datetime', models.DateTimeField(default=django.utils.timezone.now, verbose_name='Date login')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['-datetime', 'username'],
|
||||
},
|
||||
),
|
||||
]
|
||||
drop_table_sql = "DROP TABLE audits_userloginlog"
|
||||
rename_table_sql = "RENAME TABLE users_loginlog TO audits_userloginlog"
|
||||
table_exist = 'users_loginlog' in connection.introspection.table_names()
|
||||
if table_exist:
|
||||
operations.append(migrations.RunSQL(drop_table_sql))
|
||||
operations.append(migrations.RunSQL(rename_table_sql))
|
|
@ -2,9 +2,9 @@ import uuid
|
|||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils import timezone
|
||||
|
||||
from orgs.mixins import OrgModelMixin
|
||||
from .hands import LoginLog
|
||||
|
||||
__all__ = [
|
||||
'FTPLog', 'OperateLog', 'PasswordChangeLog', 'UserLoginLog',
|
||||
|
@ -55,6 +55,50 @@ class PasswordChangeLog(models.Model):
|
|||
return "{} change {}'s password".format(self.change_by, self.user)
|
||||
|
||||
|
||||
class UserLoginLog(LoginLog):
|
||||
class UserLoginLog(models.Model):
|
||||
LOGIN_TYPE_CHOICE = (
|
||||
('W', 'Web'),
|
||||
('T', 'Terminal'),
|
||||
)
|
||||
|
||||
MFA_DISABLED = 0
|
||||
MFA_ENABLED = 1
|
||||
MFA_UNKNOWN = 2
|
||||
|
||||
MFA_CHOICE = (
|
||||
(MFA_DISABLED, _('Disabled')),
|
||||
(MFA_ENABLED, _('Enabled')),
|
||||
(MFA_UNKNOWN, _('-')),
|
||||
)
|
||||
|
||||
REASON_NOTHING = 0
|
||||
REASON_PASSWORD = 1
|
||||
REASON_MFA = 2
|
||||
REASON_NOT_EXIST = 3
|
||||
REASON_PASSWORD_EXPIRED = 4
|
||||
|
||||
REASON_CHOICE = (
|
||||
(REASON_NOTHING, _('-')),
|
||||
(REASON_PASSWORD, _('Username/password check failed')),
|
||||
(REASON_MFA, _('MFA authentication failed')),
|
||||
(REASON_NOT_EXIST, _("Username does not exist")),
|
||||
(REASON_PASSWORD_EXPIRED, _("Password expired")),
|
||||
)
|
||||
|
||||
STATUS_CHOICE = (
|
||||
(True, _('Success')),
|
||||
(False, _('Failed'))
|
||||
)
|
||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||
username = models.CharField(max_length=128, verbose_name=_('Username'))
|
||||
type = models.CharField(choices=LOGIN_TYPE_CHOICE, max_length=2, verbose_name=_('Login type'))
|
||||
ip = models.GenericIPAddressField(verbose_name=_('Login ip'))
|
||||
city = models.CharField(max_length=254, blank=True, null=True, verbose_name=_('Login city'))
|
||||
user_agent = models.CharField(max_length=254, blank=True, null=True, verbose_name=_('User agent'))
|
||||
mfa = models.SmallIntegerField(default=MFA_UNKNOWN, choices=MFA_CHOICE, verbose_name=_('MFA'))
|
||||
reason = models.SmallIntegerField(default=0, choices=REASON_CHOICE, verbose_name=_('Reason'))
|
||||
status = models.BooleanField(max_length=2, default=True, choices=STATUS_CHOICE, verbose_name=_('Status'))
|
||||
datetime = models.DateTimeField(default=timezone.now, verbose_name=_('Date login'))
|
||||
|
||||
class Meta:
|
||||
proxy = True
|
||||
ordering = ['-datetime', 'username']
|
||||
|
|
|
@ -8,7 +8,6 @@ from common.permissions import AdminUserRequiredMixin
|
|||
|
||||
from orgs.utils import current_org
|
||||
from ops.views import CommandExecutionListView as UserCommandExecutionListView
|
||||
from users.models import User
|
||||
from .models import FTPLog, OperateLog, PasswordChangeLog, UserLoginLog
|
||||
|
||||
|
||||
|
|
|
@ -16,8 +16,9 @@ from common.utils import get_logger, get_request_ip
|
|||
from common.permissions import IsOrgAdminOrAppUser
|
||||
from orgs.mixins import RootOrgViewMixin
|
||||
from users.serializers import UserSerializer
|
||||
from users.models import User, LoginLog
|
||||
from users.models import User
|
||||
from assets.models import Asset, SystemUser
|
||||
from audits.models import UserLoginLog as LoginLog
|
||||
from users.utils import (
|
||||
check_user_valid, check_otp_code, increase_login_failed_count,
|
||||
is_block_login, clean_failed_count
|
||||
|
|
|
@ -8,13 +8,13 @@ from django.core.cache import cache
|
|||
from django.conf import settings
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.six import text_type
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.contrib.auth import get_user_model
|
||||
from rest_framework import HTTP_HEADER_ENCODING
|
||||
from rest_framework import authentication, exceptions
|
||||
from rest_framework.authentication import CSRFCheck
|
||||
|
||||
from common.utils import get_object_or_none, make_signature, http_to_unixtime
|
||||
from users.models import User, AccessKey, PrivateToken
|
||||
from ..models import AccessKey, PrivateToken
|
||||
|
||||
|
||||
def get_request_date_header(request):
|
||||
|
@ -42,7 +42,6 @@ class AccessKeyAuthentication(authentication.BaseAuthentication):
|
|||
失败
|
||||
"""
|
||||
keyword = 'Sign'
|
||||
model = AccessKey
|
||||
|
||||
def authenticate(self, request):
|
||||
auth = authentication.get_authorization_header(request).split()
|
||||
|
@ -109,7 +108,7 @@ class AccessKeyAuthentication(authentication.BaseAuthentication):
|
|||
|
||||
class AccessTokenAuthentication(authentication.BaseAuthentication):
|
||||
keyword = 'Bearer'
|
||||
model = User
|
||||
model = get_user_model()
|
||||
expiration = settings.TOKEN_EXPIRATION or 3600
|
||||
|
||||
def authenticate(self, request):
|
||||
|
@ -133,10 +132,9 @@ class AccessTokenAuthentication(authentication.BaseAuthentication):
|
|||
raise exceptions.AuthenticationFailed(msg)
|
||||
return self.authenticate_credentials(token)
|
||||
|
||||
@staticmethod
|
||||
def authenticate_credentials(token):
|
||||
def authenticate_credentials(self, token):
|
||||
user_id = cache.get(token)
|
||||
user = get_object_or_none(User, id=user_id)
|
||||
user = get_object_or_none(self.model, id=user_id)
|
||||
|
||||
if not user:
|
||||
msg = _('Invalid token or cache refreshed.')
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
from django import forms
|
||||
from django.contrib.auth.forms import AuthenticationForm
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from captcha.fields import CaptchaField
|
||||
|
||||
|
||||
class UserLoginForm(AuthenticationForm):
|
||||
username = forms.CharField(label=_('Username'), max_length=100)
|
||||
password = forms.CharField(
|
||||
label=_('Password'), widget=forms.PasswordInput,
|
||||
max_length=128, strip=False
|
||||
)
|
||||
|
||||
def confirm_login_allowed(self, user):
|
||||
if not user.is_staff:
|
||||
raise forms.ValidationError(
|
||||
self.error_messages['inactive'],
|
||||
code='inactive',)
|
||||
|
||||
|
||||
class UserLoginCaptchaForm(UserLoginForm):
|
||||
captcha = CaptchaField()
|
||||
|
||||
|
||||
class UserCheckOtpCodeForm(forms.Form):
|
||||
otp_code = forms.CharField(label=_('MFA code'), max_length=6)
|
|
@ -0,0 +1,51 @@
|
|||
# Generated by Django 2.1.7 on 2019-02-28 08:07
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='AccessKey',
|
||||
fields=[
|
||||
('id',
|
||||
models.UUIDField(default=uuid.uuid4, editable=False,
|
||||
primary_key=True, serialize=False,
|
||||
verbose_name='AccessKeyID')),
|
||||
('secret',
|
||||
models.UUIDField(default=uuid.uuid4, editable=False,
|
||||
verbose_name='AccessKeySecret')),
|
||||
('user', models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name='access_keys',
|
||||
to=settings.AUTH_USER_MODEL, verbose_name='User')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PrivateToken',
|
||||
fields=[
|
||||
('key',
|
||||
models.CharField(max_length=40, primary_key=True,
|
||||
serialize=False, verbose_name='Key')),
|
||||
('created', models.DateTimeField(auto_now_add=True,
|
||||
verbose_name='Created')),
|
||||
('user', models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name='auth_token',
|
||||
to=settings.AUTH_USER_MODEL, verbose_name='User')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Private Token',
|
||||
},
|
||||
),
|
||||
]
|
|
@ -0,0 +1,33 @@
|
|||
import uuid
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from rest_framework.authtoken.models import Token
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class AccessKey(models.Model):
|
||||
id = models.UUIDField(verbose_name='AccessKeyID', primary_key=True,
|
||||
default=uuid.uuid4, editable=False)
|
||||
secret = models.UUIDField(verbose_name='AccessKeySecret',
|
||||
default=uuid.uuid4, editable=False)
|
||||
user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='User',
|
||||
on_delete=models.CASCADE, related_name='access_keys')
|
||||
|
||||
def get_id(self):
|
||||
return str(self.id)
|
||||
|
||||
def get_secret(self):
|
||||
return str(self.secret)
|
||||
|
||||
def get_full_value(self):
|
||||
return '{}:{}'.format(self.id, self.secret)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.id)
|
||||
|
||||
|
||||
class PrivateToken(Token):
|
||||
"""Inherit from auth token, otherwise migration is boring"""
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Private Token')
|
|
@ -0,0 +1,16 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
from rest_framework import serializers
|
||||
|
||||
from .models import AccessKey
|
||||
|
||||
|
||||
__all__ = ['AccessKeySerializer']
|
||||
|
||||
|
||||
class AccessKeySerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = AccessKey
|
||||
fields = ['id', 'secret']
|
||||
read_only_fields = ['id', 'secret']
|
|
@ -5,7 +5,7 @@ from common.utils import get_ip_city, validate_ip
|
|||
|
||||
|
||||
def write_login_log(*args, **kwargs):
|
||||
from users.models import LoginLog
|
||||
from audits.models import UserLoginLog
|
||||
default_city = _("Unknown")
|
||||
ip = kwargs.get('ip', '')
|
||||
if not (ip and validate_ip(ip)):
|
||||
|
@ -14,5 +14,5 @@ def write_login_log(*args, **kwargs):
|
|||
else:
|
||||
city = get_ip_city(ip) or default_city
|
||||
kwargs.update({'ip': ip, 'city': city})
|
||||
LoginLog.objects.create(**kwargs)
|
||||
UserLoginLog.objects.create(**kwargs)
|
||||
|
||||
|
|
|
@ -17,14 +17,15 @@ from django.views.generic.edit import FormView
|
|||
from django.conf import settings
|
||||
|
||||
from common.utils import get_request_ip
|
||||
from authentication.signals import post_auth_success, post_auth_failed
|
||||
from users import forms
|
||||
from users.models import User, LoginLog
|
||||
from users.models import User
|
||||
from audits.models import UserLoginLog as LoginLog
|
||||
from users.utils import (
|
||||
check_otp_code, is_block_login, clean_failed_count, get_user_or_tmp_user,
|
||||
set_tmp_user_to_cache, increase_login_failed_count,
|
||||
redirect_user_first_login_or_index,
|
||||
)
|
||||
from ..signals import post_auth_success, post_auth_failed
|
||||
from .. import forms
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
|
|
@ -23,7 +23,7 @@ def on_org_create_or_update(sender, instance=None, created=False, **kwargs):
|
|||
set_current_org(old_org)
|
||||
|
||||
if instance and not created:
|
||||
instance.expire_cache()
|
||||
instance.expire_user_cache()
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=Organization.users.through)
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
|
||||
from django import forms
|
||||
from django.contrib.auth.forms import AuthenticationForm
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from captcha.fields import CaptchaField
|
||||
|
||||
from common.utils import validate_ssh_public_key
|
||||
from orgs.mixins import OrgModelForm
|
||||
|
@ -11,24 +9,6 @@ from orgs.utils import current_org
|
|||
from .models import User, UserGroup
|
||||
|
||||
|
||||
class UserLoginForm(AuthenticationForm):
|
||||
username = forms.CharField(label=_('Username'), max_length=100)
|
||||
password = forms.CharField(
|
||||
label=_('Password'), widget=forms.PasswordInput,
|
||||
max_length=128, strip=False
|
||||
)
|
||||
|
||||
def confirm_login_allowed(self, user):
|
||||
if not user.is_staff:
|
||||
raise forms.ValidationError(
|
||||
self.error_messages['inactive'],
|
||||
code='inactive',)
|
||||
|
||||
|
||||
class UserLoginCaptchaForm(UserLoginForm):
|
||||
captcha = CaptchaField()
|
||||
|
||||
|
||||
class UserCheckPasswordForm(forms.Form):
|
||||
username = forms.CharField(label=_('Username'), max_length=100)
|
||||
password = forms.CharField(
|
||||
|
|
|
@ -4,10 +4,8 @@ from __future__ import unicode_literals
|
|||
|
||||
import common.utils
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from django.conf import settings
|
||||
import django.contrib.auth.models
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
import uuid
|
||||
|
||||
|
@ -75,40 +73,6 @@ class Migration(migrations.Migration):
|
|||
('objects', django.contrib.auth.models.UserManager()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AccessKey',
|
||||
fields=[
|
||||
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='AccessKeyID')),
|
||||
('secret', models.UUIDField(default=uuid.uuid4, editable=False, verbose_name='AccessKeySecret')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='access_key', to=settings.AUTH_USER_MODEL, verbose_name='User')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='LoginLog',
|
||||
fields=[
|
||||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||
('username', models.CharField(max_length=20, verbose_name='Username')),
|
||||
('type', models.CharField(choices=[('W', 'Web'), ('T', 'Terminal')], max_length=2, verbose_name='Login type')),
|
||||
('ip', models.GenericIPAddressField(verbose_name='Login ip')),
|
||||
('city', models.CharField(blank=True, max_length=254, null=True, verbose_name='Login city')),
|
||||
('user_agent', models.CharField(blank=True, max_length=254, null=True, verbose_name='User agent')),
|
||||
('datetime', models.DateTimeField(auto_now_add=True, verbose_name='Date login')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['-datetime', 'username'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PrivateToken',
|
||||
fields=[
|
||||
('key', models.CharField(max_length=40, primary_key=True, serialize=False, verbose_name='Key')),
|
||||
('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='auth_token', to=settings.AUTH_USER_MODEL, verbose_name='User')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Private Token',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserGroup',
|
||||
fields=[
|
||||
|
|
|
@ -12,19 +12,4 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='loginlog',
|
||||
name='mfa',
|
||||
field=models.SmallIntegerField(choices=[(0, 'Disabled'), (1, 'Enabled'), (2, '-')], default=2, verbose_name='MFA'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='loginlog',
|
||||
name='reason',
|
||||
field=models.SmallIntegerField(choices=[(0, '-'), (1, 'Username/password check failed'), (2, 'MFA authentication failed')], default=0, verbose_name='Reason'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='loginlog',
|
||||
name='status',
|
||||
field=models.BooleanField(choices=[(True, 'Success'), (False, 'Failed')], default=True, max_length=2, verbose_name='Status'),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -10,14 +10,4 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='loginlog',
|
||||
name='reason',
|
||||
field=models.SmallIntegerField(choices=[(0, '-'), (1, 'Username/password check failed'), (2, 'MFA authentication failed'), (3, 'Username does not exist')], default=0, verbose_name='Reason'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='loginlog',
|
||||
name='username',
|
||||
field=models.CharField(max_length=128, verbose_name='Username'),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
# Generated by Django 2.1.1 on 2018-11-23 03:13
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
@ -17,14 +15,4 @@ class Migration(migrations.Migration):
|
|||
name='date_password_last_updated',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date password last updated'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='accesskey',
|
||||
name='user',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='access_keys', to=settings.AUTH_USER_MODEL, verbose_name='User'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='loginlog',
|
||||
name='reason',
|
||||
field=models.SmallIntegerField(choices=[(0, '-'), (1, 'Username/password check failed'), (2, 'MFA authentication failed'), (3, 'Username does not exist'), (4, 'Password expired')], default=0, verbose_name='Reason'),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -4,5 +4,4 @@
|
|||
|
||||
from .user import *
|
||||
from .group import *
|
||||
from .authentication import *
|
||||
from .utils import *
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
import uuid
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from rest_framework.authtoken.models import Token
|
||||
from .user import User
|
||||
|
||||
__all__ = ['AccessKey', 'PrivateToken', 'LoginLog']
|
||||
|
||||
|
||||
class AccessKey(models.Model):
|
||||
id = models.UUIDField(verbose_name='AccessKeyID', primary_key=True,
|
||||
default=uuid.uuid4, editable=False)
|
||||
secret = models.UUIDField(verbose_name='AccessKeySecret',
|
||||
default=uuid.uuid4, editable=False)
|
||||
user = models.ForeignKey(User, verbose_name='User',
|
||||
on_delete=models.CASCADE, related_name='access_keys')
|
||||
|
||||
def get_id(self):
|
||||
return str(self.id)
|
||||
|
||||
def get_secret(self):
|
||||
return str(self.secret)
|
||||
|
||||
def get_full_value(self):
|
||||
return '{}:{}'.format(self.id, self.secret)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.id)
|
||||
|
||||
|
||||
class PrivateToken(Token):
|
||||
"""Inherit from auth token, otherwise migration is boring"""
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Private Token')
|
||||
|
||||
|
||||
class LoginLog(models.Model):
|
||||
LOGIN_TYPE_CHOICE = (
|
||||
('W', 'Web'),
|
||||
('T', 'Terminal'),
|
||||
)
|
||||
|
||||
MFA_DISABLED = 0
|
||||
MFA_ENABLED = 1
|
||||
MFA_UNKNOWN = 2
|
||||
|
||||
MFA_CHOICE = (
|
||||
(MFA_DISABLED, _('Disabled')),
|
||||
(MFA_ENABLED, _('Enabled')),
|
||||
(MFA_UNKNOWN, _('-')),
|
||||
)
|
||||
|
||||
REASON_NOTHING = 0
|
||||
REASON_PASSWORD = 1
|
||||
REASON_MFA = 2
|
||||
REASON_NOT_EXIST = 3
|
||||
REASON_PASSWORD_EXPIRED = 4
|
||||
|
||||
REASON_CHOICE = (
|
||||
(REASON_NOTHING, _('-')),
|
||||
(REASON_PASSWORD, _('Username/password check failed')),
|
||||
(REASON_MFA, _('MFA authentication failed')),
|
||||
(REASON_NOT_EXIST, _("Username does not exist")),
|
||||
(REASON_PASSWORD_EXPIRED, _("Password expired")),
|
||||
)
|
||||
|
||||
STATUS_CHOICE = (
|
||||
(True, _('Success')),
|
||||
(False, _('Failed'))
|
||||
)
|
||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||
username = models.CharField(max_length=128, verbose_name=_('Username'))
|
||||
type = models.CharField(choices=LOGIN_TYPE_CHOICE, max_length=2, verbose_name=_('Login type'))
|
||||
ip = models.GenericIPAddressField(verbose_name=_('Login ip'))
|
||||
city = models.CharField(max_length=254, blank=True, null=True, verbose_name=_('Login city'))
|
||||
user_agent = models.CharField(max_length=254, blank=True, null=True, verbose_name=_('User agent'))
|
||||
mfa = models.SmallIntegerField(default=MFA_UNKNOWN, choices=MFA_CHOICE, verbose_name=_('MFA'))
|
||||
reason = models.SmallIntegerField(default=REASON_NOTHING, choices=REASON_CHOICE, verbose_name=_('Reason'))
|
||||
status = models.BooleanField(max_length=2, default=True, choices=STATUS_CHOICE, verbose_name=_('Status'))
|
||||
datetime = models.DateTimeField(default=timezone.now, verbose_name=_('Date login'))
|
||||
|
||||
class Meta:
|
||||
ordering = ['-datetime', 'username']
|
|
@ -16,7 +16,6 @@ from django.utils import timezone
|
|||
from django.shortcuts import reverse
|
||||
|
||||
from common.utils import get_signer, date_expired_default
|
||||
from orgs.utils import current_org
|
||||
|
||||
|
||||
__all__ = ['User']
|
||||
|
@ -104,6 +103,8 @@ class User(AbstractUser):
|
|||
verbose_name=_('Date password last updated')
|
||||
)
|
||||
|
||||
user_cache_key_prefix = '_User_{}'
|
||||
|
||||
def __str__(self):
|
||||
return '{0.name}({0.username})'.format(self)
|
||||
|
||||
|
@ -281,6 +282,7 @@ class User(AbstractUser):
|
|||
self.role = 'Admin'
|
||||
self.is_active = True
|
||||
super().save(*args, **kwargs)
|
||||
self.expire_user_cache()
|
||||
|
||||
@property
|
||||
def private_token(self):
|
||||
|
@ -422,8 +424,26 @@ class User(AbstractUser):
|
|||
def delete(self, using=None, keep_parents=False):
|
||||
if self.pk == 1 or self.username == 'admin':
|
||||
return
|
||||
self.expire_user_cache()
|
||||
return super(User, self).delete()
|
||||
|
||||
def expire_user_cache(self):
|
||||
key = self.user_cache_key_prefix.format(self.id)
|
||||
cache.delete(key)
|
||||
|
||||
@classmethod
|
||||
def get_user_or_from_cache(cls, uid):
|
||||
key = cls.user_cache_key_prefix.format(uid)
|
||||
user = cache.get(key)
|
||||
if user:
|
||||
return user
|
||||
try:
|
||||
user = cls.objects.get(id=uid)
|
||||
cache.set(key, user, 3600)
|
||||
except cls.DoesNotExist:
|
||||
user = None
|
||||
return user
|
||||
|
||||
class Meta:
|
||||
ordering = ['username']
|
||||
verbose_name = _("User")
|
||||
|
|
|
@ -2,15 +2,9 @@
|
|||
#
|
||||
from django.utils.translation import ugettext as _
|
||||
from rest_framework import serializers
|
||||
from ..models import User, AccessKey
|
||||
from ..models import User
|
||||
|
||||
|
||||
class AccessKeySerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = AccessKey
|
||||
fields = ['id', 'secret']
|
||||
read_only_fields = ['id', 'secret']
|
||||
from authentication.serializers import AccessKeySerializer
|
||||
|
||||
|
||||
class ServiceAccountSerializer(serializers.ModelSerializer):
|
||||
|
|
Loading…
Reference in New Issue