Skip to content

Commit

Permalink
Allow password change for OTPW sessions
Browse files Browse the repository at this point in the history
When provisioning new admin users on TrueNAS the sysadmin may
provide the user with a one-time password in order to set up
their own credentials. This means that OTPW authentication should
be allowed to set the associated user's password.
  • Loading branch information
anodos325 committed Jan 28, 2025
1 parent 2a8ba6b commit 4b24b41
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 3 deletions.
11 changes: 8 additions & 3 deletions src/middlewared/middlewared/plugins/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -1537,16 +1537,19 @@ async def set_password(self, app, data):
password changes will be rejected if the payload does not match the
currently-authenticated user.
API keys granting access to this endpoint will be able to reset
the password of any user.
NOTE: users authenticated with a one-time password will be able
to change the password without submitting a second time.
"""

verrors = ValidationErrors()
is_full_admin = credential_has_full_admin(app.authenticated_credentials)
is_otp_login = False
authenticated_user = None

if app.authenticated_credentials.is_user_session:
authenticated_user = app.authenticated_credentials.user['username']
if 'OTPW' in app.authenticated_credentials.user['account_attributes']:
is_otp_login = True

username = data['username']
password = data['new_password']
Expand Down Expand Up @@ -1580,7 +1583,9 @@ async def set_password(self, app, data):
f'{username}: user is not local to the TrueNAS server.'
)

if not is_full_admin:
# Require submitting password twice if this is not a full admin session
# and does not have a one-time password.
if not is_full_admin and not is_otp_login:
if data['old_password'] is None:
verrors.add(
'user.set_password.old_password',
Expand Down
20 changes: 20 additions & 0 deletions tests/api2/test_password_reset.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,23 @@ def test_restricted_user_set_password():
'old_password': TEST_PASSWORD2,
'new_password': TEST_PASSWORD2_2
})


def test_password_reset_via_onetime_password():
with unprivileged_user(
username=TEST_USERNAME,
group_name=TEST_GROUPNAME,
privilege_name='TEST_PASSWD_RESET_PRIVILEGE',
web_shell=False,
roles=['READONLY_ADMIN']
) as acct:
otp = call('auth.generate_onetime_password', {'username': acct.username})
with client(auth=(acct.username, otp)) as c:
c.call('user.set_password', {
'username': TEST_USERNAME,
'new_password': TEST_PASSWORD2_2
})

# Verify that password change worked
with client(auth=(acct.username, TEST_PASSWORD2_2)):
pass

0 comments on commit 4b24b41

Please sign in to comment.