@Test
public void testGetSignedDomains() {

    loadServerPublicKeys(zms);
    // create multiple top level domains
    TopLevelDomain dom1 = createTopLevelDomainObject("SignedDom1",
            "Test Domain1", "testOrg", adminUser);
    zms.postTopLevelDomain(mockDomRsrcCtx, auditRef, dom1);
    Group group1 = createGroupObject("signeddom1", "group1", "user.user1", "user.user2");
    zms.putGroup(mockDomRsrcCtx, "signeddom1", "group1", auditRef, group1);
    // set the meta attributes for domain
    
    DomainMeta meta = createDomainMetaObject("Tenant Domain1", null, true, false, "12345", 0);
    zms.putDomainMeta(mockDomRsrcCtx, "signeddom1", auditRef, meta);
    meta = createDomainMetaObject("Tenant Domain1", null, true, false, "12345", 0);
    zms.putDomainSystemMeta(mockDomRsrcCtx, "signeddom1", "account", auditRef, meta);
    TopLevelDomain dom2 = createTopLevelDomainObject("SignedDom2",
            "Test Domain2", "testOrg", adminUser);
    zms.postTopLevelDomain(mockDomRsrcCtx, auditRef, dom2);
    meta = createDomainMetaObject("Tenant Domain2", null, false, false, "12346", null);
    zms.putDomainMeta(mockDomRsrcCtx, "signeddom2", auditRef, meta);
    meta = createDomainMetaObject("Tenant Domain2", null, false, false, "12346", null);
    zms.putDomainSystemMeta(mockDomRsrcCtx, "signeddom2", "account", auditRef, meta);
    DomainList domList = zms.getDomainList(mockDomRsrcCtx, null, null, null, null,
            null, null, null, null, null);
    List<String> domNames = domList.getNames();
    int numDoms = domNames.size();
    zms.privateKey = new ServerPrivateKey(Crypto.loadPrivateKey(Crypto.ybase64DecodeString(privKey)), "0");
    Authority principalAuthority = new com.yahoo.athenz.common.server.debug.DebugPrincipalAuthority();
    Principal sysPrincipal = principalAuthority.authenticate("v=U1;d=sys;n=zts;s=signature",
            "10.11.12.13", "GET", null);
    ResourceContext rsrcCtx = createResourceContext(sysPrincipal);
    Response response = zms.getSignedDomains(rsrcCtx, null, null, null, null, null);
    SignedDomains sdoms = (SignedDomains) response.getEntity();
    assertNotNull(sdoms);
    List<SignedDomain> list = sdoms.getDomains();
    assertNotNull(list);
    assertEquals(list.size(), numDoms);
    boolean dom1Found = false;
    boolean dom2Found = false;
    for (SignedDomain sDomain : list) {
        String signature = sDomain.getSignature();
        String keyId = sDomain.getKeyId();
        String publicKey = zms.getPublicKey("sys.auth", "zms", keyId);
        DomainData domainData = sDomain.getDomain();
        if (domainData.getName().equals("signeddom1")) {
            assertEquals("12345", domainData.getAccount());
            dom1Found = true;
        } else if (domainData.getName().equals("signeddom2")) {
            assertEquals("12346", domainData.getAccount());
            dom2Found = true;
        }
        assertTrue(Crypto.verify(SignUtils.asCanonicalString(sDomain.getDomain()), Crypto.loadPublicKey(publicKey), signature));
    }
    assertTrue(dom1Found);
    assertTrue(dom2Found);
    zms.privateKey = new ServerPrivateKey(Crypto.loadPrivateKey(Crypto.ybase64DecodeString(privKeyK1)), "1");
    response = zms.getSignedDomains(rsrcCtx, null, null, "all", null, null);
    sdoms = (SignedDomains) response.getEntity();
    assertNotNull(sdoms);
    list = sdoms.getDomains();
    assertNotNull(list);
    assertEquals(list.size(), numDoms);
    for(SignedDomain sDomain : list) {
        String signature = sDomain.getSignature();
        String keyId = sDomain.getKeyId();
        String publicKey = zms.getPublicKey("sys.auth", "zms", keyId);
        assertTrue(Crypto.verify(SignUtils.asCanonicalString(sDomain.getDomain()), Crypto.loadPublicKey(publicKey), signature));
        
        // we now need to verify the policy struct signature as well
        
        SignedPolicies signedPolicies = sDomain.getDomain().getPolicies();
        signature = signedPolicies.getSignature();
        assertTrue(Crypto.verify(SignUtils.asCanonicalString(signedPolicies.getContents()), Crypto.loadPublicKey(publicKey), signature));
    }
    zms.privateKey = new ServerPrivateKey(Crypto.loadPrivateKey(Crypto.ybase64DecodeString(privKeyK2)), "2");
    response = zms.getSignedDomains(rsrcCtx, null, null, null, Boolean.TRUE, null);
    sdoms = (SignedDomains) response.getEntity();
    assertNotNull(sdoms);
    list = sdoms.getDomains();
    assertNotNull(list);
    assertEquals(list.size(), numDoms);
    for(SignedDomain sDomain : list) {
        String signature = sDomain.getSignature();
        String keyId = sDomain.getKeyId();
        String publicKey = zms.getPublicKey("sys.auth", "zms", keyId);
        assertTrue(Crypto.verify(SignUtils.asCanonicalString(sDomain.getDomain()), Crypto.loadPublicKey(publicKey), signature));
    }
    // test metaonly=true
    //
    response = zms.getSignedDomains(rsrcCtx, null, "tRuE", null, Boolean.FALSE, null);
    sdoms = (SignedDomains) response.getEntity();
    assertNotNull(sdoms);
    list = sdoms.getDomains();
    assertNotNull(list);
    assertEquals(list.size(), numDoms);
    for (SignedDomain sDomain : list) {
        String signature = sDomain.getSignature();
        assertTrue(signature == null || signature.isEmpty());
        String keyId = sDomain.getKeyId();
        assertTrue(keyId == null || keyId.isEmpty());
        DomainData ddata = sDomain.getDomain();
        assertNotNull(ddata);
        assertFalse(ddata.getName().isEmpty());
        assertNotNull(ddata.getModified());
        assertNull(ddata.getPolicies());
        assertNull(ddata.getRoles());
        assertNull(ddata.getServices());
    }
    // test metaonly=garbage
    //
    response = zms.getSignedDomains(rsrcCtx, null, "garbage", null, null, null);
    sdoms = (SignedDomains) response.getEntity();
    assertNotNull(sdoms);
    list = sdoms.getDomains();
    assertNotNull(list);
    assertEquals(list.size(), numDoms);
    for (SignedDomain sDomain : list) {
        String signature = sDomain.getSignature();
        String keyId = sDomain.getKeyId();
        String publicKey = zms.getPublicKey("sys.auth", "zms", keyId);
        assertTrue(Crypto.verify(SignUtils.asCanonicalString(sDomain.getDomain()), Crypto.loadPublicKey(publicKey), signature));
        DomainData ddata = sDomain.getDomain();
        assertNotNull(ddata.getPolicies());
        assertTrue(ddata.getRoles() != null && ddata.getRoles().size() > 0);
        assertNotNull(ddata.getServices());
    }
    // test metaonly=false
    //
    response = zms.getSignedDomains(rsrcCtx, null, "fAlSe", null, null, null);
    sdoms = (SignedDomains) response.getEntity();
    assertNotNull(sdoms);
    list = sdoms.getDomains();
    assertNotNull(list);
    assertEquals(list.size(), numDoms);
    for (SignedDomain sDomain : list) {
        String signature = sDomain.getSignature();
        String keyId = sDomain.getKeyId();
        String publicKey = zms.getPublicKey("sys.auth", "zms", keyId);
        assertTrue(Crypto.verify(SignUtils.asCanonicalString(sDomain.getDomain()), Crypto.loadPublicKey(publicKey), signature));
        DomainData ddata = sDomain.getDomain();
        assertNotNull(ddata.getPolicies());
        assertTrue(ddata.getRoles() != null && ddata.getRoles().size() > 0);
        assertNotNull(ddata.getServices());
    }
    // test bad tag format
    //
    String eTag  = "I am not good";
    response = zms.getSignedDomains(rsrcCtx, null, null, null, Boolean.TRUE, eTag);
    sdoms = (SignedDomains) response.getEntity();
    String eTag2 = response.getHeaderString("ETag");
    assertNotNull(eTag2);
    assertNotEquals(eTag, eTag2);
    list = sdoms.getDomains();
    assertNotNull(list);
    assertEquals(list.size(), numDoms);
    ZMSUtils.threadSleep(1000);
    Policy policy1 = createPolicyObject("SignedDom1", "Policy1");
    zms.putPolicy(mockDomRsrcCtx, "SignedDom1", "Policy1", auditRef, policy1);
    response = zms.getSignedDomains(rsrcCtx, null, null, null, true, eTag2);
    sdoms = (SignedDomains) response.getEntity();
    eTag = response.getHeaderString("ETag");
    assertNotNull(eTag);
    assertNotEquals(eTag, eTag2);
    list = sdoms.getDomains();
    assertNotNull(list);
    assertEquals(1, list.size());
    response = zms.getSignedDomains(rsrcCtx, null, null, null, Boolean.TRUE, eTag);
    assertEquals(304, response.getStatus());
    eTag2 = response.getHeaderString("ETag");
    assertNotNull(eTag2);
    assertEquals(eTag, eTag2);
    zms.deleteTopLevelDomain(mockDomRsrcCtx, "SignedDom1", auditRef);
    zms.deleteTopLevelDomain(mockDomRsrcCtx, "SignedDom2", auditRef);
}