Skip to content
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

Merged
merged 11 commits into from
Aug 23, 2021

Conversation

pgayvallet
Copy link
Contributor

@pgayvallet pgayvallet commented Aug 18, 2021

Summary

Fix #99044

Add multi-namespaces support to openPointInTimeForType and createPointInTimeFinder

Checklist

@pgayvallet pgayvallet added release_note:skip Skip the PR/issue when compiling release notes v7.16.0 Feature:Saved Objects labels Aug 18, 2021
Copy link
Contributor Author

@pgayvallet pgayvallet left a 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 {
Copy link
Contributor Author

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.

Copy link
Contributor

@jportner jportner Aug 19, 2021

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.

Copy link
Contributor Author

@pgayvallet pgayvallet Aug 20, 2021

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.

Copy link
Contributor

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

Comment on lines -526 to +529
throw error;
throw SavedObjectsErrorHelpers.decorateForbiddenError(new Error(status));
Copy link
Contributor Author

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?

Copy link
Member

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.

Copy link
Contributor

@jportner jportner Aug 19, 2021

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.

Copy link
Contributor Author

@pgayvallet pgayvallet Aug 20, 2021

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?

Copy link
Contributor Author

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

src/core/server/saved_objects/service/lib/repository.ts Outdated Show resolved Hide resolved
@pgayvallet pgayvallet added the Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc label Aug 18, 2021
Copy link
Member

@lukeelmers lukeelmers left a 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.

Comment on lines -526 to +529
throw error;
throw SavedObjectsErrorHelpers.decorateForbiddenError(new Error(status));
Copy link
Member

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.

Copy link
Contributor

@jportner jportner left a 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):

  1. Don't implement typeToNamespaceMap in openPointInTimeForType, 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 in find. 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 with find, this may be fine.

I think this approach is simpler and doesn't compromise security. See my suggestion below: #109062 (comment)

Copy link
Contributor Author

@pgayvallet pgayvallet left a 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);
Copy link
Contributor Author

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

Copy link
Contributor

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

Comment on lines +158 to +167
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`,
});
}
Copy link
Contributor Author

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.

@pgayvallet pgayvallet marked this pull request as ready for review August 20, 2021 12:47
@pgayvallet pgayvallet requested review from a team as code owners August 20, 2021 12:47
@elasticmachine
Copy link
Contributor

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.
Copy link
Contributor

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.

Suggested change
* 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

Copy link
Contributor Author

@pgayvallet pgayvallet Aug 20, 2021

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...

Copy link
Member

@lukeelmers lukeelmers left a 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 🚀

Copy link
Contributor

@jportner jportner left a 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);
Copy link
Contributor

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 () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit

Suggested change
test(`translates options.namespace: ['*']`, async () => {
test(`translates options.namespaces: ['*']`, async () => {

foo: 'bar',
namespace: currentSpace.expectedNamespace,
keepAlive: '2m',
namespaces: [currentSpace.expectedNamespace ?? 'default'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit

Suggested change
namespaces: [currentSpace.expectedNamespace ?? 'default'],
namespaces: [currentSpace.expectedNamespace ?? DEFAULT_SPACE_ID],

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Unknown metric groups

API count

id before after diff
core 2244 2245 +1

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@pgayvallet pgayvallet added the auto-backport Deprecated - use backport:version if exact versions are needed label Aug 23, 2021
@pgayvallet pgayvallet merged commit 5c5e191 into elastic:master Aug 23, 2021
kibanamachine pushed a commit to kibanamachine/kibana that referenced this pull request Aug 23, 2021
)

* 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
@kibanamachine
Copy link
Contributor

💚 Backport successful

Status Branch Result
7.x

This backport PR will be merged automatically after passing CI.

kibanamachine added a commit that referenced this pull request Aug 23, 2021
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
auto-backport Deprecated - use backport:version if exact versions are needed Feature:Saved Objects release_note:skip Skip the PR/issue when compiling release notes Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc v7.16.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[saved objects][pit finder] Add support for multiple namespaces.
6 participants