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.mixins.serializers import BulkSerializerMixin
|
||||||
from common.utils import ssh_pubkey_gen
|
from common.utils import ssh_pubkey_gen
|
||||||
from common.drf.fields import EncryptedField
|
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 common.validators import alphanumeric_re, alphanumeric_cn_re, alphanumeric_win_re
|
||||||
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
||||||
from ..models import SystemUser, Asset
|
from ..models import SystemUser, Asset
|
||||||
|
@ -252,7 +253,7 @@ class MiniSystemUserSerializer(serializers.ModelSerializer):
|
||||||
fields = SystemUserSerializer.Meta.fields_mini
|
fields = SystemUserSerializer.Meta.fields_mini
|
||||||
|
|
||||||
|
|
||||||
class SystemUserWithAuthInfoSerializer(SystemUserSerializer):
|
class SystemUserWithAuthInfoSerializer(SecretReadableMixin, SystemUserSerializer):
|
||||||
class Meta(SystemUserSerializer.Meta):
|
class Meta(SystemUserSerializer.Meta):
|
||||||
fields_mini = ['id', 'name', 'username']
|
fields_mini = ['id', 'name', 'username']
|
||||||
fields_write_only = ['password', 'public_key', 'private_key']
|
fields_write_only = ['password', 'public_key', 'private_key']
|
||||||
|
@ -268,6 +269,9 @@ class SystemUserWithAuthInfoSerializer(SystemUserSerializer):
|
||||||
'assets_amount': {'label': _('Asset')},
|
'assets_amount': {'label': _('Asset')},
|
||||||
'login_mode_display': {'label': _('Login mode display')},
|
'login_mode_display': {'label': _('Login mode display')},
|
||||||
'created_by': {'read_only': True},
|
'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:
|
try:
|
||||||
claims_response.raise_for_status()
|
claims_response.raise_for_status()
|
||||||
claims = claims_response.json()
|
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:
|
except Exception as e:
|
||||||
error = "Json claims response error, claims response " \
|
error = "Json claims response error, claims response " \
|
||||||
"content is: {}, error is: {}".format(claims_response.content, str(e))
|
"content is: {}, error is: {}".format(claims_response.content, str(e))
|
||||||
|
@ -309,5 +314,3 @@ class OIDCAuthPasswordBackend(OIDCBaseBackend):
|
||||||
openid_user_login_failed.send(
|
openid_user_login_failed.send(
|
||||||
sender=self.__class__, request=request, username=username, reason="User is invalid"
|
sender=self.__class__, request=request, username=username, reason="User is invalid"
|
||||||
)
|
)
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
|
@ -45,21 +45,7 @@ class MFAMiddleware:
|
||||||
class SessionCookieMiddleware(MiddlewareMixin):
|
class SessionCookieMiddleware(MiddlewareMixin):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def process_response(request, response: HttpResponse):
|
def set_cookie_public_key(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)
|
|
||||||
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
|
pub_key_name = settings.SESSION_RSA_PUBLIC_KEY_NAME
|
||||||
public_key = request.session.get(pub_key_name)
|
public_key = request.session.get(pub_key_name)
|
||||||
cookie_key = request.COOKIES.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
|
request.session[pri_key_name] = private_key
|
||||||
response.set_cookie(pub_key_name, public_key_decode)
|
response.set_cookie(pub_key_name, public_key_decode)
|
||||||
|
|
||||||
def __call__(self, request):
|
@staticmethod
|
||||||
response = self.get_response(request)
|
def set_cookie_session_prefix(request, response):
|
||||||
self.check_key_pair(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
|
return response
|
||||||
|
|
|
@ -35,6 +35,9 @@ def on_user_auth_login_success(sender, user, request, **kwargs):
|
||||||
session.delete()
|
session.delete()
|
||||||
cache.set(lock_key, request.session.session_key, None)
|
cache.set(lock_key, request.session.session_key, None)
|
||||||
|
|
||||||
|
# 标记登录,设置 cookie,前端可以控制刷新, Middleware 会拦截这个生成 cookie
|
||||||
|
request.session['auth_session_expiration_required'] = 1
|
||||||
|
|
||||||
|
|
||||||
@receiver(openid_user_login_success)
|
@receiver(openid_user_login_success)
|
||||||
def on_oidc_user_login_success(sender, request, user, create=False, **kwargs):
|
def on_oidc_user_login_success(sender, request, user, create=False, **kwargs):
|
||||||
|
|
|
@ -91,12 +91,13 @@ class AESCrypto:
|
||||||
|
|
||||||
def encrypt(self, text):
|
def encrypt(self, text):
|
||||||
aes = self.aes()
|
aes = self.aes()
|
||||||
return str(base64.encodebytes(aes.encrypt(self.to_16(text))),
|
cipher = base64.encodebytes(aes.encrypt(self.to_16(text)))
|
||||||
encoding='utf8').replace('\n', '') # 加密
|
return str(cipher, encoding='utf8').replace('\n', '') # 加密
|
||||||
|
|
||||||
def decrypt(self, text):
|
def decrypt(self, text):
|
||||||
aes = self.aes()
|
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:
|
class AESCryptoGCM:
|
||||||
|
@ -234,6 +235,8 @@ def rsa_decrypt(cipher_text, rsa_private_key=None):
|
||||||
|
|
||||||
def rsa_decrypt_by_session_pkey(value):
|
def rsa_decrypt_by_session_pkey(value):
|
||||||
from jumpserver.utils import current_request
|
from jumpserver.utils import current_request
|
||||||
|
if not current_request:
|
||||||
|
return value
|
||||||
private_key_name = settings.SESSION_RSA_PRIVATE_KEY_NAME
|
private_key_name = settings.SESSION_RSA_PRIVATE_KEY_NAME
|
||||||
private_key = current_request.session.get(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
|
key_cipher, password_cipher = cipher
|
||||||
aes_key = rsa_decrypt_by_session_pkey(key_cipher)
|
aes_key = rsa_decrypt_by_session_pkey(key_cipher)
|
||||||
aes = get_aes_crypto(aes_key, 'ECB')
|
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
|
return password
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,6 @@ MIDDLEWARE = [
|
||||||
'authentication.backends.cas.middleware.CASMiddleware',
|
'authentication.backends.cas.middleware.CASMiddleware',
|
||||||
'authentication.middleware.MFAMiddleware',
|
'authentication.middleware.MFAMiddleware',
|
||||||
'authentication.middleware.SessionCookieMiddleware',
|
'authentication.middleware.SessionCookieMiddleware',
|
||||||
'authentication.middleware.EncryptedMiddleware',
|
|
||||||
'simple_history.middleware.HistoryRequestMiddleware',
|
'simple_history.middleware.HistoryRequestMiddleware',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -91,10 +91,11 @@ class OrgResourceStatisticsRefreshUtil:
|
||||||
@classmethod
|
@classmethod
|
||||||
def refresh_if_need(cls, instance):
|
def refresh_if_need(cls, instance):
|
||||||
cache_field_name = cls.model_cache_field_mapper.get(type(instance))
|
cache_field_name = cls.model_cache_field_mapper.get(type(instance))
|
||||||
if cache_field_name:
|
if not cache_field_name:
|
||||||
org_cache = OrgResourceStatisticsCache(instance.org)
|
return
|
||||||
org_cache.expire(*cache_field_name)
|
OrgResourceStatisticsCache(Organization.root()).expire(*cache_field_name)
|
||||||
OrgResourceStatisticsCache(Organization.root()).expire(*cache_field_name)
|
if instance.org:
|
||||||
|
OrgResourceStatisticsCache(instance.org).expire(*cache_field_name)
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save)
|
@receiver(post_save)
|
||||||
|
|
Loading…
Reference in New Issue