Loading…
Loading…
Prevents stored secrets from being sent to a different destination. Enforces that any change to a credential's target endpoint or user requires re-entry
The Credential Target Guard is a security component that prevents stored secrets, such as connector passwords, from being redirected to an arbitrary destination. It enforces a strict security principle: a stored secret can only be sent to the endpoint and for the user that it was originally saved for.
This component solves a specific security problem: an administrative user who is permitted to manage system configurations but not to view stored secrets must not be able to exfiltrate those secrets by modifying a configuration to point to a different host. The guard acts as a check before any operation that combines a stored secret with a caller-supplied target (e.g., a hostname or username). If the target differs from the one associated with the stored secret, the guard requires the API consumer to supply the secret again in the current request.
This check is invoked by internal services, such as the Admin API, whenever a request might use a stored secret. It is not a standalone service that API consumers call directly.
The core enforcement mechanism is the requireSecretForNewTarget method. When an API request attempts to use a stored secret, this guard's logic is triggered to validate the request.
The validation follows these steps:
If a stored secret exists, the target has changed, and the secret was not re-supplied, the guard rejects the operation by throwing an IllegalArgumentException, which results in an HTTP 400 Bad Request response to the API consumer.
flowchart TD
A[Start: Request to use a stored secret] --> B{Is a secret stored?};
B -- No --> G[Allow Request];
B -- Yes --> C{Has the target destination changed?};
C -- No --> G[Allow Request];
C -- Yes --> D{Was the secret re-supplied in the request?};
D -- No --> E[Reject Request with HTTP 400];
D -- Yes --> G[Allow Request];The guard uses specific comparison logic to determine if a target has changed.
sameEndpoint)Two endpoints are considered the same if they have an identical scheme, host, effective port, and path.
https is the same as HTTPS). If no scheme is provided, https:// is assumed.api.example.com is the same as API.EXAMPLE.COM).80 for http and 443 for https./, and a single trailing slash is ignored (e.g., /v1/ becomes /v1).?foo=bar and #section) are ignored during comparison.NOTE
If a candidate endpoint URL is blank or empty, it is interpreted as "use the saved value" and always passes the sameEndpoint check. Unparseable URLs are considered a mismatch as a security precaution.
sameUsername)Usernames are compared case-sensitively after trimming leading and trailing whitespace. A blank or empty candidate username is interpreted as "use the saved value" and passes the check.
sameHostHeader)Comparison of the Host header is distinct from endpoint host comparison.
Host header value is treated as a change if a value was previously set. This is because clearing the header causes the request to fall back to the endpoint's host, potentially targeting a different virtual host.The CredentialTargetGuard provides several static methods used internally to perform its checks.
requireSecretForNewTargetThis method is the primary enforcement point. It throws an IllegalArgumentException if a stored secret would be sent to a new target without being re-supplied.
There are two overloads for this method.
Parameters for simple secrets:
| Name | Type | Description |
|---|---|---|
what | String | A human-readable name for the system the secret belongs to (e.g., "F5"). Used to construct the error message. |
storedSecretSet | boolean | true if a secret is already stored for this configuration. |
suppliedSecret | String | The secret provided in the current request. A blank or null value means the secret was not supplied. |
targetChanged | boolean | true if the request modifies the endpoint, user, or other sensitive parameters. |
Parameters for structured secrets:
This overload is for integrations where the secret is part of a larger structured object, and it allows for a custom error message.
| Name | Type | Description |
|---|---|---|
storedSecretSet | boolean | true if a secret is already stored for this configuration. |
secretSupplied | boolean | true if the secret was re-supplied in the current request. |
targetChanged | boolean | true if the request modifies the secret's destination. |
message | String | The specific error message to return to the operator if the check fails. |
These methods are used to determine if a target has changed.
| Method | Return Type | Description |
|---|---|---|
sameEndpoint(saved, candidate) | boolean | Returns true if the candidate URL string refers to the same endpoint as the saved URL string, according to the comparison logic described above. |
allKnownEndpoints(saved, candidates) | boolean | Returns true if every non-blank URL in the candidates collection matches one of the URLs in the saved collection. |
sameHostHeader(saved, resolved) | boolean | Returns true if the resolved Host header value is the same as the saved one, using case-insensitive comparison for ASCII values. A blank resolved value is considered a change. |
sameUsername(saved, candidate) | boolean | Returns true if the candidate username is blank or matches the saved username (case-sensitive). |
When the Credential Target Guard rejects a request, the API responds with an HTTP 400 Bad Request status code. The response body contains a message explaining why the request was denied.
| Error Message | Cause |
|---|---|
The <system> address (host, port or path) or username differs from the saved one. Re-enter the <system> password to use a different address or user; the saved password is only ever sent to the saved address as the saved user. | The API consumer attempted to use a stored secret while changing the target endpoint URL or username. <system> will be replaced with the name of the integration (e.g., "F5"). |
The <system> TLS-insecure setting differs from the saved one. Re-enter the <system> password to test with a different TLS setting, for example {"tlsInsecure": false, "password": "..."}; the saved password is only ever sent with the saved TLS setting. | The API consumer attempted to use a stored secret while changing the TLS verification setting (e.g., tlsInsecure). - |An API consumer attempts to change the TLS setting for a connector without re-entering the password.
Rejected Request Body:
{
"tlsInsecure": false
}
This request would be rejected with an HTTP 400 error and a message similar to the one for TLS setting changes.
Corrected Request Body:
To fix this, the consumer must re-supply the password along with the changed setting.
{
"tlsInsecure": false,
"password": "<SECRET_PASSWORD>"
}
This request will pass the guard's check because the password was supplied again.