Skip to content

Commit

Permalink
Remove multitenancy (Apicurio#3679)
Browse files Browse the repository at this point in the history
* Remove multitenancy ui checks

* Remove tenant id from sql storage

* Remove multitenancy from sql storage

* Remove multitenancy from kafkasql

* Fix sql statements

* Remove upgrade tests

* Remove kafka sql upgrader

* Simplify auto update version query
  • Loading branch information
carlesarnal authored Oct 3, 2023
1 parent ba4b384 commit 7cecfa9
Show file tree
Hide file tree
Showing 166 changed files with 1,091 additions and 7,356 deletions.
10 changes: 0 additions & 10 deletions .github/workflows/integration-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,6 @@ jobs:
- name: Run Integration Tests - sql - migration
run: make REGISTRY_IMAGE='-Dregistry-sql-image=ttl.sh/${{ github.sha }}/apicurio/apicurio-registry-sql:1d' run-sql-migration-integration-tests

- name: Run Integration Tests - sql - db upgrade
run: make REGISTRY_IMAGE='-Dregistry-sql-image=ttl.sh/${{ github.sha }}/apicurio/apicurio-registry-sql:1d' run-sql-upgrade-tests

- name: Run Integration Tests - sql - multitenancy
run: make REGISTRY_IMAGE='-Dregistry-sql-image=ttl.sh/${{ github.sha }}/apicurio/apicurio-registry-sql:1d' run-sql-multitenancy-integration-tests


- name: Collect logs
if: failure()
run: ./.github/scripts/collect_logs.sh
Expand Down Expand Up @@ -164,9 +157,6 @@ jobs:
- name: Run Integration Tests - KafkaSql - Migration
run: make REGISTRY_IMAGE='-Dregistry-kafkasql-image=ttl.sh/${{ github.sha }}/apicurio/apicurio-registry-kafkasql:1d' run-kafkasql-migration-integration-tests

- name: Run Integration Tests - KafkaSql - DBUpgrade
run: make REGISTRY_IMAGE='-Dregistry-kafkasql-image=ttl.sh/${{ github.sha }}/apicurio/apicurio-registry-kafkasql:1d' run-kafkasql-upgrade-tests

- name: Run Integration Tests - KafkaSql - Auth
run: make REGISTRY_IMAGE='-Dregistry-kafkasql-image=ttl.sh/${{ github.sha }}/apicurio/apicurio-registry-kafkasql:1d' run-kafkasql-auth-tests

Expand Down
3 changes: 0 additions & 3 deletions .github/workflows/registry-rhbq-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,6 @@ jobs:
- name: Set test profile to all
run: echo "test_profile=all" >> $GITHUB_ENV

- name: Prepare Tenant Manager
run: make build-integration-tests-multitenancy

- name: Build integration-tests-common
if: github.event.inputs.skip-tests == 'false'
run: cd registry && ./mvnw install -Pintegration-tests -pl integration-tests/integration-tests-common
Expand Down
3 changes: 0 additions & 3 deletions .github/workflows/verify.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -446,9 +446,6 @@ jobs:
- name: Run Integration Tests - sql migration
run: make REGISTRY_IMAGE='-Dregistry-sql-image=ttl.sh/${{ github.sha }}/apicurio/apicurio-registry-sql-native:1d' run-sql-migration-integration-tests

- name: Run Integration Tests - sql multitenancy
run: make REGISTRY_IMAGE='-Dregistry-sql-image=ttl.sh/${{ github.sha }}/apicurio/apicurio-registry-sql-native:1d' run-sql-multitenancy-integration-tests

- name: Collect logs
if: failure()
run: ./.github/scripts/collect_logs.sh
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ website
**/bin

apicurio-codegen
/multitenancy/
/docs/.jbang/

python-sdk/dist
Expand Down
40 changes: 1 addition & 39 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -364,23 +364,6 @@ mem-native-scratch-image:
.PHONY: multiarch-registry-images ## Builds and pushes multi-arch registry images for all variants. Variables available for override [IMAGE_REPO, IMAGE_TAG]
multiarch-registry-images: mem-multiarch-images sql-multiarch-images mssql-multiarch-images kafkasql-multiarch-images mem-native-scratch-image gitops-multiarch-images


.PHONY: pr-check ## Builds and runs basic tests for multitenant registry pipelines
pr-check:
CURRENT_ENV=mas mvn clean install -Pno-docker -Dskip.npm -Pprod -Psql -am -pl storage/sql \
-Dmaven.javadoc.skip=true --no-transfer-progress -DtrimStackTrace=false
./scripts/clean-postgres.sh
CURRENT_ENV=mas NO_DOCKER=true mvn verify -Pintegration-tests -Psql -am -pl integration-tests \
-Dmaven.javadoc.skip=true --no-transfer-progress -DtrimStackTrace=false

.PHONY: build-project ## Builds the components for multitenant registry pipelines
build-project:
# run unit tests for app module
CURRENT_ENV=mas mvn clean install -Pno-docker -Dskip.npm -Pprod -Psql -am -pl app -Dmaven.javadoc.skip=true --no-transfer-progress -DtrimStackTrace=false
# build everything without running tests in order to be able to build container images
CURRENT_ENV=mas mvn clean install -Pprod -Pno-docker -Dskip.npm -Psql -Dmaven.javadoc.skip=true --no-transfer-progress -DtrimStackTrace=false -DskipTests


.PHONY: run-ui-tests ## Runs ui e2e tests
run-ui-tests:
@echo "----------------------------------------------------------------------"
Expand Down Expand Up @@ -420,13 +403,6 @@ run-sql-integration-tests:
@echo "----------------------------------------------------------------------"
./mvnw verify -am --no-transfer-progress -Pintegration-tests -P$(INTEGRATION_TESTS_PROFILE) $(REGISTRY_IMAGE) -Premote-sql -pl integration-tests -Dmaven.javadoc.skip=true --no-transfer-progress

.PHONY: run-sql-upgrade-tests ## Runs sql e2e tests
run-sql-upgrade-tests:
@echo "----------------------------------------------------------------------"
@echo " Running Sql Integration Tests "
@echo "----------------------------------------------------------------------"
./mvnw verify -am --no-transfer-progress -Pintegration-tests -Psqlit $(REGISTRY_IMAGE) -Premote-sql -pl integration-tests -Dmaven.javadoc.skip=true --no-transfer-progress

.PHONY: run-sql-auth-tests ## Runs sql auth integration tests
run-sql-auth-tests:
@echo "----------------------------------------------------------------------"
Expand All @@ -441,14 +417,6 @@ run-sql-migration-integration-tests:
@echo "----------------------------------------------------------------------"
./mvnw verify -am --no-transfer-progress -Pintegration-tests -Pmigration -Premote-sql -pl integration-tests -Dmaven.javadoc.skip=true --no-transfer-progress

.PHONY: run-sql-multitenancy-integration-tests ## Runs multitenancy integration tests
run-sql-multitenancy-integration-tests:
@echo "----------------------------------------------------------------------"
@echo " Running Multitenancy Integration Tests "
@echo "----------------------------------------------------------------------"
./mvnw verify -am --no-transfer-progress -Pintegration-tests -Pmultitenancy -Premote-sql -pl integration-tests -Dmaven.javadoc.skip=true --no-transfer-progress -DtrimStackTrace=false


############################################# KafkaSql Integration Tests #########################################################################


Expand All @@ -459,12 +427,6 @@ run-kafkasql-integration-tests:
@echo "----------------------------------------------------------------------"
./mvnw verify -am --no-transfer-progress -Pintegration-tests -P$(INTEGRATION_TESTS_PROFILE) -Premote-kafka -pl integration-tests -Dmaven.javadoc.skip=true --no-transfer-progress

.PHONY: run-kafkasql-upgrade-tests ## Runs sql e2e tests
run-kafkasql-upgrade-tests :
@echo "----------------------------------------------------------------------"
@echo " Running KafkaSql Upgrade Integration Tests "
@echo "----------------------------------------------------------------------"
./mvnw verify -am --no-transfer-progress -Pintegration-tests -Pkafkasqlit -Premote-kafka -pl integration-tests -Dmaven.javadoc.skip=true --no-transfer-progress

.PHONY: run-kafkasql-migration-integration-tests ## Runs kafkasql migration integration tests
run-kafkasql-migration-integration-tests:
Expand Down Expand Up @@ -520,7 +482,7 @@ run-mssql-migration-integration-tests:


.PHONY: integration-tests ## Runs all integration tests [SKIP_TESTS, BUILD_FLAGS]
integration-tests: build-all run-ui-tests run-sql-integration-tests run-mssql-integration-tests run-mssql-clustered-integration-tests run-kafkasql-integration-tests run-multitenancy-integration-tests run-sql-migration-integration-tests run-mssql-migration-integration-tests run-kafkasql-migration-integration-tests run-sql-auth-integration-tests run-mssql-auth-integration-tests run-kafkasql-auth-integration-tests run-sql-legacy-tests run-mssql-legacy-tests run-kafkasql-legacy-tests
integration-tests: build-all run-ui-tests run-sql-integration-tests run-mssql-integration-tests run-mssql-clustered-integration-tests run-kafkasql-integration-tests run-sql-migration-integration-tests run-mssql-migration-integration-tests run-kafkasql-migration-integration-tests run-sql-auth-integration-tests run-mssql-auth-integration-tests run-kafkasql-auth-integration-tests run-sql-legacy-tests run-mssql-legacy-tests run-kafkasql-legacy-tests

# Please declare your targets as .PHONY in the format shown below, so that the 'make help' parses the information correctly.
#
Expand Down
4 changes: 2 additions & 2 deletions TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ This set of tests are mainly designed to work in two different modes:

### ITs with local infrastructure

This is the normal mode used when you execute the testsuite. Because Apicurio Registry supports various storage backends and various deployment time configurations(such as multitenancy, authentication,...) this tests deploy different components depending on the test executed. This is achieved using Quarkus profiles. For example, when a multitenancy test is executed, a tenant-manager instance will be deployed.
This is the normal mode used when you execute the testsuite. Because Apicurio Registry supports various storage backends and various deployment time configurations(such as authentication,...) this tests deploy different components depending on the test executed. This is achieved using Quarkus profiles.

When running from the terminal, the configuration is provided via maven profiles. You can find all the available maven profiles [here](integration-tests/pom.xml)

When executing the testsuite you normally provide two profiles:
+ test profile (which determines the tests that will be executed), with the following options: all, ci, smoke, serdes, ui, acceptance, auth, multitenancy, migration, sqlit, kafkasqlit.
+ test profile (which determines the tests that will be executed), with the following options: all, ci, smoke, serdes, ui, acceptance, auth, migration, sqlit, kafkasqlit.
+ storage variant to test (which determines the storage backend that will be deployed, and therefore tested), the available options for running the test locally are: local-mem , local-sql, local-mssql , local-kafka.

As you might expect, this testsuite mode depends on the rest of the project to be built first, in order to have the application jars/images available or the serdes module to be available as well.
Expand Down
12 changes: 0 additions & 12 deletions app/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,6 @@
<groupId>io.apicurio</groupId>
<artifactId>apicurio-common-app-components-auth</artifactId>
</dependency>

<dependency>
<groupId>io.apicurio</groupId>
<artifactId>apicurio-common-app-components-multitenancy</artifactId>
</dependency>

<!-- Tenant Manager Client -->
<dependency>
<groupId>io.apicurio</groupId>
<artifactId>apicurio-tenant-manager-client</artifactId>
</dependency>

<dependency>
<groupId>io.apicurio</groupId>
<artifactId>apicurio-common-rest-client-jdk</artifactId>
Expand Down
21 changes: 0 additions & 21 deletions app/src/main/java/io/apicurio/registry/auth/AdminOverride.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

package io.apicurio.registry.auth;

import io.apicurio.common.apps.multitenancy.MultitenancyProperties;
import io.apicurio.common.apps.multitenancy.TenantContext;
import io.quarkus.security.identity.SecurityIdentity;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Instance;
Expand All @@ -41,18 +39,7 @@ public class AdminOverride {
@Inject
Instance<JsonWebToken> jsonWebToken;

@Inject
TenantContext tenantContext;

@Inject
MultitenancyProperties mtProperties;

public boolean isAdmin() {
// When multi-tenancy is enabled, the owner of the tenant is always an admin.
if (mtProperties.isMultitenancyEnabled() && authConfig.isTenantOwnerAdminEnabled() && isTenantOwner()) {
return true;
}

if (!authConfig.adminOverrideEnabled) {
return false;
}
Expand All @@ -67,14 +54,6 @@ public boolean isAdmin() {
return false;
}

private boolean isTenantOwner() {
String tOwner = tenantContext.tenantOwner();
return tOwner != null &&
securityIdentity != null &&
securityIdentity.getPrincipal() != null &&
tOwner.equals(securityIdentity.getPrincipal().getName());
}

private boolean hasAdminRole() {
return securityIdentity.hasRole(authConfig.adminOverrideRole);
}
Expand Down
9 changes: 0 additions & 9 deletions app/src/main/java/io/apicurio/registry/auth/AuthConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,6 @@ public class AuthConfig {
@Info(category = "auth", description = "Auth roles source", availableSince = "2.1.0.Final")
String roleSource;

@ConfigProperty(name = "registry.auth.tenant-owner-is-admin.enabled", defaultValue = "true")
@Info(category = "auth", description = "Auth tenant owner admin enabled", availableSince = "2.1.0.Final")
boolean tenantOwnerIsAdminEnabled;

@ConfigProperty(name = "registry.auth.admin-override.enabled", defaultValue = "false")
@Info(category = "auth", description = "Auth admin override enabled", availableSince = "2.1.0.Final")
boolean adminOverrideEnabled;
Expand Down Expand Up @@ -125,7 +121,6 @@ void onConstruct() {
log.debug(" Role Source: " + roleSource);
}
log.debug("OBAC Enabled: " + ownerOnlyAuthorizationEnabled);
log.debug("Tenant Owner is Admin: " + tenantOwnerIsAdminEnabled);
log.debug("Admin Override Enabled: " + adminOverrideEnabled);
if (adminOverrideEnabled) {
log.debug(" Admin Override from: " + adminOverrideFrom);
Expand All @@ -149,10 +144,6 @@ public boolean isObacEnabled() {
return this.ownerOnlyAuthorizationEnabled.get();
}

public boolean isTenantOwnerAdminEnabled() {
return this.tenantOwnerIsAdminEnabled;
}

public boolean isAdminOverrideEnabled() {
return this.adminOverrideEnabled;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@

package io.apicurio.registry.auth;

import io.apicurio.common.apps.config.Info;
import io.apicurio.common.apps.multitenancy.ApicurioTenantContext;
import io.apicurio.common.apps.multitenancy.MultitenancyProperties;
import io.apicurio.common.apps.multitenancy.TenantContext;
import io.apicurio.common.apps.multitenancy.exceptions.TenantNotAuthorizedException;
import io.quarkus.security.ForbiddenException;
import io.quarkus.security.UnauthorizedException;
import io.quarkus.security.identity.SecurityIdentity;
Expand All @@ -30,18 +25,13 @@
import jakarta.interceptor.AroundInvoke;
import jakarta.interceptor.Interceptor;
import jakarta.interceptor.InvocationContext;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.jwt.JsonWebToken;
import org.slf4j.Logger;

import java.util.List;
import java.util.Optional;

/**
* This class implements authorization logic for the registry. It is driven by a combination of the
* security identity (authenticated user) and configured security level of the operation the user is
* attempting to perform. In a multitenant deployment, this authorization interceptor also checks if
* the user accessing the tenant has the proper permission level. This interceptor will be triggered
* attempting to perform. This interceptor will be triggered
* for any method that is annotated with the {@link Authorized} annotation. Please ensure that all
* JAX-RS operations are propertly annotated.
*
Expand Down Expand Up @@ -73,35 +63,9 @@ public class AuthorizedInterceptor {
@Inject
OwnerBasedAccessController obac;

@Inject
MultitenancyProperties mtProperties;

@Inject
TenantContext tenantContext;

@ConfigProperty(name = "registry.organization-id.claim-name")
@Info(category = "mt", description = "Organization ID claim name", availableSince = "2.1.0.Final")
List<String> organizationIdClaims;

@AroundInvoke
public Object authorizeMethod(InvocationContext context) throws Exception {

//execute multitenancy related authorization checks
if (mtProperties.isMultitenancyEnabled()) {

//if multitenancy is enabled but no tenant context is loaded, because no tenant was resolved from request, reject it
//this is to avoid access to default tenant "_" when multitenancy is enabled
if (!tenantContext.isLoaded()) {
log.warn("Request is rejected because the tenant could not be found, and access to default tenant is disabled in a multitenant deployment");
throw new ForbiddenException("Default tenant access is not allowed in multitenancy mode.");
}

//If multitenancy authorization is enabled, check tenant access.
if (mtProperties.isMultitenancyAuthorizationEnabled()) {
checkTenantAuthorization(tenantContext.currentContext());
}
}

// If the user is trying to invoke a role-mapping operation, deny it if
// database based RBAC is not enabled.
RoleBasedAccessApiOperation rbacOpAnnotation = context.getMethod().getAnnotation(RoleBasedAccessApiOperation.class);
Expand Down Expand Up @@ -174,36 +138,4 @@ public Object authorizeMethod(InvocationContext context) throws Exception {

return context.proceed();
}

private void checkTenantAuthorization(ApicurioTenantContext tenant) {
if (authConfig.isAuthEnabled()) {
if (!isTokenResolvable()) {
log.debug("Tenant access attempted without JWT token for tenant {} [allowing because some endpoints allow anonymous access]", tenant.getTenantId());
return;
}
String accessedOrganizationId = null;

for (String organizationIdClaim : organizationIdClaims) {
final Optional<Object> claimValue = jsonWebToken.get().claim(organizationIdClaim);
if (claimValue.isPresent()) {
accessedOrganizationId = (String) claimValue.get();
break;
}
}

if (null == accessedOrganizationId || !tenantCanAccessOrganization(tenant, accessedOrganizationId)) {
log.warn("User not authorized to access tenant.");
throw new TenantNotAuthorizedException("Tenant not authorized");
}
}
}

private boolean isTokenResolvable() {
return jsonWebToken.isResolvable() && jsonWebToken.get().getRawToken() != null;
}

private boolean tenantCanAccessOrganization(ApicurioTenantContext tenant, String accessedOrganizationId) {
return tenant == null || accessedOrganizationId.equals(tenant.getOrganizationId());
}

}
Loading

0 comments on commit 7cecfa9

Please sign in to comment.