markhoerth opened a new issue, #14442:
URL: https://github.com/apache/gravitino/issues/14442
### Version
main branch, commit bb634defdc5663a8124be5fca1c8d9e52ac096ac (2.0.0-SNAPSHOT)
### Describe what's wrong
A user creates a catalog (or a schema or fileset) with `secretBindings` and,
by mistake, gives a binding as a bare string instead of an object, for example
`"secretBindings": {"x-token": "<secret value>"}`. They expect a 400 that says
the request is malformed, without repeating the secret.
The request is rejected with 400 `Malformed json request`, but the `stack`
field of the error response contains the secret value in clear text, quoted
inside the Jackson exception message. The response goes back to the client and
through any proxy or client-side logging on the way. The same happens for
schema create. A malformed JSON document (parse error) and a binding whose
`plaintext` is a list do not echo the value, so only this deserialization error
is affected.
Cause:
- `SecretBindingDTO`
(`common/src/main/java/org/apache/gravitino/dto/secret/SecretBindingDTO.java:41`)
has no String creator, so Jackson throws `MismatchedInputException` when a
binding is a string. Jackson includes the offending string value in that
exception's message (`... from String value ('<value>')`).
`CatalogCreateRequest`, `SchemaCreateRequest` and `FilesetCreateRequest` all
hold `Map<String, SecretBindingDTO>`.
- `JsonMappingExceptionMapper.toResponse` passes the exception into the
error response
(`server/src/main/java/org/apache/gravitino/server/web/mapper/JsonMappingExceptionMapper.java:35-37`,
through
`server-common/src/main/java/org/apache/gravitino/server/web/Utils.java:112-116`).
- `ErrorResponse.getStackTrace` prints the full throwable, message included,
into the `stack` list
(`common/src/main/java/org/apache/gravitino/dto/responses/ErrorResponse.java:414-424`).
The defect is in Gravitino's own code. Possible fixes: give
`SecretBindingDTO` a deserializer that rejects a non-object value with a
message that does not quote it, or have `JsonMappingExceptionMapper` leave out
the Jackson message and stack (or redact quoted values) for requests whose body
can carry secret plaintext.
### Error message and/or stacktrace
```
POST /api/metalakes/gvtrepro_kms1/catalogs
{"name":"c1","type":"FILESET","provider":"fileset","comment":"","properties":{"location":"file:///tmp/gvtrepro_c1"},"secretBindings":{"x-token":"MY-SECRET-VALUE-123"}}
HTTP 400
{"code":1001,"type":"IllegalArgumentException","message":"Malformed json
request","stack":["com.fasterxml.jackson.databind.exc.MismatchedInputException:
Cannot construct instance of `org.apache.gravitino.dto.secret.SecretBindingDTO`
(although at least one Creator exists): no String-argument constructor/factory
method to deserialize from String value ('MY-SECRET-VALUE-123')"," at [Source:
(org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream);
line: 1, column: 145] (through reference chain:
org.apache.gravitino.dto.requests.CatalogCreateRequest[\"secretBindings\"]->java.util.LinkedHashMap[\"x-token\"])","\tat
com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)",
...]}
```
Schema create:
```
POST /api/metalakes/gvtrepro_kms1/catalogs/c2/schemas
{"name":"s1","comment":"","properties":{},"secretBindings":{"x-token":"MY-SCHEMA-SECRET-789"}}
HTTP 400
{"code":1001,"type":"IllegalArgumentException","message":"Malformed json
request","stack":["com.fasterxml.jackson.databind.exc.MismatchedInputException:
Cannot construct instance of `org.apache.gravitino.dto.secret.SecretBindingDTO`
(although at least one Creator exists): no String-argument constructor/factory
method to deserialize from String value ('MY-SCHEMA-SECRET-789')", ...]}
```
### How to reproduce
Gravitino server with a secret provider configured
(`gravitino.secret.providers=memory`,
`gravitino.secret.provider.memory.className=org.apache.gravitino.secret.memory.InMemorySecretsProvider`)
and simple auth.
```bash
A="Authorization: Basic $(printf admin:x | base64)"
G=http://127.0.0.1:8090/api
H=(-H "$A" -H 'Content-Type: application/json' -H 'Accept:
application/vnd.gravitino.v1+json')
```
1. Create a metalake:
```bash
curl -s "${H[@]}" -X POST $G/metalakes -d
'{"name":"gvtrepro_kms1","comment":"","properties":{}}'
```
2. Create a catalog with a secret binding given as a string. The response is
400 and its `stack` contains `MY-SECRET-VALUE-123`:
```bash
curl -s "${H[@]}" -X POST $G/metalakes/gvtrepro_kms1/catalogs -d
'{"name":"c1","type":"FILESET","provider":"fileset","comment":"","properties":{"location":"file:///tmp/gvtrepro_c1"},"secretBindings":{"x-token":"MY-SECRET-VALUE-123"}}'
```
3. Same for a schema:
```bash
curl -s "${H[@]}" -X POST $G/metalakes/gvtrepro_kms1/catalogs -d
'{"name":"c2","type":"FILESET","provider":"fileset","comment":"","properties":{"location":"file:///tmp/gvtrepro_c2"}}'
curl -s "${H[@]}" -X POST $G/metalakes/gvtrepro_kms1/catalogs/c2/schemas -d
'{"name":"s1","comment":"","properties":{},"secretBindings":{"x-token":"MY-SCHEMA-SECRET-789"}}'
```
### Additional context
- Related: #14437 (`******` accepted as plaintext on create), #14305 and
#14306 (other secret binding defects). None of them covers the echo.
- Not present in v1.3.1: secret bindings do not exist at that tag.
- Found by the 2.0 OSS test suite check
`test_plaintext_not_echoed_in_errors[binding_as_string]`.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]