-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add multiple namespaces support to PIT search and finder #109062
Add multiple namespaces support to PIT search and finder #109062
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a rough draft of what I think the implementation should look like given the info provided in #99044.
A question I have regarding the issue's description is regarding this point:
soClient.createPointInTimeFinder will need to ensure the typeToNamespacesMap is handed off when calling openPointInTimeForType
from my current understanding, createPointInTimeFinder
would remain unchanged, as the logic change would be handled in the internal calls of PointInTimeFinder
to client.openPointInTimeForType
which would leverage the security wrapper's modifications? Could you confirm this?
@jportner @lukeelmers could you take a look and tell me if this seems like the correct approach?
export interface SavedObjectsOpenPointInTimeOptions extends SavedObjectsBaseOptions { | ||
export interface SavedObjectsOpenPointInTimeOptions { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We no longer extend SavedObjectsBaseOptions
to remove the namespace
option, as this new namespaces
option was added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my comment in #109062 (review), I think we should leave the SavedObjectsOpenPointInTimeOptions
options as-is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with your approach, so typeToNamespacesMap
is no longer necessary here and I will remove it. However SavedObjectsOpenPointInTimeOptions
had a namespace?: string
option due to this extension, that needs to be changed to a namespaces?: string[]
, for the security wrapper to use it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I was going too fast, yep agreed
x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts
Show resolved
Hide resolved
throw error; | ||
throw SavedObjectsErrorHelpers.decorateForbiddenError(new Error(status)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the same scenario, the find
wrapper returns SavedObjectsUtils.createEmptyFindResponse
, however this is not possible for openPointInTimeForType
, as the expected return type is a SavedObjectsOpenPointInTimeResponse
. I'm throwing a forbidden error in that case, but really not sure this is the correct error type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW this makes sense to me: If you are opening a PIT against a type & you don't have permissions to access that type's backing index, I'd expect a forbidden error. But let's see what @jportner thinks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the forbidden error seems like the best approach here. Note that if you are only authorized to access a type in space A, and you attempt to open a PIT for that type only in space B, you'll run into a forbidden error. But that seems acceptable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you are only authorized to access a type in space A, and you attempt to open a PIT for that type only in space B, you'll run into a forbidden error. But that seems acceptable.
I would even think that this is expected and not just acceptable? OTOH that's right that it differs from the find
behavior that just returns an empty find response without throwing in the same situation.
The alternative would be to call baseClient.openPointInTimeForType
with an empty list of types, and have it return a stubbed PIT finder impl that returns no results in that case, but that feels a little over-complicated to me?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hum, actually we can't do that, as it would need to be done in createPointInTimeFinder
, so it doesn't solve the issue when calling openPointInTimeForType
directly. So throwing here seems the only viable option anyway
x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts
Outdated
Show resolved
Hide resolved
x-pack/plugins/spaces/server/saved_objects/spaces_saved_objects_client.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall this makes sense to me, but will defer to @jportner to make sure the behavior is what we'd expect here.
from my current understanding, createPointInTimeFinder would remain unchanged, as the logic change would be handled in the internal calls of PointInTimeFinder to client.openPointInTimeForType which would leverage the security wrapper's modifications? Could you confirm this?
Yes, this sounds correct to me as the typeToNamespacesMap
would be handled by the wrapper. That issue description was written without doing an actual POC, so most likely I had overlooked this consideration.
x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts
Show resolved
Hide resolved
throw error; | ||
throw SavedObjectsErrorHelpers.decorateForbiddenError(new Error(status)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW this makes sense to me: If you are opening a PIT against a type & you don't have permissions to access that type's backing index, I'd expect a forbidden error. But let's see what @jportner thinks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with most of the approach, with one exception:
In the SSOCW, in the openPointInTimeForType
function, I don't think we need to pass typeToNamespacesMap
down to the base client at all. When the user is partially or fully authorized, we should just pass down the types that the user can access.
The repository just needs to know what types the user is authorized to access in some space so that it can open the PIT against the appropriate indices for those types.
Re-reading the issue, Luke suggested this as an option in #99044 (comment):
- Don't implement
typeToNamespaceMap
inopenPointInTimeForType
, and simply open the PIT against the indices for all allowed types in the request. If permissions change later, the correct namespace filters should still be applied infind
. The tradeoff is that you are allowing the PIT to be open against some types which could potentially not be allowed in any namespaces, however as you aren't able to query those withfind
, this may be fine.
I think this approach is simpler and doesn't compromise security. See my suggestion below: #109062 (comment)
x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts
Outdated
Show resolved
Hide resolved
x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self-review (in addition to the previous, non-closed points)
@@ -175,32 +175,19 @@ export class SpacesSavedObjectsClient implements SavedObjectsClientContract { | |||
* @returns {promise} - { saved_objects: [{ id, type, version, attributes }], total, per_page, page } | |||
*/ | |||
public async find<T = unknown, A = unknown>(options: SavedObjectsFindOptions) { | |||
throwErrorIfNamespaceSpecified(options); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why this was there, there isn't a namespace
property on SavedObjectsFindOptions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dead code! thanks for removing it
if (id) { | ||
// "bulkGet" was unauthorized, which returns a forbidden error | ||
await expectSavedObjectForbiddenBulkGet(type)(response); | ||
} else { | ||
expect(response.body).to.eql({ | ||
statusCode: 403, | ||
error: 'Forbidden', | ||
message: `unauthorized`, | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously, per-id unauthorized were returning a 403 (due to bulkGet returning an error) and per-type were returning an empty export instead.
This PR has the side effect to change that, to now returns a 403 for per-type export when the user don't have the permissions for any of the types.
Overall, I think this is an improvement in term of consistency.
Pinging @elastic/kibana-core (Team:Core) |
@@ -343,6 +343,10 @@ export interface SavedObjectsOpenPointInTimeOptions extends SavedObjectsBaseOpti | |||
* An optional ES preference value to be used for the query. | |||
*/ | |||
preference?: string; | |||
/** | |||
* An optional list of namespaces to be used by the PIT. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our separation between core / security makes documentation really hard here. But in the absence of another good place to write documentation it feels like we should maybe add some details about how this option behaves when the spaces plugin is enabled? Otherwise it's very difficult to figure out how to use this.
* An optional list of namespaces to be used by the PIT. | |
* An optional list of namespaces to be used by the PIT. | |
* | |
* When the spaces plugin is enabled: | |
*. - this will default to the user's current space as determined by the URL | |
* - if namespaces is specified the user's current space will be ignored | |
* - `['*']` will search across all available spaces |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, that's fair. I can't think of any better place...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes here all LGTM, thanks for taking this one on 🚀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor nits below, otherwise LGTM, thanks for doing this!
@@ -397,9 +384,16 @@ export class SpacesSavedObjectsClient implements SavedObjectsClientContract { | |||
options: SavedObjectsOpenPointInTimeOptions = {} | |||
) { | |||
throwErrorIfNamespaceSpecified(options); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can get rid of this too
}); | ||
|
||
test(`supplements options with the current namespace`, async () => { | ||
test(`translates options.namespace: ['*']`, async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit
test(`translates options.namespace: ['*']`, async () => { | |
test(`translates options.namespaces: ['*']`, async () => { |
foo: 'bar', | ||
namespace: currentSpace.expectedNamespace, | ||
keepAlive: '2m', | ||
namespaces: [currentSpace.expectedNamespace ?? 'default'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit
namespaces: [currentSpace.expectedNamespace ?? 'default'], | |
namespaces: [currentSpace.expectedNamespace ?? DEFAULT_SPACE_ID], |
💚 Build SucceededMetrics [docs]History
To update your PR or re-run it, just comment with: |
💚 Backport successful
This backport PR will be merged automatically after passing CI. |
…109603) * initial modifications * change approach for openPointInTime and add tests for spaces wrapper changes * fix and add security wrapper tests * fix export security FTR tests * update generated doc * add tests for PIT finder * NIT * improve doc * nits Co-authored-by: Pierre Gayvallet <pierre.gayvallet@gmail.com>
Summary
Fix #99044
Add multi-namespaces support to
openPointInTimeForType
andcreatePointInTimeFinder
Checklist