diff --git a/apps/authentication/backends/radius.py b/apps/authentication/backends/radius.py index 6c95bf108..47f369205 100644 --- a/apps/authentication/backends/radius.py +++ b/apps/authentication/backends/radius.py @@ -5,6 +5,8 @@ from django.contrib.auth import get_user_model from radiusauth.backends import RADIUSBackend, RADIUSRealmBackend from django.conf import settings +from pyrad.packet import AccessRequest + User = get_user_model() @@ -25,6 +27,23 @@ class CreateUserMixin: user.save() return user + def _get_auth_packet(self, username, password, client): + """ + Get the pyrad authentication packet for the username/password and the + given pyrad client. + """ + pkt = client.CreateAuthPacket(code=AccessRequest, + User_Name=username) + if settings.CONFIG.RADIUS_ENCRYPT_PASSWORD: + password = pkt.PwCrypt(password) + else: + password = password + pkt["User-Password"] = password + pkt["NAS-Identifier"] = 'django-radius' + for key, val in list(getattr(settings, 'RADIUS_ATTRIBUTES', {}).items()): + pkt[key] = val + return pkt + class RadiusBackend(CreateUserMixin, RADIUSBackend): pass diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py index 9cacd465c..9a8a1c5f9 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -375,6 +375,7 @@ defaults = { 'RADIUS_SERVER': 'localhost', 'RADIUS_PORT': 1812, 'RADIUS_SECRET': '', + 'RADIUS_ENCRYPT_PASSWORD': True, 'AUTH_LDAP_SEARCH_PAGED_SIZE': 1000, 'AUTH_LDAP_SYNC_IS_PERIODIC': False, 'AUTH_LDAP_SYNC_INTERVAL': None, @@ -398,6 +399,7 @@ defaults = { 'FORCE_SCRIPT_NAME': '', 'LOGIN_CONFIRM_ENABLE': False, 'WINDOWS_SKIP_ALL_MANUAL_PASSWORD': False, + 'OTP_IN_RADIUS': False, } diff --git a/apps/users/models/user.py b/apps/users/models/user.py index bf8186174..e96fef6e0 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -375,9 +375,20 @@ class MFAMixin: self.otp_level = 0 self.otp_secret_key = None + def check_otp_on_radius(self, code): + from authentication.backends.radius import RadiusBackend + backend = RadiusBackend() + user = backend.authenticate(None, username=self.username, password=code) + if user: + return True + return False + def check_otp(self, code): from ..utils import check_otp_code - return check_otp_code(self.otp_secret_key, code) + if settings.CONFIG.OTP_IN_RADIUS: + return self.check_otp_on_radius(code) + else: + return check_otp_code(self.otp_secret_key, code) class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, AbstractUser):