Class ServerCredentialStore

java.lang.Object
com.ultikits.ultitools.utils.ServerCredentialStore

final class ServerCredentialStore extends Object
The only reader and writer of the cloud_credential entry of <server root>/.ultikits/credentials.json, always through CredentialStore.

The entry is {credential, credentialId, serverId, userId, serverName, linkedAt}. Saving it removes the 6.3.0 user token (cloud_token) in the same atomic write, because a server holds only its server credential from protocol v2 on. Every other key -- the 32-hex uuid install id among them -- is carried through unchanged.

Why these writes cannot overwrite operator content. credentials.json is framework-owned state, not operator configuration: CredentialStore is its sole owner, it is created and maintained by the framework alone (owner-only file mode), and no operator workflow edits it. Both write paths here change only the two framework keys named above inside one CredentialStore.update(java.util.function.UnaryOperator<java.util.Map<java.lang.String, java.lang.Object>>) call, and CredentialStore.update(java.util.function.UnaryOperator<java.util.Map<java.lang.String, java.lang.Object>>) refuses to write over a file it cannot parse, so a hand-damaged file is never replaced.

Since:
6.3.1
  • Field Details

    • KEY

      static final String KEY
      The document key of the server credential.
      See Also:
    • LEGACY_TOKEN_KEY

      static final String LEGACY_TOKEN_KEY
      The document key of the 6.3.0 user OAuth token, which a successful link removes.
      See Also:
    • REPORTED_MALFORMED

      private static final AtomicBoolean REPORTED_MALFORMED
      Whether the current malformed entry was already reported, so one bad file warns once.
  • Constructor Details

    • ServerCredentialStore

      private ServerCredentialStore()
  • Method Details

    • load

      static ServerCredential load()
      Returns:
      the stored credential, or null when the file is absent or unreadable, the key is missing, or the entry is malformed (reported once with a WARNING that names the file, never the content)
    • save

      static void save(ServerCredential credential)
      Writes credential under KEY and removes LEGACY_TOKEN_KEY, in one atomic write. Framework-owned state only; see the class javadoc for why this cannot overwrite operator content.
      Parameters:
      credential - the credential to persist
      Throws:
      DataAccessException - if the write fails or the current file cannot be parsed
    • replace

      static boolean replace(String serverId, String credential, String credentialId)
      Replaces the secret and its public id of the stored credential with a rotated pair (plan 22-21, D-10), in one CredentialStore.update(java.util.function.UnaryOperator<java.util.Map<java.lang.String, java.lang.Object>>) -- one atomic, owner-only write. Every other field of the entry (the server id among them) and every other key of the file is kept. Nothing is written when no valid credential is stored, or when the stored one belongs to another server identity, because a rotation can only replace the credential the rotating session holds. Called only by CloudSession.rotateCredential(java.lang.String, java.lang.String), which updates its in-memory credential in the same monitor region (the session is the one owner of the current credential). Framework-owned state only; see the class javadoc for why this cannot overwrite operator content. The secret is never logged.
      Parameters:
      serverId - the server id of the credential being rotated
      credential - the new ucs_ secret
      credentialId - the new credential's public id
      Returns:
      true when the new credential is stored
      Throws:
      DataAccessException - if the write fails or the current file cannot be parsed
    • deleteIfMatches

      static boolean deleteIfMatches(String credentialId)
      Removes the credential only if its public id still matches the rejected connection's id. The comparison and removal share one CredentialStore lock acquisition, so a newer login or rotation cannot be erased by a late rejection. Framework-owned state only; see the class javadoc for why this cannot overwrite operator content.
      Parameters:
      credentialId - the id used by the rejected connection
      Returns:
      whether that entry was removed
    • removeLegacyToken

      static ServerCredentialStore.LegacyTokenRemoval removeLegacyToken()
      Removes the unusable pre-v2 token only when it exists. CredentialStore is the sole owner of this framework state, not operator configuration; the hard cut retained no old signing key and supports no token exchange. No token means no update, preserving the file's exact bytes.
      Returns:
      whether the token was removed and a server credential was present beside it
    • delete

      static boolean delete()
      Removes only the KEY entry. The file is not rewritten when the entry is absent. Framework-owned state only; see the class javadoc.
      Returns:
      true if an entry existed and was removed