mirror of https://github.com/jumpserver/jumpserver
commit
33090c4cdf
|
@ -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}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -95,7 +95,6 @@ MIDDLEWARE = [
|
|||
'authentication.backends.cas.middleware.CASMiddleware',
|
||||
'authentication.middleware.MFAMiddleware',
|
||||
'authentication.middleware.SessionCookieMiddleware',
|
||||
'authentication.middleware.EncryptedMiddleware',
|
||||
'simple_history.middleware.HistoryRequestMiddleware',
|
||||
]
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue