From 1f3b34297a9a800c0603ed1d3a4091bfd94a2e8f Mon Sep 17 00:00:00 2001 From: Henry Avetisyan Date: Tue, 5 Feb 2019 12:19:26 -0800 Subject: [PATCH] move auditEnabled and enabled flags as domain system attributes (#626) --- clients/go/zms/zms_schema.go | 2 +- .../java/com/yahoo/athenz/zms/ZMSSchema.java | 2 +- core/zms/src/main/rdl/Domain.rdli | 5 +- libs/go/zmscli/cli.go | 34 +++-- libs/go/zmscli/domain.go | 16 ++- .../java/com/yahoo/athenz/zms/DBService.java | 38 +++++- .../java/com/yahoo/athenz/zms/ZMSConsts.java | 2 + .../java/com/yahoo/athenz/zms/ZMSImpl.java | 64 +++++++--- .../com/yahoo/athenz/zms/DBServiceTest.java | 116 ++++++++++++++++-- .../com/yahoo/athenz/zms/ZMSImplTest.java | 62 ++++++++-- 10 files changed, 285 insertions(+), 56 deletions(-) diff --git a/clients/go/zms/zms_schema.go b/clients/go/zms/zms_schema.go index 0fedc478ab9..2a6182c8db4 100644 --- a/clients/go/zms/zms_schema.go +++ b/clients/go/zms/zms_schema.go @@ -571,7 +571,7 @@ func init() { sb.AddResource(mPutDomainMeta.Build()) mPutDomainSystemMeta := rdl.NewResourceBuilder("Domain", "PUT", "/domain/{name}/meta/system/{attribute}") - mPutDomainSystemMeta.Comment("Update the specified top level domain metadata. Note that entities in the domain are not affected. Caller must have update privileges on the domain itself.") + mPutDomainSystemMeta.Comment("Set the specified top level domain metadata. Note that entities in the domain are not affected. Caller must have update privileges on the domain itself. If the system attribute is one of the string attributes, then the caller must also have delete action on the same resource in order to reset the configured value") mPutDomainSystemMeta.Name("PutDomainSystemMeta") mPutDomainSystemMeta.Input("name", "DomainName", true, "", "", false, nil, "name of the domain to be updated") mPutDomainSystemMeta.Input("attribute", "SimpleName", true, "", "", false, nil, "name of the system attribute to be modified") diff --git a/core/zms/src/main/java/com/yahoo/athenz/zms/ZMSSchema.java b/core/zms/src/main/java/com/yahoo/athenz/zms/ZMSSchema.java index 948a7c301a8..e9b3a7dd746 100644 --- a/core/zms/src/main/java/com/yahoo/athenz/zms/ZMSSchema.java +++ b/core/zms/src/main/java/com/yahoo/athenz/zms/ZMSSchema.java @@ -542,7 +542,7 @@ private static Schema build() { ; sb.resource("DomainMeta", "PUT", "/domain/{name}/meta/system/{attribute}") - .comment("Update the specified top level domain metadata. Note that entities in the domain are not affected. Caller must have update privileges on the domain itself.") + .comment("Set the specified top level domain metadata. Note that entities in the domain are not affected. Caller must have update privileges on the domain itself. If the system attribute is one of the string attributes, then the caller must also have delete action on the same resource in order to reset the configured value") .name("PutDomainSystemMeta") .pathParam("name", "DomainName", "name of the domain to be updated") .pathParam("attribute", "SimpleName", "name of the system attribute to be modified") diff --git a/core/zms/src/main/rdl/Domain.rdli b/core/zms/src/main/rdl/Domain.rdli index 87d94ae7d55..75f1d0eb514 100644 --- a/core/zms/src/main/rdl/Domain.rdli +++ b/core/zms/src/main/rdl/Domain.rdli @@ -184,8 +184,11 @@ resource Domain PUT "/domain/{name}/meta" { } } -//Update the specified top level domain metadata. Note that entities in the domain +//Set the specified top level domain metadata. Note that entities in the domain //are not affected. Caller must have update privileges on the domain itself. +//If the system attribute is one of the string attributes, then the caller +//must also have delete action on the same resource in order to reset the +//configured value resource Domain PUT "/domain/{name}/meta/system/{attribute}" (name=PutDomainSystemMeta) { DomainName name; //name of the domain to be updated SimpleName attribute; //name of the system attribute to be modified diff --git a/libs/go/zmscli/cli.go b/libs/go/zmscli/cli.go index 9ec5eb1ff3a..36ba6654114 100644 --- a/libs/go/zmscli/cli.go +++ b/libs/go/zmscli/cli.go @@ -473,19 +473,23 @@ func (cli *Zms) EvalCommand(params []string) (*string, error) { return cli.DeleteProviderResourceGroupRoles(dn, args[0], args[1], args[2]) } case "set-domain-meta": - if argc == 3 { + if argc == 2 || argc == 3 { descr := args[0] org := args[1] - auditEnabled, err := strconv.ParseBool(args[2]) - if err != nil { - return nil, err - } - return cli.SetDomainMeta(dn, descr, org, auditEnabled) + return cli.SetDomainMeta(dn, descr, org) } case "set-aws-account", "set-domain-account": if argc == 1 { return cli.SetDomainAccount(dn, args[0]) } + case "set-audit-enabled": + if argc == 1 { + auditEnabled, err := strconv.ParseBool(args[0]) + if err != nil { + return nil, err + } + return cli.SetDomainAuditEnabled(dn, auditEnabled) + } case "set-product-id", "set-domain-product-id": if argc == 1 { productID, err := cli.getInt32(args[0]) @@ -636,16 +640,15 @@ func (cli Zms) HelpSpecificCommand(interactive bool, cmd string) string { buf.WriteString(" add a subdomain hosted in domain coretech with " + cli.UserDomain + ".john, " + cli.UserDomain + ".jane and the caller as administrators\n") case "set-domain-meta": buf.WriteString(" syntax:\n") - buf.WriteString(" " + domain_param + " set-domain-meta description org audit_enabled\n") + buf.WriteString(" " + domain_param + " set-domain-meta description org\n") buf.WriteString(" parameters:\n") if !interactive { buf.WriteString(" domain : name of the domain being updated\n") } buf.WriteString(" description : set the description for the domain\n") buf.WriteString(" org : set the organization of the domain\n") - buf.WriteString(" audit_enabled : boolean flag indicating if the domain must comply with SOX auditing requirements\n") buf.WriteString(" examples:\n") - buf.WriteString(" " + domain_example + " set-domain-meta \"Coretech Hosted\" cloud.services false\n") + buf.WriteString(" " + domain_example + " set-domain-meta \"Coretech Hosted\" cloud.services\n") case "set-aws-account", "set-domain-account": buf.WriteString(" syntax:\n") buf.WriteString(" " + domain_param + " set-aws-account account-id\n") @@ -656,6 +659,16 @@ func (cli Zms) HelpSpecificCommand(interactive bool, cmd string) string { buf.WriteString(" account-id : set the aws account id for the domain\n") buf.WriteString(" examples:\n") buf.WriteString(" " + domain_example + " set-aws-account \"134901934383\"\n") + case "set-audit-enabled": + buf.WriteString(" syntax:\n") + buf.WriteString(" " + domain_param + " set-audit-enabled audit-enabled\n") + buf.WriteString(" parameters:\n") + if !interactive { + buf.WriteString(" domain : name of the domain being updated\n") + } + buf.WriteString(" audit-enabled : enable/disable audit flag for the domain\n") + buf.WriteString(" examples:\n") + buf.WriteString(" " + domain_example + " set-audit-enabled true\n") case "set-product-id", "set-domain-product-id": buf.WriteString(" syntax:\n") buf.WriteString(" " + domain_param + " set-product-id product-id\n") @@ -1470,7 +1483,8 @@ func (cli Zms) HelpListCommand() string { buf.WriteString(" lookup-domain-by-role role-member role-name\n") buf.WriteString(" add-domain domain product-id [admin ...] - to add top level domains\n") buf.WriteString(" add-domain domain [admin ...] - to add sub domains\n") - buf.WriteString(" set-domain-meta description org audit_enabled\n") + buf.WriteString(" set-domain-meta description org\n") + buf.WriteString(" set-audit-enabled audit-enabled\n") buf.WriteString(" set-aws-account account-id\n") buf.WriteString(" set-product-id product-id\n") buf.WriteString(" set-application-id application-id\n") diff --git a/libs/go/zmscli/domain.go b/libs/go/zmscli/domain.go index 4b785fe81a9..0739262e403 100644 --- a/libs/go/zmscli/domain.go +++ b/libs/go/zmscli/domain.go @@ -403,7 +403,7 @@ func (cli Zms) SetCompleteDomainMeta(dn string, descr string, org string, auditE return cli.Zms.PutDomainMeta(zms.DomainName(dn), cli.AuditRef, &meta) } -func (cli Zms) SetDomainMeta(dn string, descr string, org string, auditEnabled bool) (*string, error) { +func (cli Zms) SetDomainMeta(dn string, descr string, org string) (*string, error) { domain, err := cli.Zms.GetDomain(zms.DomainName(dn)) if err != nil { return nil, err @@ -411,8 +411,6 @@ func (cli Zms) SetDomainMeta(dn string, descr string, org string, auditEnabled b meta := zms.DomainMeta{ Description: descr, Org: zms.ResourceName(org), - Enabled: domain.Enabled, - AuditEnabled: &auditEnabled, ApplicationId: domain.ApplicationId, } err = cli.Zms.PutDomainMeta(zms.DomainName(dn), cli.AuditRef, &meta) @@ -423,6 +421,18 @@ func (cli Zms) SetDomainMeta(dn string, descr string, org string, auditEnabled b return &s, nil } +func (cli Zms) SetDomainAuditEnabled(dn string, auditEnabled bool) (*string, error) { + meta := zms.DomainMeta{ + AuditEnabled: &auditEnabled, + } + err := cli.Zms.PutDomainSystemMeta(zms.DomainName(dn), zms.SimpleName("auditenabled"), cli.AuditRef, &meta) + if err != nil { + return nil, err + } + s := "[domain " + dn + " metadata successfully updated]\n" + return &s, nil +} + func (cli Zms) SetDomainAccount(dn string, account string) (*string, error) { meta := zms.DomainMeta{ Account: account, diff --git a/servers/zms/src/main/java/com/yahoo/athenz/zms/DBService.java b/servers/zms/src/main/java/com/yahoo/athenz/zms/DBService.java index 2491bd05021..b1024e83977 100644 --- a/servers/zms/src/main/java/com/yahoo/athenz/zms/DBService.java +++ b/servers/zms/src/main/java/com/yahoo/athenz/zms/DBService.java @@ -2084,7 +2084,7 @@ List listServiceIdentities(String domainName) { } void executePutDomainMeta(ResourceContext ctx, String domainName, DomainMeta meta, - final String systemAttribute, String auditRef, String caller) { + final String systemAttribute, boolean deleteAllowed, String auditRef, String caller) { // our exception handling code does the check for retry count // and throws the exception it had received when the retry @@ -2117,7 +2117,7 @@ void executePutDomainMeta(ResourceContext ctx, String domainName, DomainMeta met // from the given object if (systemAttribute != null) { - updateSystemMetaFields(updatedDomain, systemAttribute, meta); + updateSystemMetaFields(updatedDomain, systemAttribute, deleteAllowed, meta); } else { updateDomainMetaFields(updatedDomain, meta); } @@ -2146,13 +2146,28 @@ void executePutDomainMeta(ResourceContext ctx, String domainName, DomainMeta met void updateDomainMetaFields(Domain domain, DomainMeta meta) { - domain.setAuditEnabled(meta.getAuditEnabled()); domain.setApplicationId(meta.getApplicationId()); domain.setDescription(meta.getDescription()); domain.setOrg(meta.getOrg()); } - void updateSystemMetaFields(Domain domain, final String attribute, DomainMeta meta) { + boolean isDeleteSystemMetaAllowed(boolean deleteAllowed, Object oldValue, Object newValue) { + + // if authorized or old value is not set, then there is + // no need to check any value + + if (deleteAllowed || oldValue == null) { + return true; + } + + // since our old value is not null then we will only + // allow if the new value is identical + + return (newValue != null) ? oldValue.equals(newValue) : false; + } + + void updateSystemMetaFields(Domain domain, final String attribute, boolean deleteAllowed, + DomainMeta meta) { final String caller = "putdomainsystemmeta"; @@ -2161,14 +2176,29 @@ void updateSystemMetaFields(Domain domain, final String attribute, DomainMeta me switch (attribute) { case ZMSConsts.SYSTEM_META_ACCOUNT: + if (!isDeleteSystemMetaAllowed(deleteAllowed, domain.getAccount(), meta.getAccount())) { + throw ZMSUtils.forbiddenError("unuathorized to reset system meta attribute: " + attribute, caller); + } domain.setAccount(meta.getAccount()); break; case ZMSConsts.SYSTEM_META_PRODUCT_ID: + if (!isDeleteSystemMetaAllowed(deleteAllowed, domain.getYpmId(), meta.getYpmId())) { + throw ZMSUtils.forbiddenError("unuathorized to reset system meta attribute: " + attribute, caller); + } domain.setYpmId(meta.getYpmId()); break; case ZMSConsts.SYSTEM_META_CERT_DNS_DOMAIN: + if (!isDeleteSystemMetaAllowed(deleteAllowed, domain.getCertDnsDomain(), meta.getCertDnsDomain())) { + throw ZMSUtils.forbiddenError("unuathorized to reset system meta attribute: " + attribute, caller); + } domain.setCertDnsDomain(meta.getCertDnsDomain()); break; + case ZMSConsts.SYSTEM_META_AUDIT_ENABLED: + domain.setAuditEnabled(meta.getAuditEnabled()); + break; + case ZMSConsts.SYSTEM_META_ENABLED: + domain.setEnabled(meta.getEnabled()); + break; default: throw ZMSUtils.requestError("unknown system meta attribute: " + attribute, caller); } diff --git a/servers/zms/src/main/java/com/yahoo/athenz/zms/ZMSConsts.java b/servers/zms/src/main/java/com/yahoo/athenz/zms/ZMSConsts.java index fe149d3eb31..0aabaa20d1b 100644 --- a/servers/zms/src/main/java/com/yahoo/athenz/zms/ZMSConsts.java +++ b/servers/zms/src/main/java/com/yahoo/athenz/zms/ZMSConsts.java @@ -203,6 +203,8 @@ public final class ZMSConsts { public static final String SYSTEM_META_PRODUCT_ID = "productid"; public static final String SYSTEM_META_ACCOUNT = "account"; public static final String SYSTEM_META_CERT_DNS_DOMAIN = "certdnsdomain"; + public static final String SYSTEM_META_AUDIT_ENABLED = "auditenabled"; + public static final String SYSTEM_META_ENABLED = "enabled"; // HTTP operation types used in metrics public static final String HTTP_GET = "GET"; diff --git a/servers/zms/src/main/java/com/yahoo/athenz/zms/ZMSImpl.java b/servers/zms/src/main/java/com/yahoo/athenz/zms/ZMSImpl.java index b1abac9bda2..98032487d63 100644 --- a/servers/zms/src/main/java/com/yahoo/athenz/zms/ZMSImpl.java +++ b/servers/zms/src/main/java/com/yahoo/athenz/zms/ZMSImpl.java @@ -170,7 +170,8 @@ public class ZMSImpl implements Authorizer, KeyStore, ZMSHandler { protected int statusPort; protected int serviceNameMinLength; protected Status successServerStatus = null; - + protected Set reservedSystemDomains = null; + // enum to represent our access response since in some cases we want to // handle domain not founds differently instead of just returning failure @@ -575,6 +576,14 @@ void loadConfigurationSettings() { serviceNameMinLength = Integer.parseInt( System.getProperty(ZMSConsts.ZMS_PROP_SERVICE_NAME_MIN_LENGTH, "3")); + + // setup our reserved system domain names + + reservedSystemDomains = new HashSet<>(); + reservedSystemDomains.add("sys"); + reservedSystemDomains.add("sys.auth"); + reservedSystemDomains.add(userDomain); + reservedSystemDomains.add(homeDomain); } void loadObjectStore() { @@ -763,7 +772,7 @@ void initObjectStore() { final String caller = "initstore"; List domains = dbService.listDomains(null, 0); - if (domains.size() > 0) { + if (domains.size() > 0 && domains.contains(SYS_AUTH)) { return; } @@ -1031,6 +1040,12 @@ public void deleteTopLevelDomain(ResourceContext ctx, String domainName, String Domain deleteDomain(ResourceContext ctx, String auditRef, String domainName, String caller) { + // make sure we're not deleting any of the reserved system domain + + if (reservedSystemDomains.contains(domainName)) { + throw ZMSUtils.requestError("Cannot delete reserved system domain", caller); + } + DomainList subDomainList = listDomains(null, null, domainName + ".", null, 0); if (subDomainList.getNames().size() > 0) { throw ZMSUtils.requestError(caller + ": Cannot delete domain " + @@ -1227,9 +1242,6 @@ boolean isSysAdminUser(Principal principal) { } AthenzDomain domain = getAthenzDomain(SYS_AUTH, true); - if (domain == null) { - return false; - } // evaluate our domain's roles and policies to see if access // is allowed or not for the given operation and resource @@ -1247,9 +1259,6 @@ boolean isAllowedResourceLookForAllUsers(Principal principal) { // the authorization policy resides in official sys.auth domain AthenzDomain domain = getAthenzDomain(SYS_AUTH, true); - if (domain == null) { - return false; - } // evaluate our domain's roles and policies to see if access // is allowed or not for the given operation and resource @@ -1261,7 +1270,25 @@ boolean isAllowedResourceLookForAllUsers(Principal principal) { return accessStatus == AccessStatus.ALLOWED; } - + + boolean isAllowedSystemMetaDelete(Principal principal, final String reqDomain, + final String attribute) { + + // the authorization policy resides in official sys.auth domain + + AthenzDomain domain = getAthenzDomain(SYS_AUTH, true); + + // evaluate our domain's roles and policies to see if access + // is allowed or not for the given operation and resource + // our action are always converted to lowercase + + String resource = SYS_AUTH + ":meta." + attribute + "." + reqDomain; + AccessStatus accessStatus = evaluateAccess(domain, principal.getFullName(), "delete", + resource, null, null); + + return accessStatus == AccessStatus.ALLOWED; + } + public void deleteSubDomain(ResourceContext ctx, String parent, String name, String auditRef) { final String caller = "deletesubdomain"; @@ -1457,19 +1484,13 @@ public void putDomainMeta(ResourceContext ctx, String domainName, String auditRe verifyAuthorizedServiceOperation(((RsrcCtxWrapper) ctx).principal().getAuthorizedService(), caller); - // remove system attributes from the meta object - - meta.setYpmId(null); - meta.setAccount(null); - meta.setCertDnsDomain(null); - if (LOG.isDebugEnabled()) { LOG.debug("putDomainMeta: name={}, meta={}", domainName, meta); } // process put domain meta request - dbService.executePutDomainMeta(ctx, domainName, meta, null, auditRef, caller); + dbService.executePutDomainMeta(ctx, domainName, meta, null, false, auditRef, caller); metric.stopTiming(timerMetric); } @@ -1503,14 +1524,19 @@ public void putDomainSystemMeta(ResourceContext ctx, String domainName, String a // verify that request is properly authenticated for this request - verifyAuthorizedServiceOperation(((RsrcCtxWrapper) ctx).principal().getAuthorizedService(), - caller); + Principal principal = ((RsrcCtxWrapper) ctx).principal(); + verifyAuthorizedServiceOperation(principal.getAuthorizedService(), caller); if (LOG.isDebugEnabled()) { LOG.debug("putDomainSystemMeta: name={}, attribute={}, meta={}", domainName, attribute, meta); } + // if we are resetting the configured value then the caller + // must also have a delete action available for the same resource + + boolean deleteAllowed = isAllowedSystemMetaDelete(principal, domainName, attribute); + // if this productId is already used by any domain it will be // seen in dbService and exception thrown but we want to make // sure here if product id support is required then we must @@ -1521,7 +1547,7 @@ public void putDomainSystemMeta(ResourceContext ctx, String domainName, String a throw ZMSUtils.requestError("Unique Product Id must be specified for top level domain", caller); } - dbService.executePutDomainMeta(ctx, domainName, meta, attribute, auditRef, caller); + dbService.executePutDomainMeta(ctx, domainName, meta, attribute, deleteAllowed, auditRef, caller); metric.stopTiming(timerMetric); } diff --git a/servers/zms/src/test/java/com/yahoo/athenz/zms/DBServiceTest.java b/servers/zms/src/test/java/com/yahoo/athenz/zms/DBServiceTest.java index b69b4ea73fa..649acb2d690 100644 --- a/servers/zms/src/test/java/com/yahoo/athenz/zms/DBServiceTest.java +++ b/servers/zms/src/test/java/com/yahoo/athenz/zms/DBServiceTest.java @@ -1046,10 +1046,10 @@ public void testExecutePutDomainMeta() { DomainMeta meta = new DomainMeta().setDescription("Test2 Domain").setOrg("NewOrg") .setEnabled(true).setAuditEnabled(false).setAccount("12345").setYpmId(1001) .setCertDnsDomain("athenz1.cloud"); - zms.dbService.executePutDomainMeta(mockDomRsrcCtx, "metadom1", meta, null, auditRef, "putDomainMeta"); - zms.dbService.executePutDomainMeta(mockDomRsrcCtx, "metadom1", meta, "productid", auditRef, "putDomainMeta"); - zms.dbService.executePutDomainMeta(mockDomRsrcCtx, "metadom1", meta, "account", auditRef, "putDomainMeta"); - zms.dbService.executePutDomainMeta(mockDomRsrcCtx, "metadom1", meta, "certdnsdomain", auditRef, "putDomainMeta"); + zms.dbService.executePutDomainMeta(mockDomRsrcCtx, "metadom1", meta, null, false, auditRef, "putDomainMeta"); + zms.dbService.executePutDomainMeta(mockDomRsrcCtx, "metadom1", meta, "productid", true, auditRef, "putDomainMeta"); + zms.dbService.executePutDomainMeta(mockDomRsrcCtx, "metadom1", meta, "account", true, auditRef, "putDomainMeta"); + zms.dbService.executePutDomainMeta(mockDomRsrcCtx, "metadom1", meta, "certdnsdomain", true, auditRef, "putDomainMeta"); Domain resDom2 = zms.getDomain(mockDomRsrcCtx, "MetaDom1"); assertNotNull(resDom2); @@ -1065,7 +1065,7 @@ public void testExecutePutDomainMeta() { meta = new DomainMeta().setDescription("Test2 Domain-New").setOrg("NewOrg-New") .setEnabled(true).setAuditEnabled(false); - zms.dbService.executePutDomainMeta(mockDomRsrcCtx, "metadom1", meta, null, auditRef, "putDomainMeta"); + zms.dbService.executePutDomainMeta(mockDomRsrcCtx, "metadom1", meta, null, false, auditRef, "putDomainMeta"); Domain resDom3 = zms.getDomain(mockDomRsrcCtx, "MetaDom1"); assertNotNull(resDom3); @@ -1105,7 +1105,7 @@ public void testExecutePutDomainMetaRetryException() { try { zms.dbService.executePutDomainMeta(mockDomRsrcCtx, domainName, meta, - null, auditRef, "testExecutePutDomainMetaRetryException"); + null, false, auditRef, "testExecutePutDomainMetaRetryException"); fail(); } catch (ResourceException ex) { assertEquals(ResourceException.CONFLICT, ex.getCode()); @@ -3420,17 +3420,113 @@ public void testUpdateSystemMetaFields() { .setAccount("acct") .setYpmId(1234) .setCertDnsDomain("athenz.cloud"); - zms.dbService.updateSystemMetaFields(domain, "account", meta); + zms.dbService.updateSystemMetaFields(domain, "account", true, meta); assertEquals(domain.getAccount(), "acct"); - zms.dbService.updateSystemMetaFields(domain, "productid", meta); + zms.dbService.updateSystemMetaFields(domain, "productid", true, meta); assertEquals(domain.getYpmId().intValue(), 1234); - zms.dbService.updateSystemMetaFields(domain, "certdnsdomain", meta); + zms.dbService.updateSystemMetaFields(domain, "certdnsdomain", true, meta); assertEquals(domain.getCertDnsDomain(), "athenz.cloud"); try { - zms.dbService.updateSystemMetaFields(domain, "unknown", meta); + zms.dbService.updateSystemMetaFields(domain, "unknown", true, meta); fail(); } catch (ResourceException ex) { assertEquals(ex.getCode(), 400); } + + // test setting from null to valid values with no delete set + + Domain domain1 = new Domain(); + DomainMeta meta1 = new DomainMeta() + .setAccount("acct") + .setYpmId(1234) + .setCertDnsDomain("athenz.cloud"); + zms.dbService.updateSystemMetaFields(domain1, "account", false, meta1); + assertEquals(domain1.getAccount(), "acct"); + zms.dbService.updateSystemMetaFields(domain1, "productid", false, meta1); + assertEquals(domain1.getYpmId().intValue(), 1234); + zms.dbService.updateSystemMetaFields(domain1, "certdnsdomain", false, meta1); + assertEquals(domain1.getCertDnsDomain(), "athenz.cloud"); + + // setting from set values should be all rejected + + Domain domain2 = new Domain() + .setAccount("acct") + .setYpmId(1234) + .setCertDnsDomain("athenz.cloud"); + DomainMeta meta2 = new DomainMeta() + .setAccount("acct-new") + .setYpmId(1235) + .setCertDnsDomain("athenz.cloud.new"); + + // setting from the old value to new value with + // no delete flag should be rejected + + try { + zms.dbService.updateSystemMetaFields(domain2, "account", false, meta2); + } catch (ResourceException ex) { + assertEquals(ex.getCode(), 403); + assertTrue(ex.getMessage().contains("reset system meta attribute")); + } + + try { + zms.dbService.updateSystemMetaFields(domain2, "productid", false, meta2); + } catch (ResourceException ex) { + assertEquals(ex.getCode(), 403); + assertTrue(ex.getMessage().contains("reset system meta attribute")); + } + + try { + zms.dbService.updateSystemMetaFields(domain2, "certdnsdomain", false, meta2); + } catch (ResourceException ex) { + assertEquals(ex.getCode(), 403); + assertTrue(ex.getMessage().contains("reset system meta attribute")); + } + + // setting from set value to the same value should be allowed + + Domain domain3 = new Domain() + .setAccount("acct") + .setYpmId(1234) + .setCertDnsDomain("athenz.cloud"); + DomainMeta meta3 = new DomainMeta() + .setAccount("acct") + .setYpmId(1234) + .setCertDnsDomain("athenz.cloud"); + zms.dbService.updateSystemMetaFields(domain3, "account", false, meta3); + assertEquals(domain3.getAccount(), "acct"); + zms.dbService.updateSystemMetaFields(domain3, "productid", false, meta3); + assertEquals(domain3.getYpmId().intValue(), 1234); + zms.dbService.updateSystemMetaFields(domain3, "certdnsdomain", false, meta3); + assertEquals(domain3.getCertDnsDomain(), "athenz.cloud"); + } + + @Test + public void testDeleteSystemMetaAllowed() { + + assertTrue(zms.dbService.isDeleteSystemMetaAllowed(true, null, null)); + assertTrue(zms.dbService.isDeleteSystemMetaAllowed(true, null, "new")); + assertTrue(zms.dbService.isDeleteSystemMetaAllowed(true, null, "")); + + assertTrue(zms.dbService.isDeleteSystemMetaAllowed(true, "old", null)); + assertTrue(zms.dbService.isDeleteSystemMetaAllowed(true, "old", "new")); + assertTrue(zms.dbService.isDeleteSystemMetaAllowed(true, "old", "")); + + assertTrue(zms.dbService.isDeleteSystemMetaAllowed(true, "", null)); + assertTrue(zms.dbService.isDeleteSystemMetaAllowed(true, "", "new")); + assertTrue(zms.dbService.isDeleteSystemMetaAllowed(true, "", "")); + + assertTrue(zms.dbService.isDeleteSystemMetaAllowed(false, null, null)); + assertTrue(zms.dbService.isDeleteSystemMetaAllowed(false, null, "new")); + assertTrue(zms.dbService.isDeleteSystemMetaAllowed(false, null, "")); + + assertFalse(zms.dbService.isDeleteSystemMetaAllowed(false, "old", null)); + assertFalse(zms.dbService.isDeleteSystemMetaAllowed(false, "old", "new")); + assertFalse(zms.dbService.isDeleteSystemMetaAllowed(false, "old", "")); + + assertFalse(zms.dbService.isDeleteSystemMetaAllowed(false, "", null)); + assertFalse(zms.dbService.isDeleteSystemMetaAllowed(false, "", "new")); + assertTrue(zms.dbService.isDeleteSystemMetaAllowed(false, "", "")); + + assertTrue(zms.dbService.isDeleteSystemMetaAllowed(false, "test", "test")); } } diff --git a/servers/zms/src/test/java/com/yahoo/athenz/zms/ZMSImplTest.java b/servers/zms/src/test/java/com/yahoo/athenz/zms/ZMSImplTest.java index 8ad84e567cf..84f468f8b8e 100644 --- a/servers/zms/src/test/java/com/yahoo/athenz/zms/ZMSImplTest.java +++ b/servers/zms/src/test/java/com/yahoo/athenz/zms/ZMSImplTest.java @@ -514,6 +514,35 @@ private void setupTenantDomainProviderService(ZMSImpl zms, String tenantDomain, zms.putServiceIdentity(mockDomRsrcCtx, providerDomain, providerService, auditRef, service); } + private void setupPrincipalSystemMetaDelete(ZMSImpl zms, final String principal, + final String domainName, final String attributeName) { + + Role role = createRoleObject("sys.auth", "metaadmin", null, principal, null); + zms.putRole(mockDomRsrcCtx, "sys.auth", "metaadmin", auditRef, role); + + Policy policy = new Policy(); + policy.setName("metaadmin"); + + Assertion assertion = new Assertion(); + assertion.setAction("delete"); + assertion.setEffect(AssertionEffect.ALLOW); + assertion.setResource("sys.auth:meta." + attributeName + "." + domainName); + assertion.setRole("sys.auth:role.metaadmin"); + + List assertList = new ArrayList<>(); + assertList.add(assertion); + + policy.setAssertions(assertList); + + zms.putPolicy(mockDomRsrcCtx, "sys.auth", "metaadmin", auditRef, policy); + } + + private void cleanupPrincipalSystemMetaDelete(ZMSImpl zms) { + + zms.deleteRole(mockDomRsrcCtx, "sys.auth", "metaadmin", auditRef); + zms.deletePolicy(mockDomRsrcCtx, "sys.auth", "metaadmin", auditRef); + } + private void setupTenantDomainProviderService(String tenantDomain, String providerDomain, String providerService, String providerEndpoint) { setupTenantDomainProviderService(zms, tenantDomain, providerDomain, providerService, providerEndpoint); @@ -1337,6 +1366,17 @@ public void testCreateSubdomainOnceOnly() { @Test public void testDeleteDomain() { + + // make sure we can't delete system domains + + try { + zms.deleteDomain(mockDomRsrcCtx, auditRef, "sys.auth", "testDeleteDomain"); + fail(); + } catch (ResourceException ex) { + assertEquals(ex.getCode(), 400); + assertTrue(ex.getMessage().contains("reserved system domain")); + } + TopLevelDomain dom = createTopLevelDomainObject( "TestDeleteDomain", null, null, adminUser); dom.setAuditEnabled(true); @@ -1620,11 +1660,10 @@ public void testPutDomainMeta() { DomainMeta meta = createDomainMetaObject("Test2 Domain", "NewOrg", true, true, "12345", 1001); zms.putDomainMeta(mockDomRsrcCtx, "MetaDom1", auditRef, meta); - meta = createDomainMetaObject("Test2 Domain", "NewOrg", - true, true, "12345", 1001); + zms.putDomainSystemMeta(mockDomRsrcCtx, "MetaDom1", "auditenabled", auditRef, meta); zms.putDomainSystemMeta(mockDomRsrcCtx, "MetaDom1", "account", auditRef, meta); - meta = createDomainMetaObject("Test2 Domain", "NewOrg", - true, true, "12345", 1001); + + setupPrincipalSystemMetaDelete(zms, mockDomRsrcCtx.principal().getFullName(), "metadom1", "productid"); zms.putDomainSystemMeta(mockDomRsrcCtx, "MetaDom1", "productid", auditRef, meta); Domain resDom3 = zms.getDomain(mockDomRsrcCtx, "MetaDom1"); @@ -1633,7 +1672,7 @@ public void testPutDomainMeta() { assertEquals(resDom3.getOrg(), "NewOrg"); assertTrue(resDom3.getEnabled()); assertTrue(resDom3.getAuditEnabled()); - assertEquals("12345", resDom3.getAccount()); + assertEquals(resDom3.getAccount(), "12345"); assertEquals(Integer.valueOf(1001), resDom3.getYpmId()); // put the meta data using same product id @@ -1648,7 +1687,7 @@ public void testPutDomainMeta() { assertEquals(resDom3.getOrg(), "organs"); assertTrue(resDom3.getEnabled()); assertTrue(resDom3.getAuditEnabled()); - assertEquals("12345", resDom3.getAccount()); + assertEquals(resDom3.getAccount(), "12345"); assertEquals(Integer.valueOf(1001), resDom3.getYpmId()); // put the meta data using new product @@ -1664,9 +1703,10 @@ public void testPutDomainMeta() { assertEquals(resDom3.getOrg(), "organs"); assertTrue(resDom3.getEnabled()); assertTrue(resDom3.getAuditEnabled()); - assertEquals("12345", resDom3.getAccount()); + assertEquals(resDom3.getAccount(), "12345"); assertEquals(newProductId, resDom3.getYpmId()); + cleanupPrincipalSystemMetaDelete(zms); zms.deleteTopLevelDomain(mockDomRsrcCtx, "MetaDom1", auditRef); } @@ -1690,6 +1730,7 @@ public void testPutDomainMetaInvalid() { assertFalse(resDom.getAuditEnabled()); Integer productId = resDom.getYpmId(); + setupPrincipalSystemMetaDelete(zms, mockDomRsrcCtx.principal().getFullName(), "metadomproductid", "productid"); DomainMeta meta = createDomainMetaObject("Test2 Domain", "NewOrg", true, true, "12345", null); try { @@ -1719,6 +1760,7 @@ public void testPutDomainMetaInvalid() { assertTrue(exc.getMessage().contains("is already assigned to domain")); } + cleanupPrincipalSystemMetaDelete(zms); zmsImpl.deleteTopLevelDomain(mockDomRsrcCtx, "MetaDomProductid", auditRef); zmsImpl.deleteTopLevelDomain(mockDomRsrcCtx, "MetaDomProductid2", auditRef); System.clearProperty(ZMSConsts.ZMS_PROP_PRODUCT_ID_SUPPORT); @@ -7242,6 +7284,7 @@ public void testPutTenancyMissingAuditRef() { DomainMeta meta = createDomainMetaObject("Tenant Domain", null, true, true, null, 0); zms.putDomainMeta(mockDomRsrcCtx, tenantDomain, auditRef, meta); + zms.putDomainSystemMeta(mockDomRsrcCtx, tenantDomain, "auditenabled", auditRef, meta); Tenancy tenant = createTenantObject(tenantDomain, providerDomain + "." + providerService); try { @@ -7422,6 +7465,8 @@ public void testDeleteTenancyMissingAuditRef() { DomainMeta meta = createDomainMetaObject("Tenant Domain", null, true, true, null, 0); zms.putDomainMeta(mockDomRsrcCtx, tenantDomain, auditRef, meta); + zms.putDomainSystemMeta(mockDomRsrcCtx, tenantDomain, "auditenabled", auditRef, meta); + zms.putDomainSystemMeta(mockDomRsrcCtx, tenantDomain, "enabled", auditRef, meta); // setup tenancy // @@ -14997,8 +15042,11 @@ public void testGetSignedDomainsWithMetaAttrs() { zms.putDomainMeta(mockDomRsrcCtx, "signeddom2", auditRef, meta); meta = createDomainMetaObject("Tenant Domain2", null, true, false, "12346", null); zms.putDomainSystemMeta(mockDomRsrcCtx, "signeddom2", "account", auditRef, meta); + + setupPrincipalSystemMetaDelete(zms, mockDomRsrcCtx.principal().getFullName(), "signeddom2", "productid"); meta = createDomainMetaObject("Tenant Domain2", null, true, false, "12346", null); zms.putDomainSystemMeta(mockDomRsrcCtx, "signeddom2", "productid", auditRef, meta); + cleanupPrincipalSystemMetaDelete(zms); DomainList domList = zms.getDomainList(mockDomRsrcCtx, null, null, null, null, null, null, null, null, null);