Skip to content

Commit

Permalink
support fetching cert bundles from ZTS (AthenZ#843)
Browse files Browse the repository at this point in the history
  • Loading branch information
havetisyan authored Dec 7, 2019
1 parent 78df1ee commit b92bd87
Show file tree
Hide file tree
Showing 39 changed files with 1,475 additions and 65 deletions.
32 changes: 32 additions & 0 deletions clients/go/zts/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,38 @@ func (client ZTSClient) DeleteInstanceIdentity(provider ServiceName, domain Doma
}
}

func (client ZTSClient) GetCertificateAuthorityBundle(name SimpleName) (*CertificateAuthorityBundle, error) {
var data *CertificateAuthorityBundle
url := client.URL + "/cacerts/" + fmt.Sprint(name)
resp, err := client.httpGet(url, nil)
if err != nil {
return data, err
}
defer resp.Body.Close()
switch resp.StatusCode {
case 200:
err = json.NewDecoder(resp.Body).Decode(&data)
if err != nil {
return data, err
}
return data, nil
default:
var errobj rdl.ResourceError
contentBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return data, err
}
json.Unmarshal(contentBytes, &errobj)
if errobj.Code == 0 {
errobj.Code = resp.StatusCode
}
if errobj.Message == "" {
errobj.Message = string(contentBytes)
}
return data, errobj
}
}

func (client ZTSClient) PostDomainMetrics(domainName DomainName, req *DomainMetrics) (*DomainMetrics, error) {
var data *DomainMetrics
url := client.URL + "/metrics/" + fmt.Sprint(domainName)
Expand Down
68 changes: 68 additions & 0 deletions clients/go/zts/model.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions clients/go/zts/zts_schema.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,9 @@ public void setZTSRDLGeneratedClient(ZTSRDLGeneratedClient client) {
* @param privateKeyFile path to the private key file
* @param monitorKeyCertUpdates boolean flag whether or not monitor file updates
* @return SSLContext object
* @throws InterruptedException
* @throws KeyRefresherException
* @throws IOException
*/
public SSLContext createSSLContext(final String trustStorePath, final char[] trustStorePassword,
final String publicCertFile, final String privateKeyFile, boolean monitorKeyCertUpdates)
Expand Down Expand Up @@ -2551,6 +2554,22 @@ public void deleteInstanceIdentity(String provider, String domain,
}
}

/**
* Retrieve list of CA Certificates in PEM format for the given bundle name
* @param bundleName name of the CA Certificate bundle name
* @return CA Certificate bundle including list of CA certificates on success. ZTSClientException will be thrown in case of failure
*/
public CertificateAuthorityBundle getCertificateAuthorityBundle(String bundleName) {
updateServicePrincipal();
try {
return ztsClient.getCertificateAuthorityBundle(bundleName);
} catch (ResourceException ex) {
throw new ZTSClientException(ex.getCode(), ex.getData());
} catch (Exception ex) {
throw new ZTSClientException(ZTSClientException.BAD_REQUEST, ex.getMessage());
}
}

static class ClientKeyRefresherListener implements KeyRefresherListener {

long lastCertRefreshTime = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,25 @@ public InstanceIdentity deleteInstanceIdentity(String provider, String domain, S

}

public CertificateAuthorityBundle getCertificateAuthorityBundle(String name) {
WebTarget target = base.path("/cacerts/{name}")
.resolveTemplate("name", name);
Invocation.Builder invocationBuilder = target.request("application/json");
if (credsHeader != null) {
invocationBuilder = credsHeader.startsWith("Cookie.") ? invocationBuilder.cookie(credsHeader.substring(7),
credsToken) : invocationBuilder.header(credsHeader, credsToken);
}
Response response = invocationBuilder.get();
int code = response.getStatus();
switch (code) {
case 200:
return response.readEntity(CertificateAuthorityBundle.class);
default:
throw new ResourceException(code, response.readEntity(ResourceError.class));
}

}

public DomainMetrics postDomainMetrics(String domainName, DomainMetrics req) {
WebTarget target = base.path("/metrics/{domainName}")
.resolveTemplate("domainName", domainName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3185,4 +3185,36 @@ public void testPrefetchAccessTokenShouldNotCallServer() throws Exception {
ZTSClient.cancelPrefetch();
client.close();
}

@Test
public void testGetCertificateAuthorityBundle() {

Principal principal = SimplePrincipal.create("user_domain", "user",
"auth_creds", PRINCIPAL_AUTHORITY);

ZTSRDLClientMock ztsClientMock = new ZTSRDLClientMock();
ZTSClient client = new ZTSClient("http://localhost:4080", principal);
client.setZTSRDLGeneratedClient(ztsClientMock);

CertificateAuthorityBundle bundle = client.getCertificateAuthorityBundle("athenz");
assertNotNull(bundle);
assertEquals(bundle.getName(), "athenz");
assertEquals(bundle.getCerts(), "certs");

try {
client.getCertificateAuthorityBundle("exc");
fail();
} catch (ZTSClientException ex) {
assertEquals(ex.getCode(), 400);
}

try {
client.getCertificateAuthorityBundle("system");
fail();
} catch (ZTSClientException ex) {
assertEquals(ex.getCode(), 404);
}

client.close();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package com.yahoo.athenz.zts;

import java.util.*;

import com.yahoo.rdl.Timestamp;

public class ZTSRDLClientMock extends ZTSRDLGeneratedClient implements java.io.Closeable {
Expand Down Expand Up @@ -449,4 +448,18 @@ public DomainMetrics postDomainMetrics(String domainName, DomainMetrics req) {
}
return null;
}

@Override
public CertificateAuthorityBundle getCertificateAuthorityBundle(String bundleName) {
if (bundleName.equals("exc")) {
throw new NullPointerException("Invalid request");
}
if (bundleName.equals("system")) {
throw new ResourceException(404, "Unknown bundle name");
}
CertificateAuthorityBundle bundle = new CertificateAuthorityBundle();
bundle.setName(bundleName);
bundle.setCerts("certs");
return bundle;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// This file generated by rdl 1.5.2. Do not modify!
//

package com.yahoo.athenz.zts;
import com.yahoo.rdl.*;

//
// CertificateAuthorityBundle -
//
public class CertificateAuthorityBundle {
public String name;
public String certs;

public CertificateAuthorityBundle setName(String name) {
this.name = name;
return this;
}
public String getName() {
return name;
}
public CertificateAuthorityBundle setCerts(String certs) {
this.certs = certs;
return this;
}
public String getCerts() {
return certs;
}

@Override
public boolean equals(Object another) {
if (this != another) {
if (another == null || another.getClass() != CertificateAuthorityBundle.class) {
return false;
}
CertificateAuthorityBundle a = (CertificateAuthorityBundle) another;
if (name == null ? a.name != null : !name.equals(a.name)) {
return false;
}
if (certs == null ? a.certs != null : !certs.equals(a.certs)) {
return false;
}
}
return true;
}
}
15 changes: 15 additions & 0 deletions core/zts/src/main/java/com/yahoo/athenz/zts/ZTSSchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,10 @@ private static Schema build() {
.field("serviceToken", "SignedToken", true, "service token instead of TLS certificate")
.mapField("attributes", "String", "String", true, "other config-like attributes determined at boot time");

sb.structType("CertificateAuthorityBundle")
.field("name", "SimpleName", false, "name of the bundle")
.field("certs", "String", false, "set of certificates included in the bundle");

sb.enumType("DomainMetricType")
.comment("zpe metric attributes")
.element("ACCESS_ALLOWED")
Expand Down Expand Up @@ -621,6 +625,17 @@ private static Schema build() {
.exception("UNAUTHORIZED", "ResourceError", "")
;

sb.resource("CertificateAuthorityBundle", "GET", "/cacerts/{name}")
.pathParam("name", "SimpleName", "name of the CA cert bundle")
.auth("", "", true)
.expected("OK")
.exception("BAD_REQUEST", "ResourceError", "")

.exception("NOT_FOUND", "ResourceError", "")

.exception("UNAUTHORIZED", "ResourceError", "")
;

sb.resource("DomainMetrics", "POST", "/metrics/{domainName}")
.comment("called to post multiple zpe related metric attributes")
.pathParam("domainName", "DomainName", "name of the domain the metrics pertain to")
Expand Down
16 changes: 16 additions & 0 deletions core/zts/src/main/rdl/Instance.rdli
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,19 @@ resource InstanceIdentity DELETE "/instance/{provider}/{domain}/{service}/{insta
ResourceError INTERNAL_SERVER_ERROR;
}
}

type CertificateAuthorityBundle Struct {
SimpleName name; //name of the bundle
String certs; //set of certificates included in the bundle
}

resource CertificateAuthorityBundle GET "/cacerts/{name}" {
SimpleName name; //name of the CA cert bundle
authenticate;
expected OK;
exceptions {
ResourceError BAD_REQUEST;
ResourceError UNAUTHORIZED;
ResourceError NOT_FOUND;
}
}
Loading

0 comments on commit b92bd87

Please sign in to comment.