| .. | .. |
|---|
| 1 | 1 | package net.curisit.securis.services; |
|---|
| 2 | 2 | |
|---|
| 3 | +import java.io.File; |
|---|
| 4 | +import java.io.IOException; |
|---|
| 5 | +import java.util.Date; |
|---|
| 6 | +import java.util.List; |
|---|
| 7 | +import java.util.Map; |
|---|
| 8 | +import java.util.TreeMap; |
|---|
| 9 | + |
|---|
| 3 | 10 | import javax.inject.Inject; |
|---|
| 4 | 11 | import javax.inject.Provider; |
|---|
| 5 | 12 | import javax.persistence.EntityManager; |
|---|
| 13 | +import javax.ws.rs.Consumes; |
|---|
| 6 | 14 | import javax.ws.rs.GET; |
|---|
| 15 | +import javax.ws.rs.POST; |
|---|
| 7 | 16 | import javax.ws.rs.Path; |
|---|
| 8 | 17 | import javax.ws.rs.Produces; |
|---|
| 18 | +import javax.ws.rs.core.Context; |
|---|
| 9 | 19 | import javax.ws.rs.core.MediaType; |
|---|
| 10 | 20 | import javax.ws.rs.core.Response; |
|---|
| 11 | 21 | |
|---|
| 22 | +import net.curisit.integrity.commons.JsonUtils; |
|---|
| 23 | +import net.curisit.integrity.commons.Utils; |
|---|
| 24 | +import net.curisit.securis.LicenseGenerator; |
|---|
| 25 | +import net.curisit.securis.SeCurisException; |
|---|
| 26 | +import net.curisit.securis.beans.LicenseBean; |
|---|
| 27 | +import net.curisit.securis.beans.RequestBean; |
|---|
| 28 | +import net.curisit.securis.beans.SignedLicenseBean; |
|---|
| 29 | +import net.curisit.securis.db.License; |
|---|
| 30 | +import net.curisit.securis.db.LicenseType; |
|---|
| 31 | +import net.curisit.securis.db.Pack; |
|---|
| 32 | +import net.curisit.securis.security.BasicSecurityContext; |
|---|
| 33 | +import net.curisit.securis.security.Securable; |
|---|
| 34 | +import net.curisit.securis.services.exception.SeCurisServiceException; |
|---|
| 35 | +import net.curisit.securis.services.exception.SeCurisServiceException.ErrorCodes; |
|---|
| 12 | 36 | import net.curisit.securis.utils.TokenHelper; |
|---|
| 13 | 37 | |
|---|
| 38 | +import org.apache.commons.io.IOUtils; |
|---|
| 39 | +import org.apache.commons.lang.time.DateUtils; |
|---|
| 14 | 40 | import org.apache.logging.log4j.LogManager; |
|---|
| 15 | 41 | import org.apache.logging.log4j.Logger; |
|---|
| 42 | +import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput; |
|---|
| 43 | + |
|---|
| 44 | +import com.google.inject.persist.Transactional; |
|---|
| 16 | 45 | |
|---|
| 17 | 46 | /** |
|---|
| 18 | 47 | * External API to be accessed by third parties |
|---|
| .. | .. |
|---|
| 31 | 60 | @Inject |
|---|
| 32 | 61 | Provider<EntityManager> emProvider; |
|---|
| 33 | 62 | |
|---|
| 63 | + @Inject |
|---|
| 64 | + LicenseGenerator licenseGenerator; |
|---|
| 65 | + |
|---|
| 34 | 66 | public ApiResource() { |
|---|
| 35 | 67 | } |
|---|
| 36 | 68 | |
|---|
| .. | .. |
|---|
| 47 | 79 | return Response.ok("SeCuris API").build(); |
|---|
| 48 | 80 | } |
|---|
| 49 | 81 | |
|---|
| 82 | + |
|---|
| 83 | + /** |
|---|
| 84 | + * Request a new license file based in a RequestBean object sent as parameter |
|---|
| 85 | + * @param mpfdi |
|---|
| 86 | + * @param bsc |
|---|
| 87 | + * @return |
|---|
| 88 | + * @throws IOException |
|---|
| 89 | + * @throws SeCurisServiceException |
|---|
| 90 | + */ |
|---|
| 91 | + @POST |
|---|
| 92 | + @Path("/request") |
|---|
| 93 | + @Consumes(MediaType.APPLICATION_JSON) |
|---|
| 94 | + //TODO: Enable this: @Securable |
|---|
| 95 | + @Produces({ |
|---|
| 96 | + MediaType.APPLICATION_JSON |
|---|
| 97 | + }) |
|---|
| 98 | + @Transactional |
|---|
| 99 | + public Response createFromRequest(RequestBean request, @Context BasicSecurityContext bsc) throws IOException, SeCurisServiceException, SeCurisException { |
|---|
| 100 | + LOG.info("Request to get license: {}", request); |
|---|
| 101 | + |
|---|
| 102 | + Map<String, Object> metadata = getLicenseMetadata(request); |
|---|
| 103 | + License licDB = getLicenseData(request); |
|---|
| 104 | + |
|---|
| 105 | + Date expirationDate = licDB.getExpirationDate(); |
|---|
| 106 | + String licenseTypeCode = licDB.getPack().getLicenseType().getCode(); |
|---|
| 107 | + String licenseCode = licDB.getCode(); |
|---|
| 108 | + LicenseBean lic = licenseGenerator.generateLicense(request, metadata, expirationDate, licenseTypeCode, licenseCode); |
|---|
| 109 | + SignedLicenseBean signedLic = new SignedLicenseBean(lic); |
|---|
| 110 | + return Response.ok(signedLic).build(); |
|---|
| 111 | + } |
|---|
| 112 | + |
|---|
| 113 | + /** |
|---|
| 114 | + * Returns a License file in JSON format from an uploaded Request file |
|---|
| 115 | + * @param mpfdi |
|---|
| 116 | + * @param bsc |
|---|
| 117 | + * @return |
|---|
| 118 | + * @throws IOException |
|---|
| 119 | + * @throws SeCurisServiceException |
|---|
| 120 | + * @throws SeCurisException |
|---|
| 121 | + */ |
|---|
| 122 | + @POST |
|---|
| 123 | + @Path("/request") |
|---|
| 124 | + @Consumes(MediaType.MULTIPART_FORM_DATA) |
|---|
| 125 | + @Securable |
|---|
| 126 | + @Produces({ |
|---|
| 127 | + MediaType.APPLICATION_JSON |
|---|
| 128 | + }) |
|---|
| 129 | + @Transactional |
|---|
| 130 | + @SuppressWarnings("unchecked") |
|---|
| 131 | + public Response createFromRequestFile(MultipartFormDataInput mpfdi, @Context BasicSecurityContext bsc) throws IOException, SeCurisServiceException, SeCurisException { |
|---|
| 132 | + RequestBean req = new RequestBean(); |
|---|
| 133 | + req.setAppCode(mpfdi.getFormDataPart("appCode", String.class, null)); |
|---|
| 134 | + req.setArch(mpfdi.getFormDataPart("arch", String.class, null)); |
|---|
| 135 | + req.setCrcLogo(mpfdi.getFormDataPart("crcLogo", String.class, null)); |
|---|
| 136 | + req.setCustomerCode(mpfdi.getFormDataPart("customerCode", String.class, null)); |
|---|
| 137 | + req.setMacAddresses(mpfdi.getFormDataPart("macAddresses", List.class, null)); |
|---|
| 138 | + req.setOsName(mpfdi.getFormDataPart("osName", String.class, null)); |
|---|
| 139 | + |
|---|
| 140 | + return createFromRequest(req, bsc); |
|---|
| 141 | + } |
|---|
| 142 | + |
|---|
| 143 | + /** |
|---|
| 144 | + * Create a new License file based in a previous one |
|---|
| 145 | + * |
|---|
| 146 | + * @param request |
|---|
| 147 | + * @param bsc |
|---|
| 148 | + * @return |
|---|
| 149 | + * @throws IOException |
|---|
| 150 | + * @throws SeCurisServiceException |
|---|
| 151 | + * @throws SeCurisException |
|---|
| 152 | + */ |
|---|
| 153 | + @POST |
|---|
| 154 | + @Path("/renew") |
|---|
| 155 | + @Consumes(MediaType.APPLICATION_JSON) |
|---|
| 156 | + //TODO: Enable this: @Securable |
|---|
| 157 | + @Produces({ |
|---|
| 158 | + MediaType.APPLICATION_JSON |
|---|
| 159 | + }) |
|---|
| 160 | + @Transactional |
|---|
| 161 | + public Response renewFromPreviousLicense(LicenseBean previousLic, @Context BasicSecurityContext bsc) throws IOException, SeCurisServiceException, SeCurisException { |
|---|
| 162 | + LOG.info("Renew license: {}", previousLic); |
|---|
| 163 | + |
|---|
| 164 | + if (previousLic.getExpirationDate().after(DateUtils.addMonths(new Date(), 1))) { |
|---|
| 165 | + throw new SeCurisServiceException(ErrorCodes.LICENSE_NOT_READY_FOR_RENEW, "The license is still valid, not ready for renew"); |
|---|
| 166 | + } |
|---|
| 167 | + |
|---|
| 168 | + Map<String, Object> metadata = getLicenseMetadata(previousLic); |
|---|
| 169 | + License licDB = getLicenseData(previousLic); |
|---|
| 170 | + |
|---|
| 171 | + Date expirationDate = licDB.getExpirationDate(); |
|---|
| 172 | + String licenseTypeCode = licDB.getPack().getLicenseType().getCode(); |
|---|
| 173 | + String licenseCode = licDB.getCode(); |
|---|
| 174 | + LicenseBean lic = licenseGenerator.generateLicense(previousLic, metadata, expirationDate, licenseTypeCode, licenseCode); |
|---|
| 175 | + return Response.ok(lic).build(); |
|---|
| 176 | + } |
|---|
| 177 | + |
|---|
| 178 | + /** |
|---|
| 179 | + * Returns a new License file in JSON format based in a previous license |
|---|
| 180 | + * @param mpfdi |
|---|
| 181 | + * @param bsc |
|---|
| 182 | + * @return |
|---|
| 183 | + * @throws IOException |
|---|
| 184 | + * @throws SeCurisServiceException |
|---|
| 185 | + * @throws SeCurisException |
|---|
| 186 | + */ |
|---|
| 187 | + @POST |
|---|
| 188 | + @Path("/renew") |
|---|
| 189 | + @Consumes(MediaType.MULTIPART_FORM_DATA) |
|---|
| 190 | + @Securable |
|---|
| 191 | + @Produces({ |
|---|
| 192 | + MediaType.APPLICATION_JSON |
|---|
| 193 | + }) |
|---|
| 194 | + @Transactional |
|---|
| 195 | + @SuppressWarnings("unchecked") |
|---|
| 196 | + public Response renewFromLicenseFile(MultipartFormDataInput mpfdi, @Context BasicSecurityContext bsc) throws IOException, SeCurisServiceException, SeCurisException { |
|---|
| 197 | + LicenseBean lic = new LicenseBean(); |
|---|
| 198 | + // TODO: Add more license parameters |
|---|
| 199 | + lic.setAppCode(mpfdi.getFormDataPart("appCode", String.class, null)); |
|---|
| 200 | + lic.setArch(mpfdi.getFormDataPart("arch", String.class, null)); |
|---|
| 201 | + lic.setCrcLogo(mpfdi.getFormDataPart("crcLogo", String.class, null)); |
|---|
| 202 | + lic.setCustomerCode(mpfdi.getFormDataPart("customerCode", String.class, null)); |
|---|
| 203 | + lic.setMacAddresses(mpfdi.getFormDataPart("macAddresses", List.class, null)); |
|---|
| 204 | + lic.setOsName(mpfdi.getFormDataPart("osName", String.class, null)); |
|---|
| 205 | + lic.setExpirationDate(mpfdi.getFormDataPart("expirationDate", Date.class, null)); |
|---|
| 206 | + LOG.info("Lic expires at: {}", lic.getExpirationDate()); |
|---|
| 207 | + if (lic.getExpirationDate().after(DateUtils.addMonths(new Date(), 1))) { |
|---|
| 208 | + throw new SeCurisServiceException(ErrorCodes.LICENSE_NOT_READY_FOR_RENEW, "The license is still valid, not ready for renew"); |
|---|
| 209 | + } |
|---|
| 210 | + |
|---|
| 211 | + return createFromRequest(lic, bsc); |
|---|
| 212 | + } |
|---|
| 213 | + |
|---|
| 214 | + |
|---|
| 215 | + |
|---|
| 216 | + private License getLicenseData(RequestBean req) throws SeCurisException { |
|---|
| 217 | + // TODO: The dummy expiration date is temporal, this info should be read from DB |
|---|
| 218 | + License lic = new License(); |
|---|
| 219 | + lic.setExpirationDate(new Date(new Date().getTime() + (1000L * 3600 * 24 * 365 * 10))); |
|---|
| 220 | + lic.setCode(req.getAppCode() + "-LIC-INTERNAL"); |
|---|
| 221 | + LicenseType lt = new LicenseType(); |
|---|
| 222 | + lt.setCode("TYPE-" + req.getAppCode()); |
|---|
| 223 | + Pack pack = new Pack(); |
|---|
| 224 | + pack.setLicenseType(lt); |
|---|
| 225 | + lic.setPack(pack); |
|---|
| 226 | + return lic; |
|---|
| 227 | + } |
|---|
| 228 | + |
|---|
| 229 | + /** |
|---|
| 230 | + * Extract the corresponding metadata for the Request license given |
|---|
| 231 | + * @param req |
|---|
| 232 | + * @return |
|---|
| 233 | + * @throws SeCurisException |
|---|
| 234 | + */ |
|---|
| 235 | + @SuppressWarnings("unchecked") |
|---|
| 236 | + private Map<String, Object> getLicenseMetadata(RequestBean req) throws SeCurisException { |
|---|
| 237 | + // TODO: The dummy metadata file is temporal, this info should be read from DB |
|---|
| 238 | + File dummyMetadata = new File(System.getProperty("user.home") + File.separator + ".SeCuris" + File.separator + "dummy_metadata.json"); |
|---|
| 239 | + Map<String, Object> metadata = null; |
|---|
| 240 | + try { |
|---|
| 241 | + String metadataJson = IOUtils.toString(dummyMetadata.toURI()); |
|---|
| 242 | + metadata = (Map<String, Object>)JsonUtils.json2map(metadataJson).get(req.getAppCode()); |
|---|
| 243 | + if (metadata == null) |
|---|
| 244 | + throw new SeCurisException("App code in request is unknown: " + req.getAppCode()); |
|---|
| 245 | + metadata = new TreeMap<>(metadata); |
|---|
| 246 | + } catch (IOException e) { |
|---|
| 247 | + LOG.error("Error reading dummy metadata file", e); |
|---|
| 248 | + throw new SeCurisException("Error reading dummy metadata file"); |
|---|
| 249 | + } |
|---|
| 250 | + |
|---|
| 251 | + return metadata; |
|---|
| 252 | + } |
|---|
| 253 | + |
|---|
| 254 | + |
|---|
| 50 | 255 | } |
|---|