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

Example backend of Security for Extensions for Integration Testing #6

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,15 @@
import org.opensearch.http.HttpServerTransport;
import org.opensearch.http.HttpServerTransport.Dispatcher;
import org.opensearch.core.index.Index;
import org.opensearch.identity.Subject;
import org.opensearch.identity.tokens.TokenManager;
import org.opensearch.index.IndexModule;
import org.opensearch.index.cache.query.QueryCache;
import org.opensearch.indices.IndicesService;
import org.opensearch.indices.SystemIndexDescriptor;
import org.opensearch.plugins.ClusterPlugin;
import org.opensearch.plugins.ExtensionAwarePlugin;
import org.opensearch.plugins.IdentityPlugin;
import org.opensearch.plugins.MapperPlugin;
import org.opensearch.repositories.RepositoriesService;
import org.opensearch.rest.RestController;
Expand Down Expand Up @@ -145,6 +149,8 @@
import org.opensearch.security.http.SecurityHttpServerTransport;
import org.opensearch.security.http.SecurityNonSslHttpServerTransport;
import org.opensearch.security.http.XFFResolver;
import org.opensearch.security.identity.SecuritySubject;
import org.opensearch.security.identity.SecurityTokenManager;
import org.opensearch.security.privileges.PrivilegesEvaluator;
import org.opensearch.security.privileges.PrivilegesInterceptor;
import org.opensearch.security.privileges.RestLayerPrivilegesEvaluator;
Expand Down Expand Up @@ -193,7 +199,12 @@
import org.opensearch.watcher.ResourceWatcherService;
// CS-ENFORCE-SINGLE

public final class OpenSearchSecurityPlugin extends OpenSearchSecuritySSLPlugin implements ClusterPlugin, MapperPlugin {
public final class OpenSearchSecurityPlugin extends OpenSearchSecuritySSLPlugin
implements
ClusterPlugin,
MapperPlugin,
ExtensionAwarePlugin,
IdentityPlugin {

private static final String KEYWORD = ".keyword";
private static final Logger actionTrace = LogManager.getLogger("opendistro_security_action_trace");
Expand All @@ -212,6 +223,8 @@ public final class OpenSearchSecurityPlugin extends OpenSearchSecuritySSLPlugin
private volatile ConfigurationRepository cr;
private volatile AdminDNs adminDns;
private volatile ClusterService cs;
private volatile SecuritySubject subject = new SecuritySubject();
private volatile SecurityTokenManager tokenManager;
private volatile AtomicReference<DiscoveryNode> localNode = new AtomicReference<>();
private volatile AuditLog auditLog;
private volatile BackendRegistry backendRegistry;
Expand All @@ -226,6 +239,17 @@ public final class OpenSearchSecurityPlugin extends OpenSearchSecuritySSLPlugin
private volatile Salt salt;
private volatile OpensearchDynamicSetting<Boolean> transportPassiveAuthSetting;

public static Setting RESERVED_INDICES_SETTING = Setting.listSetting(
"reserved_indices",
List.of(),
Function.identity(),
Property.ExtensionScope
);

public static Setting PERMISSIONS_SETTING = Setting.groupSetting("permissions.", Property.ExtensionScope);

public static Setting SEND_BACKEND_ROLES_SETTING = Setting.boolSetting("send_backend_roles", false, Property.ExtensionScope);

public static boolean isActionTraceEnabled() {
return actionTrace.isTraceEnabled();
}
Expand Down Expand Up @@ -990,6 +1014,9 @@ public Collection<Object> createComponents(

cr = ConfigurationRepository.create(settings, this.configPath, threadPool, localClient, clusterService, auditLog);

subject.setThreadContext(threadPool.getThreadContext());
tokenManager = new SecurityTokenManager(cs, threadPool);

userService = new UserService(cs, cr, settings, localClient);

final XFFResolver xffResolver = new XFFResolver(threadPool);
Expand Down Expand Up @@ -1044,6 +1071,7 @@ public Collection<Object> createComponents(
dcf.registerDCFListener(evaluator);
dcf.registerDCFListener(restLayerEvaluator);
dcf.registerDCFListener(securityRestHandler);
dcf.registerDCFListener(tokenManager);
if (!(auditLog instanceof NullAuditLog)) {
// Don't register if advanced modules is disabled in which case auditlog is instance of NullAuditLog
dcf.registerDCFListener(auditLog);
Expand Down Expand Up @@ -1107,6 +1135,15 @@ public Settings additionalSettings() {
return builder.build();
}

@Override
public List<Setting<?>> getExtensionSettings() {
List<Setting<?>> settings = new ArrayList<Setting<?>>();
settings.add(RESERVED_INDICES_SETTING);
settings.add(SEND_BACKEND_ROLES_SETTING);
settings.add(PERMISSIONS_SETTING);
return settings;
}

@Override
public List<Setting<?>> getSettings() {
List<Setting<?>> settings = new ArrayList<Setting<?>>();
Expand Down Expand Up @@ -1886,6 +1923,16 @@ private static String handleKeyword(final String field) {
return field;
}

@Override
public Subject getSubject() {
return subject;
}

@Override
public TokenManager getTokenManager() {
return tokenManager;
}

public static class GuiceHolder implements LifecycleComponent {

private static RepositoriesService repositoriesService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ public String getType() {

@Override
public User authenticate(final AuthCredentials credentials) {
return new User(credentials.getUsername(), credentials.getBackendRoles(), credentials);
User user = new User(credentials.getUsername(), credentials.getBackendRoles(), credentials);
user.addSecurityRoles(credentials.getSecurityRoles());
return user;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* 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.
*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/

package org.opensearch.security.authtoken.jwt;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class EncryptionDecryptionUtil {

public static String encrypt(final String secret, final String data) {
final Cipher cipher = createCipherFromSecret(secret, CipherMode.ENCRYPT);
final byte[] cipherText = createCipherText(cipher, data.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(cipherText);
}

public static String decrypt(final String secret, final String encryptedString) {
final Cipher cipher = createCipherFromSecret(secret, CipherMode.DECRYPT);
final byte[] cipherText = createCipherText(cipher, Base64.getDecoder().decode(encryptedString));
return new String(cipherText, StandardCharsets.UTF_8);
}

private static Cipher createCipherFromSecret(final String secret, final CipherMode mode) {
try {
final byte[] decodedKey = Base64.getDecoder().decode(secret);
final Cipher cipher = Cipher.getInstance("AES");
final SecretKey originalKey = new SecretKeySpec(Arrays.copyOf(decodedKey, 16), "AES");
cipher.init(mode.opmode, originalKey);
return cipher;
} catch (final Exception e) {
throw new RuntimeException("Error creating cipher from secret in mode " + mode.name());
}
}

private static byte[] createCipherText(final Cipher cipher, final byte[] data) {
try {
return cipher.doFinal(data);
} catch (final Exception e) {
throw new RuntimeException("The cipher was unable to perform pass over data");
}
}

private enum CipherMode {
ENCRYPT(Cipher.ENCRYPT_MODE),
DECRYPT(Cipher.DECRYPT_MODE);

private final int opmode;

private CipherMode(final int opmode) {
this.opmode = opmode;
}
}
}
Loading
Loading