rsanchez
2014-10-22 ddec2c5c7b7842536d6d705c2de20f96e16c8aa8
securis/src/main/java/net/curisit/securis/services/LicenseResource.java
....@@ -1,11 +1,15 @@
11 package net.curisit.securis.services;
22
33 import java.io.File;
4
+import java.io.FileWriter;
45 import java.io.IOException;
6
+import java.nio.file.Files;
7
+import java.text.MessageFormat;
58 import java.util.Date;
9
+import java.util.HashMap;
610 import java.util.List;
711 import java.util.Map;
8
-import java.util.TreeMap;
12
+import java.util.Set;
913
1014 import javax.inject.Inject;
1115 import javax.inject.Provider;
....@@ -13,6 +17,8 @@
1317 import javax.persistence.TypedQuery;
1418 import javax.ws.rs.Consumes;
1519 import javax.ws.rs.DELETE;
20
+import javax.ws.rs.DefaultValue;
21
+import javax.ws.rs.FormParam;
1622 import javax.ws.rs.GET;
1723 import javax.ws.rs.POST;
1824 import javax.ws.rs.PUT;
....@@ -27,16 +33,26 @@
2733
2834 import net.curisit.integrity.commons.JsonUtils;
2935 import net.curisit.integrity.commons.Utils;
36
+import net.curisit.integrity.exception.CurisException;
3037 import net.curisit.securis.DefaultExceptionHandler;
38
+import net.curisit.securis.LicenseGenerator;
3139 import net.curisit.securis.SeCurisException;
40
+import net.curisit.securis.beans.LicenseBean;
3241 import net.curisit.securis.beans.RequestBean;
42
+import net.curisit.securis.beans.SignedLicenseBean;
43
+import net.curisit.securis.db.Application;
3344 import net.curisit.securis.db.License;
3445 import net.curisit.securis.db.LicenseHistory;
46
+import net.curisit.securis.db.LicenseStatus;
3547 import net.curisit.securis.db.Pack;
48
+import net.curisit.securis.db.PackMetadata;
3649 import net.curisit.securis.db.User;
3750 import net.curisit.securis.security.BasicSecurityContext;
3851 import net.curisit.securis.security.Securable;
3952 import net.curisit.securis.services.exception.SeCurisServiceException;
53
+import net.curisit.securis.services.exception.SeCurisServiceException.ErrorCodes;
54
+import net.curisit.securis.utils.EmailManager;
55
+import net.curisit.securis.utils.Params;
4056 import net.curisit.securis.utils.TokenHelper;
4157
4258 import org.apache.commons.io.IOUtils;
....@@ -60,7 +76,13 @@
6076 TokenHelper tokenHelper;
6177
6278 @Inject
79
+ EmailManager emailManager;
80
+
81
+ @Inject
6382 Provider<EntityManager> emProvider;
83
+
84
+ @Inject
85
+ LicenseGenerator licenseGenerator;
6486
6587 /**
6688 *
....@@ -138,11 +160,16 @@
138160 LOG.error("License with id {} is not active, so It can not downloaded", licId, bsc.getUserPrincipal());
139161 throw new SeCurisServiceException(Status.FORBIDDEN.getStatusCode(), "License is not active, so It can not be downloaded");
140162 }
141
- return Response.ok(lic.getLicenseData()).build();
163
+ em.persist(createLicenseHistoryAction(lic, getUser(bsc, em), LicenseHistory.Actions.DOWNLOAD));
164
+ return Response
165
+ .ok(lic.getLicenseData())
166
+ .header("Content-Disposition",
167
+ String.format("attachment; filename=\"%s\"", lic.getPack().getLicenseType().getApplication().getLicenseFilename())).build();
142168 }
143169
144170 /**
145171 * Activate the given license
172
+ *
146173 * @param licId
147174 * @param bsc
148175 * @return
....@@ -168,8 +195,9 @@
168195 + " can not be activated from the current license status");
169196 }
170197
171
- lic.setStatus(License.Status.ACTIVE);
198
+ lic.setStatus(LicenseStatus.ACTIVE);
172199 lic.setModificationTimestamp(new Date());
200
+
173201 em.persist(lic);
174202 User user = getUser(bsc.getUserPrincipal().getName(), em);
175203 em.persist(createLicenseHistoryAction(lic, user, LicenseHistory.Actions.ACTIVATE));
....@@ -178,6 +206,7 @@
178206
179207 /**
180208 * Send license file by email to the organization
209
+ *
181210 * @param licId
182211 * @param bsc
183212 * @return
....@@ -192,13 +221,34 @@
192221 @Produces({
193222 MediaType.APPLICATION_JSON
194223 })
195
- public Response send(@PathParam("licId") Integer licId, @Context BasicSecurityContext bsc) throws SeCurisServiceException {
224
+ public Response send(@PathParam("licId") Integer licId, @DefaultValue("false") @FormParam("add_cc") Boolean addCC,
225
+ @Context BasicSecurityContext bsc) throws SeCurisServiceException, SeCurisException {
196226
197227 EntityManager em = emProvider.get();
198228 License lic = getCurrentLicense(licId, bsc, em);
229
+ Application app = lic.getPack().getLicenseType().getApplication();
230
+ File licFile = null;
231
+ if (lic.getLicenseData() == null) {
232
+ throw new SeCurisServiceException(Status.NOT_FOUND.getStatusCode(), "There is no license file available");
233
+ }
199234
200235 User user = getUser(bsc.getUserPrincipal().getName(), em);
201
- // TODO: Send mail with lic file
236
+ try {
237
+ String subject = MessageFormat.format(Params.get(Params.KEYS.EMAIL_LIC_DEFAULT_SUBJECT), lic.getPack().getAppName());
238
+ String email_tpl = IOUtils.toString(this.getClass().getResourceAsStream("/lic_email_template.en"));
239
+ String body = MessageFormat.format(email_tpl, lic.getFullName(), app.getName());
240
+ licFile = createTemporaryLicenseFile(lic, app.getLicenseFilename());
241
+
242
+ emailManager.sendEmail(subject, body, lic.getEmail(), addCC ? user.getEmail() : null, licFile);
243
+ } catch (IOException e) {
244
+ LOG.error("Error creating temporary license file", e);
245
+ throw new SeCurisServiceException(Status.NOT_FOUND.getStatusCode(), "There is no license file available");
246
+ } finally {
247
+ if (licFile != null) {
248
+ licFile.delete();
249
+ }
250
+ }
251
+
202252 lic.setModificationTimestamp(new Date());
203253 em.persist(lic);
204254 em.persist(createLicenseHistoryAction(lic, user, LicenseHistory.Actions.SEND, "Email sent to: " + lic.getEmail()));
....@@ -207,6 +257,7 @@
207257
208258 /**
209259 * Cancel given license
260
+ *
210261 * @param licId
211262 * @param bsc
212263 * @return
....@@ -221,7 +272,8 @@
221272 @Produces({
222273 MediaType.APPLICATION_JSON
223274 })
224
- public Response cancel(@PathParam("licId") Integer licId, @Context BasicSecurityContext bsc) throws SeCurisServiceException {
275
+ public Response cancel(@PathParam("licId") Integer licId, @FormParam("reason") String reason, @Context BasicSecurityContext bsc)
276
+ throws SeCurisServiceException {
225277
226278 EntityManager em = emProvider.get();
227279 License lic = getCurrentLicense(licId, bsc, em);
....@@ -232,12 +284,17 @@
232284 + " can not be canceled from the current license status");
233285 }
234286
235
- lic.setStatus(License.Status.CANCELED);
287
+ if (reason == null && (lic.getStatus() == LicenseStatus.ACTIVE || lic.getStatus() == LicenseStatus.PRE_ACTIVE)) {
288
+ LOG.error("To cancel an active License we need a reason, lic ID: {}, user: {}", lic.getId(), bsc.getUserPrincipal().getName());
289
+ throw new SeCurisServiceException(Status.FORBIDDEN.getStatusCode(), "Active license with id " + licId
290
+ + " can not be canceled without a reason");
291
+ }
292
+
293
+ lic.setStatus(LicenseStatus.CANCELLED);
236294 lic.setModificationTimestamp(new Date());
237295 em.persist(lic);
238296
239
- User user = getUser(bsc.getUserPrincipal().getName(), em);
240
- em.persist(createLicenseHistoryAction(lic, user, LicenseHistory.Actions.CANCEL));
297
+ em.persist(createLicenseHistoryAction(lic, getUser(bsc, em), LicenseHistory.Actions.CANCEL, "Cancelation reason: " + reason));
241298 return Response.ok(lic).build();
242299 }
243300
....@@ -250,39 +307,102 @@
250307 })
251308 @Transactional
252309 public Response create(License lic, @Context BasicSecurityContext bsc) throws SeCurisServiceException {
253
- LOG.info("Creating new license from create()");
254310 EntityManager em = emProvider.get();
255311 Pack pack = null;
256312 if (lic.getPackId() != null) {
257313 pack = em.find(Pack.class, lic.getPackId());
258
- if (pack == null) {
259
- LOG.error("License pack with id {} not found in DB", lic.getPackId());
260
- return Response.status(Status.NOT_FOUND)
261
- .header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "License's pack not found with ID: " + lic.getPackId()).build();
262
- } else {
263
- if (!bsc.isUserInRole(BasicSecurityContext.ROL_ADMIN) && !bsc.getOrganizationsIds().contains(pack.getOrganization().getId())) {
264
- LOG.error("License for pack with id {} can not be created by user {}", pack.getId(), bsc.getUserPrincipal());
265
- return Response.status(Status.UNAUTHORIZED)
266
- .header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "Unathorized action on pack license").build();
267
- }
314
+ }
315
+
316
+ if (pack == null) {
317
+ LOG.error("License pack with id {} not found in DB", lic.getPackId());
318
+ throw new SeCurisServiceException(ErrorCodes.NOT_FOUND, "License's pack not found with ID: " + lic.getPackId());
319
+ } else {
320
+ if (!bsc.isUserInRole(BasicSecurityContext.ROL_ADMIN) && !bsc.getOrganizationsIds().contains(pack.getOrganization().getId())) {
321
+ LOG.error("License for pack with id {} can not be created by user {}", pack.getId(), bsc.getUserPrincipal());
322
+ throw new SeCurisServiceException(ErrorCodes.UNAUTHORIZED_ACCESS, "Unathorized action on pack license");
268323 }
269324 }
270325
271326 User createdBy = getUser(bsc.getUserPrincipal().getName(), em);
272327
273
- // TODO: Manage status if request data is set
328
+ if (lic.getRequestData() != null) {
329
+ SignedLicenseBean signedLicense = generateLicense(lic, em);
330
+ // If user provide a request data the license status is passed
331
+ // directly to ACTIVE
332
+ lic.setStatus(LicenseStatus.ACTIVE);
333
+ try {
334
+ lic.setLicenseData(JsonUtils.toJSON(signedLicense));
335
+ } catch (CurisException e) {
336
+ LOG.error("Error generaing license JSON", e);
337
+ throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Error generaing license JSON");
338
+ }
339
+ } else {
340
+ lic.setStatus(LicenseStatus.CREATED);
341
+ }
274342 lic.setCreatedBy(createdBy);
275
- lic.setStatus(License.Status.CREATED);
276343 lic.setCreationTimestamp(new Date());
277344 lic.setModificationTimestamp(lic.getCreationTimestamp());
278345 em.persist(lic);
279346 em.persist(createLicenseHistoryAction(lic, createdBy, LicenseHistory.Actions.CREATE));
347
+ if (lic.getStatus() == LicenseStatus.ACTIVE) {
348
+ em.persist(createLicenseHistoryAction(lic, createdBy, LicenseHistory.Actions.CREATE, "Activated on creation"));
349
+ }
280350
281351 return Response.ok(lic).build();
282352 }
283
-
284353
285
-
354
+ private SignedLicenseBean generateLicense(License license, EntityManager em) throws SeCurisServiceException {
355
+ SignedLicenseBean sl = null;
356
+ Pack pack = em.find(Pack.class, license.getPackId());
357
+ RequestBean rb = validateRequestData(pack, license.getRequestData());
358
+ try {
359
+ LicenseBean lb = licenseGenerator.generateLicense(rb, extractPackMetadata(pack.getMetadata()), license.getExpirationDate(),
360
+ pack.getLicenseTypeCode(), license.getCode());
361
+ sl = new SignedLicenseBean(lb);
362
+ } catch (SeCurisException e) {
363
+ throw new SeCurisServiceException(ErrorCodes.INVALID_LICENSE_REQUEST_DATA, "Error generating license: " + e.toString());
364
+ }
365
+ return sl;
366
+ }
367
+
368
+ private Map<String, Object> extractPackMetadata(Set<PackMetadata> packMetadata) {
369
+ Map<String, Object> metadata = new HashMap<>();
370
+ for (PackMetadata md : packMetadata) {
371
+ metadata.put(md.getKey(), md.getValue());
372
+ }
373
+
374
+ return metadata;
375
+ }
376
+
377
+ /**
378
+ * We check if the given request data is valid for the current Pack and has
379
+ * a valid format
380
+ *
381
+ * @param pack
382
+ * @param requestData
383
+ * @throws SeCurisServiceException
384
+ */
385
+ private RequestBean validateRequestData(Pack pack, String requestData) throws SeCurisServiceException {
386
+ RequestBean rb = null;
387
+ try {
388
+ rb = JsonUtils.json2object(requestData, RequestBean.class);
389
+ } catch (CurisException e) {
390
+ throw new SeCurisServiceException(ErrorCodes.INVALID_REQUEST_DATA_FORMAT, "Request data has not a valid format");
391
+ }
392
+
393
+ if (!rb.getCustomerCode().equals(pack.getOrganization().getCode())) {
394
+ throw new SeCurisServiceException(ErrorCodes.INVALID_REQUEST_DATA_FORMAT, "Request data not valid, wrong Organization code");
395
+ }
396
+ if (!rb.getLicenseTypeCode().equals(pack.getLicenseTypeCode())) {
397
+ throw new SeCurisServiceException(ErrorCodes.INVALID_REQUEST_DATA_FORMAT, "Request data not valid, wrong License type code");
398
+ }
399
+ // TODO: [rsanchez] Verify that if pack code is null we ignore it
400
+ if (rb.getPackCode() != null && !rb.getPackCode().equals(pack.getCode())) {
401
+ throw new SeCurisServiceException(ErrorCodes.INVALID_REQUEST_DATA_FORMAT, "Request data not valid, wrong Pack code");
402
+ }
403
+ return rb;
404
+ }
405
+
286406 @PUT
287407 @POST
288408 @Path("/{licId}")
....@@ -302,9 +422,22 @@
302422 currentLicense.setCode(lic.getCode());
303423 currentLicense.setFullName(lic.getFullName());
304424 currentLicense.setEmail(lic.getEmail());
305
- currentLicense.setRequestData(lic.getRequestData());
425
+ if (lic.getRequestData() != null) {
426
+ SignedLicenseBean signedLicense = generateLicense(lic, em);
427
+ // If user provide a request data the license status is passed
428
+ // directly to ACTIVE
429
+ lic.setStatus(LicenseStatus.ACTIVE);
430
+ try {
431
+ lic.setLicenseData(JsonUtils.toJSON(signedLicense));
432
+ } catch (CurisException e) {
433
+ LOG.error("Error generaing license JSON", e);
434
+ throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Error generaing license JSON");
435
+ }
436
+ currentLicense.setRequestData(lic.getRequestData());
437
+ }
306438 currentLicense.setModificationTimestamp(new Date());
307439 em.persist(currentLicense);
440
+ em.persist(createLicenseHistoryAction(lic, getUser(bsc, em), LicenseHistory.Actions.MODIFY));
308441
309442 return Response.ok(currentLicense).build();
310443 }
....@@ -321,7 +454,29 @@
321454 EntityManager em = emProvider.get();
322455 License lic = getCurrentLicense(licId, bsc, em);
323456
324
- if (lic.getStatus() != License.Status.CANCELED || lic.getStatus() != License.Status.CREATED) {
457
+ if (lic.getStatus() != LicenseStatus.CANCELLED || lic.getStatus() != LicenseStatus.CREATED) {
458
+ LOG.error("License {} can not be deleted with status {}", lic.getCode(), lic.getStatus());
459
+ return Response.status(Status.FORBIDDEN)
460
+ .header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "License can not be deleted in current status").build();
461
+ }
462
+
463
+ em.remove(lic);
464
+ return Response.ok(Utils.createMap("success", true, "id", licId)).build();
465
+ }
466
+
467
+ @DELETE
468
+ @Path("/{licId}")
469
+ @Transactional
470
+ @Securable
471
+ @Produces({
472
+ MediaType.APPLICATION_JSON
473
+ })
474
+ public Response block(@PathParam("licId") Integer licId, @Context BasicSecurityContext bsc) throws SeCurisServiceException {
475
+ LOG.info("Deleting license with id: {}", licId);
476
+ EntityManager em = emProvider.get();
477
+ License lic = getCurrentLicense(licId, bsc, em);
478
+
479
+ if (lic.getStatus() != LicenseStatus.CANCELLED || lic.getStatus() != LicenseStatus.CREATED) {
325480 LOG.error("License {} can not be deleted with status {}", lic.getCode(), lic.getStatus());
326481 return Response.status(Status.FORBIDDEN)
327482 .header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "License can not be deleted in current status").build();
....@@ -349,6 +504,11 @@
349504 return lic;
350505 }
351506
507
+ private User getUser(BasicSecurityContext bsc, EntityManager em) throws SeCurisServiceException {
508
+ String username = bsc.getUserPrincipal().getName();
509
+ return getUser(username, em);
510
+ }
511
+
352512 private User getUser(String username, EntityManager em) throws SeCurisServiceException {
353513 User user = null;
354514 if (username != null) {
....@@ -358,6 +518,13 @@
358518 }
359519 }
360520 return user;
521
+ }
522
+
523
+ private File createTemporaryLicenseFile(License lic, String licFileName) throws IOException {
524
+ File f = Files.createTempDirectory("securis-server").toFile();
525
+ f = new File(f, licFileName);
526
+ IOUtils.write(lic.getLicenseData(), new FileWriter(f));
527
+ return f;
361528 }
362529
363530 private LicenseHistory createLicenseHistoryAction(License lic, User user, String action, String comments) {
....@@ -373,4 +540,12 @@
373540 private LicenseHistory createLicenseHistoryAction(License lic, User user, String action) {
374541 return createLicenseHistoryAction(lic, user, action, null);
375542 }
543
+
544
+ public static void main(String[] args) throws IOException {
545
+ File f = Files.createTempDirectory("securis-server").toFile();
546
+
547
+ LOG.info("f: {}", f);
548
+ f = new File(f, "config-server.lic");
549
+ LOG.info("f: {}", f);
550
+ }
376551 }