Compare commits

...

5 Commits

Author SHA1 Message Date
Eric_Lee
ab777aeb18 perf: update rdp params 2025-12-19 15:44:14 +08:00
fit2bot
a497b3cf94 fix: Add '/media/' to the list of whitelisted URLs for MFA login (#16412)
Co-authored-by: wangruidong <940853815@qq.com>
2025-12-10 14:19:39 +08:00
fit2bot
8548b73063 fix: Failed to switch languages (#16326)
Co-authored-by: wangruidong <940853815@qq.com>
2025-11-24 11:13:56 +08:00
fit2bot
182320f492 fix: SAML2 authentication failure with Okta integration (#16250)
Co-authored-by: wangruidong <940853815@qq.com>
2025-11-07 15:42:09 +08:00
fit2bot
40d326d6a6 fix: Any change to the LDAP server URI should require re-authentication and explicit re-entry of (#16195)
the bind password, not reuse stored credentials

Co-authored-by: wangruidong <940853815@qq.com>
2025-10-23 18:09:46 +08:00
6 changed files with 53 additions and 13 deletions

View File

@@ -66,6 +66,8 @@ class RDPFileClientProtocolURLMixin:
'autoreconnection enabled:i': '1', 'autoreconnection enabled:i': '1',
'bookmarktype:i': '3', 'bookmarktype:i': '3',
'use redirection server name:i': '0', 'use redirection server name:i': '0',
'bitmapcachepersistenable:i': '0',
'bitmapcachesize:i': '1500',
} }
# 设置多屏显示 # 设置多屏显示
multi_mon = is_true(self.request.query_params.get('multi_mon')) multi_mon = is_true(self.request.query_params.get('multi_mon'))

View File

@@ -36,7 +36,7 @@ class MFAMiddleware:
# 这个是 mfa 登录页需要的请求, 也得放出来, 用户其实已经在 CAS/OIDC 中完成登录了 # 这个是 mfa 登录页需要的请求, 也得放出来, 用户其实已经在 CAS/OIDC 中完成登录了
white_urls = [ white_urls = [
'login/mfa', 'mfa/select', 'jsi18n/', '/static/', 'login/mfa', 'mfa/select', 'jsi18n/', '/static/',
'/profile/otp', '/logout/', '/profile/otp', '/logout/', '/media/'
] ]
for url in white_urls: for url in white_urls:
if request.path.find(url) > -1: if request.path.find(url) > -1:

View File

@@ -3,10 +3,10 @@
import json import json
import os import os
import re import re
import time
from urllib.parse import urlparse, quote from urllib.parse import urlparse, quote
import pytz import pytz
import time
from django.conf import settings from django.conf import settings
from django.core.exceptions import MiddlewareNotUsed from django.core.exceptions import MiddlewareNotUsed
from django.http.response import HttpResponseForbidden from django.http.response import HttpResponseForbidden
@@ -162,9 +162,16 @@ class SafeRedirectMiddleware:
target_host = parsed.netloc target_host = parsed.netloc
if target_host in [*settings.ALLOWED_HOSTS]: if target_host in [*settings.ALLOWED_HOSTS]:
return response return response
origin = f"{request.scheme}://{request.get_host()}" target_host, target_port = self._split_host_port(parsed.netloc)
target_origin = f"{parsed.scheme}://{target_host}" origin_host, origin_port = self._split_host_port(request.get_host())
if not target_origin.startswith(origin): if target_host != origin_host:
safe_redirect_url = '%s?%s' % (reverse('redirect-confirm'), f'next={quote(location)}') safe_redirect_url = '%s?%s' % (reverse('redirect-confirm'), f'next={quote(location)}')
return redirect(safe_redirect_url) return redirect(safe_redirect_url)
return response return response
@staticmethod
def _split_host_port(netloc):
if ':' in netloc:
host, port = netloc.split(':', 1)
return host, port
return netloc, '80'

30
apps/orgs/mixins/ws.py Normal file
View File

@@ -0,0 +1,30 @@
from http.cookies import SimpleCookie
from asgiref.sync import sync_to_async
from orgs.utils import tmp_to_org
class OrgMixin:
cookie = None
org = None
def get_cookie(self):
try:
headers = self.scope['headers']
headers_dict = {key.decode('utf-8'): value.decode('utf-8') for key, value in headers}
cookie = SimpleCookie(headers_dict.get('cookie', ''))
except Exception as e:
cookie = SimpleCookie()
return cookie
def get_current_org(self):
oid = self.cookie.get('X-JMS-ORG')
return oid.value if oid else None
@sync_to_async
def has_perms(self, user, perms):
self.cookie = self.get_cookie()
self.org = self.get_current_org()
with tmp_to_org(self.org):
return user.has_perms(perms)

View File

@@ -1,21 +1,22 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
import json
import asyncio import asyncio
import json
from channels.generic.websocket import AsyncJsonWebsocketConsumer from channels.generic.websocket import AsyncJsonWebsocketConsumer
from django.core.cache import cache
from django.conf import settings from django.conf import settings
from django.core.cache import cache
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from common.db.utils import close_old_connections from common.db.utils import close_old_connections
from common.utils import get_logger from common.utils import get_logger
from orgs.mixins.ws import OrgMixin
from orgs.models import Organization
from orgs.utils import current_org
from settings.serializers import ( from settings.serializers import (
LDAPTestConfigSerializer, LDAPTestConfigSerializer,
LDAPTestLoginSerializer LDAPTestLoginSerializer
) )
from orgs.models import Organization
from orgs.utils import current_org
from settings.tasks import sync_ldap_user from settings.tasks import sync_ldap_user
from settings.utils import ( from settings.utils import (
LDAPServerUtil, LDAPCacheUtil, LDAPImportUtil, LDAPSyncUtil, LDAPServerUtil, LDAPCacheUtil, LDAPImportUtil, LDAPSyncUtil,
@@ -97,10 +98,10 @@ class ToolsWebsocket(AsyncJsonWebsocketConsumer):
close_old_connections() close_old_connections()
class LdapWebsocket(AsyncJsonWebsocketConsumer): class LdapWebsocket(AsyncJsonWebsocketConsumer, OrgMixin):
async def connect(self): async def connect(self):
user = self.scope["user"] user = self.scope["user"]
if user.is_authenticated: if user.is_authenticated and await self.has_perms(user, ['settings.view_setting']):
await self.accept() await self.accept()
else: else:
await self.close() await self.close()
@@ -133,7 +134,7 @@ class LdapWebsocket(AsyncJsonWebsocketConsumer):
attr_map = serializer.validated_data["AUTH_LDAP_USER_ATTR_MAP"] attr_map = serializer.validated_data["AUTH_LDAP_USER_ATTR_MAP"]
auth_ldap = serializer.validated_data.get('AUTH_LDAP', False) auth_ldap = serializer.validated_data.get('AUTH_LDAP', False)
if not password: if not password and server_uri == settings.AUTH_LDAP_SERVER_URI:
password = settings.AUTH_LDAP_BIND_PASSWORD password = settings.AUTH_LDAP_BIND_PASSWORD
config = { config = {

View File

@@ -147,7 +147,7 @@ mistune = "2.0.3"
openai = "^1.29.0" openai = "^1.29.0"
xlsxwriter = "^3.1.9" xlsxwriter = "^3.1.9"
exchangelib = "^5.1.0" exchangelib = "^5.1.0"
xmlsec = "1.3.13" xmlsec = "1.3.14"
lxml = "5.2.1" lxml = "5.2.1"
receptorctl = "^1.4.5" receptorctl = "^1.4.5"
pydantic = "^2.7.4" pydantic = "^2.7.4"