fix: migrate auth spec credentials to AtomicReference + defensive copies (S3077, Phase 4)#428
Open
fix: migrate auth spec credentials to AtomicReference + defensive copies (S3077, Phase 4)#428
Conversation
…ve copies (S3077) Phase 4 (final phase) of the Sonar bug remediation blueprint. Migrates the volatile username/password fields on BasicAuthenticationSpec and DigestAuthenticationSpec to AtomicReference<T>, with the char[] password defensively cloned on both set and get so callers cannot mutate the stored credential in place. Also fixes a real credential-hygiene bug surfaced by the new test suite: getPassword() previously handed back the live internal array, so any caller doing 'spec.getPassword()[0] = char' silently rewrote the stored password. The blueprint's atomic password storage pattern guards against exactly this. Closes #427
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 4 (final phase) of the Sonar bug remediation blueprint. Migrates the credential fields on
BasicAuthenticationSpecandDigestAuthenticationSpecaway fromvolatiletoAtomicReference<T>, with thechar[]password defensively cloned on both set and get.This is the third and final S3077 PR, after #423 (Phase 2 — spec POJOs) and #425 (Phase 3 — engine layer). The blueprint's bug count drops from 59 → 0 once Phases 1–4 land.
Closes #427.
What changed
io.naftiko.spec.consumes.http.BasicAuthenticationSpecusername(String),password(char[])AtomicReference<String>(Pattern A) +AtomicReference<char[]>with defensive clone on set/getio.naftiko.spec.consumes.http.DigestAuthenticationSpecusername(String),password(char[])Each
setPassword(char[])clones the input before storing; eachgetPassword()clones the stored array before returning. Constructors do the same. The public API stays exactly asString/char[]— Jackson and existing callers are unaffected.Why defensive clone, not just
AtomicReference<char[]>The blueprint's "Atomic Password Storage" pattern is explicit: defensive copies on set and get are not optional. Without them,
getPassword()hands out the live internal array — a caller doingspec.getPassword()[0] = 'x'silently rewrites the stored credential. The new test suite exercises this exact scenario and would have caught it before this PR.This pairs naturally with
AtomicReferencebecause both are about safe handoff of a credential value across threads or callers: atomic-swap for the reference itself, defensive-copy for the array contents.Test plan
New
AuthenticationSpecThreadSafetyTest(8 cases, two-tier):volatile. Same regression-guard style asSpecFieldThreadSafetyTest(fix: migrate spec POJOs to AtomicReference + immutable snapshots (S3077) #423) andEngineFieldThreadSafetyTest(fix: migrate engine fields to AtomicReference snapshots (S3077, Phase 3) #425).setPassword/getPassworddefensively clone, andsetPassword(null)round-trips correctly. These test a real bug: onmain, callers can mutate the stored credential in place via the live array reference.Bug Workflow followed strictly:
b3d00d6) — 6/8 fail onmainas expected (2 meta + 4 defensive-copy)b55a70b) — all 8 now passFull local suite: 929 tests, 14 failures, 0 errors. The 14 are the pre-existing LLM-flaky
Step{2-8,10}Shipyard*IntegrationTestcases — same set as onmainand unrelated.Notes for reviewers
volatile char[] passwordfields. I also migrated the 2volatile String usernamefields in the same classes for internal consistency — same approach as Phase 2 (which migrated 27 files for 44 hits) and Phase 3 (which migrated 13 fields for 9 explicit hits).OasImportConverteris the only production caller ofsetPassword(char[])outside tests — both call sites pass freshly-allocated"{{PASSWORD}}".toCharArray()and discard the reference, so the new defensive clone has no observable effect on them.HttpClientAdapter'schar[].toString()bug (S2116), so the read path now sees the correct password value throughnew String(password).