mirror of https://github.com/jumpserver/jumpserver
Co-authored-by: xinwen <coderWen@126.com>pull/5201/head
parent
80b03e73f6
commit
7c7de96158
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.1 on 2020-12-09 03:03
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('audits', '0010_auto_20200811_1122'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='userloginlog',
|
||||||
|
name='backend',
|
||||||
|
field=models.CharField(default='', max_length=32, verbose_name='Login backend'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -105,6 +105,7 @@ class UserLoginLog(models.Model):
|
||||||
reason = models.CharField(default='', max_length=128, blank=True, verbose_name=_('Reason'))
|
reason = models.CharField(default='', max_length=128, blank=True, verbose_name=_('Reason'))
|
||||||
status = models.BooleanField(max_length=2, default=True, choices=STATUS_CHOICE, verbose_name=_('Status'))
|
status = models.BooleanField(max_length=2, default=True, choices=STATUS_CHOICE, verbose_name=_('Status'))
|
||||||
datetime = models.DateTimeField(default=timezone.now, verbose_name=_('Date login'))
|
datetime = models.DateTimeField(default=timezone.now, verbose_name=_('Date login'))
|
||||||
|
backend = models.CharField(max_length=32, default='', verbose_name=_('Login backend'))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_login_logs(cls, date_from=None, date_to=None, user=None, keyword=None):
|
def get_login_logs(cls, date_from=None, date_to=None, user=None, keyword=None):
|
||||||
|
|
|
@ -31,7 +31,8 @@ class UserLoginLogSerializer(serializers.ModelSerializer):
|
||||||
model = models.UserLoginLog
|
model = models.UserLoginLog
|
||||||
fields = (
|
fields = (
|
||||||
'id', 'username', 'type', 'type_display', 'ip', 'city', 'user_agent',
|
'id', 'username', 'type', 'type_display', 'ip', 'city', 'user_agent',
|
||||||
'mfa', 'reason', 'status', 'status_display', 'datetime', 'mfa_display'
|
'mfa', 'reason', 'status', 'status_display', 'datetime', 'mfa_display',
|
||||||
|
'backend'
|
||||||
)
|
)
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
"user_agent": {'label': _('User agent')}
|
"user_agent": {'label': _('User agent')}
|
||||||
|
|
|
@ -5,6 +5,8 @@ from django.db.models.signals import post_save, post_delete
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from django.contrib.auth import BACKEND_SESSION_KEY
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from rest_framework.renderers import JSONRenderer
|
from rest_framework.renderers import JSONRenderer
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
|
|
||||||
|
@ -32,6 +34,19 @@ MODELS_NEED_RECORD = (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
LOGIN_BACKEND = {
|
||||||
|
'PublicKeyAuthBackend': _('SSH Key'),
|
||||||
|
'RadiusBackend': User.Source.radius.label,
|
||||||
|
'RadiusRealmBackend': User.Source.radius.label,
|
||||||
|
'LDAPAuthorizationBackend': User.Source.ldap.label,
|
||||||
|
'ModelBackend': _('Password'),
|
||||||
|
'SSOAuthentication': _('SSO'),
|
||||||
|
'CASBackend': User.Source.cas.label,
|
||||||
|
'OIDCAuthCodeBackend': User.Source.openid.label,
|
||||||
|
'OIDCAuthPasswordBackend': User.Source.openid.label,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def create_operate_log(action, sender, resource):
|
def create_operate_log(action, sender, resource):
|
||||||
user = current_request.user if current_request else None
|
user = current_request.user if current_request else None
|
||||||
if not user or not user.is_authenticated:
|
if not user or not user.is_authenticated:
|
||||||
|
@ -109,6 +124,12 @@ def on_audits_log_create(sender, instance=None, **kwargs):
|
||||||
sys_logger.info(msg)
|
sys_logger.info(msg)
|
||||||
|
|
||||||
|
|
||||||
|
def get_login_backend(request):
|
||||||
|
backend = request.session.get(BACKEND_SESSION_KEY, '')
|
||||||
|
backend = backend.rsplit('.', maxsplit=1)[-1]
|
||||||
|
return LOGIN_BACKEND.get(backend, '')
|
||||||
|
|
||||||
|
|
||||||
def generate_data(username, request):
|
def generate_data(username, request):
|
||||||
user_agent = request.META.get('HTTP_USER_AGENT', '')
|
user_agent = request.META.get('HTTP_USER_AGENT', '')
|
||||||
login_ip = get_request_ip(request) or '0.0.0.0'
|
login_ip = get_request_ip(request) or '0.0.0.0'
|
||||||
|
@ -122,7 +143,8 @@ def generate_data(username, request):
|
||||||
'ip': login_ip,
|
'ip': login_ip,
|
||||||
'type': login_type,
|
'type': login_type,
|
||||||
'user_agent': user_agent,
|
'user_agent': user_agent,
|
||||||
'datetime': timezone.now()
|
'datetime': timezone.now(),
|
||||||
|
'backend': get_login_backend(request)
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ class CreateUserMixin:
|
||||||
email_suffix = settings.EMAIL_SUFFIX
|
email_suffix = settings.EMAIL_SUFFIX
|
||||||
email = '{}@{}'.format(username, email_suffix)
|
email = '{}@{}'.format(username, email_suffix)
|
||||||
user = User(username=username, name=username, email=email)
|
user = User(username=username, name=username, email=email)
|
||||||
user.source = user.SOURCE_RADIUS
|
user.source = user.Source.radius.value
|
||||||
user.save()
|
user.save()
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import uuid
|
import uuid
|
||||||
from functools import partial
|
|
||||||
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import ugettext_lazy as _, ugettext as __
|
from django.utils.translation import ugettext_lazy as _, ugettext as __
|
||||||
from rest_framework.authtoken.models import Token
|
from rest_framework.authtoken.models import Token
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.crypto import get_random_string
|
|
||||||
|
|
||||||
from common.db import models
|
from common.db import models
|
||||||
from common.mixins.models import CommonModelMixin
|
from common.mixins.models import CommonModelMixin
|
||||||
|
|
|
@ -333,7 +333,7 @@ class LDAPImportUtil(object):
|
||||||
def update_or_create(self, user):
|
def update_or_create(self, user):
|
||||||
user['email'] = self.get_user_email(user)
|
user['email'] = self.get_user_email(user)
|
||||||
if user['username'] not in ['admin']:
|
if user['username'] not in ['admin']:
|
||||||
user['source'] = User.SOURCE_LDAP
|
user['source'] = User.Source.ldap.value
|
||||||
obj, created = User.objects.update_or_create(
|
obj, created = User.objects.update_or_create(
|
||||||
username=user['username'], defaults=user
|
username=user['username'], defaults=user
|
||||||
)
|
)
|
||||||
|
|
|
@ -28,7 +28,7 @@ class UserCreateUpdateFormMixin(OrgModelForm):
|
||||||
)
|
)
|
||||||
source = forms.ChoiceField(
|
source = forms.ChoiceField(
|
||||||
choices=get_source_choices, required=True,
|
choices=get_source_choices, required=True,
|
||||||
initial=User.SOURCE_LOCAL, label=_("Source")
|
initial=User.Source.local.value, label=_("Source")
|
||||||
)
|
)
|
||||||
public_key = forms.CharField(
|
public_key = forms.CharField(
|
||||||
label=_('ssh public key'), max_length=5000, required=False,
|
label=_('ssh public key'), max_length=5000, required=False,
|
||||||
|
|
|
@ -7,10 +7,10 @@ import string
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.hashers import make_password
|
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import TextChoices
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -481,18 +481,12 @@ class MFAMixin:
|
||||||
|
|
||||||
|
|
||||||
class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, AbstractUser):
|
class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, AbstractUser):
|
||||||
SOURCE_LOCAL = 'local'
|
class Source(TextChoices):
|
||||||
SOURCE_LDAP = 'ldap'
|
local = 'local', _('Local')
|
||||||
SOURCE_OPENID = 'openid'
|
ldap = 'ldap', 'LDAP/AD'
|
||||||
SOURCE_RADIUS = 'radius'
|
openid = 'openid', 'OpenID'
|
||||||
SOURCE_CAS = 'cas'
|
radius = 'radius', 'Radius'
|
||||||
SOURCE_CHOICES = (
|
cas = 'cas', 'CAS'
|
||||||
(SOURCE_LOCAL, _('Local')),
|
|
||||||
(SOURCE_LDAP, 'LDAP/AD'),
|
|
||||||
(SOURCE_OPENID, 'OpenID'),
|
|
||||||
(SOURCE_RADIUS, 'Radius'),
|
|
||||||
(SOURCE_CAS, 'CAS'),
|
|
||||||
)
|
|
||||||
|
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
username = models.CharField(
|
username = models.CharField(
|
||||||
|
@ -542,7 +536,7 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, AbstractUser):
|
||||||
max_length=30, default='', blank=True, verbose_name=_('Created by')
|
max_length=30, default='', blank=True, verbose_name=_('Created by')
|
||||||
)
|
)
|
||||||
source = models.CharField(
|
source = models.CharField(
|
||||||
max_length=30, default=SOURCE_LOCAL, choices=SOURCE_CHOICES,
|
max_length=30, default=Source.local.value, choices=Source.choices,
|
||||||
verbose_name=_('Source')
|
verbose_name=_('Source')
|
||||||
)
|
)
|
||||||
date_password_last_updated = models.DateTimeField(
|
date_password_last_updated = models.DateTimeField(
|
||||||
|
@ -593,7 +587,7 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, AbstractUser):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_local(self):
|
def is_local(self):
|
||||||
return self.source == self.SOURCE_LOCAL
|
return self.source == self.Source.local.value
|
||||||
|
|
||||||
def set_unprovide_attr_if_need(self):
|
def set_unprovide_attr_if_need(self):
|
||||||
if not self.name:
|
if not self.name:
|
||||||
|
@ -663,6 +657,6 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, AbstractUser):
|
||||||
user.groups.add(UserGroup.initial())
|
user.groups.add(UserGroup.initial())
|
||||||
|
|
||||||
def can_send_created_mail(self):
|
def can_send_created_mail(self):
|
||||||
if self.email and self.source == self.SOURCE_LOCAL:
|
if self.email and self.source == self.Source.local.value:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -28,7 +28,7 @@ def on_user_create(sender, user=None, **kwargs):
|
||||||
@receiver(cas_user_authenticated)
|
@receiver(cas_user_authenticated)
|
||||||
def on_cas_user_authenticated(sender, user, created, **kwargs):
|
def on_cas_user_authenticated(sender, user, created, **kwargs):
|
||||||
if created:
|
if created:
|
||||||
user.source = user.SOURCE_CAS
|
user.source = user.Source.cas.value
|
||||||
user.save()
|
user.save()
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ def on_ldap_create_user(sender, user, ldap_user, **kwargs):
|
||||||
if user and user.username not in ['admin']:
|
if user and user.username not in ['admin']:
|
||||||
exists = User.objects.filter(username=user.username).exists()
|
exists = User.objects.filter(username=user.username).exists()
|
||||||
if not exists:
|
if not exists:
|
||||||
user.source = user.SOURCE_LDAP
|
user.source = user.Source.ldap.value
|
||||||
user.save()
|
user.save()
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,9 +46,9 @@ def on_openid_create_or_update_user(sender, request, user, created, name, userna
|
||||||
if created:
|
if created:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Receive OpenID user created signal: {}, "
|
"Receive OpenID user created signal: {}, "
|
||||||
"Set user source is: {}".format(user, User.SOURCE_OPENID)
|
"Set user source is: {}".format(user, User.Source.openid.value)
|
||||||
)
|
)
|
||||||
user.source = User.SOURCE_OPENID
|
user.source = User.Source.openid.value
|
||||||
user.save()
|
user.save()
|
||||||
elif not created and settings.AUTH_OPENID_ALWAYS_UPDATE_USER:
|
elif not created and settings.AUTH_OPENID_ALWAYS_UPDATE_USER:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
|
|
|
@ -22,7 +22,7 @@ logger = get_logger(__file__)
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def check_password_expired():
|
def check_password_expired():
|
||||||
users = User.objects.filter(source=User.SOURCE_LOCAL).exclude(role=User.ROLE.APP)
|
users = User.objects.filter(source=User.Source.local.value).exclude(role=User.ROLE.APP)
|
||||||
for user in users:
|
for user in users:
|
||||||
if not user.is_valid:
|
if not user.is_valid:
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -362,18 +362,17 @@ def get_current_org_members(exclude=()):
|
||||||
|
|
||||||
def get_source_choices():
|
def get_source_choices():
|
||||||
from .models import User
|
from .models import User
|
||||||
choices_all = dict(User.SOURCE_CHOICES)
|
|
||||||
choices = [
|
choices = [
|
||||||
(User.SOURCE_LOCAL, choices_all[User.SOURCE_LOCAL]),
|
(User.Source.local.value, User.Source.local.label),
|
||||||
]
|
]
|
||||||
if settings.AUTH_LDAP:
|
if settings.AUTH_LDAP:
|
||||||
choices.append((User.SOURCE_LDAP, choices_all[User.SOURCE_LDAP]))
|
choices.append((User.Source.ldap.value, User.Source.ldap.label))
|
||||||
if settings.AUTH_OPENID:
|
if settings.AUTH_OPENID:
|
||||||
choices.append((User.SOURCE_OPENID, choices_all[User.SOURCE_OPENID]))
|
choices.append((User.Source.openid.value, User.Source.openid.label))
|
||||||
if settings.AUTH_RADIUS:
|
if settings.AUTH_RADIUS:
|
||||||
choices.append((User.SOURCE_RADIUS, choices_all[User.SOURCE_RADIUS]))
|
choices.append((User.Source.radius.value, User.Source.radius.label))
|
||||||
if settings.AUTH_CAS:
|
if settings.AUTH_CAS:
|
||||||
choices.append((User.SOURCE_CAS, choices_all[User.SOURCE_CAS]))
|
choices.append((User.Source.cas.value, User.Source.cas.label))
|
||||||
return choices
|
return choices
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue