1
0
mirror of https://github.com/dkmstr/openuds.git synced 2025-03-28 10:50:25 +03:00

Added storing state on session for mfa on radius

This commit is contained in:
Adolfo Gómez García 2023-10-13 00:18:29 +02:00
parent d21c371bf7
commit de33a96c45
No known key found for this signature in database
GPG Key ID: DD1ABF20724CDA23
4 changed files with 14 additions and 9 deletions

View File

@ -149,7 +149,10 @@ class RadiusAuth(auths.Authenticator):
) -> auths.AuthenticationResult:
try:
connection = self.radiusClient()
groups, mfaCode = connection.authenticate(username=username, password=credentials, mfaField=self.mfaAttr.value.strip())
groups, mfaCode, state = connection.authenticate(username=username, password=credentials, mfaField=self.mfaAttr.value.strip())
# If state, store in session
if state:
request.session[client.STATE_VAR_NAME] = state.decode()
# store the user mfa attribute if it is set
if mfaCode:
self.storage.putPickle(

View File

@ -52,6 +52,8 @@ ATTRIBUTE Framed-AppleTalk-Zone 39 string"""
NOT_CHECKED, INCORRECT, CORRECT = -1, 0, 1 # for pwd and otp
NOT_NEEDED, NEEDED = INCORRECT, CORRECT # for otp_needed
STATE_VAR_NAME = 'radius_state'
class RadiusAuthenticationError(Exception):
pass
@ -129,7 +131,7 @@ class RadiusClient:
# Second element of return value is the mfa code from field
def authenticate(
self, username: str, password: str, mfaField: str = ''
) -> typing.Tuple[typing.List[str], str]:
) -> typing.Tuple[typing.List[str], str, bytes]:
reply = self.sendAccessRequest(username, password)
if reply.code not in (pyrad.packet.AccessAccept, pyrad.packet.AccessChallenge):
@ -147,7 +149,7 @@ class RadiusClient:
]
else:
logger.info('No "Class (25)" attribute found')
return ([], '')
return ([], '', b'')
# ...and mfa code
mfaCode = ''
@ -157,7 +159,7 @@ class RadiusClient:
for i in typing.cast(typing.Iterable[bytes], reply['Class'])
if i.startswith(groupClassPrefix)
)
return (groups, mfaCode)
return (groups, mfaCode, typing.cast(typing.List[bytes], reply.get('State') or [b''])[0])
def authenticate_only(self, username: str, password: str) -> RadiusResult:
reply = self.sendAccessRequest(username, password)

View File

@ -224,7 +224,7 @@ class RadiusOTP(mfas.MFA):
return self.checkResult(self.allowLoginWithoutMFA.value, request)
# Store state for later use, related to this user
request.session['radius_state'] = auth_reply.state or b''
request.session[client.STATE_VAR_NAME] = auth_reply.state or b''
# correct password and otp_needed
return mfas.MFA.RESULT.OK
@ -254,10 +254,10 @@ class RadiusOTP(mfas.MFA):
web_pwd = webPassword(request)
try:
connection = self.radiusClient()
state = request.session.get('radius_state', b'')
state = request.session.get(client.STATE_VAR_NAME, b'')
if state:
# Remove state from session
del request.session['radius_state']
del request.session[client.STATE_VAR_NAME]
# Use state to validate
auth_reply = connection.authenticate_challenge(username, otp=code, state=state)
else: # No state, so full authentication

View File

@ -171,7 +171,7 @@ def mfa(request: ExtendedHttpRequest) -> HttpResponse: # pylint: disable=too-ma
logger.warning('MFA: No user or user is already authorized')
return HttpResponseRedirect(reverse('page.index')) # No user, no MFA
mfaProvider: typing.Optional['models.MFA'] = request.user.manager.mfa
mfaProvider = typing.cast('None|models.MFA', request.user.manager.mfa)
if not mfaProvider:
logger.warning('MFA: No MFA provider for user')
return HttpResponseRedirect(reverse('page.index'))
@ -187,7 +187,7 @@ def mfa(request: ExtendedHttpRequest) -> HttpResponse: # pylint: disable=too-ma
# Obtain MFA data
authInstance = request.user.manager.getInstance()
mfaInstance: 'mfas.MFA' = mfaProvider.getInstance()
mfaInstance = typing.cast('mfas.MFA', mfaProvider.getInstance())
# Get validity duration
validity = mfaProvider.validity * 60