Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## pr/CM352 #1238 +/- ##
=========================================
Coverage 51.34% 51.34%
=========================================
Files 149 149
Lines 13918 13918
=========================================
Hits 7146 7146
Misses 6160 6160
Partials 612 612 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
59b6e1b to
9d49582
Compare
|
@nbmaiti On main the default admin username is standalone, so a fresh install logs in fine. This PR sets it to "" but there's no generate-when-blank step like handleAdminPassword has. Won't a freshly downloaded exe then 401 on login (login.go:88 needs an exact match)? |
77e4f1c to
c1025cf
Compare
There was a problem hiding this comment.
🟡 Changes recommended
There’s a concrete discrepancy with the PR’s stated goal (default admin username still present in defaults) and a security-related comment/guarantee mismatch that should be corrected before merge.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR hardens credential handling by ensuring the admin password is no longer stored or compared as plaintext: it is generated when missing, normalized into a bcrypt hash, persisted safely to config.yml, and validated during login using bcrypt. It also adds regression tests around config persistence and CIRA credential checks.
Changes:
- Generate an admin password when unset, store only its bcrypt hash in config, and normalize legacy plaintext passwords into hashes on startup.
- Update
/api/v1/authorizebasic-auth verification to compare against a bcrypt-hashed admin password (with constant-time username comparison). - Add/extend tests for password persistence behavior and for CIRA APF handler credential/protocol handling.
File summaries
| File | Description |
|---|---|
| internal/controller/tcp/cira/tunnel_test.go | Adds targeted APF handler tests for credential validation, auth method handling, and keep-alive threshold behavior. |
| internal/controller/tcp/cira/handler.go | Uses constant-time comparisons for CIRA credential checks (reducing per-field timing leakage). |
| internal/controller/httpapi/v1/login.go | Switches admin password verification to bcrypt hash comparison for basic auth. |
| internal/controller/httpapi/v1/login_test.go | Updates login tests to use a bcrypt-hashed admin password in config fixtures. |
| config/config.go | Makes SaveAdminPassword resilient to missing config files (create-if-missing) while preserving other fields. |
| config/config_test.go | Adds regression tests for SaveAdminPassword creation/preservation/error paths and file permissions. |
| cmd/app/main.go | Implements admin password hashing/normalization, persistence behavior, and one-time plaintext disclosure on generation. |
| cmd/app/main_test.go | Adds tests ensuring generated passwords are persisted as hashes and legacy plaintext values are normalized correctly. |
Review details
- Files reviewed: 8/8 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| // Both comparisons always run so the response time does not reveal which | ||
| // field failed. MPSUsername is the field used for CIRA authentication. | ||
| usernameMatches := subtle.ConstantTimeCompare([]byte(device.MPSUsername), []byte(username)) | ||
| passwordMatches := subtle.ConstantTimeCompare([]byte(device.MPSPassword), []byte(password)) |
| fileCfg := defaultConfig() | ||
| if err := yaml.Unmarshal(data, fileCfg); err != nil { | ||
| return err | ||
|
|
||
| if _, statErr := os.Stat(configPath); statErr == nil { | ||
| data, readErr := os.ReadFile(configPath) | ||
| if readErr != nil { |
Console compared the admin username and password with plain string equality, so credentials were matched in cleartext and the comparison leaked timing information. Verify the admin password as a bcrypt hash and compare the username in constant time, hashing and persisting any plaintext value already present in config on startup. CIRA authentication had the same flaw: the decrypted MPSPassword was checked with a direct != comparison, which is vulnerable to a timing side channel. Use subtle.ConstantTimeCompare for both the username and the password. Add tests covering the credential rejection paths, including an unset device ID, a lookup failure, and a missing device. Signed-off-by: Nabendu Maiti <nabendu.bikash.maiti@intel.com>
4268a34 to
a6a5c13
Compare
Summary
auth.adminPasswordinto a hash on startupNote:
auth.adminUsernameintentionally keeps itsstandalonedefault so a fresh install can still log in. Only the password default is removed.Testing