#2021 feature - Added pack actions in server and in frontend
| .. | .. |
|---|
| 28 | 28 | </dependency> |
|---|
| 29 | 29 | <dependency> |
|---|
| 30 | 30 | <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> |
|---|
| 36 | 31 | <artifactId>resteasy-multipart-provider</artifactId> |
|---|
| 37 | 32 | <version>3.0.9.Final</version> |
|---|
| 38 | 33 | </dependency> |
|---|
| .. | .. |
|---|
| 76 | 71 | <artifactId>httpmime</artifactId> |
|---|
| 77 | 72 | <version>4.4-beta1</version> |
|---|
| 78 | 73 | </dependency> |
|---|
| 74 | + <dependency> |
|---|
| 75 | + <groupId>org.jboss.resteasy</groupId> |
|---|
| 76 | + <artifactId>resteasy-jackson2-provider</artifactId> |
|---|
| 77 | + <version>3.0.9.Final</version> |
|---|
| 78 | + </dependency> |
|---|
| 79 | 79 | </dependencies> |
|---|
| 80 | 80 | <build> |
|---|
| 81 | 81 | <plugins> |
|---|
| .. | .. |
|---|
| 52 | 52 | private static final Logger CONSOLE = LogManager.getLogger("console");
|
|---|
| 53 | 53 |
|
|---|
| 54 | 54 | private static final String PID_FILE = System.getProperty("user.home") + "/.SeCuris/securis-server.pid";
|
|---|
| 55 | | -
|
|---|
| 55 | +
|
|---|
| 56 | 56 | private static Server server;
|
|---|
| 57 | 57 | private static Injector injector = null;
|
|---|
| 58 | 58 |
|
|---|
| .. | .. |
|---|
| 64 | 64 | CONSOLE.info("Execute SeCuris server using:");
|
|---|
| 65 | 65 | CONSOLE.info(" $ ./securis-server.sh {start|stop}");
|
|---|
| 66 | 66 | }
|
|---|
| 67 | | -
|
|---|
| 68 | | - private void testMail() {
|
|---|
| 69 | | -
|
|---|
| 70 | | - }
|
|---|
| 71 | | -
|
|---|
| 67 | +
|
|---|
| 72 | 68 | public static void main(String[] args) throws Exception {
|
|---|
| 73 | | - String command;
|
|---|
| 69 | + String command;
|
|---|
| 74 | 70 | if (args.length > 0) {
|
|---|
| 75 | 71 | command = args[0].toLowerCase();
|
|---|
| 76 | 72 | } else {
|
|---|
| 77 | 73 | command = "start";
|
|---|
| 78 | 74 | }
|
|---|
| 79 | | -
|
|---|
| 75 | +
|
|---|
| 80 | 76 | switch (command) {
|
|---|
| 81 | 77 | case "start":
|
|---|
| 82 | 78 | startServer();
|
|---|
| .. | .. |
|---|
| 90 | 86 | System.exit(-1);
|
|---|
| 91 | 87 | }
|
|---|
| 92 | 88 | }
|
|---|
| 93 | | -
|
|---|
| 89 | +
|
|---|
| 94 | 90 | private static void stopServer() {
|
|---|
| 95 | 91 | if (!new File(PID_FILE).exists()) {
|
|---|
| 96 | 92 | CONSOLE.error("SeCuris server is NOT running or PID file is missing");
|
|---|
| .. | .. |
|---|
| 105 | 101 | LOG.error("Error getting SeCuris server process PID from file: {}", PID_FILE);
|
|---|
| 106 | 102 | }
|
|---|
| 107 | 103 | }
|
|---|
| 108 | | -
|
|---|
| 104 | +
|
|---|
| 109 | 105 | private static void startServer() {
|
|---|
| 110 | 106 |
|
|---|
| 111 | 107 | if (new File(PID_FILE).exists()) {
|
|---|
| .. | .. |
|---|
| 116 | 112 | }
|
|---|
| 117 | 113 | System.exit(-2);
|
|---|
| 118 | 114 | }
|
|---|
| 119 | | -
|
|---|
| 115 | +
|
|---|
| 120 | 116 | SecurisModule securisModule = new SecurisModule();
|
|---|
| 121 | 117 | JpaPersistModule jpaPersistModule = new JpaPersistModule("localdb");
|
|---|
| 122 | 118 | Properties props = new Properties();
|
|---|
| 123 | 119 | props.put("javax.persistence.jdbc.password", securisModule.getPassword());
|
|---|
| 124 | 120 | 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());
|
|---|
| 126 | 124 | jpaPersistModule.properties(props);
|
|---|
| 127 | 125 |
|
|---|
| 128 | 126 | injector = Guice.createInjector(securisModule, new RequestsModule(), jpaPersistModule);
|
|---|
| 129 | 127 |
|
|---|
| 130 | 128 | try {
|
|---|
| 131 | 129 | startServer(injector.getInstance(Key.get(URI.class, Names.named("base-uri"))));
|
|---|
| 132 | | -
|
|---|
| 130 | +
|
|---|
| 133 | 131 | } catch (SeCurisException e) {
|
|---|
| 134 | 132 | CONSOLE.error("Error launching the SeCuris server, {}", e);
|
|---|
| 135 | 133 | }
|
|---|
| .. | .. |
|---|
| 153 | 151 |
|
|---|
| 154 | 152 | QueuedThreadPool threadPool = new QueuedThreadPool();
|
|---|
| 155 | 153 | threadPool.setMaxThreads(50);
|
|---|
| 156 | | -
|
|---|
| 154 | +
|
|---|
| 157 | 155 | server = new Server();
|
|---|
| 158 | | -
|
|---|
| 156 | +
|
|---|
| 159 | 157 | ServerConnector httpConnector = new ServerConnector(server);
|
|---|
| 160 | 158 | httpConnector.setPort(Config.getInt(Config.KEYS.SERVER_PORT, 9080));
|
|---|
| 161 | 159 | httpConnector.setHost(Config.get(Config.KEYS.SERVER_HOSTNAME, "0.0.0.0"));
|
|---|
| 162 | 160 | server.addConnector(httpConnector);
|
|---|
| 163 | | -
|
|---|
| 161 | +
|
|---|
| 164 | 162 | ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
|---|
| 165 | 163 | context.setContextPath("/");
|
|---|
| 166 | 164 | context.addEventListener(injector.getInstance(GuiceResteasyBootstrapServletContextListener.class));
|
|---|
| .. | .. |
|---|
| 191 | 189 | contexts.setHandlers(new Handler[] {
|
|---|
| 192 | 190 | staticResources, context
|
|---|
| 193 | 191 | });
|
|---|
| 194 | | -
|
|---|
| 192 | +
|
|---|
| 195 | 193 | HttpConfiguration http_config = new HttpConfiguration();
|
|---|
| 196 | 194 | http_config.setSecureScheme("https");
|
|---|
| 197 | 195 | http_config.setSecurePort(Config.getInt(Config.KEYS.SERVER_SSL_PORT, 9443));
|
|---|
| 198 | 196 | http_config.setOutputBufferSize(32768);
|
|---|
| 199 | 197 | http_config.setSendServerVersion(true);
|
|---|
| 200 | 198 | http_config.setSendDateHeader(false);
|
|---|
| 201 | | -
|
|---|
| 202 | | -
|
|---|
| 199 | +
|
|---|
| 203 | 200 | HttpConfiguration https_config = new HttpConfiguration(http_config);
|
|---|
| 204 | 201 | https_config.addCustomizer(new SecureRequestCustomizer());
|
|---|
| 205 | | -
|
|---|
| 202 | +
|
|---|
| 206 | 203 | SslContextFactory sslContextFactory = new SslContextFactory();
|
|---|
| 207 | 204 | sslContextFactory.setKeyStorePath(Config.get(Config.KEYS.KEYSTORE_PATH));
|
|---|
| 208 | 205 | sslContextFactory.setKeyStoreType(Config.get(Config.KEYS.KEYSTORE_TYPE, "JKS"));
|
|---|
| 209 | 206 | 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");
|
|---|
| 214 | 211 | sslContextFactory.checkKeyStore();
|
|---|
| 215 | 212 | 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));
|
|---|
| 218 | 216 | sslConnector.setPort(Config.getInt(Config.KEYS.SERVER_SSL_PORT, 9443));
|
|---|
| 219 | 217 | sslConnector.setHost(Config.get(Config.KEYS.SERVER_HOSTNAME, "0.0.0.0"));
|
|---|
| 220 | | - server.addConnector( sslConnector );
|
|---|
| 218 | + server.addConnector(sslConnector);
|
|---|
| 221 | 219 |
|
|---|
| 222 | 220 | server.setHandler(context);
|
|---|
| 223 | 221 | server.setStopAtShutdown(true);
|
|---|
| .. | .. |
|---|
| 233 | 231 | }
|
|---|
| 234 | 232 |
|
|---|
| 235 | 233 | }
|
|---|
| 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) {
|
|---|
| 239 | 238 | if (new File(PID_FILE).exists())
|
|---|
| 240 | 239 | new File(PID_FILE).delete();
|
|---|
| 241 | 240 | }
|
|---|
| .. | .. |
|---|
| 89 | 89 | } |
|---|
| 90 | 90 | |
|---|
| 91 | 91 | 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); |
|---|
| 94 | 93 | } |
|---|
| 95 | 94 | |
|---|
| 96 | 95 | public static boolean isRequestBlocked(String requestData, EntityManager em) { |
|---|
| .. | .. |
|---|
| 16 | 16 | import javax.persistence.ManyToOne; |
|---|
| 17 | 17 | import javax.persistence.NamedQueries; |
|---|
| 18 | 18 | import javax.persistence.NamedQuery; |
|---|
| 19 | +import javax.persistence.NonUniqueResultException; |
|---|
| 19 | 20 | import javax.persistence.OneToMany; |
|---|
| 20 | 21 | import javax.persistence.Table; |
|---|
| 21 | 22 | import javax.persistence.TypedQuery; |
|---|
| 22 | 23 | |
|---|
| 23 | 24 | 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; |
|---|
| 24 | 30 | |
|---|
| 25 | 31 | import com.fasterxml.jackson.annotation.JsonAutoDetect; |
|---|
| 26 | 32 | import com.fasterxml.jackson.annotation.JsonIgnore; |
|---|
| .. | .. |
|---|
| 39 | 45 | @JsonIgnoreProperties(ignoreUnknown = true) |
|---|
| 40 | 46 | @NamedQueries({ |
|---|
| 41 | 47 | @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"), |
|---|
| 42 | 49 | @NamedQuery(name = "list-active-licenses-by-req-data", query = "SELECT l FROM License l where l.reqDataHash = :hash and l.status in ('AC', 'PA')") |
|---|
| 43 | 50 | }) |
|---|
| 44 | 51 | public class License implements Serializable { |
|---|
| 52 | + private static final long serialVersionUID = 2700310404904877227L; |
|---|
| 45 | 53 | |
|---|
| 46 | | - private static final long serialVersionUID = 1L; |
|---|
| 54 | + private static final Logger LOG = LogManager.getLogger(License.class); |
|---|
| 47 | 55 | |
|---|
| 48 | 56 | @Id |
|---|
| 49 | 57 | @GeneratedValue |
|---|
| .. | .. |
|---|
| 63 | 71 | |
|---|
| 64 | 72 | @JsonIgnore |
|---|
| 65 | 73 | @ManyToOne |
|---|
| 66 | | - @JoinColumn(name = "canceled_by") |
|---|
| 67 | | - private User canceledBy; |
|---|
| 74 | + @JoinColumn(name = "cancelled_by") |
|---|
| 75 | + private User cancelledBy; |
|---|
| 68 | 76 | |
|---|
| 69 | 77 | private LicenseStatus status; |
|---|
| 70 | 78 | |
|---|
| .. | .. |
|---|
| 78 | 86 | @JsonProperty("request_data") |
|---|
| 79 | 87 | private String requestData; |
|---|
| 80 | 88 | |
|---|
| 89 | + /** |
|---|
| 90 | + * request data hash is automatically set when we use |
|---|
| 91 | + * {@link License#setRequestData(String)} method |
|---|
| 92 | + */ |
|---|
| 81 | 93 | @Column(name = "request_data_hash") |
|---|
| 82 | 94 | @JsonIgnore |
|---|
| 83 | 95 | private String reqDataHash; |
|---|
| .. | .. |
|---|
| 158 | 170 | } |
|---|
| 159 | 171 | } |
|---|
| 160 | 172 | |
|---|
| 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(); |
|---|
| 164 | 176 | } |
|---|
| 165 | 177 | |
|---|
| 166 | | - @JsonProperty("canceled_by_id") |
|---|
| 167 | | - public void setCanceledById(String username) { |
|---|
| 178 | + @JsonProperty("cancelled_by_id") |
|---|
| 179 | + public void setCancelledById(String username) { |
|---|
| 168 | 180 | if (username == null) { |
|---|
| 169 | | - canceledBy = null; |
|---|
| 181 | + cancelledBy = null; |
|---|
| 170 | 182 | } else { |
|---|
| 171 | | - canceledBy = new User(); |
|---|
| 172 | | - canceledBy.setUsername(username); |
|---|
| 183 | + cancelledBy = new User(); |
|---|
| 184 | + cancelledBy.setUsername(username); |
|---|
| 173 | 185 | } |
|---|
| 174 | 186 | } |
|---|
| 175 | 187 | |
|---|
| .. | .. |
|---|
| 229 | 241 | this.id = id; |
|---|
| 230 | 242 | } |
|---|
| 231 | 243 | |
|---|
| 232 | | - public User getCanceledBy() { |
|---|
| 233 | | - return canceledBy; |
|---|
| 244 | + public User getCancelledBy() { |
|---|
| 245 | + return cancelledBy; |
|---|
| 234 | 246 | } |
|---|
| 235 | 247 | |
|---|
| 236 | | - public void setCanceledBy(User canceledBy) { |
|---|
| 237 | | - this.canceledBy = canceledBy; |
|---|
| 248 | + public void setCancelledBy(User cancelledBy) { |
|---|
| 249 | + this.cancelledBy = cancelledBy; |
|---|
| 238 | 250 | } |
|---|
| 239 | 251 | |
|---|
| 240 | 252 | public Date getLastAccessTimestamp() { |
|---|
| .. | .. |
|---|
| 251 | 263 | |
|---|
| 252 | 264 | public void setRequestData(String requestData) { |
|---|
| 253 | 265 | this.requestData = requestData; |
|---|
| 266 | + this.reqDataHash = BlockedRequest.generateHash(this.requestData); |
|---|
| 254 | 267 | } |
|---|
| 255 | 268 | |
|---|
| 256 | 269 | public String getLicenseData() { |
|---|
| .. | .. |
|---|
| 283 | 296 | |
|---|
| 284 | 297 | public void setExpirationDate(Date expirationDate) { |
|---|
| 285 | 298 | this.expirationDate = expirationDate; |
|---|
| 299 | + } |
|---|
| 300 | + |
|---|
| 301 | + public String getReqDataHash() { |
|---|
| 302 | + return reqDataHash; |
|---|
| 286 | 303 | } |
|---|
| 287 | 304 | |
|---|
| 288 | 305 | public static class Action { |
|---|
| .. | .. |
|---|
| 323 | 340 | } |
|---|
| 324 | 341 | } |
|---|
| 325 | 342 | |
|---|
| 326 | | - public License findLicenseByRequestData(String requestData, EntityManager em) { |
|---|
| 343 | + public static License findLicenseByRequestData(String requestData, EntityManager em) throws SeCurisServiceException { |
|---|
| 327 | 344 | TypedQuery<License> query = em.createNamedQuery("list-active-licenses-by-req-data", License.class); |
|---|
| 328 | 345 | 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 | + } |
|---|
| 330 | 353 | } |
|---|
| 331 | 354 | |
|---|
| 332 | | - public String getReqDataHash() { |
|---|
| 333 | | - return reqDataHash; |
|---|
| 334 | | - } |
|---|
| 335 | | - |
|---|
| 336 | | - public void setReqDataHash(String reqDataHash) { |
|---|
| 337 | | - this.reqDataHash = reqDataHash; |
|---|
| 338 | | - } |
|---|
| 339 | 355 | } |
|---|
| .. | .. |
|---|
| 116 | 116 | public static final String ACTIVATE = "activate"; |
|---|
| 117 | 117 | public static final String CANCEL = "cancel"; |
|---|
| 118 | 118 | public static final String BLOCK = "block"; |
|---|
| 119 | + public static final String UNBLOCK = "unblock"; |
|---|
| 119 | 120 | public static final String DELETE = "delete"; |
|---|
| 120 | 121 | } |
|---|
| 121 | 122 | } |
|---|
| .. | .. |
|---|
| 167 | 167 | @JsonProperty("users_ids") |
|---|
| 168 | 168 | public void setUsersIds(List<String> usersIds) { |
|---|
| 169 | 169 | 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 | + } |
|---|
| 174 | 176 | } |
|---|
| 175 | 177 | } |
|---|
| 176 | 178 | |
|---|
| .. | .. |
|---|
| 1 | 1 | package net.curisit.securis.db; |
|---|
| 2 | 2 | |
|---|
| 3 | 3 | import java.io.Serializable; |
|---|
| 4 | +import java.util.Arrays; |
|---|
| 4 | 5 | import java.util.Date; |
|---|
| 6 | +import java.util.List; |
|---|
| 7 | +import java.util.Map; |
|---|
| 5 | 8 | import java.util.Set; |
|---|
| 6 | 9 | |
|---|
| 7 | 10 | import javax.persistence.CascadeType; |
|---|
| .. | .. |
|---|
| 16 | 19 | import javax.persistence.NamedQuery; |
|---|
| 17 | 20 | import javax.persistence.OneToMany; |
|---|
| 18 | 21 | import javax.persistence.Table; |
|---|
| 22 | + |
|---|
| 23 | +import net.curisit.integrity.commons.Utils; |
|---|
| 19 | 24 | |
|---|
| 20 | 25 | import com.fasterxml.jackson.annotation.JsonAutoDetect; |
|---|
| 21 | 26 | import com.fasterxml.jackson.annotation.JsonIgnore; |
|---|
| .. | .. |
|---|
| 321 | 326 | |
|---|
| 322 | 327 | return (id == null ? 0 : id.hashCode()); |
|---|
| 323 | 328 | } |
|---|
| 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 | + } |
|---|
| 324 | 361 | } |
|---|
| .. | .. |
|---|
| 23 | 23 | public class SecurisModule extends AbstractModule { |
|---|
| 24 | 24 | |
|---|
| 25 | 25 | 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"; |
|---|
| 27 | 27 | |
|---|
| 28 | 28 | private static final Logger LOG = LogManager.getLogger(SecurisModule.class); |
|---|
| 29 | 29 | |
|---|
| .. | .. |
|---|
| 127 | 127 | @Singleton |
|---|
| 128 | 128 | public String getHashLogo() { |
|---|
| 129 | 129 | 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"; |
|---|
| 144 | 130 | } |
|---|
| 145 | 131 | |
|---|
| 146 | 132 | @Provides |
|---|
| .. | .. |
|---|
| 45 | 45 | import net.curisit.securis.db.LicenseStatus; |
|---|
| 46 | 46 | import net.curisit.securis.db.Pack; |
|---|
| 47 | 47 | import net.curisit.securis.db.PackMetadata; |
|---|
| 48 | +import net.curisit.securis.db.PackStatus; |
|---|
| 48 | 49 | import net.curisit.securis.db.User; |
|---|
| 49 | 50 | import net.curisit.securis.security.BasicSecurityContext; |
|---|
| 50 | 51 | import net.curisit.securis.security.Securable; |
|---|
| .. | .. |
|---|
| 56 | 57 | import net.curisit.securis.utils.TokenHelper; |
|---|
| 57 | 58 | |
|---|
| 58 | 59 | import org.apache.commons.io.IOUtils; |
|---|
| 60 | +import org.apache.commons.lang3.ObjectUtils; |
|---|
| 59 | 61 | import org.apache.logging.log4j.LogManager; |
|---|
| 60 | 62 | import org.apache.logging.log4j.Logger; |
|---|
| 61 | 63 | |
|---|
| .. | .. |
|---|
| 158 | 160 | } |
|---|
| 159 | 161 | if (License.Status.isActionValid(License.Action.DOWNLOAD, lic.getStatus())) { |
|---|
| 160 | 162 | 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"); |
|---|
| 162 | 164 | } |
|---|
| 163 | 165 | em.persist(createLicenseHistoryAction(lic, getUser(bsc, em), LicenseHistory.Actions.DOWNLOAD)); |
|---|
| 164 | 166 | return Response |
|---|
| .. | .. |
|---|
| 193 | 195 | LOG.error("License with id {} can not be activated from current license status", licId); |
|---|
| 194 | 196 | throw new SeCurisServiceException(Status.FORBIDDEN.getStatusCode(), "License with id " + licId |
|---|
| 195 | 197 | + " 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(); |
|---|
| 196 | 207 | } |
|---|
| 197 | 208 | |
|---|
| 198 | 209 | lic.setStatus(LicenseStatus.ACTIVE); |
|---|
| .. | .. |
|---|
| 291 | 302 | } |
|---|
| 292 | 303 | |
|---|
| 293 | 304 | lic.setStatus(LicenseStatus.CANCELLED); |
|---|
| 305 | + lic.setCancelledById(bsc.getUserPrincipal().getName()); |
|---|
| 294 | 306 | lic.setModificationTimestamp(new Date()); |
|---|
| 295 | 307 | em.persist(lic); |
|---|
| 296 | 308 | |
|---|
| 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)); |
|---|
| 298 | 310 | return Response.ok(lic).build(); |
|---|
| 299 | 311 | } |
|---|
| 300 | 312 | |
|---|
| .. | .. |
|---|
| 321 | 333 | LOG.error("License for pack with id {} can not be created by user {}", pack.getId(), bsc.getUserPrincipal()); |
|---|
| 322 | 334 | throw new SeCurisServiceException(ErrorCodes.UNAUTHORIZED_ACCESS, "Unathorized action on pack license"); |
|---|
| 323 | 335 | } |
|---|
| 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 | + } |
|---|
| 324 | 340 | } |
|---|
| 325 | 341 | |
|---|
| 326 | 342 | User createdBy = getUser(bsc.getUserPrincipal().getName(), em); |
|---|
| 327 | 343 | |
|---|
| 328 | 344 | 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 | + } |
|---|
| 329 | 352 | SignedLicenseBean signedLicense = generateLicense(lic, em); |
|---|
| 330 | 353 | // If user provide a request data the license status is passed |
|---|
| 331 | 354 | // directly to ACTIVE |
|---|
| .. | .. |
|---|
| 338 | 361 | lic.setLicenseData(JsonUtils.toJSON(signedLicense)); |
|---|
| 339 | 362 | } catch (SeCurisException e) { |
|---|
| 340 | 363 | 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"); |
|---|
| 342 | 365 | } |
|---|
| 343 | 366 | } else { |
|---|
| 344 | 367 | lic.setStatus(LicenseStatus.CREATED); |
|---|
| .. | .. |
|---|
| 387 | 410 | * @throws SeCurisServiceException |
|---|
| 388 | 411 | */ |
|---|
| 389 | 412 | 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 | + } |
|---|
| 390 | 416 | RequestBean rb = null; |
|---|
| 391 | 417 | try { |
|---|
| 392 | 418 | rb = JsonUtils.json2object(requestData, RequestBean.class); |
|---|
| .. | .. |
|---|
| 422 | 448 | EntityManager em = emProvider.get(); |
|---|
| 423 | 449 | |
|---|
| 424 | 450 | License currentLicense = getCurrentLicense(licId, bsc, em); |
|---|
| 425 | | - |
|---|
| 426 | | - currentLicense.setCode(lic.getCode()); |
|---|
| 451 | + currentLicense.setComments(lic.getComments()); |
|---|
| 427 | 452 | currentLicense.setFullName(lic.getFullName()); |
|---|
| 428 | 453 | 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"); |
|---|
| 438 | 470 | } |
|---|
| 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); |
|---|
| 443 | 474 | } |
|---|
| 444 | | - currentLicense.setRequestData(lic.getRequestData()); |
|---|
| 445 | 475 | } |
|---|
| 476 | + |
|---|
| 446 | 477 | currentLicense.setModificationTimestamp(new Date()); |
|---|
| 447 | 478 | em.persist(currentLicense); |
|---|
| 448 | 479 | em.persist(createLicenseHistoryAction(lic, getUser(bsc, em), LicenseHistory.Actions.MODIFY)); |
|---|
| .. | .. |
|---|
| 462 | 493 | EntityManager em = emProvider.get(); |
|---|
| 463 | 494 | License lic = getCurrentLicense(licId, bsc, em); |
|---|
| 464 | 495 | |
|---|
| 465 | | - if (lic.getStatus() != LicenseStatus.CANCELLED || lic.getStatus() != LicenseStatus.CREATED) { |
|---|
| 496 | + if (License.Status.isActionValid(License.Action.DELETE, lic.getStatus())) { |
|---|
| 466 | 497 | 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 | + } |
|---|
| 469 | 513 | } |
|---|
| 470 | 514 | |
|---|
| 471 | 515 | em.remove(lic); |
|---|
| 472 | 516 | return Response.ok(Utils.createMap("success", true, "id", licId)).build(); |
|---|
| 473 | 517 | } |
|---|
| 474 | 518 | |
|---|
| 475 | | - @DELETE |
|---|
| 519 | + @POST |
|---|
| 476 | 520 | @Path("/{licId}/block") |
|---|
| 477 | 521 | @Transactional |
|---|
| 478 | 522 | @Securable |
|---|
| .. | .. |
|---|
| 484 | 528 | EntityManager em = emProvider.get(); |
|---|
| 485 | 529 | License lic = getCurrentLicense(licId, bsc, em); |
|---|
| 486 | 530 | |
|---|
| 487 | | - if (lic.getStatus() != LicenseStatus.CANCELLED) { |
|---|
| 531 | + if (!License.Status.isActionValid(License.Action.BLOCK, lic.getStatus())) { |
|---|
| 488 | 532 | LOG.error("License can only be blocked in CANCELLED status, current: {}", lic.getStatus().name()); |
|---|
| 489 | 533 | throw new SeCurisServiceException(ErrorCodes.WRONG_STATUS, "License can only be blocked in CANCELLED status"); |
|---|
| 490 | 534 | } |
|---|
| .. | .. |
|---|
| 502 | 546 | return Response.ok(Utils.createMap("success", true, "id", licId)).build(); |
|---|
| 503 | 547 | } |
|---|
| 504 | 548 | |
|---|
| 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 | + |
|---|
| 505 | 572 | private License getCurrentLicense(Integer licId, BasicSecurityContext bsc, EntityManager em) throws SeCurisServiceException { |
|---|
| 506 | 573 | if (licId == null || "".equals(licId)) { |
|---|
| 507 | 574 | LOG.error("License ID is mandatory"); |
|---|
| .. | .. |
|---|
| 30 | 30 | import net.curisit.securis.db.Organization; |
|---|
| 31 | 31 | import net.curisit.securis.db.Pack; |
|---|
| 32 | 32 | import net.curisit.securis.db.PackMetadata; |
|---|
| 33 | +import net.curisit.securis.db.PackStatus; |
|---|
| 33 | 34 | import net.curisit.securis.db.User; |
|---|
| 34 | 35 | import net.curisit.securis.security.BasicSecurityContext; |
|---|
| 35 | 36 | import net.curisit.securis.security.Securable; |
|---|
| 37 | +import net.curisit.securis.services.exception.SeCurisServiceException; |
|---|
| 38 | +import net.curisit.securis.services.exception.SeCurisServiceException.ErrorCodes; |
|---|
| 36 | 39 | import net.curisit.securis.utils.TokenHelper; |
|---|
| 37 | 40 | |
|---|
| 38 | 41 | import org.apache.logging.log4j.LogManager; |
|---|
| .. | .. |
|---|
| 154 | 157 | |
|---|
| 155 | 158 | User user = em.find(User.class, bsc.getUserPrincipal().getName()); |
|---|
| 156 | 159 | |
|---|
| 160 | + pack.setStatus(PackStatus.CREATED); |
|---|
| 157 | 161 | pack.setCreatedBy(user); |
|---|
| 158 | 162 | pack.setCreationTimestamp(new Date()); |
|---|
| 159 | 163 | em.persist(pack); |
|---|
| 160 | | - Set<PackMetadata> newMD = pack.getMetadata(); |
|---|
| 161 | | - |
|---|
| 164 | + Set<PackMetadata> newMD = pack.getMetadata(); |
|---|
| 165 | + |
|---|
| 162 | 166 | if (newMD != null) { |
|---|
| 163 | 167 | for (PackMetadata md : newMD) { |
|---|
| 164 | 168 | md.setPack(pack); |
|---|
| .. | .. |
|---|
| 215 | 219 | |
|---|
| 216 | 220 | em.persist(currentPack); |
|---|
| 217 | 221 | |
|---|
| 218 | | - Set<PackMetadata> newMD = pack.getMetadata(); |
|---|
| 222 | + Set<PackMetadata> newMD = pack.getMetadata(); |
|---|
| 219 | 223 | 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); |
|---|
| 222 | 227 | } |
|---|
| 223 | | - |
|---|
| 228 | + |
|---|
| 224 | 229 | if (newMD != null) { |
|---|
| 225 | 230 | for (PackMetadata md : newMD) { |
|---|
| 226 | 231 | md.setPack(currentPack); |
|---|
| .. | .. |
|---|
| 231 | 236 | return Response.ok(pack).build(); |
|---|
| 232 | 237 | } |
|---|
| 233 | 238 | |
|---|
| 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 | + |
|---|
| 234 | 317 | private void setPackOrganization(Pack currentPack, Integer orgId, EntityManager em) throws SeCurisException { |
|---|
| 235 | 318 | Organization org = null; |
|---|
| 236 | 319 | if (orgId != null) { |
|---|
| .. | .. |
|---|
| 55 | 55 | * |
|---|
| 56 | 56 | * @throws SeCurisException |
|---|
| 57 | 57 | */ |
|---|
| 58 | | - private EmailManager() throws SeCurisException { |
|---|
| 58 | + public EmailManager() throws SeCurisException { |
|---|
| 59 | 59 | String domain = Params.get(Params.KEYS.MAILGUN_DOMAIN); |
|---|
| 60 | 60 | if (domain == null) { |
|---|
| 61 | 61 | throw new SeCurisException("Please, add '" + Params.KEYS.MAILGUN_DOMAIN + "' parameter to config file"); |
|---|
| .. | .. |
|---|
| 11 | 11 | |
|---|
| 12 | 12 | <properties> |
|---|
| 13 | 13 | <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" /> --> |
|---|
| 15 | 15 | <property name="javax.persistence.jdbc.user" value="curis" /> |
|---|
| 16 | 16 | <property name="javax.persistence.jdbc.password" value="53curi5" /> |
|---|
| 17 | 17 | <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" /> |
|---|
| .. | .. |
|---|
| 8 | 8 | drop table IF EXISTS user; |
|---|
| 9 | 9 | CREATE TABLE IF NOT EXISTS user ( |
|---|
| 10 | 10 | username VARCHAR(45) NOT NULL , |
|---|
| 11 | | - password VARCHAR(100) NULL , |
|---|
| 11 | + password VARCHAR(256) NULL , |
|---|
| 12 | 12 | roles INT NOT NULL default 0, |
|---|
| 13 | 13 | first_name VARCHAR(100) NULL , |
|---|
| 14 | 14 | last_name VARCHAR(100) NULL , |
|---|
| .. | .. |
|---|
| 113 | 113 | modification_timestamp DATETIME NULL , |
|---|
| 114 | 114 | last_access_timestamp DATETIME NULL , |
|---|
| 115 | 115 | expiration_date DATETIME NULL , |
|---|
| 116 | | - canceled_by varchar(45) NULL , |
|---|
| 116 | + cancelled_by varchar(45) NULL , |
|---|
| 117 | 117 | created_by varchar(45) NULL , |
|---|
| 118 | 118 | status VARCHAR(2) NOT NULL default 'CR', |
|---|
| 119 | 119 | PRIMARY KEY (id)); |
|---|
| 120 | 120 | |
|---|
| 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); |
|---|
| 122 | 122 | create index if not exists lic_pack_idx on license(pack_id); |
|---|
| 123 | 123 | |
|---|
| 124 | 124 | drop table IF EXISTS license_history; |
|---|
| .. | .. |
|---|
| 101 | 101 | '$store', |
|---|
| 102 | 102 | '$L', |
|---|
| 103 | 103 | 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 | + ); |
|---|
| 107 | 116 | var PACK_STATUS = [ |
|---|
| 108 | | - {id: 'PE', label: $L.get('Pending')}, |
|---|
| 117 | + {id: 'CR', label: $L.get('Created')}, |
|---|
| 109 | 118 | {id: 'AC', label: $L.get('Active')}, |
|---|
| 110 | 119 | {id: 'OH', label: $L.get('On Hold')}, |
|---|
| 111 | 120 | {id: 'EX', label: $L.get('Expired')}, |
|---|
| .. | .. |
|---|
| 165 | 174 | _savePackData(); |
|---|
| 166 | 175 | } |
|---|
| 167 | 176 | } |
|---|
| 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 | + } |
|---|
| 168 | 194 | |
|---|
| 195 | + |
|---|
| 169 | 196 | $scope.newPack = function() { |
|---|
| 170 | 197 | $scope.isNew = true; |
|---|
| 171 | 198 | $scope.showForm = true; |
|---|
| 172 | 199 | $scope.pack = { |
|---|
| 173 | 200 | license_preactivation: true, |
|---|
| 174 | | - status: 'PE', |
|---|
| 201 | + status: 'CR', |
|---|
| 175 | 202 | num_licenses: 1, |
|---|
| 176 | 203 | license_type_id: null, |
|---|
| 177 | 204 | organization_id: null //!$scope.refs.organization_id || !$scope.refs.organization_id.length ? null : $scope.refs.organization_id[0].id |
|---|
| .. | .. |
|---|
| 190 | 217 | if (!(selectedPack.end_valid_date instanceof Date)) { |
|---|
| 191 | 218 | selectedPack.end_valid_date = new Date(selectedPack.end_valid_date); |
|---|
| 192 | 219 | } |
|---|
| 220 | + |
|---|
| 193 | 221 | $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 | + |
|---|
| 194 | 227 | setTimeout(function() { |
|---|
| 195 | 228 | $('#code').focus(); |
|---|
| 196 | 229 | }, 0); |
|---|
| .. | .. |
|---|
| 223 | 256 | $scope.$parent.currentPack = pack; |
|---|
| 224 | 257 | $store.put('currentPack', pack); |
|---|
| 225 | 258 | $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; |
|---|
| 226 | 269 | } |
|---|
| 227 | 270 | |
|---|
| 228 | 271 | $scope.createMetadataRow = function() { |
|---|
| .. | .. |
|---|
| 264 | 307 | function($scope, $http, $resource, toaster, $store, $L) { |
|---|
| 265 | 308 | $scope.$on('pack_changed', function(evt, message) { |
|---|
| 266 | 309 | $scope.licenses = licenseResource.query({packId: $scope.currentPack.id}); |
|---|
| 310 | + $scope.creationAvailable = $scope.currentPack.status == 'AC'; |
|---|
| 267 | 311 | if ($scope.showForm) { |
|---|
| 268 | 312 | if ($scope.isNew) { |
|---|
| 269 | 313 | $scope.license.pack_id = $scope.currentPack.id |
|---|
| .. | .. |
|---|
| 296 | 340 | } |
|---|
| 297 | 341 | }); |
|---|
| 298 | 342 | $scope.mandatory = { |
|---|
| 299 | | - code: true |
|---|
| 343 | + code: true, |
|---|
| 344 | + email: true |
|---|
| 300 | 345 | } |
|---|
| 301 | 346 | $scope.maxlength = { |
|---|
| 302 | 347 | code: 50, |
|---|
| .. | .. |
|---|
| 356 | 401 | }); |
|---|
| 357 | 402 | return; |
|---|
| 358 | 403 | } |
|---|
| 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 | + } |
|---|
| 359 | 418 | |
|---|
| 360 | 419 | $scope.isNew = true; |
|---|
| 361 | 420 | $scope.showForm = true; |
|---|
| .. | .. |
|---|
| 110 | 110 | <div class="form-group" ng-if="!isNew"> |
|---|
| 111 | 111 | <label class="col-md-3 control-label" for="status" i18n>Status</label> |
|---|
| 112 | 112 | <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> |
|---|
| 118 | 114 | <div class="alert inline-alert alert-warning" |
|---|
| 119 | 115 | ng-show="packForm.status.$invalid"> |
|---|
| 120 | 116 | <span class="glyphicon glyphicon-warning-sign"></span> <span |
|---|
| .. | .. |
|---|
| 128 | 124 | <label class="col-md-3 control-label" for="license_type_id" i18n>License |
|---|
| 129 | 125 | type</label> |
|---|
| 130 | 126 | <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" |
|---|
| 132 | 128 | ng-change="updateMetadata()" |
|---|
| 133 | 129 | ng-required="mandatory.license_type_id" |
|---|
| 134 | 130 | ng-model="pack.license_type_id" |
|---|
| 135 | 131 | ng-options="o.id as o.label for o in refs.license_type_id"> |
|---|
| 136 | | - |
|---|
| 137 | 132 | </select> |
|---|
| 133 | + <p ng-if="!isNew" class="form-control-static" ng-bind="pack.license_type_name"></p> |
|---|
| 138 | 134 | <div class="alert inline-alert alert-warning" |
|---|
| 139 | 135 | ng-show="packForm.license_type_id.$invalid"> |
|---|
| 140 | 136 | <span class="glyphicon glyphicon-warning-sign"></span> <span |
|---|
| .. | .. |
|---|
| 147 | 143 | <div class="form-group"> |
|---|
| 148 | 144 | <label class="col-md-3 control-label" for="organization_id" i18n>Organization</label> |
|---|
| 149 | 145 | <div class="col-md-8"> |
|---|
| 150 | | - <select class="form-control" ng-required="field.mandatory" |
|---|
| 146 | + <select ng-if="isNew" class="form-control" |
|---|
| 151 | 147 | ng-model="pack.organization_id" |
|---|
| 148 | + ng-required="mandatory.organization_id" |
|---|
| 152 | 149 | ng-options="o.id as o.label for o in refs.organization_id"> |
|---|
| 153 | 150 | </select> |
|---|
| 151 | + <p ng-if="!isNew" class="form-control-static" ng-bind="pack.organization_name"></p> |
|---|
| 154 | 152 | <div class="alert inline-alert alert-warning" |
|---|
| 155 | 153 | ng-show="packForm.organization_id.$invalid"> |
|---|
| 156 | 154 | <span class="glyphicon glyphicon-warning-sign"></span> <span |
|---|
| .. | .. |
|---|
| 232 | 230 | <button id="save" type="submit" class="btn btn-primary"> |
|---|
| 233 | 231 | <span i18n class="glyphicon glyphicon-floppy-disk"></span> Save |
|---|
| 234 | 232 | </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"> |
|---|
| 236 | 234 | <span i18n class="glyphicon glyphicon-align-justify"></span> Actions |
|---|
| 237 | 235 | <span class="caret"></span> |
|---|
| 238 | 236 | </button> |
|---|
| 239 | 237 | <ul class="dropdown-menu" role="menu"> |
|---|
| 240 | | - <li><a href="#">Activate</a></li> |
|---|
| 238 | + <li><a href="#" ng-click="execute('activate')">Activate</a></li> |
|---|
| 241 | 239 | <li><a href="#">On hold</a></li> |
|---|
| 242 | 240 | <li class="divider"></li> |
|---|
| 243 | 241 | <li><a href="#">Invalidate</a></li> |
|---|
| .. | .. |
|---|
| 545 | 543 | <button id="save" type="submit" class="btn btn-primary"> |
|---|
| 546 | 544 | <span i18n class="glyphicon glyphicon-floppy-disk"></span> Save |
|---|
| 547 | 545 | </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"> |
|---|
| 549 | 547 | <span i18n class="glyphicon glyphicon-align-justify"></span> Actions |
|---|
| 550 | 548 | <span class="caret"></span> |
|---|
| 551 | 549 | </button> |
|---|