Skip to content

[Feature:System] Configurable password requirements#12455

Merged
bmcutler merged 24 commits into
Submitty:mainfrom
sushen123:feat/configurable-password-requirements
Jun 19, 2026
Merged

[Feature:System] Configurable password requirements#12455
bmcutler merged 24 commits into
Submitty:mainfrom
sushen123:feat/configurable-password-requirements

Conversation

@sushen123

@sushen123 sushen123 commented Feb 21, 2026

Copy link
Copy Markdown
Contributor

Why is this Change Important & Necessary?

Closes #12341

Password requirements are currently hardcoded (12+ chars, uppercase, lowercase, number, special character). Institutions cannot customize these rules to match their own password policies. Additionally, the Change Password modal has no validation and does not display any requirements to the user.

What is the New Behavior?

  • Password requirements are now configurable via password_requirements in submitty.json
  • The Change Password modal now displays requirements with a "Show Requirements" button (matching the Sign Up page)
  • The Change Password modal now enforces password validation server-side (previously accepted any password)
  • A system migration adds default password_requirements to existing installations
  • The Sign Up page now dynamically renders requirements from config instead of hardcoded HTML

Change Password modal now shows requirements:

Change_password

Sign Up page reflecting custom config (min_length changed to 8):

Password_requirements

What steps should a reviewer take to reproduce or test the bug or new feature?

  1. Log in as instructor/instructor, go to My Profile, click the Change Password pencil icon, verify requirements are displayed with a Show Requirements button
  2. Try submitting a weak password (e.g., abc) — verify it is rejected
  3. Visit /authentication/create_account — verify requirements are still displayed correctly
  4. Modify password_requirements in /usr/local/submitty/config/submitty.json (e.g., set min_length to 8, require_special_chars to false) — verify both Sign Up and Change Password reflect the updated config

Automated Testing & Documentation

Unit tests added for isValidPassword() with custom requirements and max length validation in UtilsTester.php.

Other information

Includes a system migration (20260220120000_add_password_requirements.py) to add default password_requirements config to existing installations.

@github-project-automation github-project-automation Bot moved this to Seeking Reviewer in Submitty Development Feb 21, 2026
@sushen123 sushen123 changed the title Add configurable password requirements and update Change Password modal [Feature:System] Configurable password requirements Feb 21, 2026
@bmcutler
bmcutler requested a review from IDzyre February 21, 2026 15:54
@automateprojectmangement automateprojectmangement Bot moved this from Seeking Reviewer to In Review in Submitty Development Feb 21, 2026

@IDzyre IDzyre left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a good start, and pretty close for a full security review.

I personally think that we shouldn't allow the password requirements to "not be defined", and require them to be in the config.
The goal of this is to consolidate the code that we have to change if the password requirements were to be updated, and this adds multiple extra places where we have to double check to make sure they are the same.

Also, could you update the Cypress login tests to reflect the different password requirements shown?

Comment thread migration/migrator/migrations/system/20260220120000_add_password_requirements.py Outdated
Comment thread migration/migrator/migrations/system/20260220120000_add_password_requirements.py Outdated
@github-project-automation github-project-automation Bot moved this from In Review to Work in Progress in Submitty Development Feb 21, 2026
@codecov

codecov Bot commented Feb 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 67.85714% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 21.50%. Comparing base (8fa4355) to head (b3d76c1).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##               main   #12455      +/-   ##
============================================
+ Coverage     21.48%   21.50%   +0.01%     
- Complexity     9842     9861      +19     
============================================
  Files           268      268              
  Lines         36851    36863      +12     
  Branches        495      495              
============================================
+ Hits           7919     7928       +9     
- Misses        28441    28444       +3     
  Partials        491      491              
Flag Coverage Δ
autograder 21.32% <ø> (ø)
js 2.01% <ø> (ø)
migrator 100.00% <ø> (ø)
php 20.54% <67.85%> (+0.02%) ⬆️
python_submitty_utils 80.08% <ø> (ø)
submitty_daemon_jobs 91.13% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…down(), and add Cypress password validation tests
@sushen123
sushen123 force-pushed the feat/configurable-password-requirements branch from 45dce5c to c607dc5 Compare February 23, 2026 10:31
@sushen123

Copy link
Copy Markdown
Contributor Author

@IDzyre I've addressed your feedback. Can you take another look?

@IDzyre IDzyre left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good on the requirements, and functionality code, I need to do a review on the visual side, but a small question.

Comment thread site/app/templates/ChangePasswordForm.twig Outdated
@sushen123
sushen123 force-pushed the feat/configurable-password-requirements branch from 99593a9 to ee66e07 Compare February 26, 2026 14:09
@sushen123

Copy link
Copy Markdown
Contributor Author

@IDzyre i have implemented all your feedback, can you look into it

@Eli-J-Schwartz

Copy link
Copy Markdown
Contributor

I tested the functionality of this PR, by first attempting to create a new account, and then attempting to change the password for an already existing account. In both instances, the password requirement behavior worked as expected, with only matching passwords that fulfilled the minimum standard being accepted.

However, when the password validation failed, somewhat annoying behavior occurred. In the account creation page, all fields were cleared, erasing the email, user id, and name. In the profile page, I was automatically redirected to the homepage, even when the password didn't update. This seems to be because the logic for password validation is fully server-side, so an invalid post request will redirect to a given page, possibly clearing all fields. If this logic could be added to the client-side, it would prevent this from being an issue.

Additionally, I have a minor concern about the isValidPassword in site/app/libraries/Utils.php. The function repeatedly uses preg_match to check whether a password fulfills a given requirement. As far as I can tell, preg_match is not a constant-time function, meaning it can leak secret data (in this case a password) based on the time it takes to evaluate the function. This does not appear to be a critical security issue, but I think it would be wise to fix now.

@Eli-J-Schwartz
Eli-J-Schwartz self-requested a review February 27, 2026 20:35
@automateprojectmangement automateprojectmangement Bot moved this from Work in Progress to In Review in Submitty Development Feb 27, 2026
@Eli-J-Schwartz
Eli-J-Schwartz removed their request for review February 27, 2026 20:46
@sushen123

Copy link
Copy Markdown
Contributor Author

I tested the functionality of this PR, by first attempting to create a new account, and then attempting to change the password for an already existing account. In both instances, the password requirement behavior worked as expected, with only matching passwords that fulfilled the minimum standard being accepted.

However, when the password validation failed, somewhat annoying behavior occurred. In the account creation page, all fields were cleared, erasing the email, user id, and name. In the profile page, I was automatically redirected to the homepage, even when the password didn't update. This seems to be because the logic for password validation is fully server-side, so an invalid post request will redirect to a given page, possibly clearing all fields. If this logic could be added to the client-side, it would prevent this from being an issue.

Additionally, I have a minor concern about the isValidPassword in site/app/libraries/Utils.php. The function repeatedly uses preg_match to check whether a password fulfills a given requirement. As far as I can tell, preg_match is not a constant-time function, meaning it can leak secret data (in this case a password) based on the time it takes to evaluate the function. This does not appear to be a critical security issue, but I think it would be wise to fix now.

@Eli-J-Schwartz I've noticed the same field-clearing issue happens when email or user ID validation fails too, all fields get cleared on the redirect. Should I create a separate issue to add client-side validation for those fields, or would you prefer I include it in this PR?

@IDzyre

IDzyre commented Feb 28, 2026

Copy link
Copy Markdown
Member

Since the purpose of this PR is for the passwords, if you fix them in this PR, I suggest that you create an issue, outlining what you did to fix it for passwords in this PR. (You can solve that issue in another PR if you wish as well)

@sushen123
sushen123 force-pushed the feat/configurable-password-requirements branch from aa8283d to 9867f81 Compare March 1, 2026 02:30
@sushen123

Copy link
Copy Markdown
Contributor Author

@IDzyre I’ve made the requested changes. Could you please review them

@IDzyre

IDzyre commented Mar 3, 2026

Copy link
Copy Markdown
Member

I will review it when I have time, I am currently a student in University, and it is an exam week, so I haven't done much reviewing. Sorry for the wait.

@github-actions github-actions Bot added the Abandoned PR - Needs New Owner No activity on PR for more than 2 weeks -- seeking new owner to complete label Apr 1, 2026

@NicholasCiuica NicholasCiuica left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tested the changes in this PR, and found everything to be working as expected. However, I've found some issues with the tests for this feature, and I have also left some feedback on opportunities for code reuse and bettering the password-matching frontend feedback.

Additionally, I don't see any tests for changing a current account's password. Given the new password requirements, I feel it will be valuable to test changing passwords in a similar way to how this PR tests account creation.

Comment thread site/tests/app/models/ConfigTester.php Outdated
Comment thread site/public/js/authentication.js Outdated
Comment thread site/app/templates/CreateNewAccount.twig Outdated
Comment thread site/app/templates/ChangePasswordForm.twig Outdated
cy.get('[data-testid="sign-up-button"]').click();
cy.get('[data-testid="popup-message"]').should('contain.text', 'Password does not meet the requirements');
// Password missing uppercase
inputData(undefined, undefined, 'nouppercase#123', 'nouppercase#123');

@NicholasCiuica NicholasCiuica Jun 9, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't look like the Cypress tests are properly testing password complexity anymore, now that the password complexity features are disabled by default. See below, where I edited the Cypress test locally to click Show Requirements.

Image

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure how to edit configurations within a Cypress test, but I believe that would solve this issue; set "require_uppercase", "require_lowercase", "require_numbers", and "require_special_chars" to true in /usr/local/submitty/config/submitty.json at the start of the test

Comment thread site/cypress/e2e/Cypress-System/self_account_creation.spec.js
addresses the following issues: now clears text fields after failing to sign in (in case page isn't reloaded after sign in fails); randomizes username and email that is used to sign in so the current contents of the database (likely) wont affect the current test run; commented out a number of password requirement tests that currently don't work because we are not yet capable of changing configs within cypress tests
I made the ChangePasswordForm and the CreateNewAccount form use the same frontend password validation. I ended up not reusing the checkPasswordsMatch function within the checkSubmittedPassword function, in the case that we want them to do different things later down the line (checkPasswordsMatched is currently called whenever you unfocus from the Confirm Password field of the Create Account form)
@NicholasCiuica NicholasCiuica self-assigned this Jun 10, 2026
@NicholasCiuica

NicholasCiuica commented Jun 10, 2026

Copy link
Copy Markdown
Member

I made some changes to fix the failing password tests. Importantly, I commented out a number of the password complexity Cypress tests because the password complexity requirements are now disabled by default, so a GitHub action will likely need to be made which enables these configs before the test runs and disables them afterward.

I also consolidated the frontend password validation logic for the Change Password/Create Account forms into a single function within authentication.js.

A note to people newly looking at this PR: you have to enable DatabaseAuthentication and create_user_account to test the features added, https://submitty.org/sysadmin/configuration/self_account_creation

removed leftover onclick tags from submit forms, and clarified comments on clearTextFields tag after retesting the Cypress password tests
bmcutler pushed a commit that referenced this pull request Jun 10, 2026
### Why is this Change Important & Necessary?
Relates to [#12455](#12455)

### What is the New Behavior?
The self_create_account Cypress test now randomizes the user id and
email used when trying to create a new account during testing, so that
the database contents of the testing VM don't affect this test.
Originally, this test would break whenever it was run more than once
locally or in CI, because the new user that the first attempt at the
test made affects how the next attempts run.

### What steps should a reviewer take to reproduce or test the bug or
new feature?
enable DatabaseAuthentication and create_user_account to test the
features added,
https://submitty.org/sysadmin/configuration/self_account_creation
run the self_create_account Cypress test locally multiple times.
You will see the "User ID or email already attached to an account"
display where it shouldn't be.

<img width="743" height="511" alt="Screenshot 2026-06-08 170523"
src="https://github.com/user-attachments/assets/d58f4d67-cc9e-477b-9d22-4f23b6695b6f"
/>

### Other information
This PR is a portion of the changes I have committed to
[#12455](#12455), but this
bugfix is important for working on other database-related PRs.
@NicholasCiuica

Copy link
Copy Markdown
Member

Another note to reviewers, when testing the Cypress test self_account_creation locally, the failure below is expected once the test makes it to the email verification steps. Something about the email verification process is not set up to run properly locally, but it succeeds in CI.

image

@IDzyre

IDzyre commented Jun 11, 2026

Copy link
Copy Markdown
Member

It passed locally when I added the feature, not sure what caused that.

changes configs in CI to enable password complexity requirements for the duration of the password tests. These tests will fail locally because password complexity is disabled by default
@NicholasCiuica NicholasCiuica moved this from Work in Progress to In Review in Submitty Development Jun 16, 2026
new spec to test changing passwords. i need to make a cleanup step after i disable password complexity requirements to revert the password set in this spec.
opted to keep change password spec self-contained, so I make a new account just for that test instead of changing the password of any other account made during setup or testing.
@NicholasCiuica

Copy link
Copy Markdown
Member

I have added steps in the CI to the enable password complexity requirements in the configs for the duration of this PR's Cypress tests, and have re-enabled my password complexity tests within the self_account_creation spec. I also made a new change_password spec that tests the ability for a user to change their password given the password complexity configs introduced in this PR.

I believe this PR is ready to be reviewed. Please see original post and my above comments for testing instructions.

@dagemcn dagemcn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did a functionality test on this PR, I tested the rendering of password requirements, the enforcements of password requirements and that changing the password still actually updated the password. All worked as intended. The cypress tests for database authentication are a good addition as previously this functionality was untested to my knowledge. Looks good to me, failing CIs seem to be the ones we already know are flaky or failing.

@github-actions github-actions Bot removed the Abandoned PR - Needs New Owner No activity on PR for more than 2 weeks -- seeking new owner to complete label Jun 19, 2026
@bmcutler
bmcutler merged commit 876cb4f into Submitty:main Jun 19, 2026
23 of 26 checks passed
@github-project-automation github-project-automation Bot moved this from In Review to Done in Submitty Development Jun 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Allow sysadmins to specify password requirements

7 participants