Merge pull request #8268 from jumpserver/dev

v2.22.0-rc4
pull/8289/head
Jiangjie.Bai 2022-05-18 19:49:11 +08:00 committed by GitHub
commit 33090c4cdf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 55 additions and 30 deletions

View File

@ -5,6 +5,7 @@ from django.db.models import Count
from common.mixins.serializers import BulkSerializerMixin
from common.utils import ssh_pubkey_gen
from common.drf.fields import EncryptedField
from common.drf.serializers import SecretReadableMixin
from common.validators import alphanumeric_re, alphanumeric_cn_re, alphanumeric_win_re
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from ..models import SystemUser, Asset
@ -252,7 +253,7 @@ class MiniSystemUserSerializer(serializers.ModelSerializer):
fields = SystemUserSerializer.Meta.fields_mini
class SystemUserWithAuthInfoSerializer(SystemUserSerializer):
class SystemUserWithAuthInfoSerializer(SecretReadableMixin, SystemUserSerializer):
class Meta(SystemUserSerializer.Meta):
fields_mini = ['id', 'name', 'username']
fields_write_only = ['password', 'public_key', 'private_key']
@ -268,6 +269,9 @@ class SystemUserWithAuthInfoSerializer(SystemUserSerializer):
'assets_amount': {'label': _('Asset')},
'login_mode_display': {'label': _('Login mode display')},
'created_by': {'read_only': True},
'password': {'write_only': False},
'private_key': {'write_only': False},
'token': {'write_only': False}
}

View File

@ -281,6 +281,11 @@ class OIDCAuthPasswordBackend(OIDCBaseBackend):
try:
claims_response.raise_for_status()
claims = claims_response.json()
preferred_username = claims.get('preferred_username')
if preferred_username and \
preferred_username.lower() == username.lower() and \
preferred_username != username:
return
except Exception as e:
error = "Json claims response error, claims response " \
"content is: {}, error is: {}".format(claims_response.content, str(e))
@ -309,5 +314,3 @@ class OIDCAuthPasswordBackend(OIDCBaseBackend):
openid_user_login_failed.send(
sender=self.__class__, request=request, username=username, reason="User is invalid"
)
return None

View File

@ -45,21 +45,7 @@ class MFAMiddleware:
class SessionCookieMiddleware(MiddlewareMixin):
@staticmethod
def process_response(request, response: HttpResponse):
key = settings.SESSION_COOKIE_NAME_PREFIX_KEY
value = settings.SESSION_COOKIE_NAME_PREFIX
if request.COOKIES.get(key) == value:
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):
def set_cookie_public_key(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)
@ -73,7 +59,29 @@ class EncryptedMiddleware:
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)
@staticmethod
def set_cookie_session_prefix(request, response):
key = settings.SESSION_COOKIE_NAME_PREFIX_KEY
value = settings.SESSION_COOKIE_NAME_PREFIX
if request.COOKIES.get(key) == value:
return response
response.set_cookie(key, value)
@staticmethod
def set_cookie_session_expire(request, response):
if not request.session.get('auth_session_expiration_required'):
return
value = 'age'
if settings.SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE or \
not request.session.get('auto_login', False):
value = 'close'
age = request.session.get_expiry_age()
response.set_cookie('jms_session_expire', value, max_age=age)
request.session.pop('auth_session_expiration_required', None)
def process_response(self, request, response: HttpResponse):
self.set_cookie_session_prefix(request, response)
self.set_cookie_public_key(request, response)
self.set_cookie_session_expire(request, response)
return response

View File

@ -35,6 +35,9 @@ def on_user_auth_login_success(sender, user, request, **kwargs):
session.delete()
cache.set(lock_key, request.session.session_key, None)
# 标记登录,设置 cookie前端可以控制刷新, Middleware 会拦截这个生成 cookie
request.session['auth_session_expiration_required'] = 1
@receiver(openid_user_login_success)
def on_oidc_user_login_success(sender, request, user, create=False, **kwargs):

View File

@ -91,12 +91,13 @@ class AESCrypto:
def encrypt(self, text):
aes = self.aes()
return str(base64.encodebytes(aes.encrypt(self.to_16(text))),
encoding='utf8').replace('\n', '') # 加密
cipher = base64.encodebytes(aes.encrypt(self.to_16(text)))
return str(cipher, encoding='utf8').replace('\n', '') # 加密
def decrypt(self, text):
aes = self.aes()
return str(aes.decrypt(base64.decodebytes(bytes(text, encoding='utf8'))).rstrip(b'\0').decode("utf8")) # 解密
text_decoded = base64.decodebytes(bytes(text, encoding='utf8'))
return str(aes.decrypt(text_decoded).rstrip(b'\0').decode("utf8"))
class AESCryptoGCM:
@ -234,6 +235,8 @@ def rsa_decrypt(cipher_text, rsa_private_key=None):
def rsa_decrypt_by_session_pkey(value):
from jumpserver.utils import current_request
if not current_request:
return value
private_key_name = settings.SESSION_RSA_PRIVATE_KEY_NAME
private_key = current_request.session.get(private_key_name)
@ -254,7 +257,11 @@ def decrypt_password(value):
key_cipher, password_cipher = cipher
aes_key = rsa_decrypt_by_session_pkey(key_cipher)
aes = get_aes_crypto(aes_key, 'ECB')
password = aes.decrypt(password_cipher)
try:
password = aes.decrypt(password_cipher)
except UnicodeDecodeError as e:
logging.error("Decript password error: {}, {}".format(password_cipher, e))
return value
return password

View File

@ -95,7 +95,6 @@ MIDDLEWARE = [
'authentication.backends.cas.middleware.CASMiddleware',
'authentication.middleware.MFAMiddleware',
'authentication.middleware.SessionCookieMiddleware',
'authentication.middleware.EncryptedMiddleware',
'simple_history.middleware.HistoryRequestMiddleware',
]

View File

@ -91,10 +91,11 @@ class OrgResourceStatisticsRefreshUtil:
@classmethod
def refresh_if_need(cls, instance):
cache_field_name = cls.model_cache_field_mapper.get(type(instance))
if cache_field_name:
org_cache = OrgResourceStatisticsCache(instance.org)
org_cache.expire(*cache_field_name)
OrgResourceStatisticsCache(Organization.root()).expire(*cache_field_name)
if not cache_field_name:
return
OrgResourceStatisticsCache(Organization.root()).expire(*cache_field_name)
if instance.org:
OrgResourceStatisticsCache(instance.org).expire(*cache_field_name)
@receiver(post_save)