-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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/Identity] Basic permissions check #6029
[Feature/Identity] Basic permissions check #6029
Conversation
Signed-off-by: Craig Perkins <[email protected]>
Signed-off-by: Craig Perkins <[email protected]>
Signed-off-by: Craig Perkins <[email protected]>
Signed-off-by: Craig Perkins <[email protected]>
Signed-off-by: Craig Perkins <[email protected]>
Signed-off-by: Craig Perkins <[email protected]>
Signed-off-by: Craig Perkins <[email protected]>
Signed-off-by: Craig Perkins <[email protected]>
Signed-off-by: Craig Perkins <[email protected]>
Signed-off-by: Craig Perkins <[email protected]>
Signed-off-by: Craig Perkins <[email protected]>
Signed-off-by: Craig Perkins <[email protected]>
Signed-off-by: Craig Perkins <[email protected]>
Signed-off-by: Craig Perkins <[email protected]>
return false; | ||
} | ||
|
||
// Uncomment the following lines if index name -> concrete index resolution is required |
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.
To fully uncomment this block and use the IndexNameExpressionResolver
then the following needs to be added to IdentityPlugin
:
@Override
public Collection<Class<? extends LifecycleComponent>> getGuiceServiceClasses() {
if (!enabled) {
return Collections.emptyList();
}
final List<Class<? extends LifecycleComponent>> services = new ArrayList<>(1);
services.add(GuiceHolder.class);
return services;
}
public static class GuiceHolder implements LifecycleComponent {
private static ClusterService clusterService;
private static RepositoriesService repositoriesService;
@Inject
public GuiceHolder(final RepositoriesService repositoriesService, final ClusterService clusterService) {
GuiceHolder.repositoriesService = repositoriesService;
GuiceHolder.clusterService = clusterService;
}
public static RepositoriesService getRepositoriesService() {
return repositoriesService;
}
public static ClusterService getClusterService() {
return clusterService;
}
@Override
public void close() {}
@Override
public Lifecycle.State lifecycleState() {
return null;
}
@Override
public void addLifecycleListener(LifecycleListener listener) {}
@Override
public void removeLifecycleListener(LifecycleListener listener) {}
@Override
public void start() {}
@Override
public void stop() {}
}
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 don't think we should be attempting to resolve the name ever, if you have permissions to the URL you get access to target, so if there is an alias, so long as you have permission, its allowed. This prevents 'transitive' permissions due to the creation of aliases or other systems... views?, food food thought.
.../identity/src/main/java/org/opensearch/identity/authz/IndexNameExpressionResolverHolder.java
Show resolved
Hide resolved
permission += "|" + Strings.join(resources.get(), ","); | ||
} | ||
|
||
if (log.isDebugEnabled()) { |
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 block logs out the result of privilege evaluation.
Add logger.org.opensearch.identity: debug
to opensearch.yml
to enable debug logging for this module.
Signed-off-by: Craig Perkins <[email protected]>
Gradle Check (Jenkins) Run Completed with:
|
Gradle Check (Jenkins) Run Completed with:
|
sandbox/libs/authn/src/main/java/org/opensearch/authn/noop/NoopSubject.java
Show resolved
Hide resolved
@@ -67,6 +72,26 @@ private <Request extends ActionRequest, Response extends ActionResponse> void ap | |||
ActionListener<Response> listener, | |||
ActionFilterChain<Request, Response> chain | |||
) { | |||
// TODO The section below shows permission check working for index create and index search, but needs |
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.
Do you know what changes will be required here for the plugins and extension functionality? We have the dual meaning of the permissions and extensions since they can both be the subject and have permissions regarding them. Do we need to define any requests for either to move things forward?
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.
Extensions can register actions and those actions need to be permissible for cluster admins to be able to permit users to use features of an extension.
Plugins run in the same JVM as the OpenSearch node, but extensions run outside. Extensions interact with the OpenSearch cluster using a rest client to make requests to the cluster. Users have sets of permissions associated with them and extensions may as well, to give cluster admins the ability to further restrict how requests originating from an extension can interact with a cluster. At the very least, an extension making a request to a cluster on behalf of a user should perform the request with the same user permissions + restrictions, restrictions like preventing the ability to query system indices even if a user has access.
I was trying to make an analogy with microsoft word and saving files to the filesystem, but I believe that word is able to save to the same folders as the current logged in user.
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 see. Thank you for the explanation of what we will need to do moving forward. I have mostly been designing from the standpoint of generic permissions so wanted to see how this would fit with a more user-centric version like you have here. That makes sense though.
sandbox/modules/identity/src/main/java/org/opensearch/identity/User.java
Show resolved
Hide resolved
sandbox/modules/identity/src/main/java/org/opensearch/identity/User.java
Outdated
Show resolved
Hide resolved
.../identity/src/main/java/org/opensearch/identity/authz/IndexNameExpressionResolverHolder.java
Show resolved
Hide resolved
// Set<String> concretePermissionIndexNames = iner.resolveExpressions(cs, this.indexPatterns.toArray(new String[0])); | ||
// Set<String> concreteRequestedIndexNames = iner.resolveExpressions(cs, requestedPermission.indexPatterns.toArray(new String[0])); | ||
|
||
boolean allRequestedPatternsMatchGranted = requestedPermission.indexPatterns.stream() |
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 may need an inline comment just cause it is somewhat complicated. It first checks for any match then tries to all match after so it is just a little complex.
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.
Sure, I can add one in. Capturing it here now:
User granted index patterns: my-index*,other-index*
Request permission on: my-index1
For all requested index patterns:
requested index pattern must match at least one pattern that the user has been granted access to
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.
Great thank you!
sandbox/modules/identity/src/main/java/org/opensearch/identity/realm/InternalRealm.java
Show resolved
Hide resolved
Signed-off-by: Craig Perkins <[email protected]>
Gradle Check (Jenkins) Run Completed with:
|
Signed-off-by: Craig Perkins <[email protected]>
Gradle Check (Jenkins) Run Completed with:
|
Gradle Check (Jenkins) Run Completed with:
|
Codecov Report
📣 This organization is not using Codecov’s GitHub App Integration. We recommend you install it so Codecov can continue to function properly for your repositories. Learn more @@ Coverage Diff @@
## feature/identity #6029 +/- ##
======================================================
- Coverage 71.08% 70.61% -0.48%
+ Complexity 59272 58899 -373
======================================================
Files 4829 4831 +2
Lines 282163 282225 +62
Branches 40686 40695 +9
======================================================
- Hits 200578 199294 -1284
- Misses 65477 66580 +1103
- Partials 16108 16351 +243
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
Gradle Check (Jenkins) Run Completed with:
|
The gradle check failure is unrelated to this PR:
|
@@ -51,6 +53,9 @@ public User(final String username, final String bcryptHash, Map<String, String> | |||
@JsonProperty(value = "attributes") | |||
private Map<String, String> attributes = Collections.emptyMap(); | |||
|
|||
@JsonProperty(value = "permissions") | |||
private List<String> permissions = Collections.emptyList(); |
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 blocking this change: I think we should retrieve permissions from the store that @scrawfor99 has created
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.
Agreed. This is added here to show a permissions check working end to end and the magic of permissions resolution (Subject -> List of Permissions) happens in doGetAuthorizationInfo
of the InternalRealm
. That method can be updated when the long-term permissions store is decided upon and implemented.
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.
Getting this merged for speed
Description
This PR shows a rudimentary implementation for permissions checking that works in common OpenSearch scenarios including any cluster related actions and indices actions like creating an index and search. This provides a base to build upon as more actions are tested with this permissions model.
In this PR the permissions are directly saved onto the user, though permissions resolution is still an open issue.
The InternalRealm has been switched to extend shiro's Authorizing realm which means that a function called
doGetAuthorizationInfo
is implemented to resolve a user to a list of permissions.Actions are compared using shiro's WildcardPermission. For requests requiring indices, all indices in the request are compared against index patterns for the action that the user has been granted to and this implementation uses the internal
Glob.globMatch
to determine if the index pattern requested matches a pattern that's been granted access.Issues Resolved
First step of: #5859
Related PRs:
Check List
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.