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/ApiResource.java | 86 +++--
securis/src/main/java/net/curisit/securis/db/BlockedRequest.java | 85 ++++++
securis/src/main/java/net/curisit/securis/db/User.java | 10
securis/src/main/resources/static/js/catalogs.json | 6
securis/src/main/java/net/curisit/securis/db/PackStatus.java | 18
securis/src/main/java/net/curisit/securis/db/Pack.java | 19
securis/src/main/java/net/curisit/securis/db/License.java | 27 -
securis/src/main/java/net/curisit/securis/SeCurisServer.java | 4
securis/pom.xml | 12
securis/src/main/resources/static/licenses.html | 43 +-
securis/src/main/java/net/curisit/securis/db/LicenseStatus.java | 40 ++
securis/src/main/java/net/curisit/securis/db/LicenseHistory.java | 2
securis/src/main/java/net/curisit/securis/services/LicenseResource.java | 227 ++++++++++++++-
securis/src/main/java/net/curisit/securis/utils/EmailManager.java | 196 ++++++++++++++
securis/src/main/resources/securis-server.properties | 5
securis/src/main/java/net/curisit/securis/services/exception/SeCurisServiceException.java | 20 +
securis/src/main/resources/db/schema.sql | 16
securis/src/main/java/net/curisit/securis/LicenseGenerator.java | 18
18 files changed, 699 insertions(+), 135 deletions(-)
diff --git a/securis/pom.xml b/securis/pom.xml
index 7b638ff..1f5b23b 100644
--- a/securis/pom.xml
+++ b/securis/pom.xml
@@ -59,13 +59,23 @@
<dependency>
<groupId>net.curisit</groupId>
<artifactId>securis-client</artifactId>
- <version>0.9.8-SNAPSHOT</version>
+ <version>1.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>4.3.6.Final</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>4.4-beta1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpmime</artifactId>
+ <version>4.4-beta1</version>
+ </dependency>
</dependencies>
<build>
<plugins>
diff --git a/securis/src/main/java/net/curisit/securis/LicenseGenerator.java b/securis/src/main/java/net/curisit/securis/LicenseGenerator.java
index 40954f4..b614e4d 100644
--- a/securis/src/main/java/net/curisit/securis/LicenseGenerator.java
+++ b/securis/src/main/java/net/curisit/securis/LicenseGenerator.java
@@ -11,7 +11,6 @@
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
-import java.text.MessageFormat;
import java.util.Date;
import java.util.Map;
import java.util.TreeMap;
@@ -57,13 +56,11 @@
* @return
* @throws SeCurisException
*/
- public LicenseBean generateLicense(RequestBean req, Map<String, Object> metadata, Date expirationDate, String licenseType, String licenseCode)
+ public LicenseBean generateLicense(RequestBean req, Map<String, Object> metadata, Date expirationDate, String licenseCode, String appName)
throws SeCurisException {
- LOG.info(MessageFormat.format("Generating license: MAC: {0}, Customer code: {1}, AppCode: {2}", req.getMacAddresses(), req.getCustomerCode(),
- req.getAppCode()));
+ LOG.debug("Generating license: MAC: {}, Customer code: {}, AppName: {}", req.getMacAddresses(), req.getCustomerCode(), appName);
LicenseBean license = new LicenseBean(req);
- license.setLicenseType(licenseType);
- license.setLicenseCode(licenseCode);
+ license.setAppName(appName);
license.setExpirationDate(expirationDate);
license.setMetadata(metadata);
sign(license);
@@ -82,7 +79,7 @@
SignedLicenseBean signedLic = new SignedLicenseBean(license);
byte[] json;
try {
- json = JsonUtils.toJSON(signedLic, true).getBytes("utf-8");
+ json = JsonUtils.toPrettyJSON(signedLic).getBytes("utf-8");
Files.write(Paths.get(file.toURI()), json, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
} catch (UnsupportedEncodingException e) {
LOG.error("Error creating json doc from license: " + license, e);
@@ -97,7 +94,6 @@
}
/**
- * TODO: This method should be removed from client code.
*
* @param licBean
* @return
@@ -113,7 +109,8 @@
Signature signature;
try {
signature = Signature.getInstance(SignatureHelper.SIGNATURE_GENERATION_ALGORITHM);
- signature.initSign(sh.generatePrivateKey(new File(System.getProperty("user.home") + File.separator + ".SeCuris" + File.separator + "keys" + File.separator + "securis_private_key.pkcs8")));
+ signature.initSign(sh.generatePrivateKey(new File(System.getProperty("user.home") + File.separator + ".SeCuris" + File.separator + "keys"
+ + File.separator + "securis_private_key.pkcs8")));
sh.prepareSignature(signature, licBean);
@@ -147,7 +144,7 @@
metadata.put("timeThreshold", 0);
metadata.put("datasetPrefix", "BP");
metadata.put("extendedMode", true);
-
+
Date expirationDate = new Date(new Date().getTime() + (1000L * 3600 * 24 * 365 * 10));
LicenseBean lic = LicenseGenerator.getInstance().generateLicense(req, metadata, expirationDate, "CI-01", "LIC-CURISTEC-0001");
LicenseGenerator.getInstance().save(lic, new File("/Users/cproberto/Desktop/AxelLicCI.lic"));
@@ -156,4 +153,3 @@
}
}
-
diff --git a/securis/src/main/java/net/curisit/securis/SeCurisServer.java b/securis/src/main/java/net/curisit/securis/SeCurisServer.java
index 1e7bb8d..8b28615 100644
--- a/securis/src/main/java/net/curisit/securis/SeCurisServer.java
+++ b/securis/src/main/java/net/curisit/securis/SeCurisServer.java
@@ -65,6 +65,10 @@
CONSOLE.info(" $ ./securis-server.sh {start|stop}");
}
+ private void testMail() {
+
+ }
+
public static void main(String[] args) throws Exception {
String command;
if (args.length > 0) {
diff --git a/securis/src/main/java/net/curisit/securis/db/BlockedRequest.java b/securis/src/main/java/net/curisit/securis/db/BlockedRequest.java
new file mode 100644
index 0000000..2233432
--- /dev/null
+++ b/securis/src/main/java/net/curisit/securis/db/BlockedRequest.java
@@ -0,0 +1,85 @@
+package net.curisit.securis.db;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonIgnore;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+/**
+ * Entity implementation class for Entity: pack
+ *
+ */
+@JsonAutoDetect
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@Entity
+@Table(name = "blocked_request")
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class BlockedRequest implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ private String hash;
+
+ @Column(name = "request_data")
+ @JsonProperty("request_data")
+ private String requestData;
+
+ @Column(name = "creation_timestamp")
+ @JsonProperty("creation_timestamp")
+ private Date creationTimestamp;
+
+ @JsonIgnore
+ @ManyToOne
+ @JoinColumn(name = "blocked_by")
+ private User blockedBy;
+
+ public Date getCreationTimestamp() {
+ return creationTimestamp;
+ }
+
+ public void setCreationTimestamp(Date creationTimestamp) {
+ this.creationTimestamp = creationTimestamp;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof BlockedRequest))
+ return false;
+ BlockedRequest other = (BlockedRequest) obj;
+ return hash.equals(other.hash);
+ }
+
+ @Override
+ public int hashCode() {
+
+ return (hash == null ? 0 : hash.hashCode());
+ }
+
+ public String getRequestData() {
+ return requestData;
+ }
+
+ public void setRequestData(String requestData) {
+ this.requestData = requestData;
+ }
+
+ public User getBlockedBy() {
+ return blockedBy;
+ }
+
+ public void setBlockedBy(User blockedBy) {
+ this.blockedBy = blockedBy;
+ }
+}
diff --git a/securis/src/main/java/net/curisit/securis/db/License.java b/securis/src/main/java/net/curisit/securis/db/License.java
index 869574e..239797c 100644
--- a/securis/src/main/java/net/curisit/securis/db/License.java
+++ b/securis/src/main/java/net/curisit/securis/db/License.java
@@ -63,7 +63,7 @@
@JoinColumn(name = "canceled_by")
private User canceledBy;
- private int status;
+ private LicenseStatus status;
@Column(name = "full_name")
@JsonProperty("full_name")
@@ -186,11 +186,11 @@
}
}
- public int getStatus() {
+ public LicenseStatus getStatus() {
return status;
}
- public void setStatus(int status) {
+ public void setStatus(LicenseStatus status) {
this.status = status;
}
@@ -289,21 +289,14 @@
}
public static class Status {
- public static final int CREATED = 1;
- public static final int REQUESTED = 2;
- public static final int PREACTIVE = 3;
- public static final int ACTIVE = 4;
- public static final int EXPIRED = 5;
- public static final int CANCELED = 6;
- public static final int DELETED = 7;
private static final Map<Integer, List<Integer>> transitions = Utils.createMap( //
- Action.REQUEST, Arrays.asList(CREATED, REQUESTED), //
- Action.ACTIVATION, Arrays.asList(REQUESTED, PREACTIVE, EXPIRED), //
- Action.SEND, Arrays.asList(ACTIVE, PREACTIVE), //
- Action.DOWNLOAD, Arrays.asList(ACTIVE, PREACTIVE), //
- Action.CANCEL, Arrays.asList(ACTIVE, PREACTIVE, REQUESTED, EXPIRED), //
- Action.DELETE, Arrays.asList(CANCELED, CREATED) //
+ Action.REQUEST, Arrays.asList(LicenseStatus.CREATED, LicenseStatus.REQUESTED), //
+ Action.ACTIVATION, Arrays.asList(LicenseStatus.REQUESTED, LicenseStatus.PRE_ACTIVE, LicenseStatus.EXPIRED), //
+ Action.SEND, Arrays.asList(LicenseStatus.ACTIVE, LicenseStatus.PRE_ACTIVE), //
+ Action.DOWNLOAD, Arrays.asList(LicenseStatus.ACTIVE, LicenseStatus.PRE_ACTIVE), //
+ Action.CANCEL, Arrays.asList(LicenseStatus.ACTIVE, LicenseStatus.PRE_ACTIVE, LicenseStatus.REQUESTED, LicenseStatus.EXPIRED), //
+ Action.DELETE, Arrays.asList(LicenseStatus.CANCELLED, LicenseStatus.CREATED) //
);
@@ -315,7 +308,7 @@
* @param newStatus
* @return
*/
- public static boolean isActionValid(Integer action, Integer currentStatus) {
+ public static boolean isActionValid(Integer action, LicenseStatus currentStatus) {
List<Integer> validStatuses = transitions.get(currentStatus);
return validStatuses != null && validStatuses.contains(currentStatus);
diff --git a/securis/src/main/java/net/curisit/securis/db/LicenseHistory.java b/securis/src/main/java/net/curisit/securis/db/LicenseHistory.java
index 7f0e549..63590f5 100644
--- a/securis/src/main/java/net/curisit/securis/db/LicenseHistory.java
+++ b/securis/src/main/java/net/curisit/securis/db/LicenseHistory.java
@@ -111,8 +111,10 @@
public static final String ADD_REQUEST = "request";
public static final String SEND = "send";
public static final String MODIFY = "modify";
+ public static final String DOWNLOAD = "download";
public static final String ACTIVATE = "activate";
public static final String CANCEL = "cancel";
+ public static final String BLOCK = "block";
public static final String DELETE = "delete";
}
}
diff --git a/securis/src/main/java/net/curisit/securis/db/LicenseStatus.java b/securis/src/main/java/net/curisit/securis/db/LicenseStatus.java
new file mode 100644
index 0000000..ff8b51f
--- /dev/null
+++ b/securis/src/main/java/net/curisit/securis/db/LicenseStatus.java
@@ -0,0 +1,40 @@
+package net.curisit.securis.db;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonValue;
+
+/**
+ * Contains the possible license statuses. For further details:
+ * https://redmine.curistec.com/projects/securis/wiki/LicensesServerManagement
+ *
+ * @author rob
+ */
+public enum LicenseStatus {
+ CREATED("CR"), REQUESTED("RE"), ACTIVE("AC"), PRE_ACTIVE("PA"), EXPIRED("EX"), CANCELLED("CA");
+
+ private final String code;
+
+ LicenseStatus(String code) {
+ this.code = code;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ @JsonCreator
+ public static LicenseStatus valueFromCode(String code) {
+ for (LicenseStatus ps : LicenseStatus.values()) {
+ if (ps.code.equals(code)) {
+ return ps;
+ }
+ }
+ return null;
+ }
+
+ @JsonValue
+ public String getName() {
+
+ return this.code;
+ }
+}
diff --git a/securis/src/main/java/net/curisit/securis/db/Pack.java b/securis/src/main/java/net/curisit/securis/db/Pack.java
index d8f6df9..dcc977e 100644
--- a/securis/src/main/java/net/curisit/securis/db/Pack.java
+++ b/securis/src/main/java/net/curisit/securis/db/Pack.java
@@ -74,7 +74,7 @@
@Column(name = "num_licenses")
@JsonProperty("num_licenses")
private int numLicenses;
-
+
@Column(name = "init_valid_date")
@JsonProperty("init_valid_date")
private Date initValidDate;
@@ -155,7 +155,7 @@
}
int num = 0;
for (License lic : licenses) {
- if (lic.getStatus() == License.Status.ACTIVE) {
+ if (lic.getStatus() == LicenseStatus.ACTIVE || lic.getStatus() == LicenseStatus.PRE_ACTIVE) {
num++;
}
}
@@ -176,7 +176,7 @@
}
int num = 0;
for (License lic : licenses) {
- if (lic.getStatus() != License.Status.CANCELED) {
+ if (lic.getStatus() != LicenseStatus.CANCELLED) {
num++;
}
}
@@ -190,7 +190,7 @@
*/
@JsonProperty("num_available")
public int getNumAvailables() {
- return numLicenses - getNumCreations();
+ return numLicenses - getNumActivations();
}
@JsonProperty("organization_name")
@@ -250,11 +250,12 @@
@JsonProperty("created_by_name")
public String getCreatedByname() {
- return createdBy == null ? null : String.format("%s %s (%s)", createdBy.getFirstName(), createdBy.getLastName() != null ? createdBy.getLastName() : "", createdBy.getUsername());
+ return createdBy == null ? null : String.format("%s %s (%s)", createdBy.getFirstName(),
+ createdBy.getLastName() != null ? createdBy.getLastName() : "", createdBy.getUsername());
}
@JsonProperty("licensetype_code")
- public String getLicenseTypcode() {
+ public String getLicenseTypeCode() {
return licenseType == null ? null : licenseType.getCode();
}
@@ -310,13 +311,13 @@
public boolean equals(Object obj) {
if (!(obj instanceof Pack))
return false;
- Pack other = (Pack)obj;
+ Pack other = (Pack) obj;
return id.equals(other.id);
}
-
+
@Override
public int hashCode() {
-
+
return (id == null ? 0 : id.hashCode());
}
}
diff --git a/securis/src/main/java/net/curisit/securis/db/PackStatus.java b/securis/src/main/java/net/curisit/securis/db/PackStatus.java
index b5a436a..bd05a69 100644
--- a/securis/src/main/java/net/curisit/securis/db/PackStatus.java
+++ b/securis/src/main/java/net/curisit/securis/db/PackStatus.java
@@ -3,17 +3,25 @@
import org.codehaus.jackson.annotate.JsonCreator;
import org.codehaus.jackson.annotate.JsonValue;
+/**
+ * Contains the possible pack statuses. For further details:
+ * https://redmine.curistec.com/projects/securis/wiki/LicensesServerManagement
+ *
+ * @author rob
+ */
public enum PackStatus {
- PENDING("PE"), ACTIVE("AC"), ON_HOLD("OH"), EXPIRED("EX"), CANCELLED("CA");
-
+ CREATED("CR"), ACTIVE("AC"), ON_HOLD("OH"), EXPIRED("EX"), CANCELLED("CA");
+
private final String code;
- PackStatus(String code ) {
+
+ PackStatus(String code) {
this.code = code;
}
+
public String getCode() {
return code;
}
-
+
@JsonCreator
public static PackStatus valueFromCode(String code) {
for (PackStatus ps : PackStatus.values()) {
@@ -26,7 +34,7 @@
@JsonValue
public String getName() {
-
+
return this.code;
}
}
diff --git a/securis/src/main/java/net/curisit/securis/db/User.java b/securis/src/main/java/net/curisit/securis/db/User.java
index ea08a53..0899dad 100644
--- a/securis/src/main/java/net/curisit/securis/db/User.java
+++ b/securis/src/main/java/net/curisit/securis/db/User.java
@@ -67,6 +67,8 @@
private String lang;
+ private String email;
+
@JsonIgnore
@ManyToMany
@JoinTable(name = "user_organization", //
@@ -223,6 +225,14 @@
}
}
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
public static class Rol {
public static final int ADVANCE = 0x01;
public static final int ADMIN = 0x02;
diff --git a/securis/src/main/java/net/curisit/securis/services/ApiResource.java b/securis/src/main/java/net/curisit/securis/services/ApiResource.java
index 7c843d0..23913e0 100644
--- a/securis/src/main/java/net/curisit/securis/services/ApiResource.java
+++ b/securis/src/main/java/net/curisit/securis/services/ApiResource.java
@@ -28,8 +28,6 @@
import net.curisit.securis.beans.SignedLicenseBean;
import net.curisit.securis.beans.StatusBean;
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;
@@ -96,9 +94,10 @@
return Response.ok(status).build();
}
-
/**
- * Request a new license file based in a RequestBean object sent as parameter
+ * Request a new license file based in a RequestBean object sent as
+ * parameter
+ *
* @param mpfdi
* @param bsc
* @return
@@ -108,17 +107,18 @@
@POST
@Path("/request")
@Consumes(MediaType.APPLICATION_JSON)
- //TODO: Enable this: @Securable
+ // TODO: Enable this: @Securable
@Produces({
MediaType.APPLICATION_JSON
})
@Transactional
- public Response createFromRequest(RequestBean request, @Context BasicSecurityContext bsc) throws IOException, SeCurisServiceException, SeCurisException {
+ public Response createFromRequest(RequestBean request, @Context BasicSecurityContext bsc) throws IOException, SeCurisServiceException,
+ SeCurisException {
LOG.info("Request to get license: {}", request);
Map<String, Object> metadata = getLicenseMetadata(request);
License licDB = getLicenseData(request);
-
+
Date expirationDate = licDB.getExpirationDate();
String licenseTypeCode = licDB.getPack().getLicenseType().getCode();
String licenseCode = licDB.getCode();
@@ -126,9 +126,10 @@
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
@@ -145,12 +146,14 @@
})
@Transactional
@SuppressWarnings("unchecked")
- public Response createFromRequestFile(MultipartFormDataInput mpfdi, @Context BasicSecurityContext bsc) throws IOException, SeCurisServiceException, SeCurisException {
+ 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.setPackCode(mpfdi.getFormDataPart("packCode", String.class, null));
+ req.setLicenseTypeCode(mpfdi.getFormDataPart("licenseTypeCode", String.class, null));
+ req.setCustomerCode(mpfdi.getFormDataPart("customerCode", 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));
@@ -170,12 +173,13 @@
@POST
@Path("/renew")
@Consumes(MediaType.APPLICATION_JSON)
- //TODO: Enable this: @Securable
+ // TODO: Enable this: @Securable
@Produces({
MediaType.APPLICATION_JSON
})
@Transactional
- public Response renewFromPreviousLicense(LicenseBean previousLic, @Context BasicSecurityContext bsc) throws IOException, SeCurisServiceException, SeCurisException {
+ 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))) {
@@ -184,16 +188,17 @@
Map<String, Object> 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
@@ -210,12 +215,15 @@
})
@Transactional
@SuppressWarnings("unchecked")
- public Response renewFromLicenseFile(MultipartFormDataInput mpfdi, @Context BasicSecurityContext bsc) throws IOException, SeCurisServiceException, SeCurisException {
+ 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.setAppName(mpfdi.getFormDataPart("appName", String.class, null));
lic.setArch(mpfdi.getFormDataPart("arch", String.class, null));
lic.setCrcLogo(mpfdi.getFormDataPart("crcLogo", String.class, null));
+ lic.setPackCode(mpfdi.getFormDataPart("packCode", String.class, null));
+ lic.setLicenseTypeCode(mpfdi.getFormDataPart("licenseCode", 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));
@@ -227,46 +235,50 @@
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
+ // 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 * 30 )));
- 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);
+ // TODO: IMPLEMENT LICENSE GENERATION
+
+ // lic.setExpirationDate(new Date(new Date().getTime() + (1000L * 3600 *
+ // 24 * 30)));
+ // lic.setCode(req.getPackCode() + "-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<String, Object> 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");
+ // 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<String, Object> metadata = null;
try {
String metadataJson = IOUtils.toString(dummyMetadata.toURI());
- metadata = (Map<String, Object>)JsonUtils.json2map(metadataJson).get(req.getAppCode());
- if (metadata == null)
- throw new SeCurisException("App code in request is unknown: " + req.getAppCode());
+ metadata = (Map<String, Object>) JsonUtils.json2map(metadataJson).get(req.getLicenseTypeCode());
+ if (metadata == null) {
+ throw new SeCurisException("App code in request is unknown: " + req.getLicenseTypeCode());
+ }
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;
}
-
}
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);
+ }
}
diff --git a/securis/src/main/java/net/curisit/securis/services/exception/SeCurisServiceException.java b/securis/src/main/java/net/curisit/securis/services/exception/SeCurisServiceException.java
index 49f7de5..1610f0b 100644
--- a/securis/src/main/java/net/curisit/securis/services/exception/SeCurisServiceException.java
+++ b/securis/src/main/java/net/curisit/securis/services/exception/SeCurisServiceException.java
@@ -4,15 +4,20 @@
public class SeCurisServiceException extends CurisException {
- private int status = 0;
+ private int errorCode = 0;
- public SeCurisServiceException(int status, String msg) {
+ public SeCurisServiceException(int errorCode, String msg) {
super(msg);
- this.status = status;
+ this.errorCode = errorCode;
+ }
+
+ public SeCurisServiceException(String msg) {
+ super(msg);
+ this.errorCode = ErrorCodes.UNEXPECTED_ERROR;
}
public int getStatus() {
- return status;
+ return errorCode;
}
/**
@@ -24,8 +29,13 @@
public static int UNEXPECTED_ERROR = 1000;
public static int INVALID_CREDENTIALS = 1001;
public static int UNAUTHORIZED_ACCESS = 1002;
-
+ public static int NOT_FOUND = 1003;
+ public static int INVALID_FORMAT = 1004;
+
public static int INVALID_LICENSE_REQUEST_DATA = 1100;
public static int LICENSE_NOT_READY_FOR_RENEW = 1101;
+
+ public static int INVALID_REQUEST_DATA = 1201;
+ public static int INVALID_REQUEST_DATA_FORMAT = 1202;
}
}
diff --git a/securis/src/main/java/net/curisit/securis/utils/EmailManager.java b/securis/src/main/java/net/curisit/securis/utils/EmailManager.java
new file mode 100644
index 0000000..41c768e
--- /dev/null
+++ b/securis/src/main/java/net/curisit/securis/utils/EmailManager.java
@@ -0,0 +1,196 @@
+package net.curisit.securis.utils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+import javax.inject.Singleton;
+
+import net.curisit.securis.SeCurisException;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.mime.HttpMultipartMode;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
+import org.apache.http.entity.mime.content.FileBody;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.apache.http.ssl.TrustStrategy;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+/**
+ * Component that send emails using Mailgun API:
+ * http://documentation.mailgun.com/user_manual.html#sending-messages
+ *
+ * @author roberto <roberto.sanchez@curisit.net>
+ */
+@Singleton
+public class EmailManager {
+
+ private static final Logger LOG = LogManager.getLogger(EmailManager.class);
+
+ private final String serverUrl;
+ private final CloseableHttpClient httpClient;
+
+ /**
+ *
+ * @throws SeCurisException
+ */
+ private EmailManager() throws SeCurisException {
+ String domain = Params.get(Params.KEYS.MAILGUN_DOMAIN);
+ if (domain == null) {
+ throw new SeCurisException("Please, add '" + Params.KEYS.MAILGUN_DOMAIN + "' parameter to config file");
+ }
+ serverUrl = String.format("https://api.mailgun.net/v2/%s/messages", domain);
+ httpClient = createHttpClient();
+
+ }
+
+ private CloseableHttpClient createHttpClient() throws SeCurisException {
+ SSLContextBuilder builder = new SSLContextBuilder();
+ SSLConnectionSocketFactory sslsf = null;
+ try {
+ builder.loadTrustMaterial((KeyStore) null, new TrustStrategy() {
+ @Override
+ public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ return true;
+ }
+ });
+ sslsf = new SSLConnectionSocketFactory(builder.build());
+ } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e1) {
+ LOG.error(e1);
+ throw new SeCurisException("Error creating SSL socket factory");
+ }
+ CredentialsProvider provider = new BasicCredentialsProvider();
+ UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("api", Params.get(Params.KEYS.MAILGUN_API_KEY));
+ provider.setCredentials(AuthScope.ANY, credentials);
+
+ return HttpClientBuilder.create().setDefaultCredentialsProvider(provider).setSSLSocketFactory(sslsf).build();
+ }
+
+ /**
+ * Basic method to send emails in text mode with attachment. The method is
+ * synchronous, It waits until server responses.
+ *
+ * @param subject
+ * @param body
+ * @param to
+ * @param file
+ * @throws SeCurisException
+ * @throws UnsupportedEncodingException
+ */
+ public void sendEmail(String subject, String body, String to, String cc, File file) throws SeCurisException, UnsupportedEncodingException {
+ HttpPost postRequest = new HttpPost(serverUrl);
+
+ MultipartEntityBuilder builder = MultipartEntityBuilder.create();
+
+ builder.setCharset(Charset.forName("utf-8"));
+ builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
+ builder.addTextBody("from", Params.get(Params.KEYS.EMAIL_FROM_ADDRESS));
+ builder.addTextBody("to", to);
+ if (cc != null)
+ builder.addTextBody("cc", cc);
+ builder.addTextBody("subject", subject, ContentType.create(ContentType.TEXT_PLAIN.getMimeType(), Charset.forName("utf-8")));
+ builder.addTextBody("text", body, ContentType.create(ContentType.TEXT_PLAIN.getMimeType(), Charset.forName("utf-8")));
+ if (file != null)
+ builder.addPart("attachment", new FileBody(file));
+
+ postRequest.setEntity(builder.build());
+ HttpResponse response;
+ try {
+ response = httpClient.execute(postRequest);
+
+ String jsonLic = IOUtils.toString(response.getEntity().getContent());
+ if (response.getStatusLine().getStatusCode() == 200) {
+ LOG.debug("Response content read OK: {}", jsonLic);
+ Map<String, Object> responseBean = JsonUtils.json2map(jsonLic);
+
+ LOG.debug("Response mail read OK: {}", responseBean);
+ } else {
+ throw new SeCurisException("Error sending email, response estatus: " + response.getStatusLine());
+ }
+ } catch (IOException e) {
+ LOG.error("Error sending email", e);
+ throw new SeCurisException("Error sending email");
+ }
+ }
+
+ /**
+ * Basic method to send emails in text mode with attachment. The method is
+ * asynchronous, It returns immediately
+ *
+ * @param subject
+ * @param body
+ * @param to
+ * @param file
+ * @throws SeCurisException
+ * @throws UnsupportedEncodingException
+ */
+ public void sendEmailAsync(String subject, String body, String to, String cc, File file, EmailCallback callback) throws SeCurisException,
+ UnsupportedEncodingException {
+ Executor ex = Executors.newSingleThreadExecutor();
+ ex.execute(new Runnable() {
+
+ @Override
+ public void run() {
+ try {
+ EmailManager.this.sendEmail(subject, body, to, cc, file);
+ callback.success();
+ } catch (UnsupportedEncodingException e) {
+ callback.error(new SeCurisException("Error sending email", e));
+ } catch (SeCurisException e) {
+ callback.error(e);
+ }
+
+ }
+ });
+
+ }
+
+ public static interface EmailCallback {
+ public void success();
+
+ public void error(SeCurisException e);
+ }
+
+ public static void main(String[] args) throws SeCurisException, UnsupportedEncodingException {
+ // new EmailManager().sendEmail("España así de bien",
+ // "Me gusta esta prueba\nCon varias líneas\n\n\n--\nNo response",
+ // "info@r75.es", new File(
+ // "/Users/rob/Downloads/test.req"));
+ new EmailManager().sendEmailAsync("España así de bien", "Me gusta esta prueba\nCon varias líneas\n\n\n--\nNo response", "info@r75.es",
+ "dev@r75.es", new File("/Users/rob/Downloads/test.req"), new EmailCallback() {
+
+ @Override
+ public void success() {
+ LOG.info("Success!!!");
+ }
+
+ @Override
+ public void error(SeCurisException e) {
+ LOG.error("Error: {} !!!", e);
+ }
+ });
+ LOG.info("Waiting for email to be sent...");
+ }
+
+}
diff --git a/securis/src/main/resources/db/schema.sql b/securis/src/main/resources/db/schema.sql
index 2741405..d16fde7 100644
--- a/securis/src/main/resources/db/schema.sql
+++ b/securis/src/main/resources/db/schema.sql
@@ -14,6 +14,7 @@
last_name VARCHAR(100) NULL ,
last_login DATETIME NULL ,
lang VARCHAR(10) NULL ,
+ email VARCHAR(150) NULL ,
creation_timestamp DATETIME NULL ,
modification_timestamp DATETIME NULL ,
PRIMARY KEY (username));
@@ -78,7 +79,7 @@
num_licenses INT NOT NULL ,
init_valid_date DATE NOT NULL default today(),
end_valid_date DATE NOT NULL default today(),
- status VARCHAR(2) NOT NULL default 'PE',
+ status VARCHAR(2) NOT NULL default 'CR',
comments VARCHAR(1024) NULL ,
license_type_id INT NOT NULL,
organization_id INT NOT NULL,
@@ -113,7 +114,7 @@
expiration_date DATETIME NULL ,
canceled_by varchar(45) NULL ,
created_by varchar(45) NULL ,
- status INT NOT NULL default 0,
+ status VARCHAR(2) NOT NULL default 'CR',
PRIMARY KEY (id));
@@ -127,5 +128,12 @@
comments VARCHAR(512) ,
PRIMARY KEY (id));
-
-
\ No newline at end of file
+
+drop table IF EXISTS blocked_request;
+CREATE TABLE IF NOT EXISTS blocked_request (
+ hash VARCHAR(256) NOT NULL ,
+ request_data VARCHAR(1024) NULL ,
+ blocked_by varchar(45) NULL ,
+ creation_timestamp DATETIME NOT NULL default now(),
+ PRIMARY KEY (id));
+
\ No newline at end of file
diff --git a/securis/src/main/resources/securis-server.properties b/securis/src/main/resources/securis-server.properties
index 80f083f..5c98340 100644
--- a/securis/src/main/resources/securis-server.properties
+++ b/securis/src/main/resources/securis-server.properties
@@ -12,3 +12,8 @@
ssl.keystore.type = PKCS12
ssl.keystore.password = curist3c
ssl.keystore.alias =
+
+email.from.address = SeCuris support securis@curisit.net
+mailgun.domain = m.curisit.net
+mailgun.api.key = key-7dekyqx56nc0irbnyk4z39ezhsrikqi8
+email.lic.default.subject = SeCuris - License file for {0} application
\ No newline at end of file
diff --git a/securis/src/main/resources/static/js/catalogs.json b/securis/src/main/resources/static/js/catalogs.json
index c0da309..ccb1948 100644
--- a/securis/src/main/resources/static/js/catalogs.json
+++ b/securis/src/main/resources/static/js/catalogs.json
@@ -154,6 +154,12 @@
"readOnly" : true,
"mandatory" : true
}, {
+ "name" : "email",
+ "display" : "Email",
+ "type" : "email",
+ "maxlength" : 150,
+ "mandatory" : true
+ }, {
"name" : "first_name",
"display" : "First name",
"type" : "string",
diff --git a/securis/src/main/resources/static/licenses.html b/securis/src/main/resources/static/licenses.html
index d9a9056..2389f82 100644
--- a/securis/src/main/resources/static/licenses.html
+++ b/securis/src/main/resources/static/licenses.html
@@ -228,10 +228,21 @@
</div>
<div class="form-group">
- <div class="col-md-offset-3 col-md-10" id="saveContainer">
+ <div class="col-md-offset-3 col-md-10 " id="saveContainer">
<button id="save" type="submit" class="btn btn-primary">
<span i18n class="glyphicon glyphicon-floppy-disk"></span> Save
</button>
+ <button id="acc" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
+ <span i18n class="glyphicon glyphicon-align-justify"></span> Actions
+ <span class="caret"></span>
+ </button>
+ <ul class="dropdown-menu" role="menu">
+ <li><a href="#">Activate</a></li>
+ <li><a href="#">On hold</a></li>
+ <li class="divider"></li>
+ <li><a href="#">Invalidate</a></li>
+ <li><a href="#">Delete</a></li>
+ </ul>
</div>
</div>
</form>
@@ -534,26 +545,18 @@
<button id="save" type="submit" class="btn btn-primary">
<span i18n class="glyphicon glyphicon-floppy-disk"></span> Save
</button>
- <button id="activate" class="btn btn-success"
- ng-click="activateLicense(license)"
- ng-if="isActionVisible('activate', license)">
- <span i18n class="glyphicon glyphicon-check"></span> Activate
+ <button id="acc" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
+ <span i18n class="glyphicon glyphicon-align-justify"></span> Actions
+ <span class="caret"></span>
</button>
- <button id="send" class="btn btn-info"
- ng-click="sendLicense(license)"
- ng-if="isActionVisible('send', license)">
- <span i18n class="glyphicon glyphicon-send"></span> Send
- </button>
- <button id="cancel" class="btn btn-warning"
- ng-click="cancelLicense(license)"
- ng-if="isActionVisible('cancel', license)">
- <span i18n class="glyphicon glyphicon-ban-circle"></span> Cancel
- </button>
- <button id="remove" class="btn btn-danger"
- ng-click="removeLicense(license)"
- ng-if="isActionVisible('delete', license)">
- <span i18n class="glyphicon glyphicon-trash"></span> Delete
- </button>
+ <ul class="dropdown-menu" role="menu">
+ <li ng-if="isActionVisible('activate', license)"><a ng-click="activateLicense(license)" href="#">Activate</a></li>
+ <li ng-if="isActionVisible('download', license)"><a ng-click="downloadLicense(license)" href="#">Download</a></li>
+ <li ng-if="isActionVisible('send', license)"><a ng-click="sendLicense(license)" href="#">Send by email</a></li>
+ <li ng-if="isActionVisible('cancel', license)"><a ng-click="cancelLicense(license)" href="#">Invalidate</a></li>
+ <li ng-if="isActionVisible('delete', license)"><a ng-click="removeLicense(license)" href="#">Delete</a></li>
+ </ul>
+
</div>
</div>
</form>
--
Gitblit v1.3.2