Repository navigation
Add an opt-in plain-text token store for machines without a keychain - #119
Open
Gorka Gonzalo (d0ubl3g) wants to merge 9 commits into
Open
Gorka Gonzalo (d0ubl3g) wants to merge 9 commits into
Gorka Gonzalo (d0ubl3g) wants to merge 9 commits into
Conversation
Replace the proposal with the decision: keep the keychain as the default and add an explicit opt-in token store that is a plain-text file, with no fallback in either direction. Record the file checks, the location in the state directory, the deferral of Windows and of the Linux kernel keyring, and the server-side refresh token lifetime that is still to be confirmed. The text now matches the fail-closed sign-in behaviour, where tokens that cannot be stored are revoked. Refs #39 Signed-off-by: d0ubl3g <48954024+d0ubl3g@users.noreply.github.com>
People who work from a jump host or another machine without a keychain could only use a tenant API key. Add a second token store, selected by HODEISHIELD_TOKEN_STORE=plaintext-file or the global token_store setting, that keeps one file per profile in the state directory. The keychain stays the default and the two stores never fall back to each other. Every read and write refuses, without repairing, a symbolic link, a file or directory owned by another user, or one open to group or others. Files are created with mode 600 and replaced atomically. The effective user id comes from rustix, which is already in the dependency graph on Linux, so no unsafe code is needed. Windows is refused for now. Refs #39 Signed-off-by: d0ubl3g <48954024+d0ubl3g@users.noreply.github.com>
Add a README section for servers, containers and remote sessions that puts API keys first and the opt-in file second with its trade-off, the new variable and setting in their tables, the network home directory note, and the exit code for a refused token file. Update the places that promised tokens are never in a file, and add the changelog entry. Refs #39 Signed-off-by: d0ubl3g <48954024+d0ubl3g@users.noreply.github.com>
Say that on macOS the sessions directory is a sibling of the application support folder, not inside the configuration folder, that the parents of the sessions directory must not be writable by other users, that the file names are a hash and not a way to hide a profile name, that running as root for a user's home does not work, and that a refused file makes login and logout exit 1 while other commands exit 3. Refs #39 Signed-off-by: d0ubl3g <48954024+d0ubl3g@users.noreply.github.com>
Keep the sessions outside the configuration directory on macOS, where the platform gives the same folder for both. Open the sessions directory once without following links, check it on the open handle and do every later operation relative to it, so replacing the path after the check cannot redirect a read, write or removal. Open files without following links and without blocking, remove stale temporary files that a crash could leave with live tokens, and choose the store once per process so a command checks and saves in the same one. State precisely in the message that group and others must have no access. Tests cover the temporary file guard, the leftovers, the opposite direction of the missing fallback, and that a refused file is left byte for byte as it was. Refs #39 Signed-off-by: d0ubl3g <48954024+d0ubl3g@users.noreply.github.com>
The sessions moved to a sibling of the configuration directory on macOS; the integration tests still looked inside it, so on macOS they found no file. Refs #39. Signed-off-by: d0ubl3g <48954024+d0ubl3g@users.noreply.github.com>
The service's token lifetimes are now known: access tokens last 15 minutes, refresh tokens 30 days from the last refresh with reuse detection, and an absolute 90-day limit is being added. The README and the decision record state today's exposure of a leaked file and how to end it, instead of an open question. Refs #39. Signed-off-by: d0ubl3g <48954024+d0ubl3g@users.noreply.github.com>
2 tasks
The test moved the sessions directory into the state directory, which does not exist on macOS (the sessions directory sits under Application Support there), so the move failed before the case under test ran. Refs #39. Signed-off-by: d0ubl3g <48954024+d0ubl3g@users.noreply.github.com>
Its only users are the Linux check and a Unix-only test, so on a Windows test build it was dead code and clippy refused it. Refs #39. Signed-off-by: d0ubl3g <48954024+d0ubl3g@users.noreply.github.com>
This branch has not been deployed
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.
Lets a person sign in on a machine without a system keychain (a server, WSL, a remote session) by choosing, explicitly, to keep the session in a file only they can read. The keychain stays the default and the CLI never falls back from one store to the other on its own. Containers and CI keep using API keys.
Opt-in
HODEISHIELD_TOKEN_STORE=plaintext-file, or the global settingtoken_store = "plaintext-file"(the environment wins). Any other value exceptkeychainis an error (exit 1).Where and how the file is kept
$XDG_STATE_HOME/hodeishield/sessions/on Linux,~/Library/Application Support/com.Hodeitek.HodeiShield.sessions/on macOS. File names are a hash of the profile name.O_NOFOLLOWand checked again on the open handle.login.Sign-in behaviour unchanged
loginchecks the chosen store before asking for approval; if saving fails after the exchange, the refresh token and then the access token are revoked.logoutrevokes, then deletes the file.loginandlogout; a corrupt file is 1. No new codes.Docs and tests
docs/decisions/0001is updated in place and accepted. README (servers and remote sessions, settings, exit codes), CHANGELOG, CONTRIBUTING and SECURITY are updated.Refs #39.
Release dependency. This change waits for a change in the service: an absolute limit of 90 days for these sessions from the original sign-in, and ending them when the password is changed. It merges after the 0.4.0 release, and the release that carries it ships only once that service change is live; before that release, the README's "How long" bullet and the decision record are updated to state the final figure.