From ddec2c5c7b7842536d6d705c2de20f96e16c8aa8 Mon Sep 17 00:00:00 2001
From: rsanchez <rsanchez@curisit.net>
Date: Wed, 22 Oct 2014 17:38:57 +0000
Subject: [PATCH] #2021 feature - Added blocked request table and refactoring License actions
---
securis/src/main/java/net/curisit/securis/services/LicenseResource.java | 227 ++++++++++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 201 insertions(+), 26 deletions(-)
diff --git a/securis/src/main/java/net/curisit/securis/services/LicenseResource.java b/securis/src/main/java/net/curisit/securis/services/LicenseResource.java
index 4032651..2930626 100644
--- a/securis/src/main/java/net/curisit/securis/services/LicenseResource.java
+++ b/securis/src/main/java/net/curisit/securis/services/LicenseResource.java
@@ -1,11 +1,15 @@
package net.curisit.securis.services;
import java.io.File;
+import java.io.FileWriter;
import java.io.IOException;
+import java.nio.file.Files;
+import java.text.MessageFormat;
import java.util.Date;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.TreeMap;
+import java.util.Set;
import javax.inject.Inject;
import javax.inject.Provider;
@@ -13,6 +17,8 @@
import javax.persistence.TypedQuery;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
@@ -27,16 +33,26 @@
import net.curisit.integrity.commons.JsonUtils;
import net.curisit.integrity.commons.Utils;
+import net.curisit.integrity.exception.CurisException;
import net.curisit.securis.DefaultExceptionHandler;
+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.Application;
import net.curisit.securis.db.License;
import net.curisit.securis.db.LicenseHistory;
+import net.curisit.securis.db.LicenseStatus;
import net.curisit.securis.db.Pack;
+import net.curisit.securis.db.PackMetadata;
import net.curisit.securis.db.User;
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.EmailManager;
+import net.curisit.securis.utils.Params;
import net.curisit.securis.utils.TokenHelper;
import org.apache.commons.io.IOUtils;
@@ -60,7 +76,13 @@
TokenHelper tokenHelper;
@Inject
+ EmailManager emailManager;
+
+ @Inject
Provider<EntityManager> emProvider;
+
+ @Inject
+ LicenseGenerator licenseGenerator;
/**
*
@@ -138,11 +160,16 @@
LOG.error("License with id {} is not active, so It can not downloaded", licId, bsc.getUserPrincipal());
throw new SeCurisServiceException(Status.FORBIDDEN.getStatusCode(), "License is not active, so It can not be downloaded");
}
- return Response.ok(lic.getLicenseData()).build();
+ em.persist(createLicenseHistoryAction(lic, getUser(bsc, em), LicenseHistory.Actions.DOWNLOAD));
+ return Response
+ .ok(lic.getLicenseData())
+ .header("Content-Disposition",
+ String.format("attachment; filename=\"%s\"", lic.getPack().getLicenseType().getApplication().getLicenseFilename())).build();
}
/**
* Activate the given license
+ *
* @param licId
* @param bsc
* @return
@@ -168,8 +195,9 @@
+ " can not be activated from the current license status");
}
- lic.setStatus(License.Status.ACTIVE);
+ lic.setStatus(LicenseStatus.ACTIVE);
lic.setModificationTimestamp(new Date());
+
em.persist(lic);
User user = getUser(bsc.getUserPrincipal().getName(), em);
em.persist(createLicenseHistoryAction(lic, user, LicenseHistory.Actions.ACTIVATE));
@@ -178,6 +206,7 @@
/**
* Send license file by email to the organization
+ *
* @param licId
* @param bsc
* @return
@@ -192,13 +221,34 @@
@Produces({
MediaType.APPLICATION_JSON
})
- public Response send(@PathParam("licId") Integer licId, @Context BasicSecurityContext bsc) throws SeCurisServiceException {
+ public Response send(@PathParam("licId") Integer licId, @DefaultValue("false") @FormParam("add_cc") Boolean addCC,
+ @Context BasicSecurityContext bsc) throws SeCurisServiceException, SeCurisException {
EntityManager em = emProvider.get();
License lic = getCurrentLicense(licId, bsc, em);
+ Application app = lic.getPack().getLicenseType().getApplication();
+ File licFile = null;
+ if (lic.getLicenseData() == null) {
+ throw new SeCurisServiceException(Status.NOT_FOUND.getStatusCode(), "There is no license file available");
+ }
User user = getUser(bsc.getUserPrincipal().getName(), em);
- // TODO: Send mail with lic file
+ try {
+ String subject = MessageFormat.format(Params.get(Params.KEYS.EMAIL_LIC_DEFAULT_SUBJECT), lic.getPack().getAppName());
+ String email_tpl = IOUtils.toString(this.getClass().getResourceAsStream("/lic_email_template.en"));
+ String body = MessageFormat.format(email_tpl, lic.getFullName(), app.getName());
+ licFile = createTemporaryLicenseFile(lic, app.getLicenseFilename());
+
+ emailManager.sendEmail(subject, body, lic.getEmail(), addCC ? user.getEmail() : null, licFile);
+ } catch (IOException e) {
+ LOG.error("Error creating temporary license file", e);
+ throw new SeCurisServiceException(Status.NOT_FOUND.getStatusCode(), "There is no license file available");
+ } finally {
+ if (licFile != null) {
+ licFile.delete();
+ }
+ }
+
lic.setModificationTimestamp(new Date());
em.persist(lic);
em.persist(createLicenseHistoryAction(lic, user, LicenseHistory.Actions.SEND, "Email sent to: " + lic.getEmail()));
@@ -207,6 +257,7 @@
/**
* Cancel given license
+ *
* @param licId
* @param bsc
* @return
@@ -221,7 +272,8 @@
@Produces({
MediaType.APPLICATION_JSON
})
- public Response cancel(@PathParam("licId") Integer licId, @Context BasicSecurityContext bsc) throws SeCurisServiceException {
+ public Response cancel(@PathParam("licId") Integer licId, @FormParam("reason") String reason, @Context BasicSecurityContext bsc)
+ throws SeCurisServiceException {
EntityManager em = emProvider.get();
License lic = getCurrentLicense(licId, bsc, em);
@@ -232,12 +284,17 @@
+ " can not be canceled from the current license status");
}
- lic.setStatus(License.Status.CANCELED);
+ if (reason == null && (lic.getStatus() == LicenseStatus.ACTIVE || lic.getStatus() == LicenseStatus.PRE_ACTIVE)) {
+ LOG.error("To cancel an active License we need a reason, lic ID: {}, user: {}", lic.getId(), bsc.getUserPrincipal().getName());
+ throw new SeCurisServiceException(Status.FORBIDDEN.getStatusCode(), "Active license with id " + licId
+ + " can not be canceled without a reason");
+ }
+
+ lic.setStatus(LicenseStatus.CANCELLED);
lic.setModificationTimestamp(new Date());
em.persist(lic);
- User user = getUser(bsc.getUserPrincipal().getName(), em);
- em.persist(createLicenseHistoryAction(lic, user, LicenseHistory.Actions.CANCEL));
+ em.persist(createLicenseHistoryAction(lic, getUser(bsc, em), LicenseHistory.Actions.CANCEL, "Cancelation reason: " + reason));
return Response.ok(lic).build();
}
@@ -250,39 +307,102 @@
})
@Transactional
public Response create(License lic, @Context BasicSecurityContext bsc) throws SeCurisServiceException {
- LOG.info("Creating new license from create()");
EntityManager em = emProvider.get();
Pack pack = null;
if (lic.getPackId() != null) {
pack = em.find(Pack.class, lic.getPackId());
- if (pack == null) {
- LOG.error("License pack with id {} not found in DB", lic.getPackId());
- return Response.status(Status.NOT_FOUND)
- .header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "License's pack not found with ID: " + lic.getPackId()).build();
- } else {
- if (!bsc.isUserInRole(BasicSecurityContext.ROL_ADMIN) && !bsc.getOrganizationsIds().contains(pack.getOrganization().getId())) {
- LOG.error("License for pack with id {} can not be created by user {}", pack.getId(), bsc.getUserPrincipal());
- return Response.status(Status.UNAUTHORIZED)
- .header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "Unathorized action on pack license").build();
- }
+ }
+
+ if (pack == null) {
+ LOG.error("License pack with id {} not found in DB", lic.getPackId());
+ throw new SeCurisServiceException(ErrorCodes.NOT_FOUND, "License's pack not found with ID: " + lic.getPackId());
+ } else {
+ if (!bsc.isUserInRole(BasicSecurityContext.ROL_ADMIN) && !bsc.getOrganizationsIds().contains(pack.getOrganization().getId())) {
+ LOG.error("License for pack with id {} can not be created by user {}", pack.getId(), bsc.getUserPrincipal());
+ throw new SeCurisServiceException(ErrorCodes.UNAUTHORIZED_ACCESS, "Unathorized action on pack license");
}
}
User createdBy = getUser(bsc.getUserPrincipal().getName(), em);
- // TODO: Manage status if request data is set
+ if (lic.getRequestData() != null) {
+ SignedLicenseBean signedLicense = generateLicense(lic, em);
+ // If user provide a request data the license status is passed
+ // directly to ACTIVE
+ lic.setStatus(LicenseStatus.ACTIVE);
+ try {
+ lic.setLicenseData(JsonUtils.toJSON(signedLicense));
+ } catch (CurisException e) {
+ LOG.error("Error generaing license JSON", e);
+ throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Error generaing license JSON");
+ }
+ } else {
+ lic.setStatus(LicenseStatus.CREATED);
+ }
lic.setCreatedBy(createdBy);
- lic.setStatus(License.Status.CREATED);
lic.setCreationTimestamp(new Date());
lic.setModificationTimestamp(lic.getCreationTimestamp());
em.persist(lic);
em.persist(createLicenseHistoryAction(lic, createdBy, LicenseHistory.Actions.CREATE));
+ if (lic.getStatus() == LicenseStatus.ACTIVE) {
+ em.persist(createLicenseHistoryAction(lic, createdBy, LicenseHistory.Actions.CREATE, "Activated on creation"));
+ }
return Response.ok(lic).build();
}
-
-
+ private SignedLicenseBean generateLicense(License license, EntityManager em) throws SeCurisServiceException {
+ SignedLicenseBean sl = null;
+ Pack pack = em.find(Pack.class, license.getPackId());
+ RequestBean rb = validateRequestData(pack, license.getRequestData());
+ try {
+ LicenseBean lb = licenseGenerator.generateLicense(rb, extractPackMetadata(pack.getMetadata()), license.getExpirationDate(),
+ pack.getLicenseTypeCode(), license.getCode());
+ sl = new SignedLicenseBean(lb);
+ } catch (SeCurisException e) {
+ throw new SeCurisServiceException(ErrorCodes.INVALID_LICENSE_REQUEST_DATA, "Error generating license: " + e.toString());
+ }
+ return sl;
+ }
+
+ private Map<String, Object> extractPackMetadata(Set<PackMetadata> packMetadata) {
+ Map<String, Object> metadata = new HashMap<>();
+ for (PackMetadata md : packMetadata) {
+ metadata.put(md.getKey(), md.getValue());
+ }
+
+ return metadata;
+ }
+
+ /**
+ * We check if the given request data is valid for the current Pack and has
+ * a valid format
+ *
+ * @param pack
+ * @param requestData
+ * @throws SeCurisServiceException
+ */
+ private RequestBean validateRequestData(Pack pack, String requestData) throws SeCurisServiceException {
+ RequestBean rb = null;
+ try {
+ rb = JsonUtils.json2object(requestData, RequestBean.class);
+ } catch (CurisException e) {
+ throw new SeCurisServiceException(ErrorCodes.INVALID_REQUEST_DATA_FORMAT, "Request data has not a valid format");
+ }
+
+ if (!rb.getCustomerCode().equals(pack.getOrganization().getCode())) {
+ throw new SeCurisServiceException(ErrorCodes.INVALID_REQUEST_DATA_FORMAT, "Request data not valid, wrong Organization code");
+ }
+ if (!rb.getLicenseTypeCode().equals(pack.getLicenseTypeCode())) {
+ throw new SeCurisServiceException(ErrorCodes.INVALID_REQUEST_DATA_FORMAT, "Request data not valid, wrong License type code");
+ }
+ // TODO: [rsanchez] Verify that if pack code is null we ignore it
+ if (rb.getPackCode() != null && !rb.getPackCode().equals(pack.getCode())) {
+ throw new SeCurisServiceException(ErrorCodes.INVALID_REQUEST_DATA_FORMAT, "Request data not valid, wrong Pack code");
+ }
+ return rb;
+ }
+
@PUT
@POST
@Path("/{licId}")
@@ -302,9 +422,22 @@
currentLicense.setCode(lic.getCode());
currentLicense.setFullName(lic.getFullName());
currentLicense.setEmail(lic.getEmail());
- currentLicense.setRequestData(lic.getRequestData());
+ if (lic.getRequestData() != null) {
+ SignedLicenseBean signedLicense = generateLicense(lic, em);
+ // If user provide a request data the license status is passed
+ // directly to ACTIVE
+ lic.setStatus(LicenseStatus.ACTIVE);
+ try {
+ lic.setLicenseData(JsonUtils.toJSON(signedLicense));
+ } catch (CurisException e) {
+ LOG.error("Error generaing license JSON", e);
+ throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Error generaing license JSON");
+ }
+ currentLicense.setRequestData(lic.getRequestData());
+ }
currentLicense.setModificationTimestamp(new Date());
em.persist(currentLicense);
+ em.persist(createLicenseHistoryAction(lic, getUser(bsc, em), LicenseHistory.Actions.MODIFY));
return Response.ok(currentLicense).build();
}
@@ -321,7 +454,29 @@
EntityManager em = emProvider.get();
License lic = getCurrentLicense(licId, bsc, em);
- if (lic.getStatus() != License.Status.CANCELED || lic.getStatus() != License.Status.CREATED) {
+ if (lic.getStatus() != LicenseStatus.CANCELLED || lic.getStatus() != LicenseStatus.CREATED) {
+ LOG.error("License {} can not be deleted with status {}", lic.getCode(), lic.getStatus());
+ return Response.status(Status.FORBIDDEN)
+ .header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "License can not be deleted in current status").build();
+ }
+
+ em.remove(lic);
+ return Response.ok(Utils.createMap("success", true, "id", licId)).build();
+ }
+
+ @DELETE
+ @Path("/{licId}")
+ @Transactional
+ @Securable
+ @Produces({
+ MediaType.APPLICATION_JSON
+ })
+ public Response block(@PathParam("licId") Integer licId, @Context BasicSecurityContext bsc) throws SeCurisServiceException {
+ LOG.info("Deleting license with id: {}", licId);
+ EntityManager em = emProvider.get();
+ License lic = getCurrentLicense(licId, bsc, em);
+
+ if (lic.getStatus() != LicenseStatus.CANCELLED || lic.getStatus() != LicenseStatus.CREATED) {
LOG.error("License {} can not be deleted with status {}", lic.getCode(), lic.getStatus());
return Response.status(Status.FORBIDDEN)
.header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "License can not be deleted in current status").build();
@@ -349,6 +504,11 @@
return lic;
}
+ private User getUser(BasicSecurityContext bsc, EntityManager em) throws SeCurisServiceException {
+ String username = bsc.getUserPrincipal().getName();
+ return getUser(username, em);
+ }
+
private User getUser(String username, EntityManager em) throws SeCurisServiceException {
User user = null;
if (username != null) {
@@ -358,6 +518,13 @@
}
}
return user;
+ }
+
+ private File createTemporaryLicenseFile(License lic, String licFileName) throws IOException {
+ File f = Files.createTempDirectory("securis-server").toFile();
+ f = new File(f, licFileName);
+ IOUtils.write(lic.getLicenseData(), new FileWriter(f));
+ return f;
}
private LicenseHistory createLicenseHistoryAction(License lic, User user, String action, String comments) {
@@ -373,4 +540,12 @@
private LicenseHistory createLicenseHistoryAction(License lic, User user, String action) {
return createLicenseHistoryAction(lic, user, action, null);
}
+
+ public static void main(String[] args) throws IOException {
+ File f = Files.createTempDirectory("securis-server").toFile();
+
+ LOG.info("f: {}", f);
+ f = new File(f, "config-server.lic");
+ LOG.info("f: {}", f);
+ }
}
--
Gitblit v1.3.2