summaryrefslogtreecommitdiffstats
path: root/controller-server/src
diff options
context:
space:
mode:
authorØyvind Grønnesby <oyving@verizonmedia.com>2020-08-04 21:29:58 +0200
committerGitHub <noreply@github.com>2020-08-04 21:29:58 +0200
commit2e82ff0ff2e24811d96c42126d81526da7ea3779 (patch)
tree88eb9029a585ff2caafae8ee05cf49559aeacd8e /controller-server/src
parent26846137d774879c1e68ed8a7975f782bb19976c (diff)
parent7cd14a2802f4f16afb40f05681cc11c61ad6fc79 (diff)
Merge pull request #13983 from vespa-engine/olaa/disallow-deleting-tenant-with-outstanding-charges
Disallow deleting tenants with outstanding charges
Diffstat (limited to 'controller-server/src')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControl.java16
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControlTest.java70
2 files changed, 80 insertions, 6 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControl.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControl.java
index 13cf992cd52..ec4d9ff3626 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControl.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControl.java
@@ -22,6 +22,8 @@ import com.yahoo.vespa.hosted.controller.tenant.CloudTenant;
import com.yahoo.vespa.hosted.controller.tenant.Tenant;
import javax.ws.rs.ForbiddenException;
+import java.math.BigDecimal;
+import java.time.LocalDate;
import java.util.List;
import static com.yahoo.vespa.hosted.controller.api.role.RoleDefinition.*;
@@ -36,13 +38,13 @@ public class CloudAccessControl implements AccessControl {
private final UserManagement userManagement;
private final BooleanFlag enablePublicSignup;
- private final BillingController planController;
+ private final BillingController billingController;
@Inject
public CloudAccessControl(UserManagement userManagement, FlagSource flagSource, ServiceRegistry serviceRegistry) {
this.userManagement = userManagement;
this.enablePublicSignup = Flags.ENABLE_PUBLIC_SIGNUP_FLOW.bindTo(flagSource);
- planController = serviceRegistry.billingController();
+ billingController = serviceRegistry.billingController();
}
@Override
@@ -101,15 +103,17 @@ public class CloudAccessControl implements AccessControl {
@Override
public void deleteTenant(TenantName tenant, Credentials credentials) {
- if(!(allowedByPrivilegedRole((Auth0Credentials) credentials) || isTrial(tenant)))
- throw new ForbiddenException("Please contact the Vespa team for assistance in deleting non-trial tenants");
+ if(!(allowedByPrivilegedRole((Auth0Credentials) credentials) || noOutstandingCharges(tenant)))
+ throw new ForbiddenException("Please contact the Vespa team for assistance in deleting tenants with outstanding charges");
for (TenantRole role : Roles.tenantRoles(tenant))
userManagement.deleteRole(role);
}
- private boolean isTrial(TenantName tenant) {
- return planController.getPlan(tenant).value().equals("trial");
+ private boolean noOutstandingCharges(TenantName tenant) {
+ return billingController.createUncommittedInvoice(tenant, LocalDate.now()).sum().compareTo(BigDecimal.ZERO) == 0 &&
+ billingController.getUnusedLineItems(tenant).size() == 0 &&
+ billingController.getPlan(tenant).value().equals("trial");
}
@Override
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControlTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControlTest.java
new file mode 100644
index 00000000000..baf7d3826f1
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/security/CloudAccessControlTest.java
@@ -0,0 +1,70 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.controller.security;
+
+import com.yahoo.config.provision.TenantName;
+import com.yahoo.vespa.flags.FlagSource;
+import com.yahoo.vespa.flags.InMemoryFlagSource;
+import com.yahoo.vespa.hosted.controller.api.integration.ServiceRegistry;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.Invoice;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.MockBillingController;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanId;
+import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockUserManagement;
+import com.yahoo.vespa.hosted.controller.api.integration.user.UserManagement;
+import com.yahoo.vespa.hosted.controller.integration.ServiceRegistryMock;
+import org.junit.Test;
+
+import javax.ws.rs.ForbiddenException;
+import java.math.BigDecimal;
+import java.security.Principal;
+import java.util.HashSet;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author olaa
+ */
+public class CloudAccessControlTest {
+
+ private final UserManagement userManagement = new MockUserManagement();
+ private final FlagSource flagSource = new InMemoryFlagSource();
+ private final ServiceRegistry serviceRegistry = new ServiceRegistryMock();
+ private final MockBillingController billingController = (MockBillingController) serviceRegistry.billingController();
+ private final CloudAccessControl cloudAccessControl = new CloudAccessControl(userManagement, flagSource, serviceRegistry);
+
+ @Test
+ public void tenant_deletion_fails_when_outstanding_charges() {
+ // First verify that it works with no outstanding charges
+ var tenant = TenantName.defaultName();
+ var principal = mock(Principal.class);
+ var credentials = new Auth0Credentials(principal, new HashSet<>());
+ cloudAccessControl.deleteTenant(tenant, credentials);
+
+ // Forbidden if plan != trial
+ billingController.setPlan(tenant, PlanId.from("subscription"), false);
+ try {
+ cloudAccessControl.deleteTenant(tenant, credentials);
+ fail();
+ } catch (ForbiddenException ignored) {}
+ billingController.setPlan(tenant, PlanId.from("trial"), false);
+
+ // Forbidden if outstanding lineitems
+ billingController.addLineItem(tenant, "Some expense", BigDecimal.TEN, "agent");
+ try {
+ cloudAccessControl.deleteTenant(tenant, credentials);
+ fail();
+ } catch (ForbiddenException ignored) {}
+ billingController.deleteLineItem("line-item-id");
+
+ // Forbidden if uncommited invoice exists
+ var invoice = mock(Invoice.class);
+ when(invoice.sum()).thenReturn(BigDecimal.TEN);
+ billingController.addInvoice(tenant, invoice, false);
+ try {
+ cloudAccessControl.deleteTenant(tenant, credentials);
+ fail();
+ } catch (ForbiddenException ignored) {}
+
+ }
+} \ No newline at end of file