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

Create ExecutionContext and show example with RestHandlerProxy #172

Open
wants to merge 87 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
3506973
Create ExecutionContext and show example with ActionPluginProxy
cwperks May 30, 2024
f8cf238
Only allow core to set the ExecutionContext
cwperks May 30, 2024
19155ca
Merge branch 'main' into plugin-aware-thread-context
cwperks May 31, 2024
b6b2a19
WIP on plugin aware thread context
cwperks May 31, 2024
8165f05
Plugin Aware API Handling
cwperks May 31, 2024
7e603e1
Merge branch 'main' into plugin-aware-thread-context
cwperks Jun 11, 2024
5b989d6
Add test to verify that ExecutionContext is being populated during Re…
cwperks Jun 11, 2024
444fde7
Merge branch 'main' into plugin-aware-thread-context
cwperks Jul 2, 2024
aaba063
Merge branch 'main' into plugin-aware-thread-context
cwperks Jul 9, 2024
eec8b96
Clear context in a finally block
cwperks Jul 10, 2024
8a98618
Create switchContext method in ThreadContext and make pluginExecution…
cwperks Jul 10, 2024
5f7a26f
Merge branch 'main' into plugin-aware-thread-context
cwperks Jul 11, 2024
6b6e955
WIP on plugin aware stash context
cwperks Jul 12, 2024
73835ed
Create class called PluginAwareNodeClient that provides a method call…
cwperks Jul 12, 2024
4d048b7
Remove ExecutionContext class
cwperks Jul 12, 2024
70c0c80
Update javadoc
cwperks Jul 12, 2024
dc5c5a8
Change createComponents to take in PluginAwareNodeClient
cwperks Jul 12, 2024
e26ac6c
Update all instances of createComponents
cwperks Jul 12, 2024
c2e0a64
Initialize clients
cwperks Jul 12, 2024
1b234b5
Merge branch 'main' into plugin-aware-thread-context
cwperks Jul 16, 2024
1d7df43
Remove casting
cwperks Jul 16, 2024
711d542
WIP on notion of ContextSwitcher
cwperks Jul 18, 2024
e2ebb36
Make stashContext package-private
cwperks Jul 23, 2024
ed71247
Make markAsSystemContext package-private
cwperks Jul 23, 2024
4b27f3a
Merge branch 'main' into plugin-aware-thread-context
cwperks Jul 23, 2024
b031db9
Add javadoc on param
cwperks Jul 23, 2024
54439a0
Remove SystemContextSwitcher
cwperks Aug 2, 2024
383fa83
Merge branch 'main' into plugin-aware-thread-context
cwperks Aug 2, 2024
dd8e7c3
Merge with main
cwperks Aug 2, 2024
2ff8f86
Cleanup
cwperks Aug 2, 2024
b006ed5
Remove SystemIndexFilter
cwperks Aug 2, 2024
f718299
Add notion of Forbidden Headers to the ThreadContext
cwperks Aug 2, 2024
526cd43
Merge branch 'main' into plugin-aware-thread-context
cwperks Aug 6, 2024
7458969
Fix tests
cwperks Aug 6, 2024
5c1d94e
Fix test
cwperks Aug 6, 2024
8fbf024
Add method to initialize plugins
cwperks Aug 6, 2024
76e8b04
Create concept of pluginNodeClient that can be used for executing tra…
cwperks Aug 7, 2024
84a325d
Add test
cwperks Aug 7, 2024
45c4a3e
Add another test for setPluginNodeClient
cwperks Aug 7, 2024
e41496a
Remove newline
cwperks Aug 7, 2024
9a89b64
Merge branch 'main' into plugin-aware-thread-context
cwperks Aug 7, 2024
bccf5eb
Add another test
cwperks Aug 8, 2024
cbeeb6a
Merge branch 'main' into plugin-aware-thread-context
cwperks Aug 8, 2024
3948acf
Merge branch 'main' into plugin-aware-thread-context
cwperks Aug 8, 2024
e685c5c
Subject.runAs and introduce PluginSubject
cwperks Aug 13, 2024
f7f245d
Do nothing when runAs is called for ShiroSubject and NoopSubject
cwperks Aug 13, 2024
6dd4153
Remove extraneous changes
cwperks Aug 13, 2024
38fe2e1
Test all methods in PluginSubject
cwperks Aug 14, 2024
7f2e545
Merge branch 'main' into plugin-aware-thread-context
cwperks Aug 14, 2024
17b4444
Pass a Callable to runAs
cwperks Aug 15, 2024
247fd59
Update import
cwperks Aug 15, 2024
8f38206
Merge branch 'main' into plugin-aware-thread-context
cwperks Aug 15, 2024
16f4251
Simplify PR, make NoopPluginSubject and introduce IdentityAwarePlugin
cwperks Aug 16, 2024
7b3b5ec
Add final
cwperks Aug 16, 2024
0a26f26
Remove server dependency
cwperks Aug 16, 2024
94a5f2c
Remove AbstractSubject
cwperks Aug 16, 2024
19dffb7
Remove unnecessary changes
cwperks Aug 16, 2024
17abb63
Add javadoc to NoopPluginSubject
cwperks Aug 16, 2024
d6be989
Merge branch 'main' into plugin-aware-thread-context
cwperks Aug 16, 2024
48bd43c
Rename to assignSubject
cwperks Aug 16, 2024
be9a89a
Add experimental label
cwperks Aug 16, 2024
ca1f297
Add getPluginSubject(plugin) to IdentityPlugin
cwperks Aug 16, 2024
84c0cc3
Make runAs generic
cwperks Aug 16, 2024
c200272
package-private constructor
cwperks Aug 16, 2024
be9b3cc
Move IdentityAwarePlugin initialization
cwperks Aug 16, 2024
9c07676
Create separate PluginSubject interface
cwperks Aug 16, 2024
901d53d
Remove authenticate method
cwperks Aug 16, 2024
55834df
Remove import
cwperks Aug 16, 2024
7374479
Separate UserSubject and PluginSubject
cwperks Aug 16, 2024
efac919
Terminate TestThreadPool
cwperks Aug 16, 2024
1536380
mock ThreadPool in RestSendToExtensionActionTests
cwperks Aug 16, 2024
e6eb37e
Fix Thread leak
cwperks Aug 17, 2024
2c9ba56
Add to CHANGELOG
cwperks Aug 19, 2024
9c5b2c4
Rename to getCurrentSubject
cwperks Aug 19, 2024
4b8c7bd
Add type check
cwperks Aug 19, 2024
5ab2f50
Merge branch 'main' into plugin-aware-thread-context
cwperks Aug 21, 2024
1a468e7
Rename to pluginSubject
cwperks Aug 21, 2024
df6b5ce
Merge branch 'main' into plugin-aware-thread-context
cwperks Aug 21, 2024
57f233b
Merge branch 'main' into plugin-aware-thread-context
cwperks Aug 22, 2024
311b019
Merge branch 'main' into plugin-aware-thread-context
cwperks Aug 22, 2024
7a4c80c
Merge branch 'main' into plugin-aware-thread-context
cwperks Aug 22, 2024
c74c677
Add runAs to ActionRequest and surround doExecute in AbstractClient
cwperks Aug 28, 2024
06259f7
Return this
cwperks Aug 28, 2024
fc5459d
Switch back to void
cwperks Aug 28, 2024
653beb4
Revert change to ActionRequest
cwperks Aug 28, 2024
a872e7c
Merge branch 'main' into plugin-aware-thread-context
cwperks Aug 28, 2024
681ea8f
Merge branch 'main' into plugin-aware-thread-context
cwperks Aug 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Add support for centralize snapshot creation with pinned timestamp ([#15124](https://github.com/opensearch-project/OpenSearch/pull/15124))
- Add concurrent search support for Derived Fields ([#15326](https://github.com/opensearch-project/OpenSearch/pull/15326))
- [Workload Management] Add query group stats constructs ([#15343](https://github.com/opensearch-project/OpenSearch/pull/15343)))
- Add runAs to Subject interface and introduce IdentityAwarePlugin extension point ([#14630](https://github.com/opensearch-project/OpenSearch/pull/14630))

### Dependencies
- Bump `netty` from 4.1.111.Final to 4.1.112.Final ([#15081](https://github.com/opensearch-project/OpenSearch/pull/15081))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,43 @@
import org.apache.logging.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.mgt.SecurityManager;
import org.opensearch.client.Client;
import org.opensearch.cluster.metadata.IndexNameExpressionResolver;
import org.opensearch.cluster.service.ClusterService;
import org.opensearch.common.annotation.ExperimentalApi;
import org.opensearch.common.settings.Settings;
import org.opensearch.core.common.io.stream.NamedWriteableRegistry;
import org.opensearch.core.xcontent.NamedXContentRegistry;
import org.opensearch.env.Environment;
import org.opensearch.env.NodeEnvironment;
import org.opensearch.identity.PluginSubject;
import org.opensearch.identity.Subject;
import org.opensearch.identity.tokens.TokenManager;
import org.opensearch.plugins.IdentityPlugin;
import org.opensearch.plugins.Plugin;
import org.opensearch.repositories.RepositoriesService;
import org.opensearch.script.ScriptService;
import org.opensearch.threadpool.ThreadPool;
import org.opensearch.watcher.ResourceWatcherService;

import java.util.Collection;
import java.util.Collections;
import java.util.function.Supplier;

/**
* Identity implementation with Shiro
*
* @opensearch.experimental
*/
@ExperimentalApi
public final class ShiroIdentityPlugin extends Plugin implements IdentityPlugin {
private Logger log = LogManager.getLogger(this.getClass());

private final Settings settings;
private final ShiroTokenManager authTokenHandler;

private ThreadPool threadPool;

/**
* Create a new instance of the Shiro Identity Plugin
*
Expand All @@ -42,13 +62,31 @@ public ShiroIdentityPlugin(final Settings settings) {
SecurityUtils.setSecurityManager(securityManager);
}

@Override
public Collection<Object> createComponents(
Client client,
ClusterService clusterService,
ThreadPool threadPool,
ResourceWatcherService resourceWatcherService,
ScriptService scriptService,
NamedXContentRegistry xContentRegistry,
Environment environment,
NodeEnvironment nodeEnvironment,
NamedWriteableRegistry namedWriteableRegistry,
IndexNameExpressionResolver expressionResolver,
Supplier<RepositoriesService> repositoriesServiceSupplier
) {
this.threadPool = threadPool;
return Collections.emptyList();
}

/**
* Return a Shiro Subject based on the provided authTokenHandler and current subject
*
* @return The current subject
*/
@Override
public Subject getSubject() {
public Subject getCurrentSubject() {
return new ShiroSubject(authTokenHandler, SecurityUtils.getSubject());
}

Expand All @@ -61,4 +99,9 @@ public Subject getSubject() {
public TokenManager getTokenManager() {
return this.authTokenHandler;
}

@Override
public PluginSubject getPluginSubject(Plugin plugin) {
return new ShiroPluginSubject(threadPool);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* 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.identity.shiro;

import org.opensearch.common.annotation.ExperimentalApi;
import org.opensearch.common.util.concurrent.ThreadContext;
import org.opensearch.identity.NamedPrincipal;
import org.opensearch.identity.PluginSubject;
import org.opensearch.threadpool.ThreadPool;

import java.security.Principal;
import java.util.concurrent.Callable;

/**
* Implementation of subject that is always authenticated
* <p>
* This class and related classes in this package will not return nulls or fail permissions checks
*
* This class is used by the ShiroIdentityPlugin to initialize IdentityAwarePlugins
*
* @opensearch.experimental
*/
@ExperimentalApi
public class ShiroPluginSubject implements PluginSubject {
private final ThreadPool threadPool;

ShiroPluginSubject(ThreadPool threadPool) {
super();
this.threadPool = threadPool;
}

@Override
public Principal getPrincipal() {
return NamedPrincipal.UNAUTHENTICATED;
}

@Override
public <T> T runAs(Callable<T> callable) throws Exception {
try (ThreadContext.StoredContext ctx = threadPool.getThreadContext().stashContext()) {
return callable.call();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
package org.opensearch.identity.shiro;

import org.opensearch.identity.Subject;
import org.opensearch.identity.UserSubject;
import org.opensearch.identity.tokens.AuthToken;

import java.security.Principal;
Expand All @@ -19,7 +20,7 @@
*
* @opensearch.experimental
*/
public class ShiroSubject implements Subject {
public class ShiroSubject implements UserSubject {
private final ShiroTokenManager authTokenHandler;
private final org.apache.shiro.subject.Subject shiroSubject;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.opensearch.identity.IdentityService;
import org.opensearch.plugins.IdentityPlugin;
import org.opensearch.test.OpenSearchTestCase;
import org.opensearch.threadpool.TestThreadPool;

import java.util.List;

Expand All @@ -24,19 +25,23 @@
public class ShiroIdentityPluginTests extends OpenSearchTestCase {

public void testSingleIdentityPluginSucceeds() {
TestThreadPool threadPool = new TestThreadPool(getTestName());
IdentityPlugin identityPlugin1 = new ShiroIdentityPlugin(Settings.EMPTY);
List<IdentityPlugin> pluginList1 = List.of(identityPlugin1);
IdentityService identityService1 = new IdentityService(Settings.EMPTY, pluginList1);
IdentityService identityService1 = new IdentityService(Settings.EMPTY, threadPool, pluginList1);
assertThat(identityService1.getTokenManager(), is(instanceOf(ShiroTokenManager.class)));
terminate(threadPool);
}

public void testMultipleIdentityPluginsFail() {
TestThreadPool threadPool = new TestThreadPool(getTestName());
IdentityPlugin identityPlugin1 = new ShiroIdentityPlugin(Settings.EMPTY);
IdentityPlugin identityPlugin2 = new ShiroIdentityPlugin(Settings.EMPTY);
IdentityPlugin identityPlugin3 = new ShiroIdentityPlugin(Settings.EMPTY);
List<IdentityPlugin> pluginList = List.of(identityPlugin1, identityPlugin2, identityPlugin3);
Exception ex = assertThrows(OpenSearchException.class, () -> new IdentityService(Settings.EMPTY, pluginList));
Exception ex = assertThrows(OpenSearchException.class, () -> new IdentityService(Settings.EMPTY, threadPool, pluginList));
assert (ex.getMessage().contains("Multiple identity plugins are not supported,"));
terminate(threadPool);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import org.opensearch.transport.TransportService;

import java.io.IOException;
import java.util.List;
import java.util.Optional;
import java.util.Set;

Expand All @@ -31,8 +30,8 @@
*/
public class NoopExtensionsManager extends ExtensionsManager {

public NoopExtensionsManager() throws IOException {
super(Set.of(), new IdentityService(Settings.EMPTY, List.of()));
public NoopExtensionsManager(IdentityService identityService) throws IOException {
super(Set.of(), identityService);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ public String executor() {
Map<String, List<String>> filteredHeaders = filterHeaders(headers, allowList, denyList);

TokenManager tokenManager = identityService.getTokenManager();
Subject subject = this.identityService.getSubject();
Subject subject = this.identityService.getCurrentSubject();
OnBehalfOfClaims claims = new OnBehalfOfClaims(discoveryExtensionNode.getId(), subject.getPrincipal().getName());

transportService.sendRequest(
Expand Down
20 changes: 16 additions & 4 deletions server/src/main/java/org/opensearch/identity/IdentityService.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
import org.opensearch.common.settings.Settings;
import org.opensearch.identity.noop.NoopIdentityPlugin;
import org.opensearch.identity.tokens.TokenManager;
import org.opensearch.plugins.IdentityAwarePlugin;
import org.opensearch.plugins.IdentityPlugin;
import org.opensearch.plugins.Plugin;
import org.opensearch.threadpool.ThreadPool;

import java.util.List;
import java.util.stream.Collectors;
Expand All @@ -27,12 +30,12 @@ public class IdentityService {
private final Settings settings;
private final IdentityPlugin identityPlugin;

public IdentityService(final Settings settings, final List<IdentityPlugin> identityPlugins) {
public IdentityService(final Settings settings, final ThreadPool threadPool, final List<IdentityPlugin> identityPlugins) {
this.settings = settings;

if (identityPlugins.size() == 0) {
log.debug("Identity plugins size is 0");
identityPlugin = new NoopIdentityPlugin();
identityPlugin = new NoopIdentityPlugin(threadPool);
} else if (identityPlugins.size() == 1) {
log.debug("Identity plugins size is 1");
identityPlugin = identityPlugins.get(0);
Expand All @@ -47,8 +50,8 @@ public IdentityService(final Settings settings, final List<IdentityPlugin> ident
/**
* Gets the current Subject
*/
public Subject getSubject() {
return identityPlugin.getSubject();
public Subject getCurrentSubject() {
return identityPlugin.getCurrentSubject();
}

/**
Expand All @@ -57,4 +60,13 @@ public Subject getSubject() {
public TokenManager getTokenManager() {
return identityPlugin.getTokenManager();
}

public void initializeIdentityAwarePlugins(final List<IdentityAwarePlugin> identityAwarePlugins) {
if (identityAwarePlugins != null) {
for (IdentityAwarePlugin plugin : identityAwarePlugins) {
PluginSubject pluginSubject = identityPlugin.getPluginSubject((Plugin) plugin);
plugin.assignSubject(pluginSubject);
}
}
}
}
19 changes: 19 additions & 0 deletions server/src/main/java/org/opensearch/identity/PluginSubject.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* 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.identity;

import org.opensearch.common.annotation.ExperimentalApi;

/**
* Similar to {@link Subject}, but represents a plugin executing actions
*
* @opensearch.experimental
*/
@ExperimentalApi
public interface PluginSubject extends Subject {}
14 changes: 7 additions & 7 deletions server/src/main/java/org/opensearch/identity/Subject.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@

package org.opensearch.identity;

import org.opensearch.identity.tokens.AuthToken;
import org.opensearch.common.annotation.ExperimentalApi;

import java.security.Principal;
import java.util.concurrent.Callable;

/**
* An individual, process, or device that causes information to flow among objects or change to the system state.
*
* @opensearch.experimental
*/
@ExperimentalApi
public interface Subject {

/**
Expand All @@ -22,11 +24,9 @@ public interface Subject {
Principal getPrincipal();

/**
* Authenticate via an auth token
* throws UnsupportedAuthenticationMethod
* throws InvalidAuthenticationToken
* throws SubjectNotFound
* throws SubjectDisabled
* runAs allows the caller to run a callable function as this subject
*/
void authenticate(final AuthToken token);
default <T> T runAs(Callable<T> callable) throws Exception {
return callable.call();
};
}
29 changes: 29 additions & 0 deletions server/src/main/java/org/opensearch/identity/UserSubject.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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.identity;

import org.opensearch.common.annotation.ExperimentalApi;
import org.opensearch.identity.tokens.AuthToken;

/**
* An instance of a subject representing a User. UserSubjects must pass credentials for authentication.
*
* @opensearch.experimental
*/
@ExperimentalApi
public interface UserSubject extends Subject {
/**
* Authenticate via an auth token
* throws UnsupportedAuthenticationMethod
* throws InvalidAuthenticationToken
* throws SubjectNotFound
* throws SubjectDisabled
*/
void authenticate(final AuthToken token);
}
Loading
Loading