From 8d99c88af55041ff06e6b9372b6b1f66220bed38 Mon Sep 17 00:00:00 2001
From: rsanchez <rsanchez@curisit.net>
Date: Mon, 10 Apr 2017 16:08:58 +0000
Subject: [PATCH] #3529 feature - Added applications to user profile and upgrade to angular4
---
securis/src/main/webapp/src/app/forms/user.form.component.ts | 29 ++
securis/src/main/java/net/curisit/securis/db/User.java | 64 +++++
securis/src/main/java/net/curisit/securis/ioc/RequestsInterceptor.java | 288 ++++++++++++++------------
securis/src/main/webapp/src/app/listing/user.list.component.html | 2
securis/src/main/java/net/curisit/securis/db/Application.java | 11 +
securis/src/main/webapp/sql_update.sql | 10
securis/src/main/java/net/curisit/securis/db/Pack.java | 1
securis/src/main/webapp/package.json | 27 +-
securis/src/main/java/net/curisit/securis/services/PackResource.java | 9
securis/src/main/webapp/src/app/forms/user.form.html | 19 -
securis/src/main/webapp/index.html | 1
securis/src/main/java/net/curisit/securis/services/UserResource.java | 36 ++
securis/src/main/java/net/curisit/securis/security/BasicSecurityContext.java | 140 +++++++-----
securis/src/main/webapp/src/app/app.module.ts | 2
securis/src/main/webapp/systemjs.config.js | 6
securis/src/main/resources/db/schema.sql | 7
16 files changed, 419 insertions(+), 233 deletions(-)
diff --git a/securis/src/main/java/net/curisit/securis/db/Application.java b/securis/src/main/java/net/curisit/securis/db/Application.java
index c994373..1dc20a5 100644
--- a/securis/src/main/java/net/curisit/securis/db/Application.java
+++ b/securis/src/main/java/net/curisit/securis/db/Application.java
@@ -10,6 +10,9 @@
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
@@ -68,6 +71,14 @@
@JsonManagedReference
private Set<ApplicationMetadata> metadata;
+ @JsonIgnore
+ // We don't include the users to limit the size of each row a the listing
+ @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
+ @JoinTable(name = "user_application", //
+ joinColumns = { @JoinColumn(name = "application_id", referencedColumnName = "id") }, //
+ inverseJoinColumns = { @JoinColumn(name = "username", referencedColumnName = "username") })
+ private Set<User> users;
+
public Integer getId() {
return id;
}
diff --git a/securis/src/main/java/net/curisit/securis/db/Pack.java b/securis/src/main/java/net/curisit/securis/db/Pack.java
index eb11298..3ff3493 100644
--- a/securis/src/main/java/net/curisit/securis/db/Pack.java
+++ b/securis/src/main/java/net/curisit/securis/db/Pack.java
@@ -43,6 +43,7 @@
@NamedQueries({ @NamedQuery(name = "list-packs", query = "SELECT pa FROM Pack pa"), //
@NamedQuery(name = "pack-by-code", query = "SELECT pa FROM Pack pa where pa.code = :code"), //
@NamedQuery(name = "list-packs-by-lic-type", query = "SELECT pa FROM Pack pa where pa.licenseType.id = :lt_id"), //
+ @NamedQuery(name = "list-packs-by-orgs-apps", query = "SELECT pa FROM Pack pa where pa.organization.id in :list_ids_org and pa.licenseType.application.id in :list_ids_app "), //
@NamedQuery(name = "list-packs-by-orgs", query = "SELECT pa FROM Pack pa where pa.organization.id in :list_ids") })
public class Pack implements Serializable {
diff --git a/securis/src/main/java/net/curisit/securis/db/User.java b/securis/src/main/java/net/curisit/securis/db/User.java
index e1e7396..d5b0f45 100644
--- a/securis/src/main/java/net/curisit/securis/db/User.java
+++ b/securis/src/main/java/net/curisit/securis/db/User.java
@@ -2,10 +2,12 @@
import java.io.Serializable;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
import javax.persistence.Column;
import javax.persistence.Entity;
@@ -76,6 +78,14 @@
inverseJoinColumns = { @JoinColumn(name = "organization_id", referencedColumnName = "id") } //
)
private Set<Organization> organizations;
+
+ @JsonIgnore
+ @ManyToMany
+ @JoinTable(name = "user_application", //
+ joinColumns = { @JoinColumn(name = "username", referencedColumnName = "username") }, //
+ inverseJoinColumns = { @JoinColumn(name = "application_id", referencedColumnName = "id") } //
+ )
+ private Set<Application> applications;
public String getUsername() {
return username;
@@ -182,6 +192,14 @@
this.organizations = organizations;
}
+ public Set<Application> getApplications() {
+ return applications;
+ }
+
+ public void setApplications(Set<Application> applications) {
+ this.applications = applications;
+ }
+
@JsonProperty("organizations_ids")
public void setOrgsIds(List<Integer> orgsIds) {
organizations = new HashSet<>();
@@ -204,6 +222,28 @@
return ids;
}
+ @JsonProperty("applications_ids")
+ public void setAppsIds(Collection<Integer> appIds) {
+ applications = new HashSet<>();
+ for (Integer appid : appIds) {
+ Application a = new Application();
+ a.setId(appid);
+ applications.add(a);
+ }
+ }
+
+ @JsonProperty("applications_ids")
+ public Set<Integer> getAppsIds() {
+ if (applications == null) {
+ return null;
+ }
+ Set<Integer> ids = new HashSet<>();
+ for (Application app : applications) {
+ ids.add(app.getId());
+ }
+ return ids;
+ }
+
@JsonIgnore
public Set<Integer> getAllOrgsIds() {
if (organizations == null) {
@@ -214,6 +254,22 @@
return ids;
}
+ @JsonIgnore
+ public Set<Integer> getAllAppsIds() {
+ if (applications == null) {
+ return null;
+ }
+ Set<Integer> ids = this.applications.parallelStream().map(app -> app.getId()).collect(Collectors.toSet());
+
+ return ids;
+ }
+
+ /**
+ * Walk into the organization hierarchy to include all descendants
+ *
+ * @param list
+ * @param orgIds
+ */
private void includeAllOrgs(Set<Organization> list, Set<Integer> orgIds) {
for (Organization org : list) {
orgIds.add(org.getId());
@@ -229,10 +285,16 @@
this.email = email;
}
+ /**
+ * Numeric rol mask. Be aware to use different bit position for each role
+ *
+ * @author rob
+ */
public static class Rol {
public static final int ADVANCE = 0x01;
public static final int ADMIN = 0x02;
- public static final int[] ALL = new int[] { ADVANCE, ADMIN };
+ public static final int BASIC = 0x04;
+ public static final int[] ALL = new int[] { ADVANCE, ADMIN, BASIC };
}
}
diff --git a/securis/src/main/java/net/curisit/securis/ioc/RequestsInterceptor.java b/securis/src/main/java/net/curisit/securis/ioc/RequestsInterceptor.java
index 0ac32bb..391ec7f 100644
--- a/securis/src/main/java/net/curisit/securis/ioc/RequestsInterceptor.java
+++ b/securis/src/main/java/net/curisit/securis/ioc/RequestsInterceptor.java
@@ -21,12 +21,6 @@
import javax.ws.rs.ext.WriterInterceptor;
import javax.ws.rs.ext.WriterInterceptorContext;
-import net.curisit.securis.db.User;
-import net.curisit.securis.security.BasicSecurityContext;
-import net.curisit.securis.security.Securable;
-import net.curisit.securis.utils.CacheTTL;
-import net.curisit.securis.utils.TokenHelper;
-
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jboss.resteasy.core.Dispatcher;
@@ -36,158 +30,188 @@
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import net.curisit.securis.db.User;
+import net.curisit.securis.security.BasicSecurityContext;
+import net.curisit.securis.security.Securable;
+import net.curisit.securis.utils.CacheTTL;
+import net.curisit.securis.utils.TokenHelper;
+
@Provider
@Priority(Priorities.AUTHENTICATION)
public class RequestsInterceptor implements ContainerRequestFilter, WriterInterceptor {
- private static final Logger LOG = LogManager.getLogger(RequestsInterceptor.class);
+ private static final Logger LOG = LogManager.getLogger(RequestsInterceptor.class);
- @Context
- private HttpServletResponse servletResponse;
+ @Context
+ private HttpServletResponse servletResponse;
- @Context
- private HttpServletRequest servletRequest;
+ @Context
+ private HttpServletRequest servletRequest;
- @Inject
- private CacheTTL cache;
+ @Inject
+ private CacheTTL cache;
- @Inject
- private TokenHelper tokenHelper;
+ @Inject
+ private TokenHelper tokenHelper;
- @Context
- private Dispatcher dispatcher;
+ @Context
+ private Dispatcher dispatcher;
- @Inject
- private EntityManagerProvider emProvider;
+ @Inject
+ private EntityManagerProvider emProvider;
- @Override
- public void filter(ContainerRequestContext containerRequestContext) throws IOException {
- EntityManager em = emProvider.getEntityManager();
- LOG.debug("GETTING EM: {}", em);
+ @Override
+ public void filter(ContainerRequestContext containerRequestContext) throws IOException {
+ EntityManager em = emProvider.getEntityManager();
+ LOG.debug("GETTING EM: {}", em);
- ResteasyProviderFactory.pushContext(EntityManager.class, em);
+ ResteasyProviderFactory.pushContext(EntityManager.class, em);
- ResourceMethodInvoker methodInvoker = (ResourceMethodInvoker) containerRequestContext
- .getProperty("org.jboss.resteasy.core.ResourceMethodInvoker");
- Method method = methodInvoker.getMethod();
+ ResourceMethodInvoker methodInvoker = (ResourceMethodInvoker) containerRequestContext.getProperty("org.jboss.resteasy.core.ResourceMethodInvoker");
+ Method method = methodInvoker.getMethod();
- LOG.debug("Stored in context, em: {}, {}", em, method.toGenericString());
+ LOG.debug("Stored in context, em: {}, {}", em, method.toGenericString());
- boolean next = checkSecurableMethods(containerRequestContext, method);
- if (next) {
- prepareTransaction(containerRequestContext, method, em);
- }
- }
+ boolean next = checkSecurableMethods(containerRequestContext, method);
+ if (next) {
+ prepareTransaction(containerRequestContext, method, em);
+ }
+ }
- private void prepareTransaction(ContainerRequestContext containerRequestContext, Method method, EntityManager em) {
+ private void prepareTransaction(ContainerRequestContext containerRequestContext, Method method, EntityManager em) {
- if (method.isAnnotationPresent(EnsureTransaction.class)) {
- LOG.debug("Beginning a new transaction");
- em.getTransaction().begin();
- }
- }
+ if (method.isAnnotationPresent(EnsureTransaction.class)) {
+ LOG.debug("Beginning a new transaction");
+ em.getTransaction().begin();
+ }
+ }
- private boolean checkSecurableMethods(ContainerRequestContext containerRequestContext, Method method) {
- if (!method.isAnnotationPresent(Securable.class)) {
- return true;
- }
- String token = servletRequest.getHeader(TokenHelper.TOKEN_HEADER_PÀRAM);
- if (token == null || !tokenHelper.isTokenValid(token)) {
- LOG.warn("Access denied, Token not valid: {} for method: {}::{}", token, method.getDeclaringClass(), method.getName());
- containerRequestContext.abortWith(Response.status(Status.UNAUTHORIZED).build());
- return false;
- } else {
+ private boolean checkSecurableMethods(ContainerRequestContext containerRequestContext, Method method) {
+ if (!method.isAnnotationPresent(Securable.class)) {
+ return true;
+ }
+ String token = servletRequest.getHeader(TokenHelper.TOKEN_HEADER_PÀRAM);
+ if (token == null || !tokenHelper.isTokenValid(token)) {
+ LOG.warn("Access denied, Token not valid: {} for method: {}::{}", token, method.getDeclaringClass(), method.getName());
+ containerRequestContext.abortWith(Response.status(Status.UNAUTHORIZED).build());
+ return false;
+ } else {
+ Securable securable = method.getAnnotation(Securable.class);
+ // If roles == 0 we only need to validate the token
+ String username = tokenHelper.extractUserFromToken(token);
+ int userRoles = getUserRoles(username);
+ if (securable.roles() != 0 && (securable.roles() & userRoles) == 0) {
+ LOG.warn("Method {} requires roles: {}, but user {} hasn't got them", method.getName(), securable.roles(), username);
+ containerRequestContext.abortWith(Response.status(Status.UNAUTHORIZED).build());
+ return false;
+ }
+ Set<Integer> orgs = getUserOrganizations(username);
+ Set<Integer> apps = getUserApplications(username);
- // If roles == 0 we only need to validate the token
- String username = tokenHelper.extractUserFromToken(token);
- int userRoles = getUserRoles(username);
- Set<Integer> orgs = getUserOrganizations(username);
+ BasicSecurityContext scw = new BasicSecurityContext(username, userRoles, servletRequest.isSecure());
+ scw.setOrganizationsIds(orgs);
+ scw.setApplicationsIds(apps);
+ containerRequestContext.setSecurityContext(scw);
+ // Next line provide injection in resource methods
+ ResteasyProviderFactory.pushContext(BasicSecurityContext.class, scw);
+ LOG.debug("Added custom SecurityContext for user {}, orgs: {}", username, orgs);
+ }
+ return true;
- BasicSecurityContext scw = new BasicSecurityContext(username, userRoles, servletRequest.isSecure());
- scw.setOrganizationsIds(orgs);
- containerRequestContext.setSecurityContext(scw);
- // Next line provide injection in resource methods
- ResteasyProviderFactory.pushContext(BasicSecurityContext.class, scw);
- LOG.debug("Added custom SecurityContext for user {}, orgs: {}", username, orgs);
- }
- return true;
+ }
- }
+ private Set<Integer> getUserOrganizations(String username) {
+ @SuppressWarnings("unchecked")
+ Set<Integer> userOrgs = cache.get("orgs_" + username, Set.class);
+ if (userOrgs == null) {
+ EntityManager em = ResteasyProviderFactory.getContextData(EntityManager.class);
- private Set<Integer> getUserOrganizations(String username) {
- @SuppressWarnings("unchecked")
- Set<Integer> userOrgs = cache.get("orgs_" + username, Set.class);
- if (userOrgs == null) {
- EntityManager em = ResteasyProviderFactory.getContextData(EntityManager.class);
+ // Theorically this shouldn't be never null, but just in case...
+ User user = em.find(User.class, username);
+ if (user != null) {
+ userOrgs = user.getAllOrgsIds();
+ // We store user orgs in cache only for one hour
+ cache.set("orgs_" + username, userOrgs, 3600);
+ }
+ }
- // Theorically this shouldn't be never null, but just in case...
- User user = em.find(User.class, username);
- if (user != null) {
- userOrgs = user.getAllOrgsIds();
- // We store user orgs in cache only for one hour
- cache.set("orgs_" + username, userOrgs, 3600);
- }
- }
+ return userOrgs;
+ }
- return userOrgs;
- }
+ private Set<Integer> getUserApplications(String username) {
+ @SuppressWarnings("unchecked")
+ Set<Integer> userApps = cache.get("apps_" + username, Set.class);
+ if (userApps == null) {
+ EntityManager em = ResteasyProviderFactory.getContextData(EntityManager.class);
- private int getUserRoles(String username) {
- if (username == null) {
- return 0;
- }
- Integer userRoles = cache.get("roles_" + username, Integer.class);
- if (userRoles == null) {
- EntityManager em = ResteasyProviderFactory.getContextData(EntityManager.class);
+ // Theorically this shouldn't be never null, but just in case...
+ User user = em.find(User.class, username);
+ if (user != null) {
+ userApps = user.getAllAppsIds();
+ // We store user orgs in cache only for one hour
+ cache.set("apps_" + username, userApps, 3600);
+ }
+ }
- User user = em.find(User.class, username);
- if (user != null) {
- userRoles = 0;
- List<Integer> roles = user.getRoles();
- if (roles != null) {
- for (Integer rol : roles) {
- userRoles += rol;
- }
- }
- // We store user roles in cache only for one hour
- cache.set("roles_" + username, userRoles, 3600);
- cache.set("orgs_" + username, user.getOrgsIds(), 3600);
- }
- }
- return userRoles == null ? 0 : userRoles.intValue();
- }
+ return userApps;
+ }
- // @Override
- public ServerResponse preProcess(HttpRequest request, ResourceMethodInvoker method) throws Failure, WebApplicationException {
- return null;
- }
+ private int getUserRoles(String username) {
+ if (username == null) {
+ return 0;
+ }
+ Integer userRoles = cache.get("roles_" + username, Integer.class);
+ if (userRoles == null) {
+ EntityManager em = ResteasyProviderFactory.getContextData(EntityManager.class);
- @Override
- public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
- context.proceed();
- EntityManager em = ResteasyProviderFactory.getContextData(EntityManager.class);
- try {
- if (em != null && em.getTransaction().isActive()) {
- if (servletResponse.getStatus() == Status.OK.getStatusCode()) {
- em.getTransaction().commit();
- LOG.debug("COMMIT");
- } else {
- // This code is never executed if there is an error the
- // filter chain is broken
- em.getTransaction().rollback();
- LOG.debug("ROLLBACK");
- }
- }
- } finally {
- if (em.isOpen()) {
- LOG.debug("CLOSING EM: {}, trans: {}", em, em.isJoinedToTransaction());
- try {
- em.close();
- } catch (Exception ex) {
- ex.printStackTrace();
- LOG.error("Error closing EM: {}, {}", em, ex);
- }
- }
- }
- }
+ User user = em.find(User.class, username);
+ if (user != null) {
+ userRoles = 0;
+ List<Integer> roles = user.getRoles();
+ if (roles != null) {
+ for (Integer rol : roles) {
+ userRoles += rol;
+ }
+ }
+ // We store user roles in cache only for one hour
+ cache.set("roles_" + username, userRoles, 3600);
+ cache.set("orgs_" + username, user.getOrgsIds(), 3600);
+ }
+ }
+ return userRoles == null ? 0 : userRoles.intValue();
+ }
+
+ // @Override
+ public ServerResponse preProcess(HttpRequest request, ResourceMethodInvoker method) throws Failure, WebApplicationException {
+ return null;
+ }
+
+ @Override
+ public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
+ context.proceed();
+ EntityManager em = ResteasyProviderFactory.getContextData(EntityManager.class);
+ try {
+ if (em != null && em.getTransaction().isActive()) {
+ if (servletResponse.getStatus() == Status.OK.getStatusCode()) {
+ em.getTransaction().commit();
+ LOG.debug("COMMIT");
+ } else {
+ // This code is never executed if there is an error the
+ // filter chain is broken
+ em.getTransaction().rollback();
+ LOG.debug("ROLLBACK");
+ }
+ }
+ } finally {
+ if (em.isOpen()) {
+ LOG.debug("CLOSING EM: {}, trans: {}", em, em.isJoinedToTransaction());
+ try {
+ em.close();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ LOG.error("Error closing EM: {}, {}", em, ex);
+ }
+ }
+ }
+ }
}
diff --git a/securis/src/main/java/net/curisit/securis/security/BasicSecurityContext.java b/securis/src/main/java/net/curisit/securis/security/BasicSecurityContext.java
index 3f20ddc..dc0f40b 100644
--- a/securis/src/main/java/net/curisit/securis/security/BasicSecurityContext.java
+++ b/securis/src/main/java/net/curisit/securis/security/BasicSecurityContext.java
@@ -11,83 +11,101 @@
public class BasicSecurityContext implements SecurityContext {
- final public static String ROL_ADVANCE = "advance";
- final public static String ROL_ADMIN = "admin";
+ final public static String ROL_ADVANCE = "advance";
+ final public static String ROL_ADMIN = "admin";
+ final public static String ROL_BASIC = "basic";
- final static Map<String, Integer> ROLES = Utils.<String, Integer> createMap(ROL_ADVANCE, User.Rol.ADVANCE, ROL_ADMIN, User.Rol.ADMIN);
+ final static Map<String, Integer> ROLES = Utils.<String, Integer> createMap(ROL_BASIC, User.Rol.BASIC, ROL_ADVANCE, User.Rol.ADVANCE, ROL_ADMIN, User.Rol.ADMIN);
- Principal user = null;
- int roles = 0;
- boolean secure = false;
- Set<Integer> organizationsIds = null;
- double ran = 0;
+ Principal user = null;
+ int roles = 0;
+ boolean secure = false;
+ Set<Integer> organizationsIds = null;
+ Set<Integer> applicationsIds = null;
+ double ran = 0;
- public BasicSecurityContext(String username, int roles, boolean secure) {
- user = new UserPrincipal(username);
- this.roles = roles;
- this.secure = secure;
- ran = Math.random();
- }
+ public BasicSecurityContext(String username, int roles, boolean secure) {
+ user = new UserPrincipal(username);
+ this.roles = roles;
+ this.secure = secure;
+ ran = Math.random();
+ }
- @Override
- public Principal getUserPrincipal() {
- return user;
- }
+ @Override
+ public Principal getUserPrincipal() {
+ return user;
+ }
- @Override
- public boolean isUserInRole(String role) {
- Integer introle = ROLES.get(role);
- return introle != null && (introle & roles) != 0;
- }
+ @Override
+ public boolean isUserInRole(String role) {
+ Integer introle = ROLES.get(role);
+ return introle != null && (introle & roles) != 0;
+ }
- @Override
- public boolean isSecure() {
- return secure;
- }
+ @Override
+ public boolean isSecure() {
+ return secure;
+ }
- @Override
- public String getAuthenticationScheme() {
- return null;
- }
+ @Override
+ public String getAuthenticationScheme() {
+ return null;
+ }
- @Override
- public String toString() {
+ @Override
+ public String toString() {
- return String.format("SecurityContextWrapper(%f) %s", ran, user);
- }
+ return String.format("SecurityContextWrapper(%f) %s", ran, user);
+ }
- public void setOrganizationsIds(Set<Integer> orgs) {
- this.organizationsIds = orgs;
- }
+ public void setOrganizationsIds(Set<Integer> orgs) {
+ this.organizationsIds = orgs;
+ }
- public Set<Integer> getOrganizationsIds() {
- return this.organizationsIds;
- }
+ public Set<Integer> getOrganizationsIds() {
+ return this.organizationsIds;
+ }
- private class UserPrincipal implements Principal {
+ public Set<Integer> getApplicationsIds() {
+ return applicationsIds;
+ }
- final String name;
+ public void setApplicationsIds(Set<Integer> applicationsIds) {
+ this.applicationsIds = applicationsIds;
+ }
- public UserPrincipal(String name) {
- this.name = name;
- }
+ private class UserPrincipal implements Principal {
- @Override
- public String getName() {
- return this.name;
- }
+ final String name;
- @Override
- public String toString() {
- return String.format("[%s]", name);
- }
+ public UserPrincipal(String name) {
+ this.name = name;
+ }
- }
+ @Override
+ public String getName() {
+ return this.name;
+ }
- public boolean isOrgAccesible(Integer orgid) {
- if (organizationsIds == null || orgid == null) {
- return false;
- }
- return organizationsIds.contains(orgid);
- }
+ @Override
+ public String toString() {
+ return String.format("[%s]", name);
+ }
+
+ }
+
+ public boolean isOrgAccesible(Integer orgid) {
+ if (organizationsIds == null || orgid == null) {
+ return false;
+ }
+ return organizationsIds.contains(orgid);
+ }
+
+ public boolean isAppAccesible(Integer appid) {
+ if (applicationsIds == null || appid == null) {
+ return false;
+ }
+ return applicationsIds.contains(appid);
+ }
+
}
diff --git a/securis/src/main/java/net/curisit/securis/services/PackResource.java b/securis/src/main/java/net/curisit/securis/services/PackResource.java
index a417a98..07bfdfa 100644
--- a/securis/src/main/java/net/curisit/securis/services/PackResource.java
+++ b/securis/src/main/java/net/curisit/securis/services/PackResource.java
@@ -90,11 +90,14 @@
LOG.info("Getting all packs for user: " + bsc.getUserPrincipal());
q = em.createNamedQuery("list-packs", Pack.class);
} else {
- if (bsc.getOrganizationsIds() == null) {
+ if (bsc.getOrganizationsIds() == null || bsc.getOrganizationsIds().isEmpty() || //
+ bsc.getApplicationsIds() == null || bsc.getApplicationsIds().isEmpty()) {
return Response.ok().build();
}
- q = em.createNamedQuery("list-packs-by-orgs", Pack.class);
- q.setParameter("list_ids", bsc.getOrganizationsIds());
+ q = em.createNamedQuery("list-packs-by-orgs-apps", Pack.class);
+ q.setParameter("list_ids_org", bsc.getOrganizationsIds());
+ q.setParameter("list_ids_app", bsc.getApplicationsIds());
+ LOG.info("Getting packs from orgs: {} and apps: {}", bsc.getOrganizationsIds(), bsc.getApplicationsIds());
}
List<Pack> list = q.getResultList();
diff --git a/securis/src/main/java/net/curisit/securis/services/UserResource.java b/securis/src/main/java/net/curisit/securis/services/UserResource.java
index 0c3e233..a4789d4 100644
--- a/securis/src/main/java/net/curisit/securis/services/UserResource.java
+++ b/securis/src/main/java/net/curisit/securis/services/UserResource.java
@@ -34,6 +34,7 @@
import net.curisit.integrity.commons.Utils;
import net.curisit.securis.DefaultExceptionHandler;
import net.curisit.securis.SeCurisException;
+import net.curisit.securis.db.Application;
import net.curisit.securis.db.Organization;
import net.curisit.securis.db.User;
import net.curisit.securis.ioc.EnsureTransaction;
@@ -131,7 +132,12 @@
}
try {
- this.setUserOrg(user, user.getOrgsIds(), em);
+ this.setUserOrgs(user, user.getOrgsIds(), em);
+ } catch (SeCurisException e) {
+ return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, e.getMessage()).build();
+ }
+ try {
+ this.setUserApps(user, user.getAppsIds(), em);
} catch (SeCurisException e) {
return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, e.getMessage()).build();
}
@@ -149,7 +155,7 @@
return Response.ok(user).build();
}
- private void setUserOrg(User user, Set<Integer> orgsIds, EntityManager em) throws SeCurisException {
+ private void setUserOrgs(User user, Set<Integer> orgsIds, EntityManager em) throws SeCurisException {
Set<Organization> orgs = null;
if (orgsIds != null && !orgsIds.isEmpty()) {
orgs = new HashSet<>();
@@ -165,6 +171,23 @@
user.setOrganizations(orgs);
+ }
+
+ private void setUserApps(User user, Set<Integer> appsIds, EntityManager em) throws SeCurisException {
+ Set<Application> apps = null;
+ if (appsIds != null && !appsIds.isEmpty()) {
+ apps = new HashSet<>();
+ for (Integer appId : appsIds) {
+ Application o = em.find(Application.class, appId);
+ if (o == null) {
+ LOG.error("User application with id {} not found in DB", appId);
+ throw new SeCurisException("User's application not found with ID: " + appId);
+ }
+ apps.add(o);
+ }
+ }
+
+ user.setApplications(apps);
}
@PUT
@@ -185,7 +208,12 @@
}
try {
- this.setUserOrg(currentUser, user.getOrgsIds(), em);
+ this.setUserOrgs(currentUser, user.getOrgsIds(), em);
+ } catch (SeCurisException e) {
+ return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, e.getMessage()).build();
+ }
+ try {
+ this.setUserApps(currentUser, user.getAppsIds(), em);
} catch (SeCurisException e) {
return Response.status(Status.NOT_FOUND).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER, e.getMessage()).build();
}
@@ -199,8 +227,6 @@
} else {
// Password has not been modified
// return
- // Response.status(DefaultExceptionHandler.DEFAULT_APP_ERROR_STATUS_CODE).header(DefaultExceptionHandler.ERROR_MESSAGE_HEADER,
- // "User password is mandatory").build();
}
currentUser.setLastLogin(user.getLastLogin());
diff --git a/securis/src/main/resources/db/schema.sql b/securis/src/main/resources/db/schema.sql
index cbe5721..b665d34 100644
--- a/securis/src/main/resources/db/schema.sql
+++ b/securis/src/main/resources/db/schema.sql
@@ -73,6 +73,13 @@
username VARCHAR(45) NOT NULL,
organization_id INT NOT NULL,
PRIMARY KEY (username, organization_id));
+
+drop table IF EXISTS user_application;
+CREATE TABLE IF NOT EXISTS user_application (
+ username VARCHAR(45) NOT NULL,
+ application_id INT NOT NULL,
+ PRIMARY KEY (username, application_id));
+
drop table IF EXISTS pack;
CREATE TABLE IF NOT EXISTS pack (
diff --git a/securis/src/main/webapp/index.html b/securis/src/main/webapp/index.html
index 32d0ecf..15087e7 100644
--- a/securis/src/main/webapp/index.html
+++ b/securis/src/main/webapp/index.html
@@ -28,6 +28,7 @@
<!-- Load the Covalent/Material prebuilt theme -->
<link href="node_modules/@covalent/core/theming/prebuilt/blue-orange.css" rel="stylesheet">
+
<link href="node_modules/ng2-toastr/bundles/ng2-toastr.min.css" rel="stylesheet" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
diff --git a/securis/src/main/webapp/package.json b/securis/src/main/webapp/package.json
index b294000..470b421 100644
--- a/securis/src/main/webapp/package.json
+++ b/securis/src/main/webapp/package.json
@@ -1,7 +1,7 @@
{
"name": "securis",
"version": "2.0.0",
- "description": "QuickStart package.json from the documentation, supplemented with testing support",
+ "description": "SeCuris front-end application based on Angular4 and Materail design",
"scripts": {
"build": "tsc -p src/",
"build:watch": "tsc -p src/ -w",
@@ -24,18 +24,19 @@
"author": "",
"license": "MIT",
"dependencies": {
- "@angular/common": "^2.4.9",
- "@angular/compiler": "~2.4.9",
- "@angular/core": "~2.4.9",
- "@angular/forms": "~2.4.9",
- "@angular/http": "~2.4.9",
- "@angular/material": "^2.0.0-beta.2",
- "@angular/platform-browser": "~2.4.9",
- "@angular/platform-browser-dynamic": "~2.4.9",
- "@angular/router": "^3.4.9",
- "@covalent/core": "^1.0.0-beta.2",
- "@covalent/dynamic-forms": "^1.0.0-beta.2",
- "@covalent/http": "^1.0.0-beta.2",
+ "@angular/common": "^4.0.1",
+ "@angular/compiler": "~4.0.1",
+ "@angular/core": "~4.0.1",
+ "@angular/forms": "~4.0.1",
+ "@angular/http": "~4.0.1",
+ "@angular/animations": "~4.0.1",
+ "@angular/material": "^2.0.0-beta.3",
+ "@angular/platform-browser": "~4.0.1",
+ "@angular/platform-browser-dynamic": "~4.0.1",
+ "@angular/router": "^4.0.1",
+ "@covalent/core": "^1.0.0-beta.3",
+ "@covalent/dynamic-forms": "^1.0.0-beta.3",
+ "@covalent/http": "^1.0.0-beta.3",
"angular-2-local-storage": "^1.0.1",
"angular-in-memory-web-api": "~0.2.4",
"core-js": "^2.4.1",
diff --git a/securis/src/main/webapp/sql_update.sql b/securis/src/main/webapp/sql_update.sql
index 08c0847..cfed213 100644
--- a/securis/src/main/webapp/sql_update.sql
+++ b/securis/src/main/webapp/sql_update.sql
@@ -1,2 +1,10 @@
alter table pack add column frozen BOOLEAN NOT NULL default false;
-alter table license add column metadata_obsolete BOOLEAN NOT NULL default false;
\ No newline at end of file
+alter table license add column metadata_obsolete BOOLEAN NOT NULL default false;
+
+drop table IF EXISTS user_application;
+CREATE TABLE IF NOT EXISTS user_application (
+ username VARCHAR(45) NOT NULL,
+ application_id INT NOT NULL,
+ PRIMARY KEY (username, application_id));
+
+
\ No newline at end of file
diff --git a/securis/src/main/webapp/src/app/app.module.ts b/securis/src/main/webapp/src/app/app.module.ts
index fe86958..512e9ca 100644
--- a/securis/src/main/webapp/src/app/app.module.ts
+++ b/securis/src/main/webapp/src/app/app.module.ts
@@ -1,5 +1,6 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
+import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import {MaterialModule} from '@angular/material';
@@ -54,6 +55,7 @@
storageType: 'localStorage'
}),
BrowserModule,
+ BrowserAnimationsModule,
FormsModule,
MaterialModule,
CovalentCoreModule.forRoot(),
diff --git a/securis/src/main/webapp/src/app/forms/user.form.component.ts b/securis/src/main/webapp/src/app/forms/user.form.component.ts
index c579366..bdf543b 100644
--- a/securis/src/main/webapp/src/app/forms/user.form.component.ts
+++ b/securis/src/main/webapp/src/app/forms/user.form.component.ts
@@ -29,12 +29,16 @@
})
export class UserFormComponent extends FormBase {
allOrganizations: IComboOption[];
+ allApplications: IComboOption[];
orgNames: string[] = [];
- allRoles: any[] = [{"id":1, "code": "advance", "label":"Advance"}, {"id":2, "code": "admin","label":"Admin"}];
+ appNames: string[] = [];
+ allRoles: any[] = [{"id":4, "code": "basic","label":"Basic"}, {"id":1, "code": "advance", "label":"Advance"}, {"id":2, "code": "admin","label":"Admin"}];
user_orgs: string[] = [];
+ user_apps: string[] = [];
user_roles: any = {};
constructor(private http: Http,
private users: UsersService,
+ private applications: ApplicationsService,
private organizations: OrganizationsService,
router: Router,
toaster: ToastsManager,
@@ -50,6 +54,10 @@
this.user_orgs.forEach(orgName => {
var selectedOrg = this.allOrganizations.find(org => org.label === orgName);
this.data.organizations_ids.push(selectedOrg.id);
+ });
+ this.user_apps.forEach(appName => {
+ var selectedApp = this.allApplications.find(app => app.label === appName);
+ this.data.applications_ids.push(selectedApp.id);
});
this.user_roles.advance && this.data.roles.push(1);
this.user_roles.admin && this.data.roles.push(2);
@@ -71,6 +79,16 @@
},
err => console.error('Error loading organizations')
);
+ this.applications.get()
+ .map(list => list.map((app : any) => <IComboOption>{id: app.id, label: app.name}))
+ .subscribe(
+ data => {
+ this.allApplications = (<IComboOption[]>data).sort((e1, e2) => e1.label.localeCompare(e2.label));
+ this.appNames = this.allApplications.map(org => org.label);
+ this._loadApps();
+ },
+ err => console.error('Error loading organizations')
+ );
}
goBack(): void {
@@ -84,6 +102,14 @@
});
}
}
+ _loadApps() {
+ if (this.data && this.data.applications_ids && this.allApplications && this.allApplications.length > 0) {
+ this.data.applications_ids.forEach((appId : number) => {
+ var selectedApp = this.allApplications.find(app => app.id === appId);
+ this.user_apps.push(selectedApp.label);
+ });
+ }
+ }
init() : void {
this.loadCombos();
this.user_orgs = [];
@@ -92,6 +118,7 @@
super.reset();
super.prepareInitialData('username', {
organizations_ids: [],
+ applications_ids: [],
roles: []
}, (data) => {
this._loadOrgs();
diff --git a/securis/src/main/webapp/src/app/forms/user.form.html b/securis/src/main/webapp/src/app/forms/user.form.html
index 1a3caa4..11ecf99 100644
--- a/securis/src/main/webapp/src/app/forms/user.form.html
+++ b/securis/src/main/webapp/src/app/forms/user.form.html
@@ -7,18 +7,6 @@
<span flex></span>
<button md-icon-button (click)="save()"><md-icon>save</md-icon></button>
</md-toolbar>
- <!--
- username: 'rym',
- roles: [ 1 ],
- lastLogin: 1488885433000,
- modificationTimestamp: 1479898458000,
- email: 'rbouchair@curistec.com',
- first_name: 'Rym',
- last_name: 'Bouchair',
- creation_timestamp: 1479898458000,
- organizations_ids: [ 1, 2, 5, 6, 7, 8 ]
-}
- -->
<div class="margin" layout-align-gt-xs="center start" layout-fill="" layout-gt-xs="row">
<md-card flex="70">
<md-card-title>
@@ -79,7 +67,7 @@
<error-checker [fieldName]="$L.get('field.email')" [formField]="form.controls.email"></error-checker>
</div>
</div>
- <div layout="row" layout-fill layout-padding >
+ <div layout="row" layout-fill layout-padding >
<td-chips flex [mdTooltip]="$L.get('Organizations that user can access')" [placeholder]="$L.get('Select organizations')"
[items]="orgNames" [(ngModel)]="user_orgs" name="user_orgs" requireMatch>
</td-chips>
@@ -92,6 +80,11 @@
</md-checkbox>
</div>
</div>
+ <div layout="row" layout-fill layout-padding >
+ <td-chips flex [mdTooltip]="$L.get('Applications that user can access')" [placeholder]="$L.get('Select applications')"
+ [items]="appNames" [(ngModel)]="user_apps" name="user_apps" requireMatch>
+ </td-chips>
+ </div>
<div layout="row" layout-fill layout-padding *ngIf="!isNew">
<field-readonly [value]="data.lastLogin || '' | timeAgo" label="field.lastLogin" flex></field-readonly>
<field-readonly [value]="data.creation_timestamp | date: 'medium'" label="field.creation_timestamp" flex></field-readonly>
diff --git a/securis/src/main/webapp/src/app/listing/user.list.component.html b/securis/src/main/webapp/src/app/listing/user.list.component.html
index 44cc658..766da66 100644
--- a/securis/src/main/webapp/src/app/listing/user.list.component.html
+++ b/securis/src/main/webapp/src/app/listing/user.list.component.html
@@ -6,7 +6,7 @@
<span class="push-left-sm" *ngIf="filteredItems < data.length">
<span class="md-body-1">{{filteredItems}} of {{data.length}} applications filtered</span>
</span>
- <td-search-box #searchBox class="push-right-sm" placeholder="Search here" (searchDebounce)="search($event)" flex>
+ <td-search-box #searchBox class="push-right-sm" [alwaysVisible]="false" [placeholder]="$L.get('Search here')" (searchDebounce)="search($event)" flex>
</td-search-box>
<button md-mini-fab color="accent" (click)="create()" [mdTooltip]="$L.get('Create a new application')">
<md-icon>add</md-icon>
diff --git a/securis/src/main/webapp/systemjs.config.js b/securis/src/main/webapp/systemjs.config.js
index 476858d..4cb7dfc 100644
--- a/securis/src/main/webapp/systemjs.config.js
+++ b/securis/src/main/webapp/systemjs.config.js
@@ -4,7 +4,7 @@
*/
(function (global) {
- var ANGULAR_LIBS = ['core', 'http', 'common', 'compiler', 'material', 'flex-layout', //
+ var ANGULAR_LIBS = ['core', 'http', 'common', 'compiler', 'material', 'flex-layout', 'animations', //
'router', 'forms', 'platform-browser', 'platform-browser-dynamic', 'common'];
var COVALENT_LIBS = ['core', 'http', 'dynamic-forms'];
var mapping = {
@@ -12,6 +12,8 @@
main: 'src/main.js',
'app': 'src/app',
'environments': 'src/environments',
+ '@angular/animations/browser': 'npm:@angular/animations/bundles/animations-browser.umd.js',
+ '@angular/platform-browser/animations': 'npm:@angular/platform-browser/bundles/platform-browser-animations.umd.js',
// other libraries
'rxjs': 'npm:rxjs',
@@ -22,7 +24,7 @@
}
ANGULAR_LIBS.forEach(function (libName) {
- mapping['@angular/' + libName] = 'npm:@angular/' + libName + '/bundles/' + libName + '.umd.js';
+ mapping['@angular/' + libName] = 'npm:@angular/' + libName + '/bundles/' + libName + '.umd.js';
});
COVALENT_LIBS.forEach(function (libName) {
--
Gitblit v1.3.2