mirror of https://github.com/jumpserver/jumpserver
150 lines
4.7 KiB
Python
150 lines
4.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
#
|
|
import ipaddress
|
|
from datetime import datetime, timedelta
|
|
from urllib.parse import urljoin, urlparse
|
|
|
|
from django.conf import settings
|
|
from django.shortcuts import reverse
|
|
from django.templatetags.static import static
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
from audits.models import UserLoginLog
|
|
from common.utils import get_ip_city, get_request_ip
|
|
from common.utils import get_logger, get_object_or_none
|
|
from common.utils import static_or_direct
|
|
from users.models import User
|
|
from .notifications import DifferentCityLoginMessage
|
|
|
|
logger = get_logger(__file__)
|
|
|
|
|
|
def check_different_city_login_if_need(user, request):
|
|
if not settings.SECURITY_CHECK_DIFFERENT_CITY_LOGIN:
|
|
return
|
|
|
|
ip = get_request_ip(request) or '0.0.0.0'
|
|
city_white = [_('LAN'), 'LAN']
|
|
is_private = ipaddress.ip_address(ip).is_private
|
|
if is_private:
|
|
return
|
|
usernames = [user.username, f"{user.name}({user.username})"]
|
|
last_user_login = UserLoginLog.objects.exclude(
|
|
city__in=city_white
|
|
).filter(username__in=usernames, status=True).first()
|
|
if not last_user_login:
|
|
return
|
|
|
|
city = get_ip_city(ip)
|
|
last_cities = UserLoginLog.objects.filter(
|
|
datetime__gte=datetime.now() - timedelta(days=7),
|
|
username__in=usernames,
|
|
status=True
|
|
).exclude(city__in=city_white).values_list('city', flat=True).distinct()
|
|
|
|
if city in last_cities:
|
|
return
|
|
|
|
DifferentCityLoginMessage(user, ip, city).publish_async()
|
|
|
|
|
|
def build_absolute_uri(request, path=None):
|
|
""" Build absolute redirect """
|
|
if path is None:
|
|
path = '/'
|
|
site_url = urlparse(settings.SITE_URL)
|
|
scheme = site_url.scheme or request.scheme
|
|
host = request.get_host()
|
|
url = f'{scheme}://{host}'
|
|
redirect_uri = urljoin(url, path)
|
|
return redirect_uri
|
|
|
|
|
|
def build_absolute_uri_for_oidc(request, path=None):
|
|
""" Build absolute redirect uri for OIDC """
|
|
if path is None:
|
|
path = '/'
|
|
if settings.BASE_SITE_URL:
|
|
# OIDC 专用配置项
|
|
redirect_uri = urljoin(settings.BASE_SITE_URL, path)
|
|
return redirect_uri
|
|
return build_absolute_uri(request, path=path)
|
|
|
|
|
|
def check_user_property_is_correct(username, **properties):
|
|
user = get_object_or_none(User, username=username)
|
|
for attr, value in properties.items():
|
|
if getattr(user, attr, None) != value:
|
|
user = None
|
|
break
|
|
return user
|
|
|
|
|
|
def get_auth_methods():
|
|
return [
|
|
{
|
|
'name': 'OpenID',
|
|
'enabled': settings.AUTH_OPENID,
|
|
'url': reverse('authentication:openid:login'),
|
|
'logo': static('img/login_oidc_logo.png'),
|
|
'auto_redirect': True # 是否支持自动重定向
|
|
},
|
|
{
|
|
'name': 'CAS',
|
|
'enabled': settings.AUTH_CAS,
|
|
'url': reverse('authentication:cas:cas-login'),
|
|
'logo': static('img/login_cas_logo.png'),
|
|
'auto_redirect': True
|
|
},
|
|
{
|
|
'name': 'SAML2',
|
|
'enabled': settings.AUTH_SAML2,
|
|
'url': reverse('authentication:saml2:saml2-login'),
|
|
'logo': static('img/login_saml2_logo.png'),
|
|
'auto_redirect': True
|
|
},
|
|
{
|
|
'name': settings.AUTH_OAUTH2_PROVIDER,
|
|
'enabled': settings.AUTH_OAUTH2,
|
|
'url': reverse('authentication:oauth2:login'),
|
|
'logo': static_or_direct(settings.AUTH_OAUTH2_LOGO_PATH),
|
|
'auto_redirect': True
|
|
},
|
|
{
|
|
'name': _('WeCom'),
|
|
'enabled': settings.AUTH_WECOM,
|
|
'url': reverse('authentication:wecom-qr-login'),
|
|
'logo': static('img/login_wecom_logo.png'),
|
|
},
|
|
{
|
|
'name': _('DingTalk'),
|
|
'enabled': settings.AUTH_DINGTALK,
|
|
'url': reverse('authentication:dingtalk-qr-login'),
|
|
'logo': static('img/login_dingtalk_logo.png')
|
|
},
|
|
{
|
|
'name': _('FeiShu'),
|
|
'enabled': settings.AUTH_FEISHU,
|
|
'url': reverse('authentication:feishu-qr-login'),
|
|
'logo': static('img/login_feishu_logo.png')
|
|
},
|
|
{
|
|
'name': 'Lark',
|
|
'enabled': settings.AUTH_LARK,
|
|
'url': reverse('authentication:lark-qr-login'),
|
|
'logo': static('img/login_lark_logo.png')
|
|
},
|
|
{
|
|
'name': _('Slack'),
|
|
'enabled': settings.AUTH_SLACK,
|
|
'url': reverse('authentication:slack-qr-login'),
|
|
'logo': static('img/login_slack_logo.png')
|
|
},
|
|
{
|
|
'name': _("Passkey"),
|
|
'enabled': settings.AUTH_PASSKEY,
|
|
'url': reverse('api-auth:passkey-login'),
|
|
'logo': static('img/login_passkey.png')
|
|
}
|
|
]
|