mirror of https://github.com/jumpserver/jumpserver
commit
afcbe60531
|
@ -288,15 +288,14 @@ class Application(CommonModelMixin, OrgModelMixin, ApplicationTreeNodeMixin):
|
||||||
raise ValueError("Remote App not has asset attr")
|
raise ValueError("Remote App not has asset attr")
|
||||||
|
|
||||||
def get_target_ip(self):
|
def get_target_ip(self):
|
||||||
|
target_ip = ''
|
||||||
if self.category_remote_app:
|
if self.category_remote_app:
|
||||||
asset = self.get_remote_app_asset()
|
asset = self.get_remote_app_asset()
|
||||||
target_ip = asset.ip
|
target_ip = asset.ip if asset else target_ip
|
||||||
elif self.category_cloud:
|
elif self.category_cloud:
|
||||||
target_ip = self.attrs.get('cluster')
|
target_ip = self.attrs.get('cluster')
|
||||||
elif self.category_db:
|
elif self.category_db:
|
||||||
target_ip = self.attrs.get('host')
|
target_ip = self.attrs.get('host')
|
||||||
else:
|
|
||||||
target_ip = ''
|
|
||||||
return target_ip
|
return target_ip
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -484,7 +484,8 @@ class UserConnectionTokenViewSet(
|
||||||
tp = 'app' if application else 'asset'
|
tp = 'app' if application else 'asset'
|
||||||
data = {
|
data = {
|
||||||
"id": token, 'secret': secret,
|
"id": token, 'secret': secret,
|
||||||
'type': tp, 'protocol': system_user.protocol
|
'type': tp, 'protocol': system_user.protocol,
|
||||||
|
'expire_time': self.get_token_ttl(token),
|
||||||
}
|
}
|
||||||
return Response(data, status=201)
|
return Response(data, status=201)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
from django.shortcuts import redirect, reverse
|
from django.shortcuts import redirect, reverse
|
||||||
|
from django.utils.deprecation import MiddlewareMixin
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
class MFAMiddleware:
|
class MFAMiddleware:
|
||||||
|
@ -34,3 +36,15 @@ class MFAMiddleware:
|
||||||
|
|
||||||
url = reverse('authentication:login-mfa') + '?_=middleware'
|
url = reverse('authentication:login-mfa') + '?_=middleware'
|
||||||
return redirect(url)
|
return redirect(url)
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from channels_redis.core import RedisChannelLayer as _RedisChannelLayer
|
||||||
|
|
||||||
from common.utils.lock import DistributedLock
|
from common.utils.lock import DistributedLock
|
||||||
from common.utils.connection import get_redis_client
|
from common.utils.connection import get_redis_client
|
||||||
from common.utils import lazyproperty
|
from common.utils import lazyproperty
|
||||||
|
@ -216,3 +218,29 @@ class CacheValueDesc:
|
||||||
|
|
||||||
def to_internal_value(self, value):
|
def to_internal_value(self, value):
|
||||||
return self.field_type.field_type(value)
|
return self.field_type.field_type(value)
|
||||||
|
|
||||||
|
|
||||||
|
class RedisChannelLayer(_RedisChannelLayer):
|
||||||
|
async def _brpop_with_clean(self, index, channel, timeout):
|
||||||
|
cleanup_script = """
|
||||||
|
local backed_up = redis.call('ZRANGE', ARGV[2], 0, -1, 'WITHSCORES')
|
||||||
|
for i = #backed_up, 1, -2 do
|
||||||
|
redis.call('ZADD', ARGV[1], backed_up[i], backed_up[i - 1])
|
||||||
|
end
|
||||||
|
redis.call('DEL', ARGV[2])
|
||||||
|
"""
|
||||||
|
backup_queue = self._backup_channel_name(channel)
|
||||||
|
async with self.connection(index) as connection:
|
||||||
|
# 部分云厂商的 Redis 此操作会报错(不支持,比如阿里云有限制)
|
||||||
|
try:
|
||||||
|
await connection.eval(cleanup_script, keys=[], args=[channel, backup_queue])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
result = await connection.bzpopmin(channel, timeout=timeout)
|
||||||
|
|
||||||
|
if result is not None:
|
||||||
|
_, member, timestamp = result
|
||||||
|
await connection.zadd(backup_queue, float(timestamp), member)
|
||||||
|
else:
|
||||||
|
member = None
|
||||||
|
return member
|
||||||
|
|
|
@ -157,6 +157,7 @@ class Config(dict):
|
||||||
'DEFAULT_EXPIRED_YEARS': 70,
|
'DEFAULT_EXPIRED_YEARS': 70,
|
||||||
'SESSION_COOKIE_DOMAIN': None,
|
'SESSION_COOKIE_DOMAIN': None,
|
||||||
'CSRF_COOKIE_DOMAIN': None,
|
'CSRF_COOKIE_DOMAIN': None,
|
||||||
|
'SESSION_COOKIE_NAME_PREFIX': None,
|
||||||
'SESSION_COOKIE_AGE': 3600 * 24,
|
'SESSION_COOKIE_AGE': 3600 * 24,
|
||||||
'SESSION_EXPIRE_AT_BROWSER_CLOSE': False,
|
'SESSION_EXPIRE_AT_BROWSER_CLOSE': False,
|
||||||
'LOGIN_URL': reverse_lazy('authentication:login'),
|
'LOGIN_URL': reverse_lazy('authentication:login'),
|
||||||
|
|
|
@ -94,6 +94,7 @@ MIDDLEWARE = [
|
||||||
'authentication.backends.oidc.middleware.OIDCRefreshIDTokenMiddleware',
|
'authentication.backends.oidc.middleware.OIDCRefreshIDTokenMiddleware',
|
||||||
'authentication.backends.cas.middleware.CASMiddleware',
|
'authentication.backends.cas.middleware.CASMiddleware',
|
||||||
'authentication.middleware.MFAMiddleware',
|
'authentication.middleware.MFAMiddleware',
|
||||||
|
'authentication.middleware.SessionCookieMiddleware',
|
||||||
'simple_history.middleware.HistoryRequestMiddleware',
|
'simple_history.middleware.HistoryRequestMiddleware',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -128,6 +129,20 @@ LOGIN_URL = reverse_lazy('authentication:login')
|
||||||
|
|
||||||
SESSION_COOKIE_DOMAIN = CONFIG.SESSION_COOKIE_DOMAIN
|
SESSION_COOKIE_DOMAIN = CONFIG.SESSION_COOKIE_DOMAIN
|
||||||
CSRF_COOKIE_DOMAIN = CONFIG.SESSION_COOKIE_DOMAIN
|
CSRF_COOKIE_DOMAIN = CONFIG.SESSION_COOKIE_DOMAIN
|
||||||
|
|
||||||
|
# 设置 SESSION_COOKIE_NAME_PREFIX_KEY
|
||||||
|
# 解决 不同域 session csrf cookie 获取混乱问题
|
||||||
|
SESSION_COOKIE_NAME_PREFIX_KEY = 'SESSION_COOKIE_NAME_PREFIX'
|
||||||
|
SESSION_COOKIE_NAME_PREFIX = CONFIG.SESSION_COOKIE_NAME_PREFIX
|
||||||
|
if SESSION_COOKIE_NAME_PREFIX is not None:
|
||||||
|
pass
|
||||||
|
elif SESSION_COOKIE_DOMAIN is not None:
|
||||||
|
SESSION_COOKIE_NAME_PREFIX = SESSION_COOKIE_DOMAIN.split('.')[0]
|
||||||
|
else:
|
||||||
|
SESSION_COOKIE_NAME_PREFIX = 'jms_'
|
||||||
|
CSRF_COOKIE_NAME = '{}csrftoken'.format(SESSION_COOKIE_NAME_PREFIX)
|
||||||
|
SESSION_COOKIE_NAME = '{}sessionid'.format(SESSION_COOKIE_NAME_PREFIX)
|
||||||
|
|
||||||
SESSION_COOKIE_AGE = CONFIG.SESSION_COOKIE_AGE
|
SESSION_COOKIE_AGE = CONFIG.SESSION_COOKIE_AGE
|
||||||
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
|
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
|
||||||
# 自定义的配置,SESSION_EXPIRE_AT_BROWSER_CLOSE 始终为 True, 下面这个来控制是否强制关闭后过期 cookie
|
# 自定义的配置,SESSION_EXPIRE_AT_BROWSER_CLOSE 始终为 True, 下面这个来控制是否强制关闭后过期 cookie
|
||||||
|
|
|
@ -96,12 +96,12 @@ else:
|
||||||
|
|
||||||
CHANNEL_LAYERS = {
|
CHANNEL_LAYERS = {
|
||||||
'default': {
|
'default': {
|
||||||
'BACKEND': 'channels_redis.core.RedisChannelLayer',
|
'BACKEND': 'common.cache.RedisChannelLayer',
|
||||||
'CONFIG': {
|
'CONFIG': {
|
||||||
"hosts": [{
|
"hosts": [{
|
||||||
'address': (CONFIG.REDIS_HOST, CONFIG.REDIS_PORT),
|
'address': (CONFIG.REDIS_HOST, CONFIG.REDIS_PORT),
|
||||||
'db': CONFIG.REDIS_DB_WS,
|
'db': CONFIG.REDIS_DB_WS,
|
||||||
'password': CONFIG.REDIS_PASSWORD,
|
'password': CONFIG.REDIS_PASSWORD or None,
|
||||||
'ssl': context
|
'ssl': context
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
|
|
|
@ -8,6 +8,7 @@ from assets.models import Asset
|
||||||
from orgs.utils import tmp_to_root_org
|
from orgs.utils import tmp_to_root_org
|
||||||
from applications.models import Application
|
from applications.models import Application
|
||||||
from terminal.models import Session
|
from terminal.models import Session
|
||||||
|
from common.permissions import IsValidUser
|
||||||
from ..models import Endpoint, EndpointRule
|
from ..models import Endpoint, EndpointRule
|
||||||
from .. import serializers
|
from .. import serializers
|
||||||
|
|
||||||
|
@ -20,9 +21,6 @@ class EndpointViewSet(JMSBulkModelViewSet):
|
||||||
search_fields = filterset_fields
|
search_fields = filterset_fields
|
||||||
serializer_class = serializers.EndpointSerializer
|
serializer_class = serializers.EndpointSerializer
|
||||||
queryset = Endpoint.objects.all()
|
queryset = Endpoint.objects.all()
|
||||||
rbac_perms = {
|
|
||||||
'smart': 'terminal.view_endpoint'
|
|
||||||
}
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_target_ip(request):
|
def get_target_ip(request):
|
||||||
|
@ -57,7 +55,7 @@ class EndpointViewSet(JMSBulkModelViewSet):
|
||||||
target_ip = instance.get_target_ip()
|
target_ip = instance.get_target_ip()
|
||||||
return target_ip
|
return target_ip
|
||||||
|
|
||||||
@action(methods=['get'], detail=False, url_path='smart')
|
@action(methods=['get'], detail=False, permission_classes=[IsValidUser], url_path='smart')
|
||||||
def smart(self, request, *args, **kwargs):
|
def smart(self, request, *args, **kwargs):
|
||||||
protocol = request.GET.get('protocol')
|
protocol = request.GET.get('protocol')
|
||||||
if not protocol:
|
if not protocol:
|
||||||
|
|
Loading…
Reference in New Issue