package net.curisit.securis.services; import java.io.File; import java.io.IOException; import java.util.Date; import java.util.List; import java.util.Map; import java.util.TreeMap; import javax.inject.Inject; import javax.inject.Provider; import javax.persistence.EntityManager; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import net.curisit.integrity.commons.JsonUtils; import net.curisit.integrity.commons.Utils; import net.curisit.securis.LicenseGenerator; import net.curisit.securis.SeCurisException; import net.curisit.securis.beans.LicenseBean; import net.curisit.securis.beans.RequestBean; import net.curisit.securis.beans.SignedLicenseBean; import net.curisit.securis.db.License; import net.curisit.securis.db.LicenseType; import net.curisit.securis.db.Pack; import net.curisit.securis.security.BasicSecurityContext; import net.curisit.securis.security.Securable; import net.curisit.securis.services.exception.SeCurisServiceException; import net.curisit.securis.services.exception.SeCurisServiceException.ErrorCodes; import net.curisit.securis.utils.TokenHelper; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.time.DateUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput; import com.google.inject.persist.Transactional; /** * External API to be accessed by third parties * * @author roberto */ @Path("/api") public class ApiResource { @SuppressWarnings("unused") private static final Logger LOG = LogManager.getLogger(ApiResource.class); @Inject TokenHelper tokenHelper; @Inject Provider emProvider; @Inject LicenseGenerator licenseGenerator; public ApiResource() { } /** * * @return Simple text message to check API status */ @GET @Path("/") @Produces({ MediaType.TEXT_PLAIN }) public Response index() { return Response.ok("SeCuris API").build(); } /** * Request a new license file based in a RequestBean object sent as parameter * @param mpfdi * @param bsc * @return * @throws IOException * @throws SeCurisServiceException */ @POST @Path("/request") @Consumes(MediaType.APPLICATION_JSON) //TODO: Enable this: @Securable @Produces({ MediaType.APPLICATION_JSON }) @Transactional public Response createFromRequest(RequestBean request, @Context BasicSecurityContext bsc) throws IOException, SeCurisServiceException, SeCurisException { LOG.info("Request to get license: {}", request); Map metadata = getLicenseMetadata(request); License licDB = getLicenseData(request); Date expirationDate = licDB.getExpirationDate(); String licenseTypeCode = licDB.getPack().getLicenseType().getCode(); String licenseCode = licDB.getCode(); LicenseBean lic = licenseGenerator.generateLicense(request, metadata, expirationDate, licenseTypeCode, licenseCode); SignedLicenseBean signedLic = new SignedLicenseBean(lic); return Response.ok(signedLic).build(); } /** * Returns a License file in JSON format from an uploaded Request file * @param mpfdi * @param bsc * @return * @throws IOException * @throws SeCurisServiceException * @throws SeCurisException */ @POST @Path("/request") @Consumes(MediaType.MULTIPART_FORM_DATA) @Securable @Produces({ MediaType.APPLICATION_JSON }) @Transactional @SuppressWarnings("unchecked") public Response createFromRequestFile(MultipartFormDataInput mpfdi, @Context BasicSecurityContext bsc) throws IOException, SeCurisServiceException, SeCurisException { RequestBean req = new RequestBean(); req.setAppCode(mpfdi.getFormDataPart("appCode", String.class, null)); req.setArch(mpfdi.getFormDataPart("arch", String.class, null)); req.setCrcLogo(mpfdi.getFormDataPart("crcLogo", String.class, null)); req.setCustomerCode(mpfdi.getFormDataPart("customerCode", String.class, null)); req.setMacAddresses(mpfdi.getFormDataPart("macAddresses", List.class, null)); req.setOsName(mpfdi.getFormDataPart("osName", String.class, null)); return createFromRequest(req, bsc); } /** * Create a new License file based in a previous one * * @param request * @param bsc * @return * @throws IOException * @throws SeCurisServiceException * @throws SeCurisException */ @POST @Path("/renew") @Consumes(MediaType.APPLICATION_JSON) //TODO: Enable this: @Securable @Produces({ MediaType.APPLICATION_JSON }) @Transactional public Response renewFromPreviousLicense(LicenseBean previousLic, @Context BasicSecurityContext bsc) throws IOException, SeCurisServiceException, SeCurisException { LOG.info("Renew license: {}", previousLic); if (previousLic.getExpirationDate().after(DateUtils.addMonths(new Date(), 1))) { throw new SeCurisServiceException(ErrorCodes.LICENSE_NOT_READY_FOR_RENEW, "The license is still valid, not ready for renew"); } Map metadata = getLicenseMetadata(previousLic); License licDB = getLicenseData(previousLic); Date expirationDate = licDB.getExpirationDate(); String licenseTypeCode = licDB.getPack().getLicenseType().getCode(); String licenseCode = licDB.getCode(); LicenseBean lic = licenseGenerator.generateLicense(previousLic, metadata, expirationDate, licenseTypeCode, licenseCode); return Response.ok(lic).build(); } /** * Returns a new License file in JSON format based in a previous license * @param mpfdi * @param bsc * @return * @throws IOException * @throws SeCurisServiceException * @throws SeCurisException */ @POST @Path("/renew") @Consumes(MediaType.MULTIPART_FORM_DATA) @Securable @Produces({ MediaType.APPLICATION_JSON }) @Transactional @SuppressWarnings("unchecked") public Response renewFromLicenseFile(MultipartFormDataInput mpfdi, @Context BasicSecurityContext bsc) throws IOException, SeCurisServiceException, SeCurisException { LicenseBean lic = new LicenseBean(); // TODO: Add more license parameters lic.setAppCode(mpfdi.getFormDataPart("appCode", String.class, null)); lic.setArch(mpfdi.getFormDataPart("arch", String.class, null)); lic.setCrcLogo(mpfdi.getFormDataPart("crcLogo", String.class, null)); lic.setCustomerCode(mpfdi.getFormDataPart("customerCode", String.class, null)); lic.setMacAddresses(mpfdi.getFormDataPart("macAddresses", List.class, null)); lic.setOsName(mpfdi.getFormDataPart("osName", String.class, null)); lic.setExpirationDate(mpfdi.getFormDataPart("expirationDate", Date.class, null)); LOG.info("Lic expires at: {}", lic.getExpirationDate()); if (lic.getExpirationDate().after(DateUtils.addMonths(new Date(), 1))) { throw new SeCurisServiceException(ErrorCodes.LICENSE_NOT_READY_FOR_RENEW, "The license is still valid, not ready for renew"); } return createFromRequest(lic, bsc); } private License getLicenseData(RequestBean req) throws SeCurisException { // TODO: The dummy expiration date is temporal, this info should be read from DB License lic = new License(); lic.setExpirationDate(new Date(new Date().getTime() + (1000L * 3600 * 24 * 365 * 10))); lic.setCode(req.getAppCode() + "-LIC-INTERNAL"); LicenseType lt = new LicenseType(); lt.setCode("TYPE-" + req.getAppCode()); Pack pack = new Pack(); pack.setLicenseType(lt); lic.setPack(pack); return lic; } /** * Extract the corresponding metadata for the Request license given * @param req * @return * @throws SeCurisException */ @SuppressWarnings("unchecked") private Map getLicenseMetadata(RequestBean req) throws SeCurisException { // TODO: The dummy metadata file is temporal, this info should be read from DB File dummyMetadata = new File(System.getProperty("user.home") + File.separator + ".SeCuris" + File.separator + "dummy_metadata.json"); Map metadata = null; try { String metadataJson = IOUtils.toString(dummyMetadata.toURI()); metadata = (Map)JsonUtils.json2map(metadataJson).get(req.getAppCode()); if (metadata == null) throw new SeCurisException("App code in request is unknown: " + req.getAppCode()); metadata = new TreeMap<>(metadata); } catch (IOException e) { LOG.error("Error reading dummy metadata file", e); throw new SeCurisException("Error reading dummy metadata file"); } return metadata; } }