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/Identity] Select AuthenticationManager via configuration #5953

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -27,3 +27,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- [Identity] Persistence for the Identity module using a System Index ([#5613](https://github.com/opensearch-project/OpenSearch/pull/5613))
- [Identity] Ensure compatibility with Security Plugin by accepting up to two rest handler wrappers ([#5837](https://github.com/opensearch-project/OpenSearch/pull/5837))
- [Identity] Move implementations of AuthenticationManager into Identity Module and keep interfaces in authn lib ([#5857](https://github.com/opensearch-project/OpenSearch/pull/5857))
- [Identity] Select AuthenticationManager via configuration ([#5953](https://github.com/opensearch-project/OpenSearch/pull/5953))
1 change: 1 addition & 0 deletions gradle/missing-javadoc.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ configure([
project(":modules:repository-url"),
project(":modules:systemd"),
project(":modules:transport-netty4"),
project(":sandbox:modules:extensible-identity"),
project(":sandbox:modules:identity"),
project(":plugins:analysis-icu"),
project(":plugins:analysis-kuromoji"),
Expand Down
64 changes: 64 additions & 0 deletions sandbox/libs/authn/docs/IDENTITY_TESTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
## Testing with Security Plugin installed

Assemble a local distribution of core:

```
./gradlew localDistro
```

Navigate to the platform specific distribution:

```
cd distribution/archives/<platform>/build/install/opensearch-<version>-SNAPSHOT
```

### Assemble the Security Plugin

Checkout the security repo: https://github.com/opensearch-project/security

Run gradlew assemble:

```
./gradlew assemble
```

### Install the Security Plugin

In the root directory of the local distribution built in core, run:

```
./bin/opensearch-plugin install --verbose file:<path-to-opensearch-security>/build/distributions/opensearch-security-<version>-SNAPSHOT.zip
```

to install the security plugin. Answer yes to the prompt. The step above may require the use of `sudo`

Navigate to the security plugin tools directory:

```
cd plugins/opensearch-security/tools
```

and run the install_demo_configuration script:

```
./install_demo_configuration.sh
```

and answer yes to all prompts.

Go back up to the root directory by running: `cd ../../..`

and open the `opensearch.yml` file:

```
vim config/opensearch.yml
```

and enter the following lines:

```
identity.enabled: true
identity.auth_manager_class: org.opensearch.identity.authmanager.internal.InternalAuthenticationManager
```

Note that `identity.auth_manager_class` is optional and will default to the InternalAuthenticationManager. Use this setting if you would like to use a non-default AuthenticationManager.
Copy link
Contributor

Choose a reason for hiding this comment

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

I really like that you added steps for people to be able to test Identity out!

Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

package org.opensearch.authn;

import java.util.Objects;

/**
* Application wide access for identity systems
*
Expand All @@ -25,6 +27,7 @@ private Identity() {}
* Gets the Authentication Manager for this application
*/
public static AuthenticationManager getAuthManager() {
Objects.requireNonNull(AUTH_MANAGER, "Auth Manager has not been set");
return AUTH_MANAGER;
}

Expand Down
22 changes: 22 additions & 0 deletions sandbox/modules/extensible-identity/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* 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.
*/
opensearchplugin {
description 'Extensible Plugin for identity features in OpenSearch.'
classname 'org.opensearch.extensible.identity.ExtensibleIdentityPlugin'
name 'extensible-identity'
licenseFile rootProject.file('licenses/APACHE-LICENSE-2.0.txt')
noticeFile rootProject.file('NOTICE.txt')
}

dependencies {
implementation project(':sandbox:libs:opensearch-authn')
}

test {
systemProperty 'opensearch.set.netty.runtime.available.processors', 'false'
Copy link
Contributor

Choose a reason for hiding this comment

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

When this gets merged will it have any impacts outside of our use or is it a relatively minor difference? I know it sets the number of processors and I think that setting it to false will make it not restrict the netty thread pool size. Is this intended?

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* 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.extensible.identity;

public class ConfigConstants {
public static final String IDENTITY_AUTH_MANAGER_CLASS = "identity.auth_manager_class";
public static final String IDENTITY_ENABLED = "identity.enabled";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
* 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.extensible.identity;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.opensearch.OpenSearchException;
import org.opensearch.authn.AuthenticationManager;
import org.opensearch.authn.Identity;
import org.opensearch.client.Client;
import org.opensearch.cluster.metadata.IndexNameExpressionResolver;
import org.opensearch.cluster.service.ClusterService;
import org.opensearch.common.io.stream.NamedWriteableRegistry;
import org.opensearch.common.settings.Setting;
import org.opensearch.common.settings.Settings;
import org.opensearch.common.xcontent.NamedXContentRegistry;
import org.opensearch.env.Environment;
import org.opensearch.env.NodeEnvironment;
import org.opensearch.plugins.ExtensiblePlugin;
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.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

public class ExtensibleIdentityPlugin extends Plugin implements ExtensiblePlugin {
private volatile Logger log = LogManager.getLogger(this.getClass());

private static final String DEFAULT_AUTHENTICATION_MANAGER_CLASS =
"org.opensearch.identity.authmanager.internal.InternalAuthenticationManager";

private static final String NOOP_AUTHENTICATION_MANAGER_CLASS = "org.opensearch.identity.authmanager.noop.NoopAuthenticationManager";

private volatile Map<String, AuthenticationManager> availableAuthManagers;
private volatile Settings settings;

private volatile Path configPath;

@SuppressWarnings("removal")
public ExtensibleIdentityPlugin(final Settings settings, final Path configPath) {
this.configPath = configPath;

if (this.configPath != null) {
log.info("OpenSearch Config path is {}", this.configPath.toAbsolutePath());
} else {
log.info("OpenSearch Config path is not set");
}

this.settings = settings;
}

private static boolean isEnabled(final Settings settings) {
return settings.getAsBoolean(ConfigConstants.IDENTITY_ENABLED, false);
}

public List<Setting<?>> getSettings() {
List<Setting<?>> settings = new ArrayList<Setting<?>>();
settings.addAll(super.getSettings());
settings.add(Setting.boolSetting(ConfigConstants.IDENTITY_ENABLED, false, Setting.Property.NodeScope, Setting.Property.Filtered));
settings.add(
Setting.simpleString(
ConfigConstants.IDENTITY_AUTH_MANAGER_CLASS,
DEFAULT_AUTHENTICATION_MANAGER_CLASS,
Setting.Property.NodeScope,
Setting.Property.Filtered
)
);

return settings;
}

@Override
public Collection<Object> createComponents(
Client localClient,
ClusterService clusterService,
ThreadPool threadPool,
ResourceWatcherService resourceWatcherService,
ScriptService scriptService,
NamedXContentRegistry xContentRegistry,
Environment environment,
NodeEnvironment nodeEnvironment,
NamedWriteableRegistry namedWriteableRegistry,
IndexNameExpressionResolver indexNameExpressionResolver,
Supplier<RepositoriesService> repositoriesServiceSupplier
) {
this.configPath = environment.configDir();
this.settings = environment.settings();

if (availableAuthManagers == null || availableAuthManagers.isEmpty()) {
throw new OpenSearchException("No available authentication managers");
}

// TODO: revisit this
final String authManagerClassName;

if (isEnabled(settings)) {
authManagerClassName = this.settings.get(ConfigConstants.IDENTITY_AUTH_MANAGER_CLASS, DEFAULT_AUTHENTICATION_MANAGER_CLASS);
} else {
authManagerClassName = NOOP_AUTHENTICATION_MANAGER_CLASS;
}

AuthenticationManager authManager = availableAuthManagers.get(authManagerClassName);
if (authManager == null) {
throw new OpenSearchException("Auth Manager with class " + authManagerClassName + " cannot be found");
}

try {
Method method = authManager.getClass().getMethod("setThreadPool", ThreadPool.class);
method.invoke(authManager, threadPool);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
/** ignore */
}

Identity.setAuthManager(authManager);

return Collections.emptyList();
}

@Override
public void loadExtensions(ExtensionLoader loader) {
List<AuthenticationManager> authManagerImplementations = loader.loadExtensions(AuthenticationManager.class);
if (authManagerImplementations != null && authManagerImplementations.size() > 0) {
availableAuthManagers = new HashMap<>();
for (AuthenticationManager authManager : authManagerImplementations) {
availableAuthManagers.put(authManager.getClass().getCanonicalName(), authManager);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* 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.
*/

/**
* Abstract plugin for Identity features into OpenSearch
*/
package org.opensearch.extensible.identity;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* 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.
*/

grant {
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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.extensible.identity;

import org.opensearch.authn.AuthenticationManager;
import org.opensearch.authn.Identity;
import org.opensearch.common.settings.Settings;
import org.opensearch.plugins.Plugin;
import org.opensearch.test.OpenSearchIntegTestCase;

import java.util.Collection;
import java.util.List;

@OpenSearchIntegTestCase.ClusterScope(scope = OpenSearchIntegTestCase.Scope.TEST, numDataNodes = 1)
public class LoadAuthenticationManagerExtensionTests extends OpenSearchIntegTestCase {

@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return List.of(ExtensibleIdentityPlugin.class, TestIdentityPlugin.class);
}

@Override
protected Settings nodeSettings(int nodeOrdinal) {
return Settings.builder().put(super.nodeSettings(nodeOrdinal)).put(nodeSettings()).build();
}

final Settings nodeSettings() {
return Settings.builder()
.put(ConfigConstants.IDENTITY_ENABLED, true)
.put(
ConfigConstants.IDENTITY_AUTH_MANAGER_CLASS,
"org.opensearch.extensible.identity.TestIdentityPlugin.TestAuthenticationManager"
)
.build();
}

public void testLoadAuthManagerExtensionSuccess() throws Exception {
ensureGreen();
AuthenticationManager authManager = Identity.getAuthManager();
assertNotNull(authManager);
assertEquals(
"org.opensearch.extensible.identity.TestIdentityPlugin.TestAuthenticationManager",
authManager.getClass().getCanonicalName()
);
}
}
Loading