diff --git a/apps/applications/migrations/0001_initial.py b/apps/applications/migrations/0001_initial.py index 221fd5e22..26948fc73 100644 --- a/apps/applications/migrations/0001_initial.py +++ b/apps/applications/migrations/0001_initial.py @@ -1,6 +1,6 @@ # Generated by Django 2.1.7 on 2019-05-20 11:04 -import common.fields.model +import common.db.fields from django.db import migrations, models import django.db.models.deletion import uuid @@ -23,7 +23,7 @@ class Migration(migrations.Migration): ('name', models.CharField(max_length=128, verbose_name='Name')), ('type', models.CharField(choices=[('Browser', (('chrome', 'Chrome'),)), ('Database tools', (('mysql_workbench', 'MySQL Workbench'),)), ('Virtualization tools', (('vmware_client', 'vSphere Client'),)), ('custom', 'Custom')], default='chrome', max_length=128, verbose_name='App type')), ('path', models.CharField(max_length=128, verbose_name='App path')), - ('params', common.fields.model.EncryptJsonDictTextField(blank=True, default={}, max_length=4096, null=True, verbose_name='Parameters')), + ('params', common.db.fields.EncryptJsonDictTextField(blank=True, default={}, max_length=4096, null=True, verbose_name='Parameters')), ('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')), ('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')), ('comment', models.TextField(blank=True, default='', max_length=128, verbose_name='Comment')), diff --git a/apps/applications/migrations/0010_appaccount_historicalappaccount.py b/apps/applications/migrations/0010_appaccount_historicalappaccount.py index fc2cf2ab9..f79fd2475 100644 --- a/apps/applications/migrations/0010_appaccount_historicalappaccount.py +++ b/apps/applications/migrations/0010_appaccount_historicalappaccount.py @@ -1,7 +1,7 @@ # Generated by Django 3.1.12 on 2021-08-26 09:07 import assets.models.base -import common.fields.model +import common.db.fields from django.conf import settings import django.core.validators from django.db import migrations, models @@ -26,9 +26,9 @@ class Migration(migrations.Migration): ('id', models.UUIDField(db_index=True, default=uuid.uuid4)), ('name', models.CharField(max_length=128, verbose_name='Name')), ('username', models.CharField(blank=True, db_index=True, max_length=128, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z_@\\-\\.]*$', 'Special char not allowed')], verbose_name='Username')), - ('password', common.fields.model.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password')), - ('private_key', common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key')), - ('public_key', common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH public key')), + ('password', common.db.fields.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password')), + ('private_key', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH private key')), + ('public_key', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH public key')), ('comment', models.TextField(blank=True, verbose_name='Comment')), ('date_created', models.DateTimeField(blank=True, editable=False, verbose_name='Date created')), ('date_updated', models.DateTimeField(blank=True, editable=False, verbose_name='Date updated')), @@ -56,9 +56,9 @@ class Migration(migrations.Migration): ('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)), ('name', models.CharField(max_length=128, verbose_name='Name')), ('username', models.CharField(blank=True, db_index=True, max_length=128, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z_@\\-\\.]*$', 'Special char not allowed')], verbose_name='Username')), - ('password', common.fields.model.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password')), - ('private_key', common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key')), - ('public_key', common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH public key')), + ('password', common.db.fields.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password')), + ('private_key', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH private key')), + ('public_key', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH public key')), ('comment', models.TextField(blank=True, verbose_name='Comment')), ('date_created', models.DateTimeField(auto_now_add=True, verbose_name='Date created')), ('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')), diff --git a/apps/assets/api/system_user.py b/apps/assets/api/system_user.py index f679b4e3f..f95303a5e 100644 --- a/apps/assets/api/system_user.py +++ b/apps/assets/api/system_user.py @@ -4,7 +4,6 @@ from rest_framework.response import Response from rest_framework.decorators import action from common.utils import get_logger, get_object_or_none -from common.utils.crypto import get_aes_crypto from common.permissions import IsValidUser from common.mixins.api import SuggestionMixin from orgs.mixins.api import OrgBulkModelViewSet @@ -102,27 +101,17 @@ class SystemUserTempAuthInfoApi(generics.CreateAPIView): permission_classes = (IsValidUser,) serializer_class = SystemUserTempAuthSerializer - def decrypt_data_if_need(self, data): - csrf_token = self.request.META.get('CSRF_COOKIE') - aes = get_aes_crypto(csrf_token, 'ECB') - password = data.get('password', '') - try: - data['password'] = aes.decrypt(password) - except: - pass - return data - def create(self, request, *args, **kwargs): serializer = super().get_serializer(data=request.data) serializer.is_valid(raise_exception=True) pk = kwargs.get('pk') - data = self.decrypt_data_if_need(serializer.validated_data) - instance_id = data.get('instance_id') + data = serializer.validated_data + asset_or_app_id = data.get('instance_id') with tmp_to_root_org(): instance = get_object_or_404(SystemUser, pk=pk) - instance.set_temp_auth(instance_id, self.request.user.id, data) + instance.set_temp_auth(asset_or_app_id, self.request.user.id, data) return Response(serializer.data, status=201) diff --git a/apps/assets/migrations/0032_auto_20190624_2108.py b/apps/assets/migrations/0032_auto_20190624_2108.py index 441f13cdb..275308e99 100644 --- a/apps/assets/migrations/0032_auto_20190624_2108.py +++ b/apps/assets/migrations/0032_auto_20190624_2108.py @@ -1,7 +1,7 @@ # Generated by Django 2.1.7 on 2019-06-24 13:08 import assets.models.utils -import common.fields.model +import common.db.fields from django.db import migrations @@ -15,61 +15,61 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='adminuser', name='_password', - field=common.fields.model.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password'), + field=common.db.fields.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password'), ), migrations.AlterField( model_name='adminuser', name='_private_key', - field=common.fields.model.EncryptTextField(blank=True, null=True, validators=[assets.models.utils.private_key_validator], verbose_name='SSH private key'), + field=common.db.fields.EncryptTextField(blank=True, null=True, validators=[assets.models.utils.private_key_validator], verbose_name='SSH private key'), ), migrations.AlterField( model_name='adminuser', name='_public_key', - field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH public key'), + field=common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH public key'), ), migrations.AlterField( model_name='authbook', name='_password', - field=common.fields.model.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password'), + field=common.db.fields.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password'), ), migrations.AlterField( model_name='authbook', name='_private_key', - field=common.fields.model.EncryptTextField(blank=True, null=True, validators=[assets.models.utils.private_key_validator], verbose_name='SSH private key'), + field=common.db.fields.EncryptTextField(blank=True, null=True, validators=[assets.models.utils.private_key_validator], verbose_name='SSH private key'), ), migrations.AlterField( model_name='authbook', name='_public_key', - field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH public key'), + field=common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH public key'), ), migrations.AlterField( model_name='gateway', name='_password', - field=common.fields.model.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password'), + field=common.db.fields.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password'), ), migrations.AlterField( model_name='gateway', name='_private_key', - field=common.fields.model.EncryptTextField(blank=True, null=True, validators=[assets.models.utils.private_key_validator], verbose_name='SSH private key'), + field=common.db.fields.EncryptTextField(blank=True, null=True, validators=[assets.models.utils.private_key_validator], verbose_name='SSH private key'), ), migrations.AlterField( model_name='gateway', name='_public_key', - field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH public key'), + field=common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH public key'), ), migrations.AlterField( model_name='systemuser', name='_password', - field=common.fields.model.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password'), + field=common.db.fields.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password'), ), migrations.AlterField( model_name='systemuser', name='_private_key', - field=common.fields.model.EncryptTextField(blank=True, null=True, validators=[assets.models.utils.private_key_validator], verbose_name='SSH private key'), + field=common.db.fields.EncryptTextField(blank=True, null=True, validators=[assets.models.utils.private_key_validator], verbose_name='SSH private key'), ), migrations.AlterField( model_name='systemuser', name='_public_key', - field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH public key'), + field=common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH public key'), ), ] diff --git a/apps/assets/migrations/0035_auto_20190711_2018.py b/apps/assets/migrations/0035_auto_20190711_2018.py index 9dcbad1db..00eb41fe5 100644 --- a/apps/assets/migrations/0035_auto_20190711_2018.py +++ b/apps/assets/migrations/0035_auto_20190711_2018.py @@ -1,6 +1,6 @@ # Generated by Django 2.1.7 on 2019-07-11 12:18 -import common.fields.model +import common.db.fields from django.db import migrations @@ -14,21 +14,21 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='adminuser', name='private_key', - field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'), + field=common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'), ), migrations.AlterField( model_name='authbook', name='private_key', - field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'), + field=common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'), ), migrations.AlterField( model_name='gateway', name='private_key', - field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'), + field=common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'), ), migrations.AlterField( model_name='systemuser', name='private_key', - field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'), + field=common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'), ), ] diff --git a/apps/assets/migrations/0044_platform.py b/apps/assets/migrations/0044_platform.py index 8d45a8ee3..2e1ab723e 100644 --- a/apps/assets/migrations/0044_platform.py +++ b/apps/assets/migrations/0044_platform.py @@ -1,6 +1,6 @@ # Generated by Django 2.2.7 on 2019-12-06 07:26 -import common.fields.model +import common.db.fields from django.db import migrations, models @@ -36,7 +36,7 @@ class Migration(migrations.Migration): ('name', models.SlugField(allow_unicode=True, unique=True, verbose_name='Name')), ('base', models.CharField(choices=[('Linux', 'Linux'), ('Unix', 'Unix'), ('MacOS', 'MacOS'), ('BSD', 'BSD'), ('Windows', 'Windows'), ('Other', 'Other')], default='Linux', max_length=16, verbose_name='Base')), ('charset', models.CharField(choices=[('utf8', 'UTF-8'), ('gbk', 'GBK')], default='utf8', max_length=8, verbose_name='Charset')), - ('meta', common.fields.model.JsonDictTextField(blank=True, null=True, verbose_name='Meta')), + ('meta', common.db.fields.JsonDictTextField(blank=True, null=True, verbose_name='Meta')), ('internal', models.BooleanField(default=False, verbose_name='Internal')), ('comment', models.TextField(blank=True, null=True, verbose_name='Comment')), ], diff --git a/apps/assets/migrations/0072_historicalauthbook.py b/apps/assets/migrations/0072_historicalauthbook.py index 978584824..e28949c1f 100644 --- a/apps/assets/migrations/0072_historicalauthbook.py +++ b/apps/assets/migrations/0072_historicalauthbook.py @@ -1,6 +1,6 @@ # Generated by Django 3.1.6 on 2021-06-05 16:10 -import common.fields.model +import common.db.fields from django.conf import settings import django.core.validators from django.db import migrations, models @@ -58,9 +58,9 @@ class Migration(migrations.Migration): ('id', models.UUIDField(db_index=True, default=uuid.uuid4)), ('name', models.CharField(max_length=128, verbose_name='Name')), ('username', models.CharField(blank=True, db_index=True, max_length=128, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z_@\\-\\.]*$', 'Special char not allowed')], verbose_name='Username')), - ('password', common.fields.model.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password')), - ('private_key', common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key')), - ('public_key', common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH public key')), + ('password', common.db.fields.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password')), + ('private_key', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH private key')), + ('public_key', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='SSH public key')), ('comment', models.TextField(blank=True, verbose_name='Comment')), ('date_created', models.DateTimeField(blank=True, editable=False, verbose_name='Date created')), ('date_updated', models.DateTimeField(blank=True, editable=False, verbose_name='Date updated')), diff --git a/apps/assets/models/asset.py b/apps/assets/models/asset.py index 85ac6c918..7dde0862f 100644 --- a/apps/assets/models/asset.py +++ b/apps/assets/models/asset.py @@ -11,7 +11,7 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ from rest_framework.exceptions import ValidationError -from common.fields.model import JsonDictTextField +from common.db.fields import JsonDictTextField from common.utils import lazyproperty from orgs.mixins.models import OrgModelMixin, OrgManager diff --git a/apps/assets/models/base.py b/apps/assets/models/base.py index 38b7218c4..493036efc 100644 --- a/apps/assets/models/base.py +++ b/apps/assets/models/base.py @@ -19,7 +19,7 @@ from common.utils import ( ) from common.utils.encode import ssh_pubkey_gen from common.validators import alphanumeric -from common import fields +from common.db import fields from orgs.mixins.models import OrgModelMixin diff --git a/apps/assets/serializers/base.py b/apps/assets/serializers/base.py index 2f3486d01..7c8760562 100644 --- a/apps/assets/serializers/base.py +++ b/apps/assets/serializers/base.py @@ -6,12 +6,13 @@ from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers from common.utils import ssh_pubkey_gen, ssh_private_key_gen, validate_ssh_private_key +from common.drf.fields import EncryptedField from assets.models import Type class AuthSerializer(serializers.ModelSerializer): - password = serializers.CharField(required=False, allow_blank=True, allow_null=True, max_length=1024) - private_key = serializers.CharField(required=False, allow_blank=True, allow_null=True, max_length=4096) + password = EncryptedField(required=False, allow_blank=True, allow_null=True, max_length=1024) + private_key = EncryptedField(required=False, allow_blank=True, allow_null=True, max_length=4096) def gen_keys(self, private_key=None, password=None): if private_key is None: @@ -31,6 +32,8 @@ class AuthSerializer(serializers.ModelSerializer): class AuthSerializerMixin(serializers.ModelSerializer): + password = EncryptedField(required=False, allow_blank=True, allow_null=True, max_length=1024) + private_key = EncryptedField(required=False, allow_blank=True, allow_null=True, max_length=4096) passphrase = serializers.CharField( allow_blank=True, allow_null=True, required=False, max_length=512, write_only=True, label=_('Key password') diff --git a/apps/audits/migrations/0014_auto_20220505_1902.py b/apps/audits/migrations/0014_auto_20220505_1902.py new file mode 100644 index 000000000..8c483560c --- /dev/null +++ b/apps/audits/migrations/0014_auto_20220505_1902.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.14 on 2022-05-05 11:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('audits', '0013_auto_20211130_1037'), + ] + + operations = [ + migrations.AlterField( + model_name='operatelog', + name='action', + field=models.CharField(choices=[('create', 'Create'), ('view', 'View'), ('update', 'Update'), ('delete', 'Delete')], max_length=16, verbose_name='Action'), + ), + ] diff --git a/apps/authentication/api/token.py b/apps/authentication/api/token.py index e5fe8bf2c..3bc8a33d1 100644 --- a/apps/authentication/api/token.py +++ b/apps/authentication/api/token.py @@ -27,8 +27,10 @@ class TokenCreateApi(AuthMixin, CreateAPIView): def create(self, request, *args, **kwargs): self.create_session_if_need() # 如果认证没有过,检查账号密码 + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) try: - user = self.check_user_auth_if_need() + user = self.get_user_or_auth(serializer.validated_data) self.check_user_mfa_if_need(user) self.check_user_login_confirm_if_need(user) self.send_auth_signal(success=True, user=user) diff --git a/apps/authentication/forms.py b/apps/authentication/forms.py index 16ca659c0..bd7fa7d67 100644 --- a/apps/authentication/forms.py +++ b/apps/authentication/forms.py @@ -1,15 +1,25 @@ # -*- coding: utf-8 -*- # - from django import forms from django.conf import settings from django.utils.translation import ugettext_lazy as _ from captcha.fields import CaptchaField, CaptchaTextInput +from common.utils import get_logger, rsa_decrypt_by_session_pkey + +logger = get_logger(__name__) + + +class EncryptedField(forms.CharField): + def to_python(self, value): + value = super().to_python(value) + return rsa_decrypt_by_session_pkey(value) + class UserLoginForm(forms.Form): days_auto_login = int(settings.SESSION_COOKIE_AGE / 3600 / 24) - disable_days_auto_login = settings.SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE or days_auto_login < 1 + disable_days_auto_login = settings.SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE \ + or days_auto_login < 1 username = forms.CharField( label=_('Username'), max_length=100, @@ -18,7 +28,7 @@ class UserLoginForm(forms.Form): 'autofocus': 'autofocus' }) ) - password = forms.CharField( + password = EncryptedField( label=_('Password'), widget=forms.PasswordInput, max_length=1024, strip=False ) diff --git a/apps/authentication/middleware.py b/apps/authentication/middleware.py index 42bbb27cb..d2b4ff19e 100644 --- a/apps/authentication/middleware.py +++ b/apps/authentication/middleware.py @@ -1,8 +1,12 @@ +import base64 + from django.shortcuts import redirect, reverse from django.utils.deprecation import MiddlewareMixin from django.http import HttpResponse from django.conf import settings +from common.utils import gen_key_pair + class MFAMiddleware: """ @@ -48,3 +52,28 @@ class SessionCookieMiddleware(MiddlewareMixin): return response response.set_cookie(key, value) return response + + +class EncryptedMiddleware: + def __init__(self, get_response): + self.get_response = get_response + + @staticmethod + def check_key_pair(request, response): + pub_key_name = settings.SESSION_RSA_PUBLIC_KEY_NAME + public_key = request.session.get(pub_key_name) + cookie_key = request.COOKIES.get(pub_key_name) + if public_key and public_key == cookie_key: + return + + pri_key_name = settings.SESSION_RSA_PRIVATE_KEY_NAME + private_key, public_key = gen_key_pair() + public_key_decode = base64.b64encode(public_key.encode()).decode() + request.session[pub_key_name] = public_key_decode + request.session[pri_key_name] = private_key + response.set_cookie(pub_key_name, public_key_decode) + + def __call__(self, request): + response = self.get_response(request) + self.check_key_pair(request, response) + return response diff --git a/apps/authentication/mixins.py b/apps/authentication/mixins.py index 56216e91f..698601d4c 100644 --- a/apps/authentication/mixins.py +++ b/apps/authentication/mixins.py @@ -23,9 +23,7 @@ from acls.models import LoginACL from users.models import User from users.utils import LoginBlockUtil, MFABlockUtils, LoginIpBlockUtil from . import errors -from .utils import rsa_decrypt, gen_key_pair from .signals import post_auth_success, post_auth_failed -from .const import RSA_PRIVATE_KEY, RSA_PUBLIC_KEY logger = get_logger(__name__) @@ -91,46 +89,8 @@ def authenticate(request=None, **credentials): auth.authenticate = authenticate -class PasswordEncryptionViewMixin: - request = None - - def get_decrypted_password(self, password=None, username=None): - request = self.request - if hasattr(request, 'data'): - data = request.data - else: - data = request.POST - - username = username or data.get('username') - password = password or data.get('password') - - password = self.decrypt_passwd(password) - if not password: - self.raise_password_decrypt_failed(username=username) - return password - - def raise_password_decrypt_failed(self, username): - ip = self.get_request_ip() - raise errors.CredentialError( - error=errors.reason_password_decrypt_failed, - username=username, ip=ip, request=self.request - ) - - def decrypt_passwd(self, raw_passwd): - # 获取解密密钥,对密码进行解密 - rsa_private_key = self.request.session.get(RSA_PRIVATE_KEY) - if rsa_private_key is None: - return raw_passwd - - try: - return rsa_decrypt(raw_passwd, rsa_private_key) - except Exception as e: - logger.error(e, exc_info=True) - logger.error( - f'Decrypt password failed: password[{raw_passwd}] ' - f'rsa_private_key[{rsa_private_key}]' - ) - return None +class CommonMixin: + request: Request def get_request_ip(self): ip = '' @@ -139,26 +99,6 @@ class PasswordEncryptionViewMixin: ip = ip or get_request_ip(self.request) return ip - def get_context_data(self, **kwargs): - # 生成加解密密钥对,public_key传递给前端,private_key存入session中供解密使用 - rsa_public_key = self.request.session.get(RSA_PUBLIC_KEY) - rsa_private_key = self.request.session.get(RSA_PRIVATE_KEY) - if not all([rsa_private_key, rsa_public_key]): - rsa_private_key, rsa_public_key = gen_key_pair() - rsa_public_key = rsa_public_key.replace('\n', '\\n') - self.request.session[RSA_PRIVATE_KEY] = rsa_private_key - self.request.session[RSA_PUBLIC_KEY] = rsa_public_key - - kwargs.update({ - 'rsa_public_key': rsa_public_key, - }) - return super().get_context_data(**kwargs) - - -class CommonMixin(PasswordEncryptionViewMixin): - request: Request - get_request_ip: Callable - def raise_credential_error(self, error): raise self.partial_credential_error(error=error) @@ -193,20 +133,13 @@ class CommonMixin(PasswordEncryptionViewMixin): user.backend = self.request.session.get("auth_backend") return user - def get_auth_data(self, decrypt_passwd=False): + def get_auth_data(self, data): request = self.request - if hasattr(request, 'data'): - data = request.data - else: - data = request.POST items = ['username', 'password', 'challenge', 'public_key', 'auto_login'] username, password, challenge, public_key, auto_login = bulk_get(data, items, default='') ip = self.get_request_ip() self._set_partial_credential_error(username=username, ip=ip, request=request) - - if decrypt_passwd: - password = self.get_decrypted_password() password = password + challenge.strip() return username, password, public_key, ip, auto_login @@ -482,10 +415,10 @@ class AuthMixin(CommonMixin, AuthPreCheckMixin, AuthACLMixin, MFAMixin, AuthPost need = cache.get(self.key_prefix_captcha.format(ip)) return need - def check_user_auth(self, decrypt_passwd=False): + def check_user_auth(self, valid_data=None): # pre check self.check_is_block() - username, password, public_key, ip, auto_login = self.get_auth_data(decrypt_passwd) + username, password, public_key, ip, auto_login = self.get_auth_data(valid_data) self._check_only_allow_exists_user_auth(username) # check auth @@ -537,11 +470,12 @@ class AuthMixin(CommonMixin, AuthPreCheckMixin, AuthACLMixin, MFAMixin, AuthPost self.mark_password_ok(user, False) return user - def check_user_auth_if_need(self, decrypt_passwd=False): + def get_user_or_auth(self, valid_data): request = self.request - if not request.session.get('auth_password'): - return self.check_user_auth(decrypt_passwd=decrypt_passwd) - return self.get_user_from_session() + if request.session.get('auth_password'): + return self.get_user_from_session() + else: + return self.check_user_auth(valid_data) def clear_auth_mark(self): keys = ['auth_password', 'user_id', 'auth_confirm', 'auth_ticket_id'] diff --git a/apps/authentication/serializers/password_mfa.py b/apps/authentication/serializers/password_mfa.py index c4c0679c6..cf3452af3 100644 --- a/apps/authentication/serializers/password_mfa.py +++ b/apps/authentication/serializers/password_mfa.py @@ -2,6 +2,8 @@ # from rest_framework import serializers +from common.drf.fields import EncryptedField + __all__ = [ 'OtpVerifySerializer', 'MFAChallengeSerializer', 'MFASelectTypeSerializer', @@ -10,7 +12,7 @@ __all__ = [ class PasswordVerifySerializer(serializers.Serializer): - password = serializers.CharField() + password = EncryptedField() class MFASelectTypeSerializer(serializers.Serializer): diff --git a/apps/authentication/templates/authentication/login.html b/apps/authentication/templates/authentication/login.html index 677ee70d4..477df7af4 100644 --- a/apps/authentication/templates/authentication/login.html +++ b/apps/authentication/templates/authentication/login.html @@ -161,6 +161,7 @@ {{ JMS_TITLE }}
+
{% csrf_token %}
@@ -241,20 +242,10 @@ {% include '_foot_js.html' %} + {% endblock %} diff --git a/apps/users/templates/users/user_password_verify.html b/apps/users/templates/users/user_password_verify.html index bfc72ee87..65dacc75d 100644 --- a/apps/users/templates/users/user_password_verify.html +++ b/apps/users/templates/users/user_password_verify.html @@ -15,10 +15,23 @@ {% endif %} {% csrf_token %}
- +
+ {% endblock %} + diff --git a/apps/users/views/profile/password.py b/apps/users/views/profile/password.py index 7c69dccd3..bb51b8aa4 100644 --- a/apps/users/views/profile/password.py +++ b/apps/users/views/profile/password.py @@ -7,7 +7,7 @@ from django.shortcuts import redirect from django.utils.translation import ugettext as _ from django.views.generic.edit import FormView -from authentication.mixins import PasswordEncryptionViewMixin, AuthMixin +from authentication.mixins import AuthMixin from authentication import errors from common.utils import get_logger @@ -31,7 +31,7 @@ class UserVerifyPasswordView(AuthMixin, FormView): return redirect('authentication:login') try: - password = self.get_decrypted_password(username=user.username) + password = form.cleaned_data['password'] except errors.AuthFailedError as e: form.add_error("password", _(f"Password invalid") + f'({e.msg})') return self.form_invalid(form)