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

[Feature/Extensions] Principal identity for Opensearch requests to/from extensions #4299

Conversation

DarshitChanpura
Copy link
Member

Description

Adds a basic identifiers to determine owner for each request from OpenSearch to extensions.

Issues Resolved

Check List

  • New functionality includes testing.
    • All tests pass
  • New functionality has been documented.
    • New functionality has javadoc added
  • Commits are signed per the DCO using --signoff
  • Commit changes are listed out in CHANGELOG.md file (See: Changelog)

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

@github-actions
Copy link
Contributor

Gradle Check (Jenkins) Run Completed with:

@github-actions
Copy link
Contributor

Gradle Check (Jenkins) Run Completed with:

  • RESULT: null ❌
  • URL: null
  • CommitID: d15b1a10f1839ae0e163c264c69160cec421bffe

@github-actions
Copy link
Contributor

Gradle Check (Jenkins) Run Completed with:

@dbwiddis
Copy link
Member

Hey @DarshitChanpura thanks for this draft PR. Some quick feedback that should hopefully help you iterate:

  • Don't use the RegisterRestActionsRequest. That's inbound to OpenSearch from an extension that just registers the action on the RestController.
  • Take a look at [Feature/extensions] Register REST API and forward REST requests to associated extension #4282. In the RestActionsRequestHandler class we are registering the RestController to respond to a User's REST request by forwarding it to the extension. This forwarding process is where I think you'll need to insert identity information
    • The RestSendToExtensionAction directly handles the RestRequest. You may have to back up and see where that Request comes from and how you can attach a principal to it. Then we could send it along to the extension with the method and URI, just add a third String parameter which is a key to an internal map where the user is the principal. (Eventually we'll actually want to send a JWT containing an Access Token.)

@dbwiddis
Copy link
Member

Continuing on the above comment, the RestRequest does include the headers which would have the user's authorization info in it. So I'd suggest using that class as a basis (it's not merged yet but you can copy it and start with it for now) and:

Later the extension will send this key back with a different request or transport, and you can look up the Principal with it.

@dbwiddis
Copy link
Member

As far as storing in the map, if you go with Apache Shiro, it looks like the RememberMeManager is probably built for this purpose. Not sure if the token it produces is an "access token" but worth looking into.

@dbwiddis
Copy link
Member

Finally comment for today: where to put the map? I'd suggest a brand new object somewhere. Look in Node.java where a lot of individual objects are instantiated, such as the RestController and ExtensionsOrchestrator and others. Find a nice home in org.opensearch.identity and build a new object to your liking and instantiate it in Node and pass it around where it's needed.

@DarshitChanpura DarshitChanpura changed the title Principal identity for Opensearch requests to extensions [Feature/Extensions] Principal identity for Opensearch requests to extensions Aug 26, 2022
Copy link
Member

@peternied peternied left a comment

Choose a reason for hiding this comment

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

Thanks for getting this out there and forwarding the discussion around our identities!

Comment on lines 36 to 37
/* A non-unique human readable identifier */
String getUserName();
Copy link
Member

Choose a reason for hiding this comment

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

Should an extension be able to know a human readable identifier?

If we are being privacy focused - no seems like the answer. Get access to user data such as there name should involve a permission that must be requested.

If this Principal is be used as a cache key, then we wouldn't want fields that could change - would the username as well as the other fields be consistent or do they store mutable data? I like the notion from Shiro of a principal collection (mutable) being composed of immutable principals.

If we want to simplify calling patterns, less back/forth for often used data can offer big gains in roundtrip impact.

For me, a separate set of APIs for getting identity information limits the amount of work we need to do in the moment and removes assumptions from extensions implementations.

@dbwiddis What do you think about the role of this object, be more user property bag focused or identity token? What scenarios are more important for extensions writers?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm following SCIM definition. However this implementation is open to suggestions and changes


protected final static class AnonymousIdentity extends Identity {
// TODO: Determine risk of collision when generating random UUID
private final static UUID ID = new UUID(0L, 0L);
Copy link
Member

Choose a reason for hiding this comment

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

I think this should be an non-zero constant value, new UUID(0x817a6e, 0x817a6e) would be a quirky entry. Inspired by @dbwiddis comment #4028 (comment)

Comment on lines 33 to 34
/* Contains principal type definition */
List<String> getSchemas();
Copy link
Member

Choose a reason for hiding this comment

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

Do you have an example of what kind of data would be in here?

String getUserName();

/* Contains metadata relevant to entity*/
Map<String, String> getMetaData();
Copy link
Member

Choose a reason for hiding this comment

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

What kind of data would we store in here? I would prefer strong types when possible to avoid blind gets/casts, but maybe we need it?

Copy link
Member Author

Choose a reason for hiding this comment

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

Refer this comment: #4028 (comment)

@@ -24,49 +26,57 @@
*/
public class RegisterRestActionsRequest extends TransportRequest {
Copy link
Member

Choose a reason for hiding this comment

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

I think we would want similar treatment on any request from OpenSearch -> Extension interactions - should a there be a base class for all interactions, or a common wrapper? @saratvemulapalli have you had thoughts about this space?

Making this more concrete, lets consider the IndicesModuleRequest.

IndicesModuleRequest is translated by ExtensionsOrchestrator to send the request to the Extension (ExtensionRunner). When the call is send off to the extension, the identity of the operation should be included. Attaching this information onto of the Request object seems most straight forward, but is there another way that would better integrate it?

This would also mean that before transiting the OpenSearch -> Extension boundary there would be some kind of 'get current identity and associate it as a Principle with outbound request' component.

Copy link
Member

@saratvemulapalli saratvemulapalli Sep 7, 2022

Choose a reason for hiding this comment

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

@peternied Absolutely, as we are working through the security features I think we should start implementing generic message handler which mandates including node identity, security identity etc.
May be lets start opening up an issue ?

Comment on lines 26 to 27
// TODO: Determine how this principal can be shared between threads and
// the effects of extending NamedWriteable class
Copy link
Member

Choose a reason for hiding this comment

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

image

Copy link
Member

Choose a reason for hiding this comment

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

I'm not certain the implications of using extending NamedWritable - is there a good reference or implementation that I could follow?

Copy link
Member Author

@DarshitChanpura DarshitChanpura Aug 30, 2022

Choose a reason for hiding this comment

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

I'm not sure about that yet.. but you can search for NamedWritable in the codebase. It is for arbitrary seralizable objects. See interface definition here

@dblock
Copy link
Member

dblock commented Aug 30, 2022

I believe it should be "Username" and "Metadata" vs. "UserName" and "MetaData".
https://english.stackexchange.com/questions/43436/username-user-name-or-user-name

@github-actions
Copy link
Contributor

Gradle Check (Jenkins) Run Completed with:

@github-actions
Copy link
Contributor

Gradle Check (Jenkins) Run Completed with:

@github-actions
Copy link
Contributor

Gradle Check (Jenkins) Run Completed with:

@github-actions
Copy link
Contributor

Gradle Check (Jenkins) Run Completed with:

@github-actions
Copy link
Contributor

Gradle Check (Jenkins) Run Completed with:

@github-actions
Copy link
Contributor

Gradle Check (Jenkins) Run Completed with:

@github-actions
Copy link
Contributor

Gradle Check (Jenkins) Run Completed with:

@github-actions
Copy link
Contributor

Gradle Check (Jenkins) Run Completed with:

@github-actions
Copy link
Contributor

Gradle Check (Jenkins) Run Completed with:

@github-actions
Copy link
Contributor

github-actions bot commented Sep 1, 2022

Gradle Check (Jenkins) Run Completed with:

@github-actions
Copy link
Contributor

github-actions bot commented Sep 2, 2022

Gradle Check (Jenkins) Run Completed with:

@github-actions
Copy link
Contributor

github-actions bot commented Sep 2, 2022

Gradle Check (Jenkins) Run Completed with:

peternied and others added 6 commits September 14, 2022 16:05
Signed-off-by: Peter Nied <[email protected]>
Signed-off-by: Peter Nied <[email protected]>
Signed-off-by: Darshit Chanpura <[email protected]>
@github-actions
Copy link
Contributor

Gradle Check (Jenkins) Run Completed with:

@DarshitChanpura
Copy link
Member Author

DarshitChanpura commented Sep 14, 2022

Pre-commit task failed with unable to resolve netty dependencies. Unable to reproduce it locally.

Update: Resolved on its own

@github-actions
Copy link
Contributor

Gradle Check (Jenkins) Run Completed with:

@github-actions
Copy link
Contributor

Gradle Check (Jenkins) Run Completed with:

@DarshitChanpura DarshitChanpura requested review from dbwiddis and saratvemulapalli and removed request for reta and dbwiddis September 15, 2022 15:06
@github-actions
Copy link
Contributor

Gradle Check (Jenkins) Run Completed with:

@DarshitChanpura
Copy link
Member Author

Build failed with this:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':distribution:bwc:staged:buildBwcLinuxTar'.
> Building 2.3.0 didn't generate expected file /var/jenkins/workspace/gradle-check/search/distribution/bwc/staged/build/bwc/checkout-2.3/distribution/archives/linux-tar/build/distributions/opensearch-min-2.3.0-SNAPSHOT-linux-x64.tar.gz

Probably need to re-trigger the check

@github-actions
Copy link
Contributor

Gradle Check (Jenkins) Run Completed with:

@github-actions
Copy link
Contributor

Gradle Check (Jenkins) Run Completed with:

@codecov-commenter
Copy link

Codecov Report

Merging #4299 (803c044) into feature/extensions (edde6a4) will increase coverage by 0.14%.
The diff coverage is 73.46%.

@@                   Coverage Diff                    @@
##             feature/extensions    #4299      +/-   ##
========================================================
+ Coverage                 70.57%   70.72%   +0.14%     
- Complexity                57370    57527     +157     
========================================================
  Files                      4642     4644       +2     
  Lines                    276302   276347      +45     
  Branches                  40389    40394       +5     
========================================================
+ Hits                     195012   195446     +434     
+ Misses                    64936    64557     -379     
+ Partials                  16354    16344      -10     
Impacted Files Coverage Δ
...rch/extensions/rest/RestSendToExtensionAction.java 27.63% <25.00%> (-0.15%) ⬇️
...extensions/rest/RestExecuteOnExtensionRequest.java 63.33% <45.45%> (-1.89%) ⬇️
.../opensearch/identity/PrincipalIdentifierToken.java 86.66% <86.66%> (ø)
...g/opensearch/identity/ExtensionTokenProcessor.java 88.88% <88.88%> (ø)
...a/org/opensearch/common/network/NetworkModule.java 92.10% <100.00%> (+0.10%) ⬆️
...cluster/coordination/PendingClusterStateStats.java 20.00% <0.00%> (-48.00%) ⬇️
...ain/java/org/opensearch/search/sort/MinAndMax.java 63.15% <0.00%> (-36.85%) ⬇️
...tions/InternalSingleBucketAggregationTestCase.java 59.74% <0.00%> (-28.58%) ⬇️
.../java/org/opensearch/index/reindex/RemoteInfo.java 50.45% <0.00%> (-28.45%) ⬇️
...opensearch/index/reindex/BulkByScrollResponse.java 48.38% <0.00%> (-28.23%) ⬇️
... and 514 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

Copy link
Member

@saratvemulapalli saratvemulapalli left a comment

Choose a reason for hiding this comment

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

Overall the changes look good to me. @DarshitChanpura thanks for this start.

Dropped a couple of questions but it shouldn't be blocking the merge.

@@ -16,6 +16,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Update previous release bwc version to 2.4.0 ([#4455](https://github.com/opensearch-project/OpenSearch/pull/4455))
- 2.3.0 release notes ([#4457](https://github.com/opensearch-project/OpenSearch/pull/4457))
- Warn future developers not to pass headers to extensions ([#4430](https://github.com/opensearch-project/OpenSearch/pull/4430))
- Principal Identity for Opensearch requests to/from extensions ([#4299](https://github.com/opensearch-project/OpenSearch/pull/4299))
Copy link
Member

Choose a reason for hiding this comment

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

How do you guys plan to get feature/extensions and feature/identity to be in sync?
Its going to be pain because you might need changes in feature/extensions in feature/identity but they might not work.

* Requester Token for requests to/from an extension
* Each user will have different token for different extension
*
* @opensearch.internal
Copy link
Member

Choose a reason for hiding this comment

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

opensearch.internal is used for everything internal to opensearch which is not exposed to plugins/extensions.
@dbwiddis @owaiskazi19 how do you want to name this? (cc: @nknize)

Not a blocker for this PR but I think we need to think about it.

Copy link
Member

Choose a reason for hiding this comment

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

How about we create a new javadoc flag and call it as opensearch.extensions?

Copy link
Member

Choose a reason for hiding this comment

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

As we refactor, I think we would want to call out for both plugins and extensions.

Copy link
Member

Choose a reason for hiding this comment

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

I'll create a follow up.

* Token processor class to handle token encryption/decryption
* This processor is will be instantiated for every extension
*/
public class ExtensionTokenProcessor {
Copy link
Member

Choose a reason for hiding this comment

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

This is very much tied to an extension, do you want to do something more generic which we can use for non-extensions?

Again, not a blocker for this PR. Trying to understand how we could make it better for rest of the use-cases.

@saratvemulapalli saratvemulapalli merged commit 3a73a44 into opensearch-project:feature/extensions Sep 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants