From 5a4ff633bf92cf5f368d0d1728d6c5dd8f69fc65 Mon Sep 17 00:00:00 2001 From: Abhi Kalra <99718513+abhivka7@users.noreply.github.com> Date: Fri, 7 Apr 2023 21:51:26 +0530 Subject: [PATCH] Dynamic_Tenancy_Configurations changes (#2607) Signed-off-by: Abhi Kalra Co-authored-by: Abhi Kalra Signed-off-by: Maciej Mierzwa --- config/config.yml | 2 + legacy/securityconfig_v6/config.yml | 1 + .../security/OpenSearchSecurityPlugin.java | 10 ++ .../security/action/tenancy/EmptyRequest.java | 35 ++++ .../tenancy/TenancyConfigRestHandler.java | 65 ++++++++ .../tenancy/TenancyConfigRetrieveActions.java | 24 +++ .../TenancyConfigRetrieveResponse.java | 70 ++++++++ .../TenancyConfigRetrieveTransportAction.java | 63 +++++++ .../tenancy/TenancyConfigUpdateAction.java | 26 +++ .../tenancy/TenancyConfigUpdateRequest.java | 69 ++++++++ .../TenancyConfigUpdateTransportAction.java | 155 ++++++++++++++++++ .../action/tenancy/TenancyConfigs.java | 18 ++ .../PrivilegesInterceptorImpl.java | 7 + .../dlic/rest/api/AbstractApiAction.java | 18 +- .../dlic/rest/api/AccountApiAction.java | 2 +- .../dlic/rest/api/AllowlistApiAction.java | 2 +- .../dlic/rest/api/InternalUsersApiAction.java | 2 +- .../dlic/rest/api/MigrateApiAction.java | 10 +- .../rest/api/PatchableResourceApiAction.java | 4 +- .../dlic/rest/api/RolesMappingApiAction.java | 2 +- .../privileges/PrivilegesEvaluator.java | 9 + .../security/rest/DashboardsInfoAction.java | 3 + .../securityconf/DynamicConfigModel.java | 2 + .../securityconf/DynamicConfigModelV6.java | 6 + .../securityconf/DynamicConfigModelV7.java | 6 + .../securityconf/impl/v6/ConfigV6.java | 4 + .../securityconf/impl/v7/ConfigV7.java | 10 +- .../security/support/ConfigConstants.java | 4 + .../test/TenancyDefaultTenantTests.java | 96 +++++++++++ .../test/TenancyMultitenancyEnabledTests.java | 89 ++++++++++ .../TenancyPrivateTenantEnabledTests.java | 101 ++++++++++++ .../security/test/helper/rest/RestHelper.java | 14 +- src/test/resources/auditlog/config.yml | 2 + src/test/resources/cache/config.yml | 2 + src/test/resources/composite_config.yml | 2 + src/test/resources/config.yml | 2 + src/test/resources/config_anon.yml | 2 + src/test/resources/config_clientcert.yml | 2 + src/test/resources/config_disable_all.yml | 2 + src/test/resources/config_dnfof.yml | 2 + src/test/resources/config_invalidlic.yml | 2 + src/test/resources/config_lic.yml | 2 + src/test/resources/config_lic_rk.yml | 2 + src/test/resources/config_multirolespan.yml | 2 + .../resources/config_protected_indices.yml | 2 + src/test/resources/config_proxy.yml | 2 + src/test/resources/config_proxy_custom.yml | 2 + .../config_respect_indices_options.yml | 2 + .../resources/config_rest_impersonation.yml | 2 + src/test/resources/config_system_indices.yml | 2 + .../resources/config_transport_username.yml | 2 + src/test/resources/config_xff.yml | 2 + src/test/resources/dlsfls/config.yml | 2 + src/test/resources/ldap/config.yml | 2 + src/test/resources/ldap/config_ldap2.yml | 2 + src/test/resources/multitenancy/config.yml | 2 + .../multitenancy/config_anonymous.yml | 2 + .../multitenancy/config_basic_auth.yml | 2 + .../resources/multitenancy/config_nodnfof.yml | 2 + src/test/resources/restapi/config.yml | 2 + .../resources/restapi/invalid_config.json | 2 + .../resources/restapi/security_config.json | 2 + .../resources/restapi/securityconfig.json | 2 + .../restapi/securityconfig_nondefault.json | 2 + .../resources/security_passive/config.yml | 2 + 65 files changed, 965 insertions(+), 30 deletions(-) create mode 100644 src/main/java/org/opensearch/security/action/tenancy/EmptyRequest.java create mode 100644 src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRestHandler.java create mode 100644 src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveActions.java create mode 100644 src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveResponse.java create mode 100644 src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveTransportAction.java create mode 100644 src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateAction.java create mode 100644 src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateRequest.java create mode 100644 src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateTransportAction.java create mode 100644 src/main/java/org/opensearch/security/action/tenancy/TenancyConfigs.java create mode 100644 src/test/java/org/opensearch/security/multitenancy/test/TenancyDefaultTenantTests.java create mode 100644 src/test/java/org/opensearch/security/multitenancy/test/TenancyMultitenancyEnabledTests.java create mode 100644 src/test/java/org/opensearch/security/multitenancy/test/TenancyPrivateTenantEnabledTests.java diff --git a/config/config.yml b/config/config.yml index 0537ff8406..1493a0d7f1 100644 --- a/config/config.yml +++ b/config/config.yml @@ -68,6 +68,8 @@ config: #kibana: # Kibana multitenancy #multitenancy_enabled: true + #private_tenant_enabled: true + #default_tenant: "" #server_username: kibanaserver #index: '.kibana' http: diff --git a/legacy/securityconfig_v6/config.yml b/legacy/securityconfig_v6/config.yml index da2be1e38d..15d5ee9973 100644 --- a/legacy/securityconfig_v6/config.yml +++ b/legacy/securityconfig_v6/config.yml @@ -60,6 +60,7 @@ opendistro_security: #filtered_alias_mode: warn #kibana: #multitenancy_enabled: true + #server_username: kibanaserver #index: '.kibana' #do_not_fail_on_forbidden: false diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index af089584a9..ffd7f730ed 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -115,6 +115,11 @@ import org.opensearch.search.query.QuerySearchResult; import org.opensearch.security.action.configupdate.ConfigUpdateAction; import org.opensearch.security.action.configupdate.TransportConfigUpdateAction; +import org.opensearch.security.action.tenancy.TenancyConfigRestHandler; +import org.opensearch.security.action.tenancy.TenancyConfigRetrieveActions; +import org.opensearch.security.action.tenancy.TenancyConfigRetrieveTransportAction; +import org.opensearch.security.action.tenancy.TenancyConfigUpdateAction; +import org.opensearch.security.action.tenancy.TenancyConfigUpdateTransportAction; import org.opensearch.security.action.whoami.TransportWhoAmIAction; import org.opensearch.security.action.whoami.WhoAmIAction; import org.opensearch.security.auditlog.AuditLog; @@ -469,6 +474,7 @@ public List getRestHandlers(Settings settings, RestController restC Objects.requireNonNull(cs), Objects.requireNonNull(adminDns), Objects.requireNonNull(cr))); handlers.add(new SecurityConfigUpdateAction(settings, restController, Objects.requireNonNull(threadPool), adminDns, configPath, principalExtractor)); handlers.add(new SecurityWhoAmIAction(settings, restController, Objects.requireNonNull(threadPool), adminDns, configPath, principalExtractor)); + handlers.add(new TenancyConfigRestHandler()); handlers.addAll( SecurityRestApiActions.getHandler( settings, @@ -505,6 +511,10 @@ public UnaryOperator getRestHandlerWrapper(final ThreadContext thre if(!disabled && !SSLConfig.isSslOnlyMode()) { actions.add(new ActionHandler<>(ConfigUpdateAction.INSTANCE, TransportConfigUpdateAction.class)); actions.add(new ActionHandler<>(WhoAmIAction.INSTANCE, TransportWhoAmIAction.class)); + + actions.add(new ActionHandler<>(TenancyConfigRetrieveActions.INSTANCE, TenancyConfigRetrieveTransportAction.class)); + actions.add(new ActionHandler<>(TenancyConfigUpdateAction.INSTANCE, TenancyConfigUpdateTransportAction.class)); + } return actions; } diff --git a/src/main/java/org/opensearch/security/action/tenancy/EmptyRequest.java b/src/main/java/org/opensearch/security/action/tenancy/EmptyRequest.java new file mode 100644 index 0000000000..607216a8c3 --- /dev/null +++ b/src/main/java/org/opensearch/security/action/tenancy/EmptyRequest.java @@ -0,0 +1,35 @@ +/* + * 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.action.tenancy; + +import java.io.IOException; + +import org.opensearch.action.ActionRequest; +import org.opensearch.action.ActionRequestValidationException; +import org.opensearch.common.io.stream.StreamInput; + +public class EmptyRequest extends ActionRequest { + + public EmptyRequest(final StreamInput in) throws IOException { + super(in); + } + + public EmptyRequest() throws IOException { + super(); + } + + @Override + public ActionRequestValidationException validate() + { + return null; + } +} diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRestHandler.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRestHandler.java new file mode 100644 index 0000000000..0a00d16694 --- /dev/null +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRestHandler.java @@ -0,0 +1,65 @@ +/* + * 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.action.tenancy; + +import java.io.IOException; +import java.util.List; + +import com.google.common.collect.ImmutableList; + +import org.opensearch.client.node.NodeClient; +import org.opensearch.rest.BaseRestHandler; +import org.opensearch.rest.RestRequest; +import org.opensearch.rest.action.RestToXContentListener; + +import static org.opensearch.rest.RestRequest.Method.GET; +import static org.opensearch.rest.RestRequest.Method.PUT; + +public class TenancyConfigRestHandler extends BaseRestHandler { + + public TenancyConfigRestHandler() { + super(); + } + + @Override + public String getName() { + return "Multi Tenancy actions to Retrieve / Update configs."; + } + + @Override + public List routes() { + return ImmutableList.of( + new Route(GET, "/_plugins/_security/api/tenancy/config"), + new Route(PUT, "/_plugins/_security/api/tenancy/config") + ); + } + + @Override + protected RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient nodeClient) throws IOException { + + switch (request.method()) { + case GET: + return channel -> nodeClient.execute( + TenancyConfigRetrieveActions.INSTANCE, + new EmptyRequest(), + new RestToXContentListener<>(channel)); + case PUT: + return channel -> nodeClient.execute( + TenancyConfigUpdateAction.INSTANCE, + TenancyConfigUpdateRequest.fromXContent(request.contentParser()), + new RestToXContentListener<>(channel)); + default: + throw new RuntimeException("Not implemented"); + } + } + +} diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveActions.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveActions.java new file mode 100644 index 0000000000..796f233f13 --- /dev/null +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveActions.java @@ -0,0 +1,24 @@ +/* + * 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.action.tenancy; + +import org.opensearch.action.ActionType; + +public class TenancyConfigRetrieveActions extends ActionType { + + public static final TenancyConfigRetrieveActions INSTANCE = new TenancyConfigRetrieveActions(); + public static final String NAME = "cluster:feature/tenancy/config/read"; + + protected TenancyConfigRetrieveActions() { + super(NAME, TenancyConfigRetrieveResponse::new); + } +} diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveResponse.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveResponse.java new file mode 100644 index 0000000000..463cc7d831 --- /dev/null +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveResponse.java @@ -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. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.security.action.tenancy; + +import java.io.IOException; + +import org.opensearch.action.ActionResponse; +import org.opensearch.common.Strings; +import org.opensearch.common.io.stream.StreamInput; +import org.opensearch.common.io.stream.StreamOutput; +import org.opensearch.common.xcontent.XContentType; +import org.opensearch.core.xcontent.ToXContentObject; +import org.opensearch.core.xcontent.XContentBuilder; + +public class TenancyConfigRetrieveResponse extends ActionResponse implements ToXContentObject { + + public TenancyConfigs tenancyConfigs = new TenancyConfigs(); + + public TenancyConfigRetrieveResponse(final StreamInput in) throws IOException { + super(in); + this.tenancyConfigs.multitenancy_enabled = in.readOptionalBoolean(); + this.tenancyConfigs.private_tenant_enabled = in.readOptionalBoolean(); + this.tenancyConfigs.default_tenant = in.readOptionalString(); + } + + public TenancyConfigRetrieveResponse(final TenancyConfigs tenancyConfigs) { + this.tenancyConfigs = tenancyConfigs; + } + + public TenancyConfigs getMultitenancyConfig() { + return tenancyConfigs; + } + + public Boolean getMultitenancyEnabled() { return tenancyConfigs.multitenancy_enabled; } + + public Boolean getPrivateTenantEnabled() { return tenancyConfigs.private_tenant_enabled; } + + public String getDefaultTenant() { return tenancyConfigs.default_tenant; } + + @Override + public void writeTo(final StreamOutput out) throws IOException { + out.writeBoolean(getMultitenancyEnabled()); + out.writeBoolean(getPrivateTenantEnabled()); + out.writeString(getDefaultTenant()); + } + + @Override + public String toString() { + return Strings.toString(XContentType.JSON, this, true, true); + } + + @Override + public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException { + builder.startObject(); + builder.field("multitenancy_enabled", getMultitenancyEnabled()); + builder.field("private_tenant_enabled", getPrivateTenantEnabled()); + builder.field("default_tenant", getDefaultTenant()); + builder.endObject(); + return builder; + } +} diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveTransportAction.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveTransportAction.java new file mode 100644 index 0000000000..a68bbae85e --- /dev/null +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveTransportAction.java @@ -0,0 +1,63 @@ +/* + * 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.action.tenancy; + +import java.util.Collections; + +import org.opensearch.action.ActionListener; +import org.opensearch.action.support.ActionFilters; +import org.opensearch.action.support.HandledTransportAction; +import org.opensearch.common.inject.Inject; +import org.opensearch.common.settings.Settings; +import org.opensearch.security.configuration.ConfigurationRepository; +import org.opensearch.security.securityconf.impl.CType; +import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; +import org.opensearch.security.securityconf.impl.v7.ConfigV7; +import org.opensearch.tasks.Task; +import org.opensearch.transport.TransportService; + +public class TenancyConfigRetrieveTransportAction + extends HandledTransportAction { + + private final ConfigurationRepository config; + + @Inject + public TenancyConfigRetrieveTransportAction(final Settings settings, + final TransportService transportService, + final ActionFilters actionFilters, + final ConfigurationRepository config) { + super(TenancyConfigRetrieveActions.NAME, transportService, actionFilters, EmptyRequest::new); + + this.config = config; + } + + /** Load the configuration from the security index and return a copy */ + protected final SecurityDynamicConfiguration load() { + return config.getConfigurationsFromIndex(Collections.singleton(CType.CONFIG), false).get(CType.CONFIG).deepClone(); + } + + @Override + protected void doExecute(final Task task, final EmptyRequest request, final ActionListener listener) { + + // Get the security configuration and lookup the config setting state + final SecurityDynamicConfiguration dynamicConfig = load(); + ConfigV7 config = (ConfigV7)dynamicConfig.getCEntry("config"); + + final TenancyConfigs tenancyConfigs= new TenancyConfigs(); + + tenancyConfigs.multitenancy_enabled = config.dynamic.kibana.multitenancy_enabled; + tenancyConfigs.private_tenant_enabled = config.dynamic.kibana.private_tenant_enabled; + tenancyConfigs.default_tenant = config.dynamic.kibana.default_tenant; + + listener.onResponse(new TenancyConfigRetrieveResponse(tenancyConfigs)); + } +} diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateAction.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateAction.java new file mode 100644 index 0000000000..73d515b7d8 --- /dev/null +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateAction.java @@ -0,0 +1,26 @@ +/* + * 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.action.tenancy; + +import org.opensearch.action.ActionType; + +public class TenancyConfigUpdateAction extends ActionType { + + public static final TenancyConfigUpdateAction INSTANCE = new TenancyConfigUpdateAction(); + public static final String NAME = "cluster:feature/tenancy/config/update"; + + + protected TenancyConfigUpdateAction() + { + super(NAME, TenancyConfigRetrieveResponse::new); + } +} diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateRequest.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateRequest.java new file mode 100644 index 0000000000..2d03f698a6 --- /dev/null +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateRequest.java @@ -0,0 +1,69 @@ +/* + * 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.action.tenancy; +import java.io.IOException; + +import org.opensearch.action.ActionRequest; +import org.opensearch.action.ActionRequestValidationException; +import org.opensearch.common.io.stream.StreamInput; +import org.opensearch.core.ParseField; +import org.opensearch.core.xcontent.ConstructingObjectParser; +import org.opensearch.core.xcontent.XContentParser; + +public class TenancyConfigUpdateRequest extends ActionRequest { + + private TenancyConfigs tenancyConfigs = new TenancyConfigs(); + + public TenancyConfigUpdateRequest(final StreamInput in) throws IOException { + super(in); + in.readOptionalBoolean(); + in.readOptionalBoolean(); + in.readOptionalString(); + } + + public TenancyConfigUpdateRequest(final Boolean multitenancy_enabled, final Boolean private_tenant_enabled, final String default_tenant) { + super(); + this.tenancyConfigs.multitenancy_enabled = multitenancy_enabled; + this.tenancyConfigs.private_tenant_enabled = private_tenant_enabled; + this.tenancyConfigs.default_tenant = default_tenant; + } + + public TenancyConfigs getTenancyConfigs() { + return tenancyConfigs; + } + + @Override + public ActionRequestValidationException validate() { + if (getTenancyConfigs() == null) { + final ActionRequestValidationException validationException = new ActionRequestValidationException(); + validationException.addValidationError("Missing tenancy configs"); + return validationException; + } + return null; + } + + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( + TenancyConfigUpdateRequest.class.getName(), + args -> new TenancyConfigUpdateRequest((Boolean)args[0], (Boolean) args[1], (String) args[2]) + ); + + static { + PARSER.declareBoolean(ConstructingObjectParser.optionalConstructorArg(), new ParseField("multitenancy_enabled")); + PARSER.declareBoolean(ConstructingObjectParser.optionalConstructorArg(), new ParseField("private_tenant_enabled")); + PARSER.declareString(ConstructingObjectParser.optionalConstructorArg(), new ParseField("default_tenant")); + + } + + public static TenancyConfigUpdateRequest fromXContent(final XContentParser parser) { + return PARSER.apply(parser, null); + } +} diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateTransportAction.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateTransportAction.java new file mode 100644 index 0000000000..1d4b563ca4 --- /dev/null +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateTransportAction.java @@ -0,0 +1,155 @@ +/* + * 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.action.tenancy; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import org.opensearch.action.ActionListener; +import org.opensearch.action.index.IndexResponse; +import org.opensearch.action.support.ActionFilters; +import org.opensearch.action.support.HandledTransportAction; +import org.opensearch.client.Client; +import org.opensearch.common.inject.Inject; +import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.security.configuration.ConfigurationRepository; +import org.opensearch.security.dlic.rest.api.AbstractApiAction; +import org.opensearch.security.securityconf.impl.CType; +import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; +import org.opensearch.security.securityconf.impl.v7.ConfigV7; +import org.opensearch.security.support.ConfigConstants; +import org.opensearch.tasks.Task; +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.transport.TransportService; + +public class TenancyConfigUpdateTransportAction extends HandledTransportAction { + + private static final Logger log = LogManager.getLogger(TenancyConfigUpdateTransportAction.class); + + private final String securityIndex; + private final ConfigurationRepository config; + private final Client client; + private final ThreadPool pool; + + @Inject + public TenancyConfigUpdateTransportAction(final Settings settings, + final TransportService transportService, + final ActionFilters actionFilters, + final ConfigurationRepository config, + final ThreadPool pool, + final Client client) { + super(TenancyConfigUpdateAction.NAME, transportService, actionFilters, TenancyConfigUpdateRequest::new); + + this.securityIndex = settings.get(ConfigConstants.SECURITY_CONFIG_INDEX_NAME, ConfigConstants.OPENDISTRO_SECURITY_DEFAULT_CONFIG_INDEX); + + this.config = config; + this.client = client; + this.pool = pool; + } + + /** Load the configuration from the security index and return a copy */ + protected final SecurityDynamicConfiguration load() { + return config.getConfigurationsFromIndex(Collections.singleton(CType.CONFIG), false).get(CType.CONFIG).deepClone(); + } + + private Set getAcceptableDefaultTenants() { + Set acceptableDefaultTenants = new HashSet(); + acceptableDefaultTenants.add(ConfigConstants.TENANCY_GLOBAL_TENANT_DEFAULT_NAME); + acceptableDefaultTenants.add(ConfigConstants.TENANCY_GLOBAL_TENANT_NAME); + acceptableDefaultTenants.add(ConfigConstants.TENANCY_PRIVATE_TENANT_NAME); + return acceptableDefaultTenants; + } + + private Set getAllConfiguredTenantNames() { + + return this.config.getConfiguration(CType.TENANTS).getCEntries().keySet(); + } + + protected void validate(ConfigV7 updatedConfig) { + if(!updatedConfig.dynamic.kibana.private_tenant_enabled && (updatedConfig.dynamic.kibana.default_tenant).equals(ConfigConstants.TENANCY_PRIVATE_TENANT_NAME)) { + throw new IllegalArgumentException("Private tenant can not be disabled if it is the default tenant."); + } + + Set acceptableDefaultTenants = getAcceptableDefaultTenants(); + + if(acceptableDefaultTenants.contains(updatedConfig.dynamic.kibana.default_tenant)) { + return; + } + + Set availableTenants = getAllConfiguredTenantNames(); + + if(!availableTenants.contains(updatedConfig.dynamic.kibana.default_tenant)){ + throw new IllegalArgumentException(updatedConfig.dynamic.kibana.default_tenant + " can not be set to default tenant. Default tenant should be selected from one of the available tenants."); + } + + } + + @Override + protected void doExecute(final Task task, final TenancyConfigUpdateRequest request, final ActionListener listener) { + + // Get the current security config and prepare the config with the updated value + final SecurityDynamicConfiguration dynamicConfig = load(); + final ConfigV7 config = (ConfigV7)dynamicConfig.getCEntry("config"); + + final TenancyConfigs tenancyConfigs = request.getTenancyConfigs(); + if(tenancyConfigs.multitenancy_enabled != null) + { + config.dynamic.kibana.multitenancy_enabled = tenancyConfigs.multitenancy_enabled; + } + + if(tenancyConfigs.private_tenant_enabled != null) + { + config.dynamic.kibana.private_tenant_enabled = tenancyConfigs.private_tenant_enabled; + } + + if(tenancyConfigs.default_tenant != null) + { + config.dynamic.kibana.default_tenant = tenancyConfigs.default_tenant; + } + + validate(config); + + dynamicConfig.putCEntry("config", config); + + // When performing an update to the configuration run as admin + try (final ThreadContext.StoredContext stashedContext = pool.getThreadContext().stashContext()) { + // Update the security configuration and make sure the cluster has fully refreshed + AbstractApiAction.saveAndUpdateConfigs(this.securityIndex, this.client, CType.CONFIG, dynamicConfig, new ActionListener(){ + + @Override + public void onResponse(final IndexResponse response) { + // After processing the request, restore the user context + stashedContext.close(); + try { + // Lookup the current value and notify the listener + client.execute(TenancyConfigRetrieveActions.INSTANCE, new EmptyRequest(), listener); + } catch (IOException ioe) { + log.error(ioe); + listener.onFailure(ioe); + } + } + + @Override + public void onFailure(Exception e) { + log.error(e); + listener.onFailure(e); + } + }); + } + } +} diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigs.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigs.java new file mode 100644 index 0000000000..4e8fc41ef4 --- /dev/null +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigs.java @@ -0,0 +1,18 @@ +/* + * 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.action.tenancy; + +public class TenancyConfigs { + public Boolean multitenancy_enabled; + public Boolean private_tenant_enabled; + public String default_tenant; +} diff --git a/src/main/java/org/opensearch/security/configuration/PrivilegesInterceptorImpl.java b/src/main/java/org/opensearch/security/configuration/PrivilegesInterceptorImpl.java index 262aadf424..e2f10dfcae 100644 --- a/src/main/java/org/opensearch/security/configuration/PrivilegesInterceptorImpl.java +++ b/src/main/java/org/opensearch/security/configuration/PrivilegesInterceptorImpl.java @@ -108,6 +108,13 @@ public ReplaceResult replaceDashboardsIndex(final ActionRequest request, final S final String dashboardsIndexName = config.getDashboardsIndexname();//config.dynamic.kibana.index; String requestedTenant = user.getRequestedTenant(); + if(USER_TENANT.equals(requestedTenant)) { + final boolean private_tenant_enabled = config.isDashboardsPrivateTenantEnabled(); + if(!private_tenant_enabled) { + return ACCESS_DENIED_REPLACE_RESULT; + } + } + final boolean isDebugEnabled = log.isDebugEnabled(); if (isDebugEnabled) { log.debug("raw requestedTenant: '" + requestedTenant + "'"); diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java index fa69be0ad4..a73b174ee2 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java @@ -75,7 +75,7 @@ public abstract class AbstractApiAction extends BaseRestHandler { protected final ConfigurationRepository cl; protected final ClusterService cs; final ThreadPool threadPool; - protected String opendistroIndex; + protected String securityIndexName; private final RestApiPrivilegesEvaluator restApiPrivilegesEvaluator; protected final RestApiAdminPrivilegesEvaluator restApiAdminPrivilegesEvaluator; protected final AuditLog auditLog; @@ -87,7 +87,7 @@ protected AbstractApiAction(final Settings settings, final Path configPath, fina ThreadPool threadPool, AuditLog auditLog) { super(); this.settings = settings; - this.opendistroIndex = settings.get(ConfigConstants.SECURITY_CONFIG_INDEX_NAME, + this.securityIndexName = settings.get(ConfigConstants.SECURITY_CONFIG_INDEX_NAME, ConfigConstants.OPENDISTRO_SECURITY_DEFAULT_CONFIG_INDEX); this.cl = cl; @@ -157,7 +157,7 @@ protected void handleDelete(final RestChannel channel, final RestRequest request existingConfiguration.remove(name); if (existed) { - saveAnUpdateConfigs(client, request, getConfigName(), existingConfiguration, new OnSucessActionListener(channel) { + AbstractApiAction.saveAndUpdateConfigs(this.securityIndexName, client, getConfigName(), existingConfiguration, new OnSucessActionListener(channel) { @Override public void onResponse(IndexResponse response) { @@ -207,7 +207,7 @@ protected void handlePut(final RestChannel channel, final RestRequest request, f } existingConfiguration.putCObject(name, newContent); - saveAnUpdateConfigs(client, request, getConfigName(), existingConfiguration, new OnSucessActionListener(channel) { + AbstractApiAction.saveAndUpdateConfigs(this.securityIndexName, client, getConfigName(), existingConfiguration, new OnSucessActionListener(channel) { @Override public void onResponse(IndexResponse response) { @@ -270,7 +270,7 @@ protected final SecurityDynamicConfiguration load(final CType config, boolean } protected boolean ensureIndexExists() { - if (!cs.state().metadata().hasConcreteIndex(this.opendistroIndex)) { + if (!cs.state().metadata().hasConcreteIndex(this.securityIndexName)) { return false; } return true; @@ -313,11 +313,8 @@ public final void onFailure(Exception e) { } - protected void saveAnUpdateConfigs(final Client client, final RestRequest request, final CType cType, - final SecurityDynamicConfiguration configuration, OnSucessActionListener actionListener) { - final IndexRequest ir = new IndexRequest(this.opendistroIndex); - - //final String type = "_doc"; + public static void saveAndUpdateConfigs(final String indexName, final Client client, final CType cType, final SecurityDynamicConfiguration configuration, final ActionListener actionListener) { + final IndexRequest ir = new IndexRequest(indexName); final String id = cType.toLCString(); configuration.removeStatic(); @@ -485,6 +482,7 @@ protected void successResponse(RestChannel channel) { try { final XContentBuilder builder = channel.newBuilder(); builder.startObject(); + builder.endObject(); channel.sendResponse( new BytesRestResponse(RestStatus.OK, builder)); } catch (IOException e) { diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AccountApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AccountApiAction.java index 885a5476af..5e4799d655 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AccountApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AccountApiAction.java @@ -224,7 +224,7 @@ protected void handlePut(RestChannel channel, final RestRequest request, final C internalUserEntry.setHash(hash); - saveAnUpdateConfigs(client, request, CType.INTERNALUSERS, internalUser, new OnSucessActionListener(channel) { + AccountApiAction.saveAndUpdateConfigs(this.securityIndexName, client, CType.INTERNALUSERS, internalUser, new OnSucessActionListener(channel) { @Override public void onResponse(IndexResponse response) { successResponse(channel, "'" + username + "' updated."); diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AllowlistApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AllowlistApiAction.java index b37375a461..cefaeb5c6c 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AllowlistApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AllowlistApiAction.java @@ -141,7 +141,7 @@ protected void handlePut(final RestChannel channel, final RestRequest request, f boolean existed = existingConfiguration.exists(name); existingConfiguration.putCObject(name, DefaultObjectMapper.readTree(content, existingConfiguration.getImplementingClass())); - saveAnUpdateConfigs(client, request, getConfigName(), existingConfiguration, new OnSucessActionListener(channel) { + saveAndUpdateConfigs(this.securityIndexName,client, getConfigName(), existingConfiguration, new OnSucessActionListener(channel) { @Override public void onResponse(IndexResponse response) { diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java index 417465e353..646e1f81d6 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java @@ -172,7 +172,7 @@ protected void handlePut(RestChannel channel, final RestRequest request, final C // checks complete, create or update the user internalUsersConfiguration.putCObject(username, DefaultObjectMapper.readTree(contentAsNode, internalUsersConfiguration.getImplementingClass())); - saveAnUpdateConfigs(client, request, CType.INTERNALUSERS, internalUsersConfiguration, new OnSucessActionListener(channel) { + saveAndUpdateConfigs(this.securityIndexName,client, CType.INTERNALUSERS, internalUsersConfiguration, new OnSucessActionListener(channel) { @Override public void onResponse(IndexResponse response) { diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/MigrateApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/MigrateApiAction.java index 1a1092e2fb..d252515f72 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/MigrateApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/MigrateApiAction.java @@ -140,8 +140,8 @@ protected void handlePost(RestChannel channel, RestRequest request, Client clien final SecurityDynamicConfiguration auditConfigV7 = Migration.migrateAudit(auditConfigV6); builder.add(auditConfigV7); - final int replicas = cs.state().metadata().index(opendistroIndex).getNumberOfReplicas(); - final String autoExpandReplicas = cs.state().metadata().index(opendistroIndex).getSettings().get(IndexMetadata.SETTING_AUTO_EXPAND_REPLICAS); + final int replicas = cs.state().metadata().index(securityIndexName).getNumberOfReplicas(); + final String autoExpandReplicas = cs.state().metadata().index(securityIndexName).getSettings().get(IndexMetadata.SETTING_AUTO_EXPAND_REPLICAS); final Builder securityIndexSettings = Settings.builder(); @@ -153,7 +153,7 @@ protected void handlePost(RestChannel channel, RestRequest request, Client clien securityIndexSettings.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1); - client.admin().indices().prepareDelete(this.opendistroIndex).execute(new ActionListener() { + client.admin().indices().prepareDelete(this.securityIndexName).execute(new ActionListener() { @Override public void onResponse(AcknowledgedResponse response) { @@ -161,14 +161,14 @@ public void onResponse(AcknowledgedResponse response) { if (response.isAcknowledged()) { log.debug("opendistro_security index deleted successfully"); - client.admin().indices().prepareCreate(opendistroIndex).setSettings(securityIndexSettings) + client.admin().indices().prepareCreate(securityIndexName).setSettings(securityIndexSettings) .execute(new ActionListener() { @Override public void onResponse(CreateIndexResponse response) { final List> dynamicConfigurations = builder.build(); final ImmutableList.Builder cTypes = ImmutableList.builderWithExpectedSize(dynamicConfigurations.size()); - final BulkRequestBuilder br = client.prepareBulk(opendistroIndex); + final BulkRequestBuilder br = client.prepareBulk(securityIndexName); br.setRefreshPolicy(RefreshPolicy.IMMEDIATE); try { for (SecurityDynamicConfiguration dynamicConfiguration : dynamicConfigurations) { diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/PatchableResourceApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/PatchableResourceApiAction.java index 6d644c1eae..deb56a69c7 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/PatchableResourceApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/PatchableResourceApiAction.java @@ -162,7 +162,7 @@ private void handleSinglePatch(RestChannel channel, RestRequest request, Client } } - saveAnUpdateConfigs(client, request, getConfigName(), mdc, new OnSucessActionListener(channel){ + saveAndUpdateConfigs(this.securityIndexName,client, getConfigName(), mdc, new OnSucessActionListener(channel){ @Override public void onResponse(IndexResponse response) { @@ -244,7 +244,7 @@ private void handleBulkPatch(RestChannel channel, RestRequest request, Client cl } } - saveAnUpdateConfigs(client, request, getConfigName(), mdc, new OnSucessActionListener(channel) { + saveAndUpdateConfigs(this.securityIndexName,client, getConfigName(), mdc, new OnSucessActionListener(channel) { @Override public void onResponse(IndexResponse response) { diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/RolesMappingApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/RolesMappingApiAction.java index b056a25ad2..72928cd0ad 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/RolesMappingApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/RolesMappingApiAction.java @@ -82,7 +82,7 @@ protected void handlePut(RestChannel channel, final RestRequest request, final C } rolesMappingConfiguration.putCObject(name, DefaultObjectMapper.readTree(content, rolesMappingConfiguration.getImplementingClass())); - saveAnUpdateConfigs(client, request, getConfigName(), rolesMappingConfiguration, new OnSucessActionListener(channel) { + saveAndUpdateConfigs(this.securityIndexName,client, getConfigName(), rolesMappingConfiguration, new OnSucessActionListener(channel) { @Override public void onResponse(IndexResponse response) { diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java index cceaeb4cb0..2c0e7ac7c0 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java @@ -525,6 +525,15 @@ public boolean multitenancyEnabled() { && dcm.isDashboardsMultitenancyEnabled(); } + public boolean privateTenantEnabled() { + return privilegesInterceptor.getClass() != PrivilegesInterceptor.class + && dcm.isDashboardsPrivateTenantEnabled(); + } + + public String dashboardsDefaultTenant() { + return dcm.getDashboardsDefaultTenant(); + } + public boolean notFailOnForbiddenEnabled() { return privilegesInterceptor.getClass() != PrivilegesInterceptor.class && dcm.isDnfofEnabled(); diff --git a/src/main/java/org/opensearch/security/rest/DashboardsInfoAction.java b/src/main/java/org/opensearch/security/rest/DashboardsInfoAction.java index aa714ebcbb..0fd88e7565 100644 --- a/src/main/java/org/opensearch/security/rest/DashboardsInfoAction.java +++ b/src/main/java/org/opensearch/security/rest/DashboardsInfoAction.java @@ -103,6 +103,9 @@ public void accept(RestChannel channel) throws Exception { builder.field("opensearch_dashboards_mt_enabled", evaluator.multitenancyEnabled()); builder.field("opensearch_dashboards_index", evaluator.dashboardsIndex()); builder.field("opensearch_dashboards_server_user", evaluator.dashboardsServerUsername()); + builder.field("multitenancy_enabled", evaluator.multitenancyEnabled()); + builder.field("private_tenant_enabled", evaluator.privateTenantEnabled()); + builder.field("default_tenant", evaluator.dashboardsDefaultTenant()); builder.endObject(); response = new BytesRestResponse(RestStatus.OK, builder); diff --git a/src/main/java/org/opensearch/security/securityconf/DynamicConfigModel.java b/src/main/java/org/opensearch/security/securityconf/DynamicConfigModel.java index 2c22da4f34..0033b3bf5f 100644 --- a/src/main/java/org/opensearch/security/securityconf/DynamicConfigModel.java +++ b/src/main/java/org/opensearch/security/securityconf/DynamicConfigModel.java @@ -69,6 +69,8 @@ public abstract class DynamicConfigModel { public abstract String getDashboardsOpenSearchRole(); public abstract String getDashboardsIndexname(); public abstract boolean isDashboardsMultitenancyEnabled(); + public abstract boolean isDashboardsPrivateTenantEnabled(); + public abstract String getDashboardsDefaultTenant(); public abstract boolean isDnfofEnabled(); public abstract boolean isMultiRolespanEnabled(); public abstract String getFilteredAliasMode(); diff --git a/src/main/java/org/opensearch/security/securityconf/DynamicConfigModelV6.java b/src/main/java/org/opensearch/security/securityconf/DynamicConfigModelV6.java index e962326797..515ad6dcac 100644 --- a/src/main/java/org/opensearch/security/securityconf/DynamicConfigModelV6.java +++ b/src/main/java/org/opensearch/security/securityconf/DynamicConfigModelV6.java @@ -141,6 +141,12 @@ public boolean isDashboardsMultitenancyEnabled() { return config.dynamic.kibana.multitenancy_enabled; } @Override + public boolean isDashboardsPrivateTenantEnabled() { + return config.dynamic.kibana.private_tenant_enabled; + } + @Override + public String getDashboardsDefaultTenant() { return config.dynamic.kibana.default_tenant; } + @Override public boolean isDnfofEnabled() { return config.dynamic.do_not_fail_on_forbidden || config.dynamic.kibana.do_not_fail_on_forbidden; } diff --git a/src/main/java/org/opensearch/security/securityconf/DynamicConfigModelV7.java b/src/main/java/org/opensearch/security/securityconf/DynamicConfigModelV7.java index e33b756e2b..fa914677a7 100644 --- a/src/main/java/org/opensearch/security/securityconf/DynamicConfigModelV7.java +++ b/src/main/java/org/opensearch/security/securityconf/DynamicConfigModelV7.java @@ -141,6 +141,12 @@ public boolean isDashboardsMultitenancyEnabled() { return config.dynamic.kibana.multitenancy_enabled; } @Override + public boolean isDashboardsPrivateTenantEnabled() { + return config.dynamic.kibana.private_tenant_enabled; + } + @Override + public String getDashboardsDefaultTenant() { return config.dynamic.kibana.default_tenant; } + @Override public boolean isDnfofEnabled() { return config.dynamic.do_not_fail_on_forbidden; } diff --git a/src/main/java/org/opensearch/security/securityconf/impl/v6/ConfigV6.java b/src/main/java/org/opensearch/security/securityconf/impl/v6/ConfigV6.java index f99ab3ac81..99d83d0679 100644 --- a/src/main/java/org/opensearch/security/securityconf/impl/v6/ConfigV6.java +++ b/src/main/java/org/opensearch/security/securityconf/impl/v6/ConfigV6.java @@ -85,6 +85,10 @@ public static class Kibana { @JsonInclude(JsonInclude.Include.NON_NULL) public boolean multitenancy_enabled = true; + @JsonInclude(JsonInclude.Include.NON_NULL) + public boolean private_tenant_enabled = true; + @JsonInclude(JsonInclude.Include.NON_NULL) + public String default_tenant = ""; public String server_username = "kibanaserver"; public String opendistro_role = null; public String index = ".kibana"; diff --git a/src/main/java/org/opensearch/security/securityconf/impl/v7/ConfigV7.java b/src/main/java/org/opensearch/security/securityconf/impl/v7/ConfigV7.java index 1a9a07e53e..e8ecd6bd97 100644 --- a/src/main/java/org/opensearch/security/securityconf/impl/v7/ConfigV7.java +++ b/src/main/java/org/opensearch/security/securityconf/impl/v7/ConfigV7.java @@ -70,6 +70,8 @@ public ConfigV7(ConfigV6 c6) { dynamic.kibana.index = c6.dynamic.kibana.index; dynamic.kibana.multitenancy_enabled = c6.dynamic.kibana.multitenancy_enabled; + dynamic.kibana.private_tenant_enabled = true; + dynamic.kibana.default_tenant = ""; dynamic.kibana.server_username = c6.dynamic.kibana.server_username; dynamic.http = new Http(); @@ -137,12 +139,18 @@ public static class Kibana { @JsonInclude(JsonInclude.Include.NON_NULL) public boolean multitenancy_enabled = true; + @JsonInclude(JsonInclude.Include.NON_NULL) + public boolean private_tenant_enabled = true; + @JsonInclude(JsonInclude.Include.NON_NULL) + public String default_tenant = ""; public String server_username = "kibanaserver"; public String opendistro_role = null; public String index = ".kibana"; @Override public String toString() { - return "Kibana [multitenancy_enabled=" + multitenancy_enabled + ", server_username=" + server_username + ", opendistro_role=" + opendistro_role + return "Kibana [multitenancy_enabled=" + multitenancy_enabled + ", private_tenant_enabled=" + + private_tenant_enabled + ", default_tenant=" + default_tenant + ", server_username=" + + server_username + ", opendistro_role=" + opendistro_role + ", index=" + index + "]"; } diff --git a/src/main/java/org/opensearch/security/support/ConfigConstants.java b/src/main/java/org/opensearch/security/support/ConfigConstants.java index 375b22b65f..f81d89810b 100644 --- a/src/main/java/org/opensearch/security/support/ConfigConstants.java +++ b/src/main/java/org/opensearch/security/support/ConfigConstants.java @@ -287,6 +287,10 @@ public enum RolesMappingResolution { public static final String SECURITY_SYSTEM_INDICES_KEY = "plugins.security.system_indices.indices"; public static final List SECURITY_SYSTEM_INDICES_DEFAULT = Collections.emptyList(); + public static final String TENANCY_PRIVATE_TENANT_NAME = "Private"; + public static final String TENANCY_GLOBAL_TENANT_NAME = "Global"; + public static final String TENANCY_GLOBAL_TENANT_DEFAULT_NAME = ""; + public static Set getSettingAsSet(final Settings settings, final String key, final List defaultList, final boolean ignoreCaseForNone) { final List list = settings.getAsList(key, defaultList); if (list.size() == 1 && "NONE".equals(ignoreCaseForNone? list.get(0).toUpperCase() : list.get(0))) { diff --git a/src/test/java/org/opensearch/security/multitenancy/test/TenancyDefaultTenantTests.java b/src/test/java/org/opensearch/security/multitenancy/test/TenancyDefaultTenantTests.java new file mode 100644 index 0000000000..b4d6aa4b59 --- /dev/null +++ b/src/test/java/org/opensearch/security/multitenancy/test/TenancyDefaultTenantTests.java @@ -0,0 +1,96 @@ +/* + * 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.multitenancy.test; + +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpStatus; +import org.junit.Test; + +import org.opensearch.security.support.ConfigConstants; +import org.opensearch.security.test.SingleClusterTest; +import org.opensearch.security.test.helper.rest.RestHelper.HttpResponse; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.StringContains.containsString; + +public class TenancyDefaultTenantTests extends SingleClusterTest { + private final Header asAdminUser = encodeBasicHeader("admin", "admin"); + private final Header asUser = encodeBasicHeader("kirk", "kirk"); + + @Override + protected String getResourceFolder() { + return "multitenancy"; + } + + @Test + public void testDefaultTenantUpdate() throws Exception { + setup(); + + final HttpResponse getSettingResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/api/tenancy/config", asAdminUser); + assertThat(getSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(getSettingResponse.findValueInJson("default_tenant"), equalTo(ConfigConstants.TENANCY_GLOBAL_TENANT_DEFAULT_NAME)); + + HttpResponse getDashboardsinfoResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/dashboardsinfo", asAdminUser); + assertThat(getDashboardsinfoResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(getDashboardsinfoResponse.findValueInJson("default_tenant"), equalTo(ConfigConstants.TENANCY_GLOBAL_TENANT_DEFAULT_NAME)); + + final HttpResponse setPrivateTenantAsDefaultResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"default_tenant\": \"Private\"}", asAdminUser); + assertThat(setPrivateTenantAsDefaultResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + getDashboardsinfoResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/dashboardsinfo", asAdminUser); + assertThat(getDashboardsinfoResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(getDashboardsinfoResponse.findValueInJson("default_tenant"), equalTo(ConfigConstants.TENANCY_PRIVATE_TENANT_NAME)); + } + + @Test + public void testDefaultTenant_UpdateFailed() throws Exception { + setup(); + + final HttpResponse disablePrivateTenantResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"private_tenant_enabled\":false}", asAdminUser); + assertThat(disablePrivateTenantResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + + + final HttpResponse setPrivateTenantAsDefaultFailResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"default_tenant\": \"Private\"}", asAdminUser); + assertThat(setPrivateTenantAsDefaultFailResponse.getStatusCode(), equalTo(HttpStatus.SC_BAD_REQUEST)); + assertThat(setPrivateTenantAsDefaultFailResponse.findValueInJson("error.reason"), containsString("Private tenant can not be disabled if it is the default tenant.")); + + final HttpResponse enablePrivateTenantResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"private_tenant_enabled\":true}", asAdminUser); + assertThat(enablePrivateTenantResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + + final HttpResponse setPrivateTenantAsDefaultResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"default_tenant\": \"Private\"}", asAdminUser); + assertThat(setPrivateTenantAsDefaultResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + + final HttpResponse getSettingResponseAfterUpdate = nonSslRestHelper().executeGetRequest("/_plugins/_security/api/tenancy/config", asAdminUser); + assertThat(getSettingResponseAfterUpdate.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(getSettingResponseAfterUpdate.findValueInJson("default_tenant"), equalTo(ConfigConstants.TENANCY_PRIVATE_TENANT_NAME)); + + HttpResponse getDashboardsinfoResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/dashboardsinfo", asAdminUser); + assertThat(getDashboardsinfoResponse.findValueInJson("default_tenant"),equalTo(ConfigConstants.TENANCY_PRIVATE_TENANT_NAME)); + + final HttpResponse setRandomStringAsDefaultTenant = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"default_tenant\": \"NonExistentTenant\"}", asAdminUser); + assertThat(setRandomStringAsDefaultTenant.getStatusCode(), equalTo(HttpStatus.SC_BAD_REQUEST)); + assertThat(setRandomStringAsDefaultTenant.findValueInJson("error.reason"), containsString("Default tenant should be selected from one of the available tenants.")); + + } + @Test + public void testForbiddenAccess() throws Exception { + setup(); + + final HttpResponse getSettingResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/api/tenancy/config", asUser); + assertThat(getSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_FORBIDDEN)); + assertThat(getSettingResponse.findValueInJson("error.reason"), containsString("no permissions for [cluster:feature/tenancy/config/read]")); + + final HttpResponse updateSettingResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"default_tenant\": \"Private\"}", asUser); + assertThat(updateSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_FORBIDDEN)); + assertThat(updateSettingResponse.findValueInJson("error.reason"), containsString("no permissions for [cluster:feature/tenancy/config/update]")); + } +} diff --git a/src/test/java/org/opensearch/security/multitenancy/test/TenancyMultitenancyEnabledTests.java b/src/test/java/org/opensearch/security/multitenancy/test/TenancyMultitenancyEnabledTests.java new file mode 100644 index 0000000000..033d38ed41 --- /dev/null +++ b/src/test/java/org/opensearch/security/multitenancy/test/TenancyMultitenancyEnabledTests.java @@ -0,0 +1,89 @@ +/* + * 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.multitenancy.test; + +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.message.BasicHeader; +import org.junit.Test; + +import org.opensearch.security.test.SingleClusterTest; +import org.opensearch.security.test.helper.rest.RestHelper.HttpResponse; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.StringContains.containsString; + +public class TenancyMultitenancyEnabledTests extends SingleClusterTest { + private final Header asAdminUser = encodeBasicHeader("admin", "admin"); + private final Header asUser = encodeBasicHeader("kirk", "kirk"); + private final Header onUserTenant = new BasicHeader("securitytenant", "__user__"); + + private static String createIndexPatternDoc(final String title) { + return "{"+ + "\"type\" : \"index-pattern\","+ + "\"updated_at\" : \"2018-09-29T08:56:59.066Z\","+ + "\"index-pattern\" : {"+ + "\"title\" : \"" + title + "\""+ + "}}"; + } + + @Override + protected String getResourceFolder() { + return "multitenancy"; + } + + @Test + public void testMultitenancyDisabled_endToEndTest() throws Exception { + setup(); + + final HttpResponse getSettingResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/api/tenancy/config", asAdminUser); + assertThat(getSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(getSettingResponse.findValueInJson("multitenancy_enabled"), equalTo("true")); + + HttpResponse getDashboardsinfoResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/dashboardsinfo", asAdminUser); + assertThat(getDashboardsinfoResponse.findValueInJson("multitenancy_enabled"),equalTo("true")); + + final HttpResponse createDocInGlobalTenantResponse = nonSslRestHelper().executePostRequest(".kibana/_doc?refresh=true", createIndexPatternDoc("globalIndex"), asAdminUser); + assertThat(createDocInGlobalTenantResponse.getStatusCode(), equalTo(HttpStatus.SC_CREATED)); + final HttpResponse createDocInUserTenantResponse = nonSslRestHelper().executePostRequest(".kibana/_doc?refresh=true", createIndexPatternDoc("userIndex"), onUserTenant, asAdminUser); + assertThat(createDocInUserTenantResponse.getStatusCode(), equalTo(HttpStatus.SC_CREATED)); + + final HttpResponse searchInUserTenantWithMutlitenancyEnabled = nonSslRestHelper().executeGetRequest(".kibana/_search", onUserTenant, asAdminUser); + assertThat(searchInUserTenantWithMutlitenancyEnabled.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(searchInUserTenantWithMutlitenancyEnabled.findValueInJson("hits.hits[0]._source.index-pattern.title"), equalTo("userIndex")); + + final HttpResponse updateMutlitenancyToDisabled = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"multitenancy_enabled\": \"false\"}", asAdminUser); + assertThat(updateMutlitenancyToDisabled.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(updateMutlitenancyToDisabled.findValueInJson("multitenancy_enabled"), equalTo("false")); + + getDashboardsinfoResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/dashboardsinfo", asAdminUser); + assertThat(getDashboardsinfoResponse.findValueInJson("multitenancy_enabled"),equalTo("false")); + + final HttpResponse searchInUserTenantWithMutlitenancyDisabled = nonSslRestHelper().executeGetRequest(".kibana/_search", onUserTenant, asAdminUser); + assertThat(searchInUserTenantWithMutlitenancyDisabled.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(searchInUserTenantWithMutlitenancyDisabled.findValueInJson("hits.hits[0]._source.index-pattern.title"), equalTo("globalIndex")); + } + + @Test + public void testForbiddenAccess() throws Exception { + setup(); + + final HttpResponse getSettingResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/api/tenancy/config", asUser); + assertThat(getSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_FORBIDDEN)); + assertThat(getSettingResponse.findValueInJson("error.reason"), containsString("no permissions for [cluster:feature/tenancy/config/read]")); + + final HttpResponse updateSettingResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"multitenancy_enabled\": \"false\"}", asUser); + assertThat(updateSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_FORBIDDEN)); + assertThat(updateSettingResponse.findValueInJson("error.reason"), containsString("no permissions for [cluster:feature/tenancy/config/update]")); + } +} diff --git a/src/test/java/org/opensearch/security/multitenancy/test/TenancyPrivateTenantEnabledTests.java b/src/test/java/org/opensearch/security/multitenancy/test/TenancyPrivateTenantEnabledTests.java new file mode 100644 index 0000000000..c6927dbbf8 --- /dev/null +++ b/src/test/java/org/opensearch/security/multitenancy/test/TenancyPrivateTenantEnabledTests.java @@ -0,0 +1,101 @@ +/* + * 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.multitenancy.test; + +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.message.BasicHeader; +import org.junit.Test; + +import org.opensearch.security.test.SingleClusterTest; +import org.opensearch.security.test.helper.rest.RestHelper.HttpResponse; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.StringContains.containsString; + +public class TenancyPrivateTenantEnabledTests extends SingleClusterTest { + private final Header asAdminUser = encodeBasicHeader("admin", "admin"); + private final Header asUser = encodeBasicHeader("kirk", "kirk"); + private final Header onUserTenant = new BasicHeader("securitytenant", "__user__"); + + private static String createIndexPatternDoc(final String title) { + return "{"+ + "\"type\" : \"index-pattern\","+ + "\"updated_at\" : \"2018-09-29T08:56:59.066Z\","+ + "\"index-pattern\" : {"+ + "\"title\" : \"" + title + "\""+ + "}}"; + } + + @Override + protected String getResourceFolder() { + return "multitenancy"; + } + + @Test + public void testPrivateTenantDisabled_Update() throws Exception { + setup(); + + final HttpResponse getSettingResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/api/tenancy/config", asAdminUser); + assertThat(getSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(getSettingResponse.findValueInJson("private_tenant_enabled"), equalTo("true")); + + HttpResponse getDashboardsinfoResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/dashboardsinfo", asAdminUser); + assertThat(getDashboardsinfoResponse.findValueInJson("private_tenant_enabled"), equalTo("true")); + + final HttpResponse createDocInGlobalTenantResponse = nonSslRestHelper().executePostRequest(".kibana/_doc?refresh=true", createIndexPatternDoc("globalIndex"), asAdminUser); + assertThat(createDocInGlobalTenantResponse.getStatusCode(), equalTo(HttpStatus.SC_CREATED)); + final HttpResponse createDocInUserTenantResponse = nonSslRestHelper().executePostRequest(".kibana/_doc?refresh=true", createIndexPatternDoc("userIndex"), onUserTenant, asUser); + assertThat(createDocInUserTenantResponse.getStatusCode(), equalTo(HttpStatus.SC_CREATED)); + + final HttpResponse searchInUserTenantWithPrivateTenantEnabled = nonSslRestHelper().executeGetRequest(".kibana/_search", onUserTenant, asUser); + assertThat(searchInUserTenantWithPrivateTenantEnabled.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(searchInUserTenantWithPrivateTenantEnabled.findValueInJson("hits.hits[0]._source.index-pattern.title"), equalTo("userIndex")); + + final HttpResponse disablePrivateTenantResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"private_tenant_enabled\": \"false\"}", asAdminUser); + assertThat(disablePrivateTenantResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(disablePrivateTenantResponse.findValueInJson("private_tenant_enabled"), equalTo("false")); + + getDashboardsinfoResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/dashboardsinfo", asAdminUser); + assertThat(getDashboardsinfoResponse.findValueInJson("private_tenant_enabled"),equalTo("false")); + + final HttpResponse searchInUserTenantWithPrivateTenantDisabled = nonSslRestHelper().executeGetRequest(".kibana/_search", onUserTenant, asUser); + assertThat(searchInUserTenantWithPrivateTenantDisabled.getStatusCode(), equalTo(HttpStatus.SC_FORBIDDEN)); + assertThat(searchInUserTenantWithPrivateTenantDisabled.findValueInJson("error.reason"), containsString("no permissions for [indices:data/read/search] and User")); + + } + + @Test + public void testPrivateTenantDisabled_UpdateFailed() throws Exception { + setup(); + + final HttpResponse setPrivateTenantAsDefaultResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"default_tenant\": \"Private\"}", asAdminUser); + assertThat(setPrivateTenantAsDefaultResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + final HttpResponse updateSettingResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"private_tenant_enabled\":false}", asAdminUser); + assertThat(updateSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_BAD_REQUEST)); + assertThat(updateSettingResponse.findValueInJson("error.reason"), containsString("Private tenant can not be disabled if it is the default tenant.")); + } + + @Test + public void testForbiddenAccess() throws Exception { + setup(); + + final HttpResponse getSettingResponse = nonSslRestHelper().executeGetRequest("/_plugins/_security/api/tenancy/config", asUser); + assertThat(getSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_FORBIDDEN)); + assertThat(getSettingResponse.findValueInJson("error.reason"), containsString("no permissions for [cluster:feature/tenancy/config/read]")); + + final HttpResponse updateSettingResponse = nonSslRestHelper().executePutRequest("/_plugins/_security/api/tenancy/config", "{\"private_tenant_enabled\": false}", asUser); + assertThat(updateSettingResponse.getStatusCode(), equalTo(HttpStatus.SC_FORBIDDEN)); + assertThat(updateSettingResponse.findValueInJson("error.reason"), containsString("no permissions for [cluster:feature/tenancy/config/update]")); + } +} diff --git a/src/test/java/org/opensearch/security/test/helper/rest/RestHelper.java b/src/test/java/org/opensearch/security/test/helper/rest/RestHelper.java index ff9a5b536b..367332f160 100644 --- a/src/test/java/org/opensearch/security/test/helper/rest/RestHelper.java +++ b/src/test/java/org/opensearch/security/test/helper/rest/RestHelper.java @@ -92,8 +92,6 @@ import org.opensearch.security.test.helper.cluster.ClusterInfo; import org.opensearch.security.test.helper.file.FileHelper; -import static org.junit.jupiter.api.Assertions.fail; - public class RestHelper { protected final Logger log = LogManager.getLogger(RestHelper.class); @@ -480,7 +478,7 @@ public String toString() { public String findValueInJson(final String jsonDotPath) { // Make sure its json / then parse it if (!isJsonContentType()) { - fail("Response was expected to be JSON, body was: \n" + body); + throw new RuntimeException("Response was expected to be JSON, body was: \n" + body); } JsonNode currentNode = null; try { @@ -492,7 +490,7 @@ public String findValueInJson(final String jsonDotPath) { // Break the path into parts, and scan into the json object try (final Scanner jsonPathScanner = new Scanner(jsonDotPath).useDelimiter("\\.")) { if (!jsonPathScanner.hasNext()) { - fail("Invalid json dot path '" + jsonDotPath + "', rewrite with '.' characters between path elements."); + throw new RuntimeException("Invalid json dot path '" + jsonDotPath + "', rewrite with '.' characters between path elements."); } do { String pathEntry = jsonPathScanner.next(); @@ -510,23 +508,23 @@ public String findValueInJson(final String jsonDotPath) { } if (!currentNode.has(pathEntry)) { - fail("Unable to resolve '" + jsonDotPath + "', on path entry '" + pathEntry + "' from available fields " + currentNode.toPrettyString()); + throw new RuntimeException("Unable to resolve '" + jsonDotPath + "', on path entry '" + pathEntry + "' from available fields " + currentNode.toPrettyString()); } currentNode = currentNode.get(pathEntry); // if it's an Array lookup we get the requested index item if (arrayEntryIdx > -1) { if(!currentNode.isArray()) { - fail("Unable to resolve '" + jsonDotPath + "', the '" + pathEntry + "' field is not an array " + currentNode.toPrettyString()); + throw new RuntimeException("Unable to resolve '" + jsonDotPath + "', the '" + pathEntry + "' field is not an array " + currentNode.toPrettyString()); } else if (!currentNode.has(arrayEntryIdx)) { - fail("Unable to resolve '" + jsonDotPath + "', index '" + arrayEntryIdx + "' is out of bounds for array '" + pathEntry + "' \n" + currentNode.toPrettyString()); + throw new RuntimeException("Unable to resolve '" + jsonDotPath + "', index '" + arrayEntryIdx + "' is out of bounds for array '" + pathEntry + "' \n" + currentNode.toPrettyString()); } currentNode = currentNode.get(arrayEntryIdx); } } while (jsonPathScanner.hasNext()); if (!currentNode.isValueNode()) { - fail("Unexpected value note, index directly to the object to reference, object\n" + currentNode.toPrettyString()); + throw new RuntimeException("Unexpected value note, index directly to the object to reference, object\n" + currentNode.toPrettyString()); } return currentNode.asText(); } diff --git a/src/test/resources/auditlog/config.yml b/src/test/resources/auditlog/config.yml index 938a38cd38..c1d0c63174 100644 --- a/src/test/resources/auditlog/config.yml +++ b/src/test/resources/auditlog/config.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/cache/config.yml b/src/test/resources/cache/config.yml index 2a48434203..1a5e86fc2f 100644 --- a/src/test/resources/cache/config.yml +++ b/src/test/resources/cache/config.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/composite_config.yml b/src/test/resources/composite_config.yml index f636d823e0..3f6eb78627 100644 --- a/src/test/resources/composite_config.yml +++ b/src/test/resources/composite_config.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config.yml b/src/test/resources/config.yml index a57bb123fb..abdeb86421 100644 --- a/src/test/resources/config.yml +++ b/src/test/resources/config.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_anon.yml b/src/test/resources/config_anon.yml index 7c8a037f25..0c2c5ccbcc 100644 --- a/src/test/resources/config_anon.yml +++ b/src/test/resources/config_anon.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_clientcert.yml b/src/test/resources/config_clientcert.yml index 441f6c9e5f..c50d770c26 100644 --- a/src/test/resources/config_clientcert.yml +++ b/src/test/resources/config_clientcert.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_disable_all.yml b/src/test/resources/config_disable_all.yml index 8f8e414672..fef8297b7f 100644 --- a/src/test/resources/config_disable_all.yml +++ b/src/test/resources/config_disable_all.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_dnfof.yml b/src/test/resources/config_dnfof.yml index 84c71d231a..6e0a2dcd93 100644 --- a/src/test/resources/config_dnfof.yml +++ b/src/test/resources/config_dnfof.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_invalidlic.yml b/src/test/resources/config_invalidlic.yml index 34f4aff093..3663b3c706 100644 --- a/src/test/resources/config_invalidlic.yml +++ b/src/test/resources/config_invalidlic.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_lic.yml b/src/test/resources/config_lic.yml index 34f4aff093..3663b3c706 100644 --- a/src/test/resources/config_lic.yml +++ b/src/test/resources/config_lic.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_lic_rk.yml b/src/test/resources/config_lic_rk.yml index 34f4aff093..3663b3c706 100644 --- a/src/test/resources/config_lic_rk.yml +++ b/src/test/resources/config_lic_rk.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_multirolespan.yml b/src/test/resources/config_multirolespan.yml index dee3d042b1..388cba2903 100644 --- a/src/test/resources/config_multirolespan.yml +++ b/src/test/resources/config_multirolespan.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_protected_indices.yml b/src/test/resources/config_protected_indices.yml index 791656523d..86b01d197c 100644 --- a/src/test/resources/config_protected_indices.yml +++ b/src/test/resources/config_protected_indices.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_proxy.yml b/src/test/resources/config_proxy.yml index 52f5880806..b3151d9748 100644 --- a/src/test/resources/config_proxy.yml +++ b/src/test/resources/config_proxy.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_proxy_custom.yml b/src/test/resources/config_proxy_custom.yml index 78e0aa70f3..cf03610e4b 100644 --- a/src/test/resources/config_proxy_custom.yml +++ b/src/test/resources/config_proxy_custom.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_respect_indices_options.yml b/src/test/resources/config_respect_indices_options.yml index 9508c12b34..86e9e6487b 100644 --- a/src/test/resources/config_respect_indices_options.yml +++ b/src/test/resources/config_respect_indices_options.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_rest_impersonation.yml b/src/test/resources/config_rest_impersonation.yml index 36c1b09cf1..a34232ff77 100644 --- a/src/test/resources/config_rest_impersonation.yml +++ b/src/test/resources/config_rest_impersonation.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_system_indices.yml b/src/test/resources/config_system_indices.yml index 791656523d..86b01d197c 100644 --- a/src/test/resources/config_system_indices.yml +++ b/src/test/resources/config_system_indices.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_transport_username.yml b/src/test/resources/config_transport_username.yml index 0cd5204005..f473a47320 100644 --- a/src/test/resources/config_transport_username.yml +++ b/src/test/resources/config_transport_username.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/config_xff.yml b/src/test/resources/config_xff.yml index 85ceca5e21..ed93efc2b1 100644 --- a/src/test/resources/config_xff.yml +++ b/src/test/resources/config_xff.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/dlsfls/config.yml b/src/test/resources/dlsfls/config.yml index 1288ebeea2..cf110efda5 100644 --- a/src/test/resources/dlsfls/config.yml +++ b/src/test/resources/dlsfls/config.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/ldap/config.yml b/src/test/resources/ldap/config.yml index ea8271c6df..9257fa5b50 100644 --- a/src/test/resources/ldap/config.yml +++ b/src/test/resources/ldap/config.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/ldap/config_ldap2.yml b/src/test/resources/ldap/config_ldap2.yml index 51956d4cfc..a9b477fcec 100644 --- a/src/test/resources/ldap/config_ldap2.yml +++ b/src/test/resources/ldap/config_ldap2.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/multitenancy/config.yml b/src/test/resources/multitenancy/config.yml index 704937b9ee..d1514e9cb2 100644 --- a/src/test/resources/multitenancy/config.yml +++ b/src/test/resources/multitenancy/config.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/multitenancy/config_anonymous.yml b/src/test/resources/multitenancy/config_anonymous.yml index 97a43b20a8..1ae5e145fe 100644 --- a/src/test/resources/multitenancy/config_anonymous.yml +++ b/src/test/resources/multitenancy/config_anonymous.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/multitenancy/config_basic_auth.yml b/src/test/resources/multitenancy/config_basic_auth.yml index 289eb19cd2..f60caab0b7 100644 --- a/src/test/resources/multitenancy/config_basic_auth.yml +++ b/src/test/resources/multitenancy/config_basic_auth.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/multitenancy/config_nodnfof.yml b/src/test/resources/multitenancy/config_nodnfof.yml index 462e3e9e64..f4afce87d4 100644 --- a/src/test/resources/multitenancy/config_nodnfof.yml +++ b/src/test/resources/multitenancy/config_nodnfof.yml @@ -11,6 +11,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/restapi/config.yml b/src/test/resources/restapi/config.yml index 899a17a1fc..2ed865657a 100644 --- a/src/test/resources/restapi/config.yml +++ b/src/test/resources/restapi/config.yml @@ -10,6 +10,8 @@ config: license: null kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: diff --git a/src/test/resources/restapi/invalid_config.json b/src/test/resources/restapi/invalid_config.json index 76ac5e7c0f..7bbbf2201f 100644 --- a/src/test/resources/restapi/invalid_config.json +++ b/src/test/resources/restapi/invalid_config.json @@ -7,6 +7,8 @@ "respect_request_indices_options":false, "kibana":{ "multitenancy_enabled":true, + "private_tenant_enabled" : true, + "default_tenant" : "", "server_username":"kibanaserver", "index":".kibana" }, diff --git a/src/test/resources/restapi/security_config.json b/src/test/resources/restapi/security_config.json index 8a230f283c..e8acc0a22a 100644 --- a/src/test/resources/restapi/security_config.json +++ b/src/test/resources/restapi/security_config.json @@ -7,6 +7,8 @@ "respect_request_indices_options":false, "kibana":{ "multitenancy_enabled":true, + "private_tenant_enabled" : true, + "default_tenant" : "", "server_username":"kibanaserver", "index":".kibana" }, diff --git a/src/test/resources/restapi/securityconfig.json b/src/test/resources/restapi/securityconfig.json index 9e7fb32342..4e4b1bba63 100644 --- a/src/test/resources/restapi/securityconfig.json +++ b/src/test/resources/restapi/securityconfig.json @@ -7,6 +7,8 @@ "respect_request_indices_options":false, "kibana":{ "multitenancy_enabled":true, + "private_tenant_enabled" : true, + "default_tenant" : "", "server_username":"kibanaserver", "index":".kibana" }, diff --git a/src/test/resources/restapi/securityconfig_nondefault.json b/src/test/resources/restapi/securityconfig_nondefault.json index c9e6aaec5e..6fb297be37 100644 --- a/src/test/resources/restapi/securityconfig_nondefault.json +++ b/src/test/resources/restapi/securityconfig_nondefault.json @@ -6,6 +6,8 @@ "respect_request_indices_options" : false, "kibana" : { "multitenancy_enabled" : true, + "private_tenant_enabled" : true, + "default_tenant" : "", "server_username" : "kibanaserver", "index" : ".kibana" }, diff --git a/src/test/resources/security_passive/config.yml b/src/test/resources/security_passive/config.yml index 34f4aff093..3663b3c706 100644 --- a/src/test/resources/security_passive/config.yml +++ b/src/test/resources/security_passive/config.yml @@ -10,6 +10,8 @@ config: respect_request_indices_options: false kibana: multitenancy_enabled: true + private_tenant_enabled: true + default_tenant: "" server_username: "kibanaserver" index: ".kibana" http: