Class PushCredentials
- All Implemented Interfaces:
IPushUserRegistry, AutoCloseable
PUSH-CREDENTIALS.md: the credentials file (sections 2 to 6 and 8), the users registered from Java (section 7) and the group definitions the database users are matched against (section 4).Location (section 2): the system property "iizi.push.credentials", else the environment variable "IIZI_PUSH_CREDENTIALS"; neither means no file, and the built-in group definitions of section 6 apply. A path that is set but does not exist, cannot be read or is refused for its permissions is SEVERE and the server runs as if no file were configured - it does not fall back to a location nobody configured.
Reload (section 3.5, amended 2026-09-26): the file is watched by the JDK's WatchService through PushFileWatcher - the parent directory registered, a burst of events debounced into one reload, a rename into place seen as a create - never by polling. A reload that finds refused lines applies the valid ones and logs every refusal; a file that cannot be read at reload keeps the previous content in force; a deleted file drops every file user with a WARNING and keeps the last load's group definitions, so that a deletion never widens what the database users may do.
Built-ins replaced entirely (section 6): once a file has loaded, its [groups] are the only group definitions; nothing is merged, and a database group the file does not define grants nothing.
The [server] section (section 3.6, ruled 2026-09-26) configures application ID *; getServerSection() hands it to ServerPushKeys, which applies the precedence of S-4. Its fcmServiceAccountFile names Google's service-account key file and, since PUSH-KEYFILES-DESIGN.md (rulings K-7, K-8), its VPrivKeyFile names a VAPID key file: each a path, %USERPROFILE% and ~ expanded, a relative one under the server's key directory; each read through the engine's PushKeyFiles when a send needs it (S-3), held until the engine's watcher reports it changed, and never logged: a file that is missing, refused for its permissions or unusable is SEVERE once, naming the path, and that transport for * is then not configured. A reload whose [server] VAPID pair differs from the previous one logs the WARNING of S-5, because every existing * Browser subscription is bound to the old pair.
Secrets (section 8): no log line carries a password, a hash, a line of the file or anything of the key file. The permission rule of section 8 - the POSIX refusal and the Windows ACL WARNING - and the path expansion of S-3 live in PushKeyFiles since PUSH-KEYFILES-DESIGN.md, which applies them to every key file; the credentials file is checked by the same code. The weak-entry WARNING of section 3.4 carries a count and no user ID; the messages that concern one user name the user ID and nothing else.
Thread-safe: the file content is an immutable snapshot swapped at load, read without a lock; loads and the registry are synchronized.
- Author:
- Christopher Mindus
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic interfaceHow anIZ1password is hashed and checked: the server's ownPasswordHasherin production, supplied so that a test needs no server.static interfaceSupplies the engine's file watcher, creating it at the first file to watch.Field Summary
FieldsModifier and TypeFieldDescriptionWhether a user name is a database user (IZS.USERS), for the section 4 WARNING; a database that cannot answer counts as no.static final StringThe environment variable naming the file: "IIZI_PUSH_CREDENTIALS".static final StringThe system property naming the file: "iizi.push.credentials".static final PushCredentials.PasswordHashingThe server's own hasher:com.iizix.server.user.PasswordHasher, reached throughUserAuthentication, exactly what every database password goes through.static final StringThe name of the watcher thread: "iizi-push-credentials".Constructor Summary
ConstructorsConstructorDescriptionPushCredentials(Path file, PushCredentials.PasswordHashing hashing, Predicate<String> databaseHasUser) Constructor with key files of its own and no VAPID key-file storage, for a caller that names no[server]VPrivKeyFile.PushCredentials(Path file, PushCredentials.PasswordHashing hashing, Predicate<String> databaseHasUser, PushKeyFiles keyFiles, PushKeyFiles.VapidStorage storage) Constructor.Method Summary
Modifier and TypeMethodDescriptionauthenticate(String userName, String password, boolean development) Authenticates a program user: one of the file (section 3) or registered from Java (section 7), the file winning.voidclose()Stops watching: a watcher of the credentials' own is closed, the engine's is left to the engine.static PathResolves the configured file: the system property, else the environment variable.static PushCredentialsThe production instance: the file fromPROPERTYorENVIRONMENT, the server's hasher and the server's database, key files of its own and no VAPID key-file storage.static PushCredentialsfromConfiguration(PushKeyFiles keyFiles, PushKeyFiles.VapidStorage storage) The production instance over the engine's key files: the file fromPROPERTYorENVIRONMENT, the server's hasher and the server's database.getFile()Gets the configured file.intGets the number of file users as last loaded.Gets the lower-case IDs of the file users, for diagnostics.Gets the group names a file defines, for diagnostics.Gets the key files.intGets the number of completed loads, initial and on change, whatever their outcome.Gets a map of the members as last loaded, for diagnostics.Gets the[server]section as last loaded, its key files read through the reader when the section names them and a send has not read them yet: the service-account JSON (S-3) and the VAPID pair ofVPrivKeyFile(K-7), the latter checked againstVPubKeywhen the section sets one.Gets the expanded path of the service-account key file.Gets the resolved path of the[server]VAPID key file.Gets the watcher.booleanTells whether a file is configured, whether or not it has loaded.booleanTells whether a file's definitions are in force: a file has loaded at least once, so its groups replace the built-ins (section 6).booleanisRegistered(String userID) Tells whether a user is registered from Java.voidload()Loads the file once, asstart()does first; for a caller that watches nothing.privilegesOfGroups(Collection<String> groupNames, boolean development) Gets the union of the privileges a set of groups grants: under the file's[groups]when a file is in force, under the built-in definitions of section 6 otherwise.booleanregisterPushUser(String userID, String clearTextPassword, Set<String> groups) --- The registry (section 7) ---voidreload()Reloads the file after a change.voidstart()Loads the file and starts watching it through a watcher of its own.voidstart(PushCredentials.WatcherSource shared) Loads the file and watches it through the engine's watcher, created at this first file to watch; the key files the section names are watched through the same one, from their first read.toString()A summary for the log: the file and the counts, never a secret.booleanunregisterPushUser(String userID) Removes a user registered withIPushUserRegistry.registerPushUser(String, String, Set).
Field Details
PROPERTY
The system property naming the file: "iizi.push.credentials". Wins over the environment variable.- See Also:
ENVIRONMENT
The environment variable naming the file: "IIZI_PUSH_CREDENTIALS". Read when the property is absent.- See Also:
THREAD_NAME
The name of the watcher thread: "iizi-push-credentials".- See Also:
SERVER_HASHING
The server's own hasher:com.iizix.server.user.PasswordHasher, reached throughUserAuthentication, exactly what every database password goes through.DATABASE_HAS_USER
Constructor Details
PushCredentials
public PushCredentials(Path file, PushCredentials.PasswordHashing hashing, Predicate<String> databaseHasUser) Constructor with key files of its own and no VAPID key-file storage, for a caller that names no[server]VPrivKeyFile. Nothing is read untilstart()orload().- Parameters:
file- The credentials file, or null when none is configured.hashing- TheIZ1hasher.databaseHasUser- Answers whether a user name is a database user, or null to skip the section 4 WARNING.
PushCredentials
public PushCredentials(Path file, PushCredentials.PasswordHashing hashing, Predicate<String> databaseHasUser, PushKeyFiles keyFiles, PushKeyFiles.VapidStorage storage) - Parameters:
file- The credentials file, or null when none is configured.hashing- TheIZ1hasher.databaseHasUser- Answers whether a user name is a database user, or null to skip the section 4 WARNING.keyFiles- The key files: the reader of the section's two key files, shared with the engine.storage- Loads a VAPID key file as its$pushcontainer, or null when[server]VPrivKeyFilecannot be served.
Method Details
fromConfiguration
The production instance: the file fromPROPERTYorENVIRONMENT, the server's hasher and the server's database, key files of its own and no VAPID key-file storage.- Returns:
- The credentials, not yet loaded.
fromConfiguration
public static PushCredentials fromConfiguration(PushKeyFiles keyFiles, PushKeyFiles.VapidStorage storage) The production instance over the engine's key files: the file fromPROPERTYorENVIRONMENT, the server's hasher and the server's database.- Parameters:
keyFiles- The key files, shared with the engine.storage- Loads a VAPID key file as its$pushcontainer, or null.- Returns:
- The credentials, not yet loaded.
configuredPath
Resolves the configured file: the system property, else the environment variable.- Returns:
- The path, or null when neither is set.
getFile
isFileConfigured
public boolean isFileConfigured()Tells whether a file is configured, whether or not it has loaded.- Returns:
- true when a path is set.
isFileInForce
public boolean isFileInForce()Tells whether a file's definitions are in force: a file has loaded at least once, so its groups replace the built-ins (section 6).- Returns:
- true once a file has loaded.
getFileUserCount
public int getFileUserCount()Gets the number of file users as last loaded.- Returns:
- The count.
getLoadCount
public int getLoadCount()Gets the number of completed loads, initial and on change, whatever their outcome.- Returns:
- The count.
getWatcher
Gets the watcher.- Returns:
- The watcher, null when no file is configured or before
start().
getServiceAccountFile
Gets the expanded path of the service-account key file.- Returns:
- The path, or null when
[server]names none.
getVapidKeyFile
Gets the resolved path of the[server]VAPID key file.- Returns:
- The path, or null when
[server]names none.
getKeyFiles
start
public void start()Loads the file and starts watching it through a watcher of its own. Without a configured file nothing runs and no thread is started.start
Loads the file and watches it through the engine's watcher, created at this first file to watch; the key files the section names are watched through the same one, from their first read. Without a configured file nothing runs and nothing is watched.- Parameters:
shared- Supplies the engine's watcher, or null for a watcher of the credentials' own, closed byclose().
close
public void close()Stops watching: a watcher of the credentials' own is closed, the engine's is left to the engine. The last content stays in force.- Specified by:
closein interfaceAutoCloseable
load
public void load()Loads the file once, asstart()does first; for a caller that watches nothing.reload
public void reload()Reloads the file after a change.authenticate
public PushHttpHandler.AuthUser authenticate(String userName, String password, boolean development) throws PushError Authenticates a program user: one of the file (section 3) or registered from Java (section 7), the file winning. A user found here is authenticated here and nowhere else (PUSH-WIRE-CONTRACT 3.2): a wrong password is 401, never a fall-through to the database. Every comparison is constant-time.- Parameters:
userName- The user name presented.password- The clear-text password presented.development- true on a development server, where the built-indefaultalso grantssend; matters only while no file is in force.- Returns:
- The caller, with
PushHttpHandler.NO_UIDand the union of its groups' privileges; null when the name is neither in the file nor registered, so the caller continues with the database. - Throws:
PushError- 401 when the user is known here and the password is wrong.
privilegesOfGroups
Gets the union of the privileges a set of groups grants: under the file's[groups]when a file is in force, under the built-in definitions of section 6 otherwise. Used for the database users (section 4) and the registered users.- Parameters:
groupNames- The group names, in any case.development- true on a development server (built-ins only).- Returns:
- The privileges, never null.
getServerSection
Gets the[server]section as last loaded, its key files read through the reader when the section names them and a send has not read them yet: the service-account JSON (S-3) and the VAPID pair ofVPrivKeyFile(K-7), the latter checked againstVPubKeywhen the section sets one. A named file that cannot be used leaves its member null, whichServerPushKeysturns into "not configured" for that transport.- Returns:
- The section,
PushServerSection.EMPTYwhen the file has none.
registerPushUser
--- The registry (section 7) ---- Specified by:
registerPushUserin interfaceIPushUserRegistry- Parameters:
userID- The user ID: at least one character, no whitespace, no colon.clearTextPassword- The password the program will send with Basic authentication.groups- The groups whose privileges the user gets, as defined in the credentials file or, without one, by the built-in definitions.- Returns:
trueif registered;false, with a WARNING naming the user ID, if the user ID is invalid, is already in the credentials file or is already registered - the credentials file always wins.
unregisterPushUser
Description copied from interface:IPushUserRegistryRemoves a user registered withIPushUserRegistry.registerPushUser(String, String, Set). Users of the credentials file are not affected.- Specified by:
unregisterPushUserin interfaceIPushUserRegistry- Parameters:
userID- The user ID.- Returns:
trueif a registered user was removed,falseif none was registered under that ID.
isRegistered
Tells whether a user is registered from Java.- Parameters:
userID- The user ID, in any case.- Returns:
- true when registered.
toString
getGroupNames
getFileUserKeys
getMembers