package com.intrbiz.bergamot.ui.api; import java.io.IOException; import java.security.PublicKey; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.sql.Timestamp; import java.util.Arrays; import java.util.List; import java.util.UUID; import com.intrbiz.balsa.engine.route.Router; import com.intrbiz.balsa.metadata.WithDataAdapter; import com.intrbiz.bergamot.crypto.util.CertificateRequest; import com.intrbiz.bergamot.crypto.util.PEMUtil; import com.intrbiz.bergamot.crypto.util.SerialNum; import com.intrbiz.bergamot.data.BergamotDB; import com.intrbiz.bergamot.metadata.IgnoreBinding; import com.intrbiz.bergamot.metadata.IsaObjectId; import com.intrbiz.bergamot.model.AgentRegistration; import com.intrbiz.bergamot.model.Contact; import com.intrbiz.bergamot.model.Site; import com.intrbiz.bergamot.ui.BergamotApp; import com.intrbiz.metadata.Any; import com.intrbiz.metadata.CheckStringLength; import com.intrbiz.metadata.JSON; import com.intrbiz.metadata.Param; import com.intrbiz.metadata.Prefix; import com.intrbiz.metadata.RequirePermission; import com.intrbiz.metadata.RequireValidPrincipal; import com.intrbiz.metadata.Var; @Prefix("/api/agent") @RequireValidPrincipal() @RequirePermission("api.sign.agent") @RequirePermission("sign.agent") public class AgentAPIRouter extends Router<BergamotApp> { /** * Sign an agent certificate request */ @Any("/sign-agent") @JSON @WithDataAdapter(BergamotDB.class) @IgnoreBinding public List<String> signAgent( BergamotDB db, @Var("site") Site site, @Param("certificate-request") @CheckStringLength(min = 1, max = 16384, mandatory = true) String certReq ) throws IOException { // parse the certificate request CertificateRequest req = PEMUtil.loadCertificateRequest(certReq); // is an agent already registered AgentRegistration existingAgent = db.getAgentRegistrationByName(site.getId(), req.getCommonName()); // assign the agent UUID UUID agentId = var("agentId", existingAgent != null ? existingAgent.getId() : Site.randomId(site.getId())); // get the Root CA Certificate Certificate rootCrt = action("get-root-ca"); // get the Site CA Certificate Certificate siteCrt = action("get-site-ca", site.getId()); // ok, actually sign the agent certificate Certificate agentCrt = action("sign-agent", site.getId(), agentId, req, ((Contact) currentPrincipal()).getId()); // store the registration db.setAgentRegistration(new AgentRegistration(site.getId(), agentId, req.getCommonName(), SerialNum.fromBigInt(((X509Certificate) agentCrt).getSerialNumber()).toString())); // return the certificate chain return Arrays.asList(new String[] { PEMUtil.saveCertificate(agentCrt), PEMUtil.saveCertificate(siteCrt), PEMUtil.saveCertificate(rootCrt), }); } /** * Sign an agent key */ @Any("/sign-agent-key") @JSON @WithDataAdapter(BergamotDB.class) @IgnoreBinding public List<String> signAgentKey( BergamotDB db, @Var("site") Site site, @Param("common-name") @CheckStringLength(min = 1, max = 255, mandatory = true) String commonName, @Param("public-key") @CheckStringLength(min = 1, max = 16384, mandatory = true) String publicKey ) throws IOException { // is an agent already registered AgentRegistration existingAgent = db.getAgentRegistrationByName(site.getId(), commonName); // decode the key PublicKey key = PEMUtil.loadPublicKey(publicKey); // assign the agent UUID UUID agentId = var("agentId", existingAgent != null ? existingAgent.getId() : Site.randomId(site.getId())); // get the Root CA Certificate Certificate rootCrt = action("get-root-ca"); // get the Site CA Certificate Certificate siteCrt = action("get-site-ca", site.getId()); // ok, actually sign the agent certificate Certificate agentCrt = action("sign-agent-key", site.getId(), agentId, commonName, key, ((Contact) currentPrincipal()).getId()); // store the registration db.setAgentRegistration(new AgentRegistration(site.getId(), agentId, commonName, SerialNum.fromBigInt(((X509Certificate) agentCrt).getSerialNumber()).toString())); // return the certificate chain return Arrays.asList(new String[] { PEMUtil.saveCertificate(agentCrt), PEMUtil.saveCertificate(siteCrt), PEMUtil.saveCertificate(rootCrt), }); } /** * Revoke an agent certificate */ @Any("/revoke-agent") @JSON @WithDataAdapter(BergamotDB.class) @IgnoreBinding public String revokeAgent(BergamotDB db, @Var("site") Site site, @Param("id") @IsaObjectId UUID agentId) throws IOException { AgentRegistration agent = notNull(db.getAgentRegistration(agentId), "No such agent: " + agentId); agent.setRevoked(true); agent.setRevokedOn(new Timestamp(System.currentTimeMillis())); db.setAgentRegistration(agent); return "revoked"; } }