feat(security): enforce password complexity policy (min length + common-password blocklist)#40670
feat(security): enforce password complexity policy (min length + common-password blocklist)#40670rusackas wants to merge 1 commit into
Conversation
SupersetSecurityManager did not enforce any password policy, so DB-auth self-registration / password changes accepted trivially short or common passwords (ASVS 6.2.1 / 6.2.4, CWE-521). Add superset.security.password_complexity.validate_password_complexity (minimum length via AUTH_PASSWORD_MIN_LENGTH, default 8, plus a common-password blocklist extendable via AUTH_PASSWORD_COMMON_BLOCKLIST), and wire it through Flask-AppBuilder's FAB_PASSWORD_COMPLEXITY_ENABLED / _VALIDATOR. FAB runs this callable from both the WTForms password fields (self-registration, user edit, reset password) and the User REST API, so one function covers all password-setting flows. The policy is intentionally less draconian than FAB's built-in default_password_complexity. DRAFT: enabling the policy by default changes registration / password-change behavior (short or common passwords are now rejected) and any API-driven user provisioning that used weak passwords. Needs validation of the end-to-end flows before merge. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
✅ Deploy Preview for superset-docs-preview ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #40670 +/- ##
==========================================
- Coverage 64.18% 63.81% -0.38%
==========================================
Files 2591 2652 +61
Lines 138471 142172 +3701
Branches 32120 32568 +448
==========================================
+ Hits 88883 90724 +1841
- Misses 48056 49885 +1829
- Partials 1532 1563 +31
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds a Superset-specific password complexity policy (min length + common-password blocklist) and wires it into Flask-AppBuilder so it applies consistently across password-setting flows (registration, reset/change forms, and User REST API).
Changes:
- Introduces
superset.security.password_complexity.validate_password_complexityenforcing minimum length and rejecting common passwords (plus configurable extra blocklist). - Enables FAB password complexity enforcement by default and adds config knobs (
AUTH_PASSWORD_MIN_LENGTH,AUTH_PASSWORD_COMMON_BLOCKLIST). - Adds unit tests covering acceptance/rejection cases and config overrides.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
superset/security/password_complexity.py |
New validator implementing the policy and producing localized validation errors. |
superset/config.py |
Enables FAB password complexity by default and defines policy configuration defaults. |
tests/unit_tests/security/test_password_complexity.py |
Unit tests for the validator behavior and config override handling. |
| min_length = current_app.config.get("AUTH_PASSWORD_MIN_LENGTH", DEFAULT_MIN_LENGTH) | ||
| if len(password) < min_length: |
| extra = current_app.config.get("AUTH_PASSWORD_COMMON_BLOCKLIST") or [] | ||
| blocklist = COMMON_PASSWORDS | {str(item).lower() for item in extra} | ||
| if password.lower() in blocklist: |
| # Password complexity policy, enforced (via Flask-AppBuilder) across | ||
| # self-registration, the user edit/reset forms, and the User REST API. | ||
| # The Superset validator requires a minimum length and rejects common | ||
| # passwords; tune via AUTH_PASSWORD_MIN_LENGTH / AUTH_PASSWORD_COMMON_BLOCKLIST, | ||
| # or replace FAB_PASSWORD_COMPLEXITY_VALIDATOR with your own callable. | ||
| from superset.security.password_complexity import ( # noqa: E402 | ||
| validate_password_complexity as _validate_password_complexity, | ||
| ) | ||
|
|
||
| FAB_PASSWORD_COMPLEXITY_ENABLED = True | ||
| FAB_PASSWORD_COMPLEXITY_VALIDATOR = _validate_password_complexity | ||
| AUTH_PASSWORD_MIN_LENGTH = 8 | ||
| AUTH_PASSWORD_COMMON_BLOCKLIST: list[str] = [] |
SUMMARY
SupersetSecurityManagerenforced no password policy, so DB-auth self-registration and password changes accepted trivially short or common passwords (FINDING-014 / 015 — ASVS 6.2.1, 6.2.4, CWE-521).This adds
superset.security.password_complexity.validate_password_complexity:AUTH_PASSWORD_MIN_LENGTH(default 8), andAUTH_PASSWORD_COMMON_BLOCKLIST).It's wired through Flask-AppBuilder's
FAB_PASSWORD_COMPLEXITY_ENABLED+FAB_PASSWORD_COMPLEXITY_VALIDATOR. FAB runs this callable from both the WTForms password fields (self-registration, user edit, reset password) and the User REST API — so a single function covers every password-setting flow, with clean validation errors. The policy is intentionally less draconian than FAB's built-indefault_password_complexity(which requires 2 uppercase + 1 special + 2 digits + 3 lowercase + length 10).WHY DRAFT (
hold:testing)Enabling the policy by default changes behavior: short/common passwords are now rejected at registration, password change, and API-driven user provisioning. Needs validation that the form flows and the User API surface the error cleanly and that no existing automated provisioning relies on weak passwords.
TESTING INSTRUCTIONS
Tests: strong password accepted; short rejected; common rejected (case-insensitive); configurable min length; extra blocklist honored.
ADDITIONAL INFORMATION
🤖 Generated with Claude Code