rsanchez
2014-10-23 c4d513ca26fe80946a5d90264de5d8e13e4ea974
#2021 feature - Added pack actions in server and in frontend
15 files modified
changed files
securis/pom.xml patch | view | blame | history
securis/src/main/java/net/curisit/securis/SeCurisServer.java patch | view | blame | history
securis/src/main/java/net/curisit/securis/db/BlockedRequest.java patch | view | blame | history
securis/src/main/java/net/curisit/securis/db/License.java patch | view | blame | history
securis/src/main/java/net/curisit/securis/db/LicenseHistory.java patch | view | blame | history
securis/src/main/java/net/curisit/securis/db/Organization.java patch | view | blame | history
securis/src/main/java/net/curisit/securis/db/Pack.java patch | view | blame | history
securis/src/main/java/net/curisit/securis/ioc/SecurisModule.java patch | view | blame | history
securis/src/main/java/net/curisit/securis/services/LicenseResource.java patch | view | blame | history
securis/src/main/java/net/curisit/securis/services/PackResource.java patch | view | blame | history
securis/src/main/java/net/curisit/securis/utils/EmailManager.java patch | view | blame | history
securis/src/main/resources/META-INF/persistence.xml patch | view | blame | history
securis/src/main/resources/db/schema.sql patch | view | blame | history
securis/src/main/resources/static/js/licenses.js patch | view | blame | history
securis/src/main/resources/static/licenses.html patch | view | blame | history
securis/pom.xml
....@@ -28,11 +28,6 @@
2828 </dependency>
2929 <dependency>
3030 <groupId>org.jboss.resteasy</groupId>
31
- <artifactId>resteasy-jackson-provider</artifactId>
32
- <version>3.0.9.Final</version>
33
- </dependency>
34
- <dependency>
35
- <groupId>org.jboss.resteasy</groupId>
3631 <artifactId>resteasy-multipart-provider</artifactId>
3732 <version>3.0.9.Final</version>
3833 </dependency>
....@@ -76,6 +71,11 @@
7671 <artifactId>httpmime</artifactId>
7772 <version>4.4-beta1</version>
7873 </dependency>
74
+ <dependency>
75
+ <groupId>org.jboss.resteasy</groupId>
76
+ <artifactId>resteasy-jackson2-provider</artifactId>
77
+ <version>3.0.9.Final</version>
78
+ </dependency>
7979 </dependencies>
8080 <build>
8181 <plugins>
securis/src/main/java/net/curisit/securis/SeCurisServer.java
....@@ -52,7 +52,7 @@
5252 private static final Logger CONSOLE = LogManager.getLogger("console");
5353
5454 private static final String PID_FILE = System.getProperty("user.home") + "/.SeCuris/securis-server.pid";
55
-
55
+
5656 private static Server server;
5757 private static Injector injector = null;
5858
....@@ -64,19 +64,15 @@
6464 CONSOLE.info("Execute SeCuris server using:");
6565 CONSOLE.info(" $ ./securis-server.sh {start|stop}");
6666 }
67
-
68
- private void testMail() {
69
-
70
- }
71
-
67
+
7268 public static void main(String[] args) throws Exception {
73
- String command;
69
+ String command;
7470 if (args.length > 0) {
7571 command = args[0].toLowerCase();
7672 } else {
7773 command = "start";
7874 }
79
-
75
+
8076 switch (command) {
8177 case "start":
8278 startServer();
....@@ -90,7 +86,7 @@
9086 System.exit(-1);
9187 }
9288 }
93
-
89
+
9490 private static void stopServer() {
9591 if (!new File(PID_FILE).exists()) {
9692 CONSOLE.error("SeCuris server is NOT running or PID file is missing");
....@@ -105,7 +101,7 @@
105101 LOG.error("Error getting SeCuris server process PID from file: {}", PID_FILE);
106102 }
107103 }
108
-
104
+
109105 private static void startServer() {
110106
111107 if (new File(PID_FILE).exists()) {
....@@ -116,20 +112,22 @@
116112 }
117113 System.exit(-2);
118114 }
119
-
115
+
120116 SecurisModule securisModule = new SecurisModule();
121117 JpaPersistModule jpaPersistModule = new JpaPersistModule("localdb");
122118 Properties props = new Properties();
123119 props.put("javax.persistence.jdbc.password", securisModule.getPassword());
124120 props.put("javax.persistence.jdbc.url", securisModule.getUrl(securisModule.getAppDir()));
125
- //LOG.info("BD Url: {} {}", securisModule.getUrl(securisModule.getAppDir()), securisModule.getPassword());
121
+ // LOG.info("BD Url: {} {}",
122
+ // securisModule.getUrl(securisModule.getAppDir()),
123
+ // securisModule.getPassword());
126124 jpaPersistModule.properties(props);
127125
128126 injector = Guice.createInjector(securisModule, new RequestsModule(), jpaPersistModule);
129127
130128 try {
131129 startServer(injector.getInstance(Key.get(URI.class, Names.named("base-uri"))));
132
-
130
+
133131 } catch (SeCurisException e) {
134132 CONSOLE.error("Error launching the SeCuris server, {}", e);
135133 }
....@@ -153,14 +151,14 @@
153151
154152 QueuedThreadPool threadPool = new QueuedThreadPool();
155153 threadPool.setMaxThreads(50);
156
-
154
+
157155 server = new Server();
158
-
156
+
159157 ServerConnector httpConnector = new ServerConnector(server);
160158 httpConnector.setPort(Config.getInt(Config.KEYS.SERVER_PORT, 9080));
161159 httpConnector.setHost(Config.get(Config.KEYS.SERVER_HOSTNAME, "0.0.0.0"));
162160 server.addConnector(httpConnector);
163
-
161
+
164162 ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
165163 context.setContextPath("/");
166164 context.addEventListener(injector.getInstance(GuiceResteasyBootstrapServletContextListener.class));
....@@ -191,33 +189,33 @@
191189 contexts.setHandlers(new Handler[] {
192190 staticResources, context
193191 });
194
-
192
+
195193 HttpConfiguration http_config = new HttpConfiguration();
196194 http_config.setSecureScheme("https");
197195 http_config.setSecurePort(Config.getInt(Config.KEYS.SERVER_SSL_PORT, 9443));
198196 http_config.setOutputBufferSize(32768);
199197 http_config.setSendServerVersion(true);
200198 http_config.setSendDateHeader(false);
201
-
202
-
199
+
203200 HttpConfiguration https_config = new HttpConfiguration(http_config);
204201 https_config.addCustomizer(new SecureRequestCustomizer());
205
-
202
+
206203 SslContextFactory sslContextFactory = new SslContextFactory();
207204 sslContextFactory.setKeyStorePath(Config.get(Config.KEYS.KEYSTORE_PATH));
208205 sslContextFactory.setKeyStoreType(Config.get(Config.KEYS.KEYSTORE_TYPE, "JKS"));
209206 sslContextFactory.setKeyStorePassword(Config.get(Config.KEYS.KEYSTORE_PASSWORD, ""));
210
- //sslContextFactory.setCertAlias("1");
211
-// sslContextFactory.setKeyManagerPassword("curist3c");
212
-// sslContextFactory.setTrustStorePath("/Users/rob/.ssh/keys/keystore");
213
-// sslContextFactory.setTrustStorePassword("curist3c");
207
+ // sslContextFactory.setCertAlias("1");
208
+ // sslContextFactory.setKeyManagerPassword("curist3c");
209
+ // sslContextFactory.setTrustStorePath("/Users/rob/.ssh/keys/keystore");
210
+ // sslContextFactory.setTrustStorePassword("curist3c");
214211 sslContextFactory.checkKeyStore();
215212 sslContextFactory.setNeedClientAuth(false);
216
-
217
- ServerConnector sslConnector = new ServerConnector(server, new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()), new HttpConnectionFactory(https_config));
213
+
214
+ ServerConnector sslConnector = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
215
+ new HttpConnectionFactory(https_config));
218216 sslConnector.setPort(Config.getInt(Config.KEYS.SERVER_SSL_PORT, 9443));
219217 sslConnector.setHost(Config.get(Config.KEYS.SERVER_HOSTNAME, "0.0.0.0"));
220
- server.addConnector( sslConnector );
218
+ server.addConnector(sslConnector);
221219
222220 server.setHandler(context);
223221 server.setStopAtShutdown(true);
....@@ -233,9 +231,10 @@
233231 }
234232
235233 }
236
-
237
- static class ServerStoppedListener extends AbstractLifeCycleListener {
238
- @Override public void lifeCycleStopped(LifeCycle event) {
234
+
235
+ static class ServerStoppedListener extends AbstractLifeCycleListener {
236
+ @Override
237
+ public void lifeCycleStopped(LifeCycle event) {
239238 if (new File(PID_FILE).exists())
240239 new File(PID_FILE).delete();
241240 }
securis/src/main/java/net/curisit/securis/db/BlockedRequest.java
....@@ -89,8 +89,7 @@
8989 }
9090
9191 public static String generateHash(String reqData) {
92
- String hash = reqData != null ? Utils.sha256(reqData) : null;
93
- return hash;
92
+ return (reqData != null ? Utils.sha256(reqData) : null);
9493 }
9594
9695 public static boolean isRequestBlocked(String requestData, EntityManager em) {
securis/src/main/java/net/curisit/securis/db/License.java
....@@ -16,11 +16,17 @@
1616 import javax.persistence.ManyToOne;
1717 import javax.persistence.NamedQueries;
1818 import javax.persistence.NamedQuery;
19
+import javax.persistence.NonUniqueResultException;
1920 import javax.persistence.OneToMany;
2021 import javax.persistence.Table;
2122 import javax.persistence.TypedQuery;
2223
2324 import net.curisit.integrity.commons.Utils;
25
+import net.curisit.securis.services.exception.SeCurisServiceException;
26
+import net.curisit.securis.services.exception.SeCurisServiceException.ErrorCodes;
27
+
28
+import org.apache.logging.log4j.LogManager;
29
+import org.apache.logging.log4j.Logger;
2430
2531 import com.fasterxml.jackson.annotation.JsonAutoDetect;
2632 import com.fasterxml.jackson.annotation.JsonIgnore;
....@@ -39,11 +45,13 @@
3945 @JsonIgnoreProperties(ignoreUnknown = true)
4046 @NamedQueries({
4147 @NamedQuery(name = "list-licenses-by-pack", query = "SELECT l FROM License l where l.pack.id = :packId"),
48
+ @NamedQuery(name = "list-licenses-by-req-data", query = "SELECT l FROM License l where l.reqDataHash = :hash"),
4249 @NamedQuery(name = "list-active-licenses-by-req-data", query = "SELECT l FROM License l where l.reqDataHash = :hash and l.status in ('AC', 'PA')")
4350 })
4451 public class License implements Serializable {
52
+ private static final long serialVersionUID = 2700310404904877227L;
4553
46
- private static final long serialVersionUID = 1L;
54
+ private static final Logger LOG = LogManager.getLogger(License.class);
4755
4856 @Id
4957 @GeneratedValue
....@@ -63,8 +71,8 @@
6371
6472 @JsonIgnore
6573 @ManyToOne
66
- @JoinColumn(name = "canceled_by")
67
- private User canceledBy;
74
+ @JoinColumn(name = "cancelled_by")
75
+ private User cancelledBy;
6876
6977 private LicenseStatus status;
7078
....@@ -78,6 +86,10 @@
7886 @JsonProperty("request_data")
7987 private String requestData;
8088
89
+ /**
90
+ * request data hash is automatically set when we use
91
+ * {@link License#setRequestData(String)} method
92
+ */
8193 @Column(name = "request_data_hash")
8294 @JsonIgnore
8395 private String reqDataHash;
....@@ -158,18 +170,18 @@
158170 }
159171 }
160172
161
- @JsonProperty("canceled_by_id")
162
- public String getCanceledById() {
163
- return canceledBy == null ? null : canceledBy.getUsername();
173
+ @JsonProperty("cancelled_by_id")
174
+ public String getCancelledById() {
175
+ return cancelledBy == null ? null : cancelledBy.getUsername();
164176 }
165177
166
- @JsonProperty("canceled_by_id")
167
- public void setCanceledById(String username) {
178
+ @JsonProperty("cancelled_by_id")
179
+ public void setCancelledById(String username) {
168180 if (username == null) {
169
- canceledBy = null;
181
+ cancelledBy = null;
170182 } else {
171
- canceledBy = new User();
172
- canceledBy.setUsername(username);
183
+ cancelledBy = new User();
184
+ cancelledBy.setUsername(username);
173185 }
174186 }
175187
....@@ -229,12 +241,12 @@
229241 this.id = id;
230242 }
231243
232
- public User getCanceledBy() {
233
- return canceledBy;
244
+ public User getCancelledBy() {
245
+ return cancelledBy;
234246 }
235247
236
- public void setCanceledBy(User canceledBy) {
237
- this.canceledBy = canceledBy;
248
+ public void setCancelledBy(User cancelledBy) {
249
+ this.cancelledBy = cancelledBy;
238250 }
239251
240252 public Date getLastAccessTimestamp() {
....@@ -251,6 +263,7 @@
251263
252264 public void setRequestData(String requestData) {
253265 this.requestData = requestData;
266
+ this.reqDataHash = BlockedRequest.generateHash(this.requestData);
254267 }
255268
256269 public String getLicenseData() {
....@@ -283,6 +296,10 @@
283296
284297 public void setExpirationDate(Date expirationDate) {
285298 this.expirationDate = expirationDate;
299
+ }
300
+
301
+ public String getReqDataHash() {
302
+ return reqDataHash;
286303 }
287304
288305 public static class Action {
....@@ -323,17 +340,16 @@
323340 }
324341 }
325342
326
- public License findLicenseByRequestData(String requestData, EntityManager em) {
343
+ public static License findLicenseByRequestData(String requestData, EntityManager em) throws SeCurisServiceException {
327344 TypedQuery<License> query = em.createNamedQuery("list-active-licenses-by-req-data", License.class);
328345 query.setParameter("hash", BlockedRequest.generateHash(requestData));
329
- return null;
346
+ try {
347
+ return query.getSingleResult();
348
+ } catch (NonUniqueResultException e) {
349
+ LOG.error("There are more than 1 active license for request data: {}\nHash: {}", requestData, BlockedRequest.generateHash(requestData));
350
+ throw new SeCurisServiceException(ErrorCodes.DUPLICATED_REQUEST_DATA, "There are more than 1 active license for request data hash: "
351
+ + BlockedRequest.generateHash(requestData));
352
+ }
330353 }
331354
332
- public String getReqDataHash() {
333
- return reqDataHash;
334
- }
335
-
336
- public void setReqDataHash(String reqDataHash) {
337
- this.reqDataHash = reqDataHash;
338
- }
339355 }
securis/src/main/java/net/curisit/securis/db/LicenseHistory.java
....@@ -116,6 +116,7 @@
116116 public static final String ACTIVATE = "activate";
117117 public static final String CANCEL = "cancel";
118118 public static final String BLOCK = "block";
119
+ public static final String UNBLOCK = "unblock";
119120 public static final String DELETE = "delete";
120121 }
121122 }
securis/src/main/java/net/curisit/securis/db/Organization.java
....@@ -167,10 +167,12 @@
167167 @JsonProperty("users_ids")
168168 public void setUsersIds(List<String> usersIds) {
169169 users = new ArrayList<>();
170
- for (String userid : usersIds) {
171
- User u = new User();
172
- u.setUsername(userid);
173
- users.add(u);
170
+ if (usersIds != null) {
171
+ for (String userid : usersIds) {
172
+ User u = new User();
173
+ u.setUsername(userid);
174
+ users.add(u);
175
+ }
174176 }
175177 }
176178
securis/src/main/java/net/curisit/securis/db/Pack.java
....@@ -1,7 +1,10 @@
11 package net.curisit.securis.db;
22
33 import java.io.Serializable;
4
+import java.util.Arrays;
45 import java.util.Date;
6
+import java.util.List;
7
+import java.util.Map;
58 import java.util.Set;
69
710 import javax.persistence.CascadeType;
....@@ -16,6 +19,8 @@
1619 import javax.persistence.NamedQuery;
1720 import javax.persistence.OneToMany;
1821 import javax.persistence.Table;
22
+
23
+import net.curisit.integrity.commons.Utils;
1924
2025 import com.fasterxml.jackson.annotation.JsonAutoDetect;
2126 import com.fasterxml.jackson.annotation.JsonIgnore;
....@@ -321,4 +326,36 @@
321326
322327 return (id == null ? 0 : id.hashCode());
323328 }
329
+
330
+ public static class Action {
331
+ public static final int CREATE = 1;
332
+ public static final int ACTIVATION = 2;
333
+ public static final int PUT_ONHOLD = 3;
334
+ public static final int CANCEL = 4;
335
+ public static final int DELETE = 5;
336
+ }
337
+
338
+ public static class Status {
339
+
340
+ private static final Map<Integer, List<Integer>> transitions = Utils.createMap( //
341
+ Action.ACTIVATION, Arrays.asList(PackStatus.CREATED, PackStatus.ON_HOLD, PackStatus.EXPIRED), //
342
+ Action.PUT_ONHOLD, Arrays.asList(PackStatus.ACTIVE), //
343
+ Action.CANCEL, Arrays.asList(PackStatus.ACTIVE, PackStatus.ON_HOLD, PackStatus.EXPIRED), //
344
+ Action.DELETE, Arrays.asList(PackStatus.CANCELLED, PackStatus.CREATED) //
345
+ );
346
+
347
+ /**
348
+ * It checks if a given action is valid for the License, passing the
349
+ * action and the current license status
350
+ *
351
+ * @param oldStatus
352
+ * @param newStatus
353
+ * @return
354
+ */
355
+ public static boolean isActionValid(Integer action, PackStatus currentStatus) {
356
+ List<Integer> validStatuses = transitions.get(currentStatus);
357
+
358
+ return validStatuses != null && validStatuses.contains(currentStatus);
359
+ }
360
+ }
324361 }
securis/src/main/java/net/curisit/securis/ioc/SecurisModule.java
....@@ -23,7 +23,7 @@
2323 public class SecurisModule extends AbstractModule {
2424
2525 private static final int DEFAULT_PORT = 9997;
26
- private static final String PROPERTIES_FILE_NAME = "/server.properties";
26
+ private static final String PROPERTIES_FILE_NAME = "/securis-server.properties";
2727
2828 private static final Logger LOG = LogManager.getLogger(SecurisModule.class);
2929
....@@ -127,20 +127,6 @@
127127 @Singleton
128128 public String getHashLogo() {
129129 return "1b42616809d4cd8ccf109e3c30d0ab25067f160b30b7354a08ddd563de0096ba";
130
- }
131
-
132
- @Named("license-req-file-name")
133
- @Provides
134
- @Singleton
135
- public String getLicenseReqFileName() {
136
- return "license.req";
137
- }
138
-
139
- @Named("license-file-name")
140
- @Provides
141
- @Singleton
142
- public String getLicenseFileName() {
143
- return "license.lic";
144130 }
145131
146132 @Provides
securis/src/main/java/net/curisit/securis/services/LicenseResource.java
....@@ -45,6 +45,7 @@
4545 import net.curisit.securis.db.LicenseStatus;
4646 import net.curisit.securis.db.Pack;
4747 import net.curisit.securis.db.PackMetadata;
48
+import net.curisit.securis.db.PackStatus;
4849 import net.curisit.securis.db.User;
4950 import net.curisit.securis.security.BasicSecurityContext;
5051 import net.curisit.securis.security.Securable;
....@@ -56,6 +57,7 @@
5657 import net.curisit.securis.utils.TokenHelper;
5758
5859 import org.apache.commons.io.IOUtils;
60
+import org.apache.commons.lang3.ObjectUtils;
5961 import org.apache.logging.log4j.LogManager;
6062 import org.apache.logging.log4j.Logger;
6163
....@@ -158,7 +160,7 @@
158160 }
159161 if (License.Status.isActionValid(License.Action.DOWNLOAD, lic.getStatus())) {
160162 LOG.error("License with id {} is not active, so It can not downloaded", licId, bsc.getUserPrincipal());
161
- throw new SeCurisServiceException(Status.FORBIDDEN.getStatusCode(), "License is not active, so It can not be downloaded");
163
+ throw new SeCurisServiceException(ErrorCodes.WRONG_STATUS, "License is not active, so It can not be downloaded");
162164 }
163165 em.persist(createLicenseHistoryAction(lic, getUser(bsc, em), LicenseHistory.Actions.DOWNLOAD));
164166 return Response
....@@ -193,6 +195,15 @@
193195 LOG.error("License with id {} can not be activated from current license status", licId);
194196 throw new SeCurisServiceException(Status.FORBIDDEN.getStatusCode(), "License with id " + licId
195197 + " can not be activated from the current license status");
198
+ }
199
+ validateRequestData(lic.getPack(), lic.getRequestData());
200
+
201
+ License existingLicense = License.findLicenseByRequestData(lic.getRequestData(), em);
202
+ if (existingLicense != null) {
203
+ return Response.status(DefaultExceptionHandler.DEFAULT_APP_ERROR_STATUS_CODE)
204
+ .header(DefaultExceptionHandler.ERROR_CODE_MESSAGE_HEADER, ErrorCodes.DUPLICATED_REQUEST_DATA)
205
+ .header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "There is already an active license for current request data")
206
+ .type(MediaType.APPLICATION_JSON).entity(existingLicense).build();
196207 }
197208
198209 lic.setStatus(LicenseStatus.ACTIVE);
....@@ -291,10 +302,11 @@
291302 }
292303
293304 lic.setStatus(LicenseStatus.CANCELLED);
305
+ lic.setCancelledById(bsc.getUserPrincipal().getName());
294306 lic.setModificationTimestamp(new Date());
295307 em.persist(lic);
296308
297
- em.persist(createLicenseHistoryAction(lic, getUser(bsc, em), LicenseHistory.Actions.CANCEL, "Cancelation reason: " + reason));
309
+ em.persist(createLicenseHistoryAction(lic, getUser(bsc, em), LicenseHistory.Actions.CANCEL, "Cancellation reason: " + reason));
298310 return Response.ok(lic).build();
299311 }
300312
....@@ -321,11 +333,22 @@
321333 LOG.error("License for pack with id {} can not be created by user {}", pack.getId(), bsc.getUserPrincipal());
322334 throw new SeCurisServiceException(ErrorCodes.UNAUTHORIZED_ACCESS, "Unathorized action on pack license");
323335 }
336
+ if (pack.getStatus() != PackStatus.ACTIVE) {
337
+ LOG.error("Current pack, {}, is not active so licenses cannot be created", pack.getId());
338
+ throw new SeCurisServiceException(ErrorCodes.WRONG_STATUS, "Current pack is not active so licenses cannot be created");
339
+ }
324340 }
325341
326342 User createdBy = getUser(bsc.getUserPrincipal().getName(), em);
327343
328344 if (lic.getRequestData() != null) {
345
+ License existingLicense = License.findLicenseByRequestData(lic.getRequestData(), em);
346
+ if (existingLicense != null) {
347
+ return Response.status(DefaultExceptionHandler.DEFAULT_APP_ERROR_STATUS_CODE)
348
+ .header(DefaultExceptionHandler.ERROR_CODE_MESSAGE_HEADER, ErrorCodes.DUPLICATED_REQUEST_DATA)
349
+ .header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "There is already an active license for current request data")
350
+ .type(MediaType.APPLICATION_JSON).entity(existingLicense).build();
351
+ }
329352 SignedLicenseBean signedLicense = generateLicense(lic, em);
330353 // If user provide a request data the license status is passed
331354 // directly to ACTIVE
....@@ -338,7 +361,7 @@
338361 lic.setLicenseData(JsonUtils.toJSON(signedLicense));
339362 } catch (SeCurisException e) {
340363 LOG.error("Error generaing license JSON", e);
341
- throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Error generaing license JSON");
364
+ throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Error generating license JSON");
342365 }
343366 } else {
344367 lic.setStatus(LicenseStatus.CREATED);
....@@ -387,6 +410,9 @@
387410 * @throws SeCurisServiceException
388411 */
389412 private RequestBean validateRequestData(Pack pack, String requestData) throws SeCurisServiceException {
413
+ if (requestData == null) {
414
+ throw new SeCurisServiceException(ErrorCodes.INVALID_REQUEST_DATA, "Request data is empty");
415
+ }
390416 RequestBean rb = null;
391417 try {
392418 rb = JsonUtils.json2object(requestData, RequestBean.class);
....@@ -422,27 +448,32 @@
422448 EntityManager em = emProvider.get();
423449
424450 License currentLicense = getCurrentLicense(licId, bsc, em);
425
-
426
- currentLicense.setCode(lic.getCode());
451
+ currentLicense.setComments(lic.getComments());
427452 currentLicense.setFullName(lic.getFullName());
428453 currentLicense.setEmail(lic.getEmail());
429
- if (lic.getRequestData() != null && currentLicense.getStatus() == LicenseStatus.CREATED) {
430
- SignedLicenseBean signedLicense = generateLicense(lic, em);
431
- lic.setStatus(LicenseStatus.ACTIVE);
432
- try {
433
- // Next line is necessary to normalize the String that contains
434
- // the request.
435
- lic.setRequestData(JsonUtils.toJSON((RequestBean) signedLicense));
436
- if (BlockedRequest.isRequestBlocked(lic.getRequestData(), em)) {
437
- throw new SeCurisServiceException(ErrorCodes.BLOCKED_REQUEST_DATA, "Given request data is blocked and cannot be activate");
454
+
455
+ if (currentLicense.getStatus() == LicenseStatus.CREATED && !ObjectUtils.equals(currentLicense.getReqDataHash(), lic.getReqDataHash())) {
456
+ if (lic.getRequestData() != null) {
457
+ SignedLicenseBean signedLicense = generateLicense(lic, em);
458
+ try {
459
+ // Next line is necessary to normalize the String that
460
+ // contains
461
+ // the request.
462
+ lic.setRequestData(JsonUtils.toJSON((RequestBean) signedLicense));
463
+ if (BlockedRequest.isRequestBlocked(lic.getRequestData(), em)) {
464
+ throw new SeCurisServiceException(ErrorCodes.BLOCKED_REQUEST_DATA, "Given request data is blocked and cannot be used again");
465
+ }
466
+ lic.setLicenseData(JsonUtils.toJSON(signedLicense));
467
+ } catch (SeCurisException e) {
468
+ LOG.error("Error generaing license JSON", e);
469
+ throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Error generaing license JSON");
438470 }
439
- lic.setLicenseData(JsonUtils.toJSON(signedLicense));
440
- } catch (SeCurisException e) {
441
- LOG.error("Error generaing license JSON", e);
442
- throw new SeCurisServiceException(ErrorCodes.INVALID_FORMAT, "Error generaing license JSON");
471
+ } else {
472
+ // This set method could pass a null value
473
+ currentLicense.setRequestData(null);
443474 }
444
- currentLicense.setRequestData(lic.getRequestData());
445475 }
476
+
446477 currentLicense.setModificationTimestamp(new Date());
447478 em.persist(currentLicense);
448479 em.persist(createLicenseHistoryAction(lic, getUser(bsc, em), LicenseHistory.Actions.MODIFY));
....@@ -462,17 +493,30 @@
462493 EntityManager em = emProvider.get();
463494 License lic = getCurrentLicense(licId, bsc, em);
464495
465
- if (lic.getStatus() != LicenseStatus.CANCELLED || lic.getStatus() != LicenseStatus.CREATED) {
496
+ if (License.Status.isActionValid(License.Action.DELETE, lic.getStatus())) {
466497 LOG.error("License {} can not be deleted with status {}", lic.getCode(), lic.getStatus());
467
- return Response.status(Status.FORBIDDEN)
468
- .header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, "License can not be deleted in current status").build();
498
+ throw new SeCurisServiceException(ErrorCodes.WRONG_STATUS, "License can not be deleted in current status: " + lic.getStatus().name());
499
+ }
500
+ if (lic.getStatus() == LicenseStatus.CANCELLED) {
501
+ // If license is removed and it's blocked then the blocked request
502
+ // should be removed, that is,
503
+ // the license deletion will unblock the request data
504
+ TypedQuery<License> query = em.createNamedQuery("list-licenses-by-req-data", License.class);
505
+ query.setParameter("hash", lic.getReqDataHash());
506
+ List<License> list = query.getResultList();
507
+ if (list == null || list.size() == 0) {
508
+ BlockedRequest br = em.find(BlockedRequest.class, lic.getReqDataHash());
509
+ if (br != null) {
510
+ em.remove(br);
511
+ }
512
+ }
469513 }
470514
471515 em.remove(lic);
472516 return Response.ok(Utils.createMap("success", true, "id", licId)).build();
473517 }
474518
475
- @DELETE
519
+ @POST
476520 @Path("/{licId}/block")
477521 @Transactional
478522 @Securable
....@@ -484,7 +528,7 @@
484528 EntityManager em = emProvider.get();
485529 License lic = getCurrentLicense(licId, bsc, em);
486530
487
- if (lic.getStatus() != LicenseStatus.CANCELLED) {
531
+ if (!License.Status.isActionValid(License.Action.BLOCK, lic.getStatus())) {
488532 LOG.error("License can only be blocked in CANCELLED status, current: {}", lic.getStatus().name());
489533 throw new SeCurisServiceException(ErrorCodes.WRONG_STATUS, "License can only be blocked in CANCELLED status");
490534 }
....@@ -502,6 +546,29 @@
502546 return Response.ok(Utils.createMap("success", true, "id", licId)).build();
503547 }
504548
549
+ @POST
550
+ @Path("/{licId}/unblock")
551
+ @Transactional
552
+ @Securable
553
+ @Produces({
554
+ MediaType.APPLICATION_JSON
555
+ })
556
+ public Response unblock(@PathParam("licId") Integer licId, @Context BasicSecurityContext bsc) throws SeCurisServiceException {
557
+ LOG.info("Unblocking license with id: {}", licId);
558
+ EntityManager em = emProvider.get();
559
+ License lic = getCurrentLicense(licId, bsc, em);
560
+
561
+ if (BlockedRequest.isRequestBlocked(lic.getRequestData(), em)) {
562
+ BlockedRequest blockedReq = em.find(BlockedRequest.class, lic.getReqDataHash());
563
+ em.remove(blockedReq);
564
+ em.persist(createLicenseHistoryAction(lic, getUser(bsc, em), LicenseHistory.Actions.UNBLOCK));
565
+ } else {
566
+ LOG.info("Request data for license {} is NOT blocked", licId);
567
+ }
568
+
569
+ return Response.ok(Utils.createMap("success", true, "id", licId)).build();
570
+ }
571
+
505572 private License getCurrentLicense(Integer licId, BasicSecurityContext bsc, EntityManager em) throws SeCurisServiceException {
506573 if (licId == null || "".equals(licId)) {
507574 LOG.error("License ID is mandatory");
securis/src/main/java/net/curisit/securis/services/PackResource.java
....@@ -30,9 +30,12 @@
3030 import net.curisit.securis.db.Organization;
3131 import net.curisit.securis.db.Pack;
3232 import net.curisit.securis.db.PackMetadata;
33
+import net.curisit.securis.db.PackStatus;
3334 import net.curisit.securis.db.User;
3435 import net.curisit.securis.security.BasicSecurityContext;
3536 import net.curisit.securis.security.Securable;
37
+import net.curisit.securis.services.exception.SeCurisServiceException;
38
+import net.curisit.securis.services.exception.SeCurisServiceException.ErrorCodes;
3639 import net.curisit.securis.utils.TokenHelper;
3740
3841 import org.apache.logging.log4j.LogManager;
....@@ -154,11 +157,12 @@
154157
155158 User user = em.find(User.class, bsc.getUserPrincipal().getName());
156159
160
+ pack.setStatus(PackStatus.CREATED);
157161 pack.setCreatedBy(user);
158162 pack.setCreationTimestamp(new Date());
159163 em.persist(pack);
160
- Set<PackMetadata> newMD = pack.getMetadata();
161
-
164
+ Set<PackMetadata> newMD = pack.getMetadata();
165
+
162166 if (newMD != null) {
163167 for (PackMetadata md : newMD) {
164168 md.setPack(pack);
....@@ -215,12 +219,13 @@
215219
216220 em.persist(currentPack);
217221
218
- Set<PackMetadata> newMD = pack.getMetadata();
222
+ Set<PackMetadata> newMD = pack.getMetadata();
219223 for (PackMetadata currentMd : currentPack.getMetadata()) {
220
- if (newMD == null || !newMD.contains(currentMd));
221
- em.remove(currentMd);
224
+ if (newMD == null || !newMD.contains(currentMd))
225
+ ;
226
+ em.remove(currentMd);
222227 }
223
-
228
+
224229 if (newMD != null) {
225230 for (PackMetadata md : newMD) {
226231 md.setPack(currentPack);
....@@ -231,6 +236,84 @@
231236 return Response.ok(pack).build();
232237 }
233238
239
+ @POST
240
+ @Path("/{packId}/activate")
241
+ @Transactional
242
+ @Securable
243
+ @RolesAllowed(BasicSecurityContext.ROL_ADMIN)
244
+ @Consumes(MediaType.APPLICATION_JSON)
245
+ @Produces({
246
+ MediaType.APPLICATION_JSON
247
+ })
248
+ public Response activate(@PathParam("packId") Integer packId) throws SeCurisServiceException {
249
+ LOG.info("Activating pack with id: {}", packId);
250
+ EntityManager em = emProvider.get();
251
+
252
+ Pack currentPack = em.find(Pack.class, packId);
253
+
254
+ if (!Pack.Status.isActionValid(Pack.Action.ACTIVATION, currentPack.getStatus())) {
255
+ LOG.error("Pack with id {} cannot be activaed from status {}", packId, currentPack.getStatus().name());
256
+ throw new SeCurisServiceException(ErrorCodes.WRONG_STATUS, "Pack cannot be activated in status: " + currentPack.getStatus().name());
257
+ }
258
+
259
+ currentPack.setStatus(PackStatus.ACTIVE);
260
+ em.persist(currentPack);
261
+
262
+ return Response.ok(currentPack).build();
263
+ }
264
+
265
+ @POST
266
+ @Path("/{packId}/putonhold")
267
+ @Transactional
268
+ @Securable
269
+ @RolesAllowed(BasicSecurityContext.ROL_ADMIN)
270
+ @Consumes(MediaType.APPLICATION_JSON)
271
+ @Produces({
272
+ MediaType.APPLICATION_JSON
273
+ })
274
+ public Response onhold(@PathParam("packId") Integer packId) throws SeCurisServiceException {
275
+ LOG.info("Putting On hold pack with id: {}", packId);
276
+ EntityManager em = emProvider.get();
277
+
278
+ Pack currentPack = em.find(Pack.class, packId);
279
+
280
+ if (!Pack.Status.isActionValid(Pack.Action.PUT_ONHOLD, currentPack.getStatus())) {
281
+ LOG.error("Pack with id {} cannot be put on hold from status {}", packId, currentPack.getStatus().name());
282
+ throw new SeCurisServiceException(ErrorCodes.WRONG_STATUS, "Pack cannot be put on hold in status: " + currentPack.getStatus().name());
283
+ }
284
+
285
+ currentPack.setStatus(PackStatus.ON_HOLD);
286
+ em.persist(currentPack);
287
+
288
+ return Response.ok(currentPack).build();
289
+ }
290
+
291
+ @POST
292
+ @Path("/{packId}/cancel")
293
+ @Transactional
294
+ @Securable
295
+ @RolesAllowed(BasicSecurityContext.ROL_ADMIN)
296
+ @Consumes(MediaType.APPLICATION_JSON)
297
+ @Produces({
298
+ MediaType.APPLICATION_JSON
299
+ })
300
+ public Response cancel(@PathParam("packId") Integer packId) throws SeCurisServiceException {
301
+ LOG.info("Putting On hold pack with id: {}", packId);
302
+ EntityManager em = emProvider.get();
303
+
304
+ Pack currentPack = em.find(Pack.class, packId);
305
+
306
+ if (!Pack.Status.isActionValid(Pack.Action.CANCEL, currentPack.getStatus())) {
307
+ LOG.error("Pack with id {} cannot cancelled from status {}", packId, currentPack.getStatus().name());
308
+ throw new SeCurisServiceException(ErrorCodes.WRONG_STATUS, "Pack cannot be cancelled in status: " + currentPack.getStatus().name());
309
+ }
310
+
311
+ currentPack.setStatus(PackStatus.CANCELLED);
312
+ em.persist(currentPack);
313
+
314
+ return Response.ok(currentPack).build();
315
+ }
316
+
234317 private void setPackOrganization(Pack currentPack, Integer orgId, EntityManager em) throws SeCurisException {
235318 Organization org = null;
236319 if (orgId != null) {
securis/src/main/java/net/curisit/securis/utils/EmailManager.java
....@@ -55,7 +55,7 @@
5555 *
5656 * @throws SeCurisException
5757 */
58
- private EmailManager() throws SeCurisException {
58
+ public EmailManager() throws SeCurisException {
5959 String domain = Params.get(Params.KEYS.MAILGUN_DOMAIN);
6060 if (domain == null) {
6161 throw new SeCurisException("Please, add '" + Params.KEYS.MAILGUN_DOMAIN + "' parameter to config file");
securis/src/main/resources/META-INF/persistence.xml
....@@ -11,7 +11,7 @@
1111
1212 <properties>
1313 <property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
14
- <property name="javax.persistence.jdbc.url" value="jdbc:h2:/tmp/.CurisIntegrity/db/curissecuris" />
14
+<!-- <property name="javax.persistence.jdbc.url" value="jdbc:h2:~/.SeCuris/db/securis" /> -->
1515 <property name="javax.persistence.jdbc.user" value="curis" />
1616 <property name="javax.persistence.jdbc.password" value="53curi5" />
1717 <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
securis/src/main/resources/db/schema.sql
....@@ -8,7 +8,7 @@
88 drop table IF EXISTS user;
99 CREATE TABLE IF NOT EXISTS user (
1010 username VARCHAR(45) NOT NULL ,
11
- password VARCHAR(100) NULL ,
11
+ password VARCHAR(256) NULL ,
1212 roles INT NOT NULL default 0,
1313 first_name VARCHAR(100) NULL ,
1414 last_name VARCHAR(100) NULL ,
....@@ -113,12 +113,12 @@
113113 modification_timestamp DATETIME NULL ,
114114 last_access_timestamp DATETIME NULL ,
115115 expiration_date DATETIME NULL ,
116
- canceled_by varchar(45) NULL ,
116
+ cancelled_by varchar(45) NULL ,
117117 created_by varchar(45) NULL ,
118118 status VARCHAR(2) NOT NULL default 'CR',
119119 PRIMARY KEY (id));
120120
121
-create index if not exists lic_hash_req_idx on license(hash_request_data);
121
+create index if not exists lic_hash_req_idx on license(request_data_hash);
122122 create index if not exists lic_pack_idx on license(pack_id);
123123
124124 drop table IF EXISTS license_history;
securis/src/main/resources/static/js/licenses.js
....@@ -101,11 +101,20 @@
101101 '$store',
102102 '$L',
103103 function($scope, $http, $resource, toaster, Catalogs, $store, $L) {
104
- var packResource = $resource('/pack/:packId', {
105
- packId : '@id'
106
- });
104
+ var packResource = $resource('/pack/:packId/:action',
105
+ {
106
+ packId : '@id',
107
+ action : '@action'
108
+ },
109
+ {
110
+ activate: {
111
+ method: "POST",
112
+ params: {action: "activate"}
113
+ }
114
+ }
115
+ );
107116 var PACK_STATUS = [
108
- {id: 'PE', label: $L.get('Pending')},
117
+ {id: 'CR', label: $L.get('Created')},
109118 {id: 'AC', label: $L.get('Active')},
110119 {id: 'OH', label: $L.get('On Hold')},
111120 {id: 'EX', label: $L.get('Expired')},
....@@ -165,13 +174,31 @@
165174 _savePackData();
166175 }
167176 }
177
+
178
+ /**
179
+ * Execute an action over the pack, activation, onhold, cancellation
180
+ */
181
+ $scope.execute = function(action) {
182
+ console.log('Action: '+ action +' on pack: ' + $scope.pack.id);
183
+ var _success = function() {
184
+ if (!$scope.isNew) $scope.showForm = false;
185
+ $scope.packs = packResource.query();
186
+ toaster.pop('success', Catalogs.getName(), $L.get("Pack '{0}' {1} successfully", $scope.pack.code, $L.get("activated")));
187
+ }
188
+ var _error = function(error) {
189
+ console.log(error);
190
+ toaster.pop('error', Catalogs.getName(), $L.get("Error {0} pack '{1}'. Reason: {2}", $L.get("activating"), $scope.pack.code, $L.get(error.headers('X-SECURIS-ERROR'))));
191
+ }
192
+ packResource.activate({id: $scope.pack.id}, _success, _error);
193
+ }
168194
195
+
169196 $scope.newPack = function() {
170197 $scope.isNew = true;
171198 $scope.showForm = true;
172199 $scope.pack = {
173200 license_preactivation: true,
174
- status: 'PE',
201
+ status: 'CR',
175202 num_licenses: 1,
176203 license_type_id: null,
177204 organization_id: null //!$scope.refs.organization_id || !$scope.refs.organization_id.length ? null : $scope.refs.organization_id[0].id
....@@ -190,7 +217,13 @@
190217 if (!(selectedPack.end_valid_date instanceof Date)) {
191218 selectedPack.end_valid_date = new Date(selectedPack.end_valid_date);
192219 }
220
+
193221 $scope.pack = selectedPack;
222
+
223
+ //$scope.pack.organization_name = $scope.getLabelFromId('organization_id', $scope.pack.organization_id);
224
+ $scope.pack.license_type_name = $scope.getLabelFromId('license_type_id', $scope.pack.license_type_id);
225
+ $scope.pack.status_name = $scope.getLabelFromId('pack_status', $scope.pack.status);
226
+
194227 setTimeout(function() {
195228 $('#code').focus();
196229 }, 0);
....@@ -223,6 +256,16 @@
223256 $scope.$parent.currentPack = pack;
224257 $store.put('currentPack', pack);
225258 $scope.$parent.$broadcast('pack_changed', pack);
259
+ }
260
+
261
+ $scope.getLabelFromId = function(field, myid) {
262
+ var label = null;
263
+ $scope.refs[field].forEach(function (elem) {
264
+ if (elem.id === myid) {
265
+ label = elem.label;
266
+ }
267
+ });
268
+ return label;
226269 }
227270
228271 $scope.createMetadataRow = function() {
....@@ -264,6 +307,7 @@
264307 function($scope, $http, $resource, toaster, $store, $L) {
265308 $scope.$on('pack_changed', function(evt, message) {
266309 $scope.licenses = licenseResource.query({packId: $scope.currentPack.id});
310
+ $scope.creationAvailable = $scope.currentPack.status == 'AC';
267311 if ($scope.showForm) {
268312 if ($scope.isNew) {
269313 $scope.license.pack_id = $scope.currentPack.id
....@@ -296,7 +340,8 @@
296340 }
297341 });
298342 $scope.mandatory = {
299
- code: true
343
+ code: true,
344
+ email: true
300345 }
301346 $scope.maxlength = {
302347 code: 50,
....@@ -356,6 +401,20 @@
356401 });
357402 return;
358403 }
404
+ if (!$scope.creationAvailable) {
405
+ BootstrapDialog.show({
406
+ title: $L.get('Pack not active'),
407
+ type: BootstrapDialog.TYPE_WARNING,
408
+ message: $L.get('Current pack is not active, so licenses cannot be created'),
409
+ buttons: [{
410
+ label: 'OK',
411
+ action: function(dialog) {
412
+ dialog.close();
413
+ }
414
+ }]
415
+ });
416
+ return;
417
+ }
359418
360419 $scope.isNew = true;
361420 $scope.showForm = true;
securis/src/main/resources/static/licenses.html
....@@ -110,11 +110,7 @@
110110 <div class="form-group" ng-if="!isNew">
111111 <label class="col-md-3 control-label" for="status" i18n>Status</label>
112112 <div class="col-md-8">
113
- <select class="form-control" id="status"
114
- ng-required="mandatory.status"
115
- ng-model="pack.status"
116
- ng-options="o.id as o.label for o in refs.pack_status">
117
- </select>
113
+ <p class="form-control-static" ng-bind="pack.status_name"></p>
118114 <div class="alert inline-alert alert-warning"
119115 ng-show="packForm.status.$invalid">
120116 <span class="glyphicon glyphicon-warning-sign"></span> <span
....@@ -128,13 +124,13 @@
128124 <label class="col-md-3 control-label" for="license_type_id" i18n>License
129125 type</label>
130126 <div class="col-md-8">
131
- <select class="form-control" id="license_type_id"
127
+ <select ng-if="isNew" class="form-control" id="license_type_id"
132128 ng-change="updateMetadata()"
133129 ng-required="mandatory.license_type_id"
134130 ng-model="pack.license_type_id"
135131 ng-options="o.id as o.label for o in refs.license_type_id">
136
-
137132 </select>
133
+ <p ng-if="!isNew" class="form-control-static" ng-bind="pack.license_type_name"></p>
138134 <div class="alert inline-alert alert-warning"
139135 ng-show="packForm.license_type_id.$invalid">
140136 <span class="glyphicon glyphicon-warning-sign"></span> <span
....@@ -147,10 +143,12 @@
147143 <div class="form-group">
148144 <label class="col-md-3 control-label" for="organization_id" i18n>Organization</label>
149145 <div class="col-md-8">
150
- <select class="form-control" ng-required="field.mandatory"
146
+ <select ng-if="isNew" class="form-control"
151147 ng-model="pack.organization_id"
148
+ ng-required="mandatory.organization_id"
152149 ng-options="o.id as o.label for o in refs.organization_id">
153150 </select>
151
+ <p ng-if="!isNew" class="form-control-static" ng-bind="pack.organization_name"></p>
154152 <div class="alert inline-alert alert-warning"
155153 ng-show="packForm.organization_id.$invalid">
156154 <span class="glyphicon glyphicon-warning-sign"></span> <span
....@@ -232,12 +230,12 @@
232230 <button id="save" type="submit" class="btn btn-primary">
233231 <span i18n class="glyphicon glyphicon-floppy-disk"></span> Save
234232 </button>
235
- <button id="acc" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
233
+ <button ng-if="!isNew" id="acc" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
236234 <span i18n class="glyphicon glyphicon-align-justify"></span> Actions
237235 <span class="caret"></span>
238236 </button>
239237 <ul class="dropdown-menu" role="menu">
240
- <li><a href="#">Activate</a></li>
238
+ <li><a href="#" ng-click="execute('activate')">Activate</a></li>
241239 <li><a href="#">On hold</a></li>
242240 <li class="divider"></li>
243241 <li><a href="#">Invalidate</a></li>
....@@ -545,7 +543,7 @@
545543 <button id="save" type="submit" class="btn btn-primary">
546544 <span i18n class="glyphicon glyphicon-floppy-disk"></span> Save
547545 </button>
548
- <button id="acc" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
546
+ <button ng-if="!isNew" id="acc" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
549547 <span i18n class="glyphicon glyphicon-align-justify"></span> Actions
550548 <span class="caret"></span>
551549 </button>