-
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
[DRAFT] [Feature]Introduces ability to control access to and share resources #16030
base: main
Are you sure you want to change the base?
Changes from 15 commits
909a85b
66a849c
08cdcb3
d7169e4
58ae851
fd00243
ef8a0b7
e98cb61
96f09b0
c86dfc9
7c6ec2a
c04762e
f95a67f
8b8fffd
7e7cd0a
e1a1b62
23fcfba
fba48ab
9cb8d0e
848234e
eaf0c6e
6a6e6f7
566913a
b4f876f
9baac32
0eb47ac
e313071
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* The OpenSearch Contributors require contributions made to | ||
* this file be licensed under the Apache-2.0 license or a | ||
* compatible open source license. | ||
*/ | ||
|
||
package org.opensearch.accesscontrol.resources; | ||
|
||
import org.opensearch.core.xcontent.ToXContentFragment; | ||
import org.opensearch.core.xcontent.XContentBuilder; | ||
|
||
import java.io.IOException; | ||
|
||
/** | ||
* This class contains information on the creator of a resource. | ||
* Creator can either be a user or a backend_role. | ||
* | ||
* @opensearch.experimental | ||
*/ | ||
public class CreatedBy implements ToXContentFragment { | ||
|
||
private String user; | ||
|
||
private String backendRole; | ||
|
||
public CreatedBy(String user, String backendRole) { | ||
this.user = user; | ||
this.backendRole = backendRole; | ||
} | ||
|
||
public String getBackendRole() { | ||
return backendRole; | ||
} | ||
|
||
public void setBackendRole(String backendRole) { | ||
this.backendRole = backendRole; | ||
} | ||
|
||
public String getUser() { | ||
return user; | ||
} | ||
|
||
public void setUser(String user) { | ||
this.user = user; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "CreatedBy {" + "user='" + user + '\'' + ", backendRole='" + backendRole + '\'' + '}'; | ||
} | ||
|
||
@Override | ||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { | ||
return builder.startObject().field("user", user).field("backend_role", backendRole).endObject(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* The OpenSearch Contributors require contributions made to | ||
* this file be licensed under the Apache-2.0 license or a | ||
* compatible open source license. | ||
*/ | ||
|
||
package org.opensearch.accesscontrol.resources; | ||
|
||
/** | ||
* This enum contains the type of entities a resource can be shared with. | ||
* | ||
* @opensearch.experimental | ||
*/ | ||
public enum EntityType { | ||
|
||
USERS, | ||
|
||
ROLES, | ||
|
||
BACKEND_ROLES, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package org.opensearch.accesscontrol.resources; | ||
|
||
import org.apache.logging.log4j.LogManager; | ||
import org.apache.logging.log4j.Logger; | ||
import org.opensearch.OpenSearchException; | ||
import org.opensearch.plugins.NoOpResourceAccessControlPlugin; | ||
import org.opensearch.plugins.ResourceAccessControlPlugin; | ||
import org.opensearch.plugins.ResourcePlugin; | ||
|
||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
/** | ||
* Resource access control for OpenSearch | ||
* | ||
* @opensearch.experimental | ||
* */ | ||
public class ResourceService { | ||
private static final Logger log = LogManager.getLogger(ResourceService.class); | ||
|
||
private final ResourceAccessControlPlugin resourceACPlugin; | ||
private final List<ResourcePlugin> resourcePlugins; | ||
|
||
public ResourceService(final List<ResourceAccessControlPlugin> resourceACPlugins, List<ResourcePlugin> resourcePlugins) { | ||
this.resourcePlugins = resourcePlugins; | ||
|
||
if (resourceACPlugins.isEmpty()) { | ||
log.info("Security plugin disabled: Using NoOpResourceAccessControlPlugin"); | ||
resourceACPlugin = new NoOpResourceAccessControlPlugin(); | ||
} else if (resourceACPlugins.size() == 1) { | ||
log.info("Security plugin enabled: Using OpenSearchSecurityPlugin"); | ||
resourceACPlugin = resourceACPlugins.get(0); | ||
} else { | ||
throw new OpenSearchException( | ||
"Multiple resource access control plugins are not supported, found: " | ||
+ resourceACPlugins.stream().map(Object::getClass).map(Class::getName).collect(Collectors.joining(",")) | ||
); | ||
} | ||
} | ||
|
||
/** | ||
* Gets the current ResourcePlugin to perform authorization | ||
*/ | ||
public ResourceAccessControlPlugin getResourceAccessControlPlugin() { | ||
return resourceACPlugin; | ||
} | ||
|
||
/** | ||
* List active plugins that define resources | ||
*/ | ||
public List<ResourcePlugin> listResourcePlugins() { | ||
return resourcePlugins; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
/* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* The OpenSearch Contributors require contributions made to | ||
* this file be licensed under the Apache-2.0 license or a | ||
* compatible open source license. | ||
*/ | ||
|
||
package org.opensearch.accesscontrol.resources; | ||
|
||
import org.opensearch.core.xcontent.ToXContentFragment; | ||
import org.opensearch.core.xcontent.XContentBuilder; | ||
|
||
import java.io.IOException; | ||
import java.util.Objects; | ||
|
||
/** | ||
* A document in .resource_sharing index. | ||
* Holds information about the resource (obtained from defining plugin's meta-data), | ||
* the index which defines the resources, the creator of the resource, | ||
* and the information on whom this resource is shared with. | ||
* | ||
* @opensearch.experimental | ||
*/ | ||
public class ResourceSharing implements ToXContentFragment { | ||
|
||
private String sourceIdx; | ||
|
||
private String resourceId; | ||
|
||
private CreatedBy createdBy; | ||
|
||
private ShareWith shareWith; | ||
|
||
public ResourceSharing(String sourceIdx, String resourceId, CreatedBy createdBy, ShareWith shareWith) { | ||
this.sourceIdx = sourceIdx; | ||
this.resourceId = resourceId; | ||
this.createdBy = createdBy; | ||
this.shareWith = shareWith; | ||
} | ||
|
||
public String getSourceIdx() { | ||
return sourceIdx; | ||
} | ||
|
||
public void setSourceIdx(String sourceIdx) { | ||
this.sourceIdx = sourceIdx; | ||
} | ||
|
||
public String getResourceId() { | ||
return resourceId; | ||
} | ||
|
||
public void setResourceId(String resourceId) { | ||
this.resourceId = resourceId; | ||
} | ||
|
||
public CreatedBy getCreatedBy() { | ||
return createdBy; | ||
} | ||
|
||
public void setCreatedBy(CreatedBy createdBy) { | ||
this.createdBy = createdBy; | ||
} | ||
|
||
public ShareWith getShareWith() { | ||
return shareWith; | ||
} | ||
|
||
public void setShareWith(ShareWith shareWith) { | ||
this.shareWith = shareWith; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) return true; | ||
if (o == null || getClass() != o.getClass()) return false; | ||
ResourceSharing resourceSharing = (ResourceSharing) o; | ||
return Objects.equals(getSourceIdx(), resourceSharing.getSourceIdx()) | ||
&& Objects.equals(getResourceId(), resourceSharing.getResourceId()) | ||
&& Objects.equals(getCreatedBy(), resourceSharing.getCreatedBy()) | ||
&& Objects.equals(getShareWith(), resourceSharing.getShareWith()); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(getSourceIdx(), getResourceId(), getCreatedBy(), getShareWith()); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "Resource {" | ||
+ "sourceIdx='" | ||
+ sourceIdx | ||
+ '\'' | ||
+ ", resourceId='" | ||
+ resourceId | ||
+ '\'' | ||
+ ", createdBy=" | ||
+ createdBy | ||
+ ", sharedWith=" | ||
+ shareWith | ||
+ '}'; | ||
} | ||
|
||
@Override | ||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { | ||
return builder.startObject() | ||
.field("source_idx", sourceIdx) | ||
.field("resource_id", resourceId) | ||
.field("created_by", createdBy) | ||
.field("share_with", shareWith) | ||
.endObject(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
/* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* The OpenSearch Contributors require contributions made to | ||
* this file be licensed under the Apache-2.0 license or a | ||
* compatible open source license. | ||
*/ | ||
|
||
package org.opensearch.accesscontrol.resources; | ||
|
||
import org.opensearch.core.xcontent.ToXContentFragment; | ||
import org.opensearch.core.xcontent.XContentBuilder; | ||
|
||
import java.io.IOException; | ||
import java.util.List; | ||
|
||
/** | ||
* This class contains information about whom a resource is shared with. | ||
* It could be a user-name, a role or a backend_role. | ||
* | ||
* @opensearch.experimental | ||
*/ | ||
public class ShareWith implements ToXContentFragment { | ||
|
||
private List<String> users; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm hesitant to introduce notions of roles, backend roles or user into the core. I'm wondering if Security can provide a class similar to this to plugins (similar to SPI model from JS), but not have plugins formally extending the security plugin. If a plugin extends another plugin then it means that the other plugin must be installed in a cluster before the plugin that depends on another can be installed. With resource sharing, if the security plugin is not installed then all users will have full access to all plugin resources. With the security plugin installed it can enforce authz on plugin resources using this new mechanism. |
||
|
||
private List<String> roles; | ||
|
||
private List<String> backendRoles; | ||
|
||
public ShareWith(List<String> users, List<String> roles, List<String> backendRoles) { | ||
this.users = users; | ||
this.roles = roles; | ||
this.backendRoles = backendRoles; | ||
} | ||
|
||
public List<String> getUsers() { | ||
return users; | ||
} | ||
|
||
public void setUsers(List<String> users) { | ||
this.users = users; | ||
} | ||
|
||
public List<String> getRoles() { | ||
return roles; | ||
} | ||
|
||
public void setRoles(List<String> roles) { | ||
this.roles = roles; | ||
} | ||
|
||
public List<String> getBackendRoles() { | ||
return backendRoles; | ||
} | ||
|
||
public void setBackendRoles(List<String> backendRoles) { | ||
this.backendRoles = backendRoles; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "ShareWith {" + "users=" + users + ", roles=" + roles + ", backendRoles=" + backendRoles + '}'; | ||
} | ||
|
||
@Override | ||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { | ||
return builder.startObject().field("users", users).field("roles", roles).field("backend_roles", backendRoles).endObject(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* The OpenSearch Contributors require contributions made to | ||
* this file be licensed under the Apache-2.0 license or a | ||
* compatible open source license. | ||
*/ | ||
|
||
/* | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The License below can be removed |
||
* Licensed to Elasticsearch under one or more contributor | ||
* license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright | ||
* ownership. Elasticsearch licenses this file to you under | ||
* the Apache License, Version 2.0 (the "License"); you may | ||
* not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
|
||
/** | ||
* Actions that OpenSearch can take either on the data stored on disk or on other nodes. | ||
*/ | ||
/* | ||
* Modifications Copyright OpenSearch Contributors. See | ||
* GitHub history for details. | ||
*/ | ||
|
||
/** | ||
* This package defines all classes required for Resource Sharing and Access Control | ||
*/ | ||
package org.opensearch.accesscontrol.resources; |
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.
Is it really necessary to support all three criteria (user name, roles, backend roles)? Especially back end roles can vary between auth backend (e.g. users authenticated via LDAP might have different backend roles than users authenticated via OIDC).
Such disparities can lead to confusion.
Who is supposed to specify these criteria when?
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.
Unfortunately, backend roles is already in place amongst plugins that implement custom resource authz.
Its already in place in:
I think there may be others as well (possibly Reporting?).
Backend roles would need to be supported in order for those plugins to adopt the mechanism provided by security.
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.
Ah, so this has the goal of a seamless transition from the older methods used in these different plugins?
Still, from a UX point of view, having too many options for a single thing is not optimal. It requires users to make a choice which is the optimal option. Proper information on how to make the right choice might be hard to find or might even not exist.
This is actually demonstrated by the broad range of artifacts which require backend roles in their configuration.
Thus, maybe the backend role option should be marked as deprecated? Or, maybe the docs should be clearer on how to use the roles?