mirror of https://github.com/jumpserver/jumpserver
fix: OpenID Only allow existing users to log in operate log error
parent
a732cc614e
commit
5c66b3524a
|
@ -134,6 +134,7 @@ class OIDCAuthCallbackView(View, FlashMessageMixin):
|
||||||
log_prompt = "Process GET requests [OIDCAuthCallbackView]: {}"
|
log_prompt = "Process GET requests [OIDCAuthCallbackView]: {}"
|
||||||
logger.debug(log_prompt.format('Start'))
|
logger.debug(log_prompt.format('Start'))
|
||||||
callback_params = request.GET
|
callback_params = request.GET
|
||||||
|
error_title = _("OpenID Error")
|
||||||
|
|
||||||
# Retrieve the state value that was previously generated. No state means that we cannot
|
# Retrieve the state value that was previously generated. No state means that we cannot
|
||||||
# authenticate the user (so a failure should be returned).
|
# authenticate the user (so a failure should be returned).
|
||||||
|
@ -172,10 +173,9 @@ class OIDCAuthCallbackView(View, FlashMessageMixin):
|
||||||
try:
|
try:
|
||||||
user = auth.authenticate(nonce=nonce, request=request, code_verifier=code_verifier)
|
user = auth.authenticate(nonce=nonce, request=request, code_verifier=code_verifier)
|
||||||
except IntegrityError as e:
|
except IntegrityError as e:
|
||||||
title = _("OpenID Error")
|
|
||||||
msg = _('Please check if a user with the same username or email already exists')
|
msg = _('Please check if a user with the same username or email already exists')
|
||||||
logger.error(e, exc_info=True)
|
logger.error(e, exc_info=True)
|
||||||
response = self.get_failed_response('/', title, msg)
|
response = self.get_failed_response('/', error_title, msg)
|
||||||
return response
|
return response
|
||||||
if user:
|
if user:
|
||||||
logger.debug(log_prompt.format('Login: {}'.format(user)))
|
logger.debug(log_prompt.format('Login: {}'.format(user)))
|
||||||
|
@ -194,7 +194,6 @@ class OIDCAuthCallbackView(View, FlashMessageMixin):
|
||||||
return HttpResponseRedirect(
|
return HttpResponseRedirect(
|
||||||
next_url or settings.AUTH_OPENID_AUTHENTICATION_REDIRECT_URI
|
next_url or settings.AUTH_OPENID_AUTHENTICATION_REDIRECT_URI
|
||||||
)
|
)
|
||||||
|
|
||||||
if 'error' in callback_params:
|
if 'error' in callback_params:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
log_prompt.format('Error in callback params: {}'.format(callback_params['error']))
|
log_prompt.format('Error in callback params: {}'.format(callback_params['error']))
|
||||||
|
@ -205,9 +204,12 @@ class OIDCAuthCallbackView(View, FlashMessageMixin):
|
||||||
# OpenID Connect Provider authenticate endpoint.
|
# OpenID Connect Provider authenticate endpoint.
|
||||||
logger.debug(log_prompt.format('Logout'))
|
logger.debug(log_prompt.format('Logout'))
|
||||||
auth.logout(request)
|
auth.logout(request)
|
||||||
|
redirect_url = settings.AUTH_OPENID_AUTHENTICATION_FAILURE_REDIRECT_URI
|
||||||
|
if not user and getattr(request, 'error_message', ''):
|
||||||
|
response = self.get_failed_response(redirect_url, title=error_title, msg=request.error_message)
|
||||||
|
return response
|
||||||
logger.debug(log_prompt.format('Redirect'))
|
logger.debug(log_prompt.format('Redirect'))
|
||||||
return HttpResponseRedirect(settings.AUTH_OPENID_AUTHENTICATION_FAILURE_REDIRECT_URI)
|
return HttpResponseRedirect(redirect_url)
|
||||||
|
|
||||||
|
|
||||||
class OIDCAuthCallbackClientView(BaseAuthCallbackClientView):
|
class OIDCAuthCallbackClientView(BaseAuthCallbackClientView):
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
import inspect
|
import inspect
|
||||||
|
import threading
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
@ -12,6 +13,7 @@ from django.contrib.auth import (
|
||||||
BACKEND_SESSION_KEY, load_backend,
|
BACKEND_SESSION_KEY, load_backend,
|
||||||
PermissionDenied, user_login_failed, _clean_credentials,
|
PermissionDenied, user_login_failed, _clean_credentials,
|
||||||
)
|
)
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.shortcuts import reverse, redirect, get_object_or_404
|
from django.shortcuts import reverse, redirect, get_object_or_404
|
||||||
|
@ -46,6 +48,10 @@ def _get_backends(return_tuples=False):
|
||||||
return backends
|
return backends
|
||||||
|
|
||||||
|
|
||||||
|
class OnlyAllowExistUserAuthError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
auth._get_backends = _get_backends
|
auth._get_backends = _get_backends
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,6 +60,24 @@ def authenticate(request=None, **credentials):
|
||||||
If the given credentials are valid, return a User object.
|
If the given credentials are valid, return a User object.
|
||||||
之所以 hack 这个 authenticate
|
之所以 hack 这个 authenticate
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
UserModel = get_user_model()
|
||||||
|
original_get_or_create = UserModel.objects.get_or_create
|
||||||
|
|
||||||
|
thread_local = threading.local()
|
||||||
|
thread_local.thread_id = threading.get_ident()
|
||||||
|
|
||||||
|
def custom_get_or_create(self, *args, **kwargs):
|
||||||
|
logger.debug(f"get_or_create: thread_id={threading.get_ident()}, username={username}")
|
||||||
|
if threading.get_ident() != thread_local.thread_id or not settings.ONLY_ALLOW_EXIST_USER_AUTH:
|
||||||
|
return original_get_or_create(*args, **kwargs)
|
||||||
|
create_username = kwargs.get('username')
|
||||||
|
try:
|
||||||
|
UserModel.objects.get(username=create_username)
|
||||||
|
except UserModel.DoesNotExist:
|
||||||
|
raise OnlyAllowExistUserAuthError
|
||||||
|
return original_get_or_create(*args, **kwargs)
|
||||||
|
|
||||||
username = credentials.get('username')
|
username = credentials.get('username')
|
||||||
|
|
||||||
temp_user = None
|
temp_user = None
|
||||||
|
@ -71,10 +95,19 @@ def authenticate(request=None, **credentials):
|
||||||
# This backend doesn't accept these credentials as arguments. Try the next one.
|
# This backend doesn't accept these credentials as arguments. Try the next one.
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
|
UserModel.objects.get_or_create = custom_get_or_create.__get__(UserModel.objects)
|
||||||
user = backend.authenticate(request, **credentials)
|
user = backend.authenticate(request, **credentials)
|
||||||
except PermissionDenied:
|
except PermissionDenied:
|
||||||
# This backend says to stop in our tracks - this user should not be allowed in at all.
|
# This backend says to stop in our tracks - this user should not be allowed in at all.
|
||||||
break
|
break
|
||||||
|
except OnlyAllowExistUserAuthError:
|
||||||
|
request.error_message = _(
|
||||||
|
'''The administrator has enabled "Only allow existing users to log in",
|
||||||
|
and the current user is not in the user list. Please contact the administrator.'''
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
finally:
|
||||||
|
UserModel.objects.get_or_create = original_get_or_create
|
||||||
if user is None:
|
if user is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ from common.utils import get_logger
|
||||||
from common.utils.common import get_request_ip
|
from common.utils.common import get_request_ip
|
||||||
from common.utils.django import reverse, get_object_or_none
|
from common.utils.django import reverse, get_object_or_none
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from users.signal_handlers import check_only_allow_exist_user_auth, bind_user_to_org_role
|
from users.signal_handlers import bind_user_to_org_role, check_only_allow_exist_user_auth
|
||||||
from .mixins import FlashMessageMixin
|
from .mixins import FlashMessageMixin
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
|
@ -55,7 +55,6 @@ class BaseLoginCallbackView(AuthMixin, FlashMessageMixin, IMClientMixin, View):
|
||||||
)
|
)
|
||||||
|
|
||||||
if not check_only_allow_exist_user_auth(create):
|
if not check_only_allow_exist_user_auth(create):
|
||||||
user.delete()
|
|
||||||
return user, (self.msg_client_err, self.request.error_message)
|
return user, (self.msg_client_err, self.request.error_message)
|
||||||
|
|
||||||
setattr(user, f'{self.user_type}_id', user_id)
|
setattr(user, f'{self.user_type}_id', user_id)
|
||||||
|
|
Loading…
Reference in New Issue