Repository navigation
fix(auth): decode the base64-encoded password in setupAdmin - #393
Conversation
The frontend base64-encodes the password sent to setup-admin, as it does for login, but setupAdmin forwarded the encoded string straight to the auth service, which bcrypt-hashed the base64 text. Every subsequent login (which does decode) then compared the real plaintext against that hash and failed, locking the bootstrap admin out permanently. Decode with decodeBase64Password before calling auth.SetupAdmin, exactly like login and resetPassword, and drop the now-stale setupAdmin exemption from the base64-password-guard test. Closes #224
|
Warning Review limit reached
This review includes 5 billable files and costs up to $1.25.
Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing. Or wait 3 minutes for your next included review. View limit detailsLimit details: You’ve used all 4 included reviews currently available. Your 37 included PR review attempts over the past 7 days set your current allowance at 4 reviews per hour. Review configuration: ⚙️ Run configurationConfiguration used: Repository: LeanerCloud/cloud-commitments-platform/.coderabbit.yaml Review profile: CHILL Plan: Essentials Run ID: 📒 Files selected for processing (5)
Comment |
|
Independent adversarial review + local verification: MERGE at 3fa4ccc. setupAdmin now decodes the base64 password with the same strict decoder login uses, so the bootstrap admin can log in; no double-decode path; CLI/MCP have no setup flow. Round-trip test fails pre-fix and passes; checks green incl. E2E. |
Summary
setupAdminforwarded the base64-encoded password straight to the authservice instead of decoding it first, so the bootstrap admin's stored
bcrypt hash covered the base64 text instead of the real password. Every
later login (which does decode) then failed, locking the bootstrap admin
out permanently.
Root cause
The frontend base64-encodes the setup-admin password identically to how it
encodes the login password (
frontend/src/api/auth.ts).logindecodeswith
decodeBase64Passwordbefore callingauth.Login(
internal/api/handler_auth.go), butsetupAdminpassedsetupReqstraight through to
auth.SetupAdmin, which bcrypt-hashes whatever it isgiven. The base64-password guard test (
internal/api/base64_password_guard_test.go)had a
knownExemptFunctionsentry forsetupAdminwith a justificationthat did not actually address the encoding mismatch.
Fix
internal/api/handler_auth.go:setupAdminnow callsdecodeBase64Password(setupReq.Password)before callingh.auth.SetupAdmin, exactly likeloginandresetPassword.internal/api/base64_password_guard_test.go: removed the stalesetupAdminexemption;knownExemptFunctionsis now empty, and theguard test itself catches a future regression of this class.
TestHandler_setupAdmin_Successand the router coverage test tosend a base64-encoded password body, matching the real frontend contract.
Regression test
Added
TestSetupAdminThenLogin_RoundTripininternal/server/adapter_test.go.It drives the real request path (
api.Router.Route->api.Handler.setupAdmin/
login->authServiceAdapter-> the real*auth.Service, backed by anauth.MockStorethat persists the usersetupAdmincreates and hands itback to
login), so the actual bcrypt hashsetupAdminproduces isexercised by
login's bcrypt compare.Proof it fails pre-fix: stashed
internal/api/handler_auth.go(revertingjust the decode call) and reran the test --
loginfailed withErrInvalidCredentials-class error because the stored hash covered thebase64 text. Restoring the fix makes it pass.
Verification
go build ./...go vet ./internal/api/... ./internal/server/... ./internal/auth/...go test -race -short ./internal/api/... ./internal/server/... ./internal/auth/...-- 3529 passedgolangci-lint runat the CI-pinned v2.10.1 -- 0 issuesgo mod tidy -diff-- emptyCloses #224