diff --git a/pom.xml b/pom.xml
index 143097f80..30d7630fb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -203,6 +203,13 @@
3.1.0
provided
+
+
+ com.nimbusds
+ nimbus-jose-jwt
+ jdk16
+ 4.11.2
+
diff --git a/src/com/rjconsultores/ventaboletos/dao/EmpresaDAO.java b/src/com/rjconsultores/ventaboletos/dao/EmpresaDAO.java
index f81b99488..c088a3c8b 100644
--- a/src/com/rjconsultores/ventaboletos/dao/EmpresaDAO.java
+++ b/src/com/rjconsultores/ventaboletos/dao/EmpresaDAO.java
@@ -73,5 +73,7 @@ public interface EmpresaDAO {
public void gerarSeqNumFolioSistema(Integer idEmpresa, String cveEstado) throws RuntimeException;
public List buscarEmpresaPtoVtaComissao();
+
+ public boolean isPrimeiraVezLicenca();
}
diff --git a/src/com/rjconsultores/ventaboletos/dao/hibernate/EmpresaHibernateDAO.java b/src/com/rjconsultores/ventaboletos/dao/hibernate/EmpresaHibernateDAO.java
index fa24233f0..d9ebf341a 100644
--- a/src/com/rjconsultores/ventaboletos/dao/hibernate/EmpresaHibernateDAO.java
+++ b/src/com/rjconsultores/ventaboletos/dao/hibernate/EmpresaHibernateDAO.java
@@ -14,6 +14,7 @@ import java.util.List;
import javax.sql.DataSource;
import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.Query;
@@ -21,6 +22,7 @@ import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
+import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.type.BooleanType;
import org.hibernate.type.IntegerType;
@@ -50,6 +52,7 @@ public class EmpresaHibernateDAO extends GenericHibernateDAO i
private static String FS_BPE = "FS_BPE_";
+ private static Logger log = Logger.getLogger(EmpresaHibernateDAO.class);
@Autowired
private DataSource dataSource;
@@ -106,6 +109,36 @@ public class EmpresaHibernateDAO extends GenericHibernateDAO i
}
+ /**
+ * Indica se está no momento em que nenhuma empresa tem a licença.
+ *
+ * @return
+ */
+ @Override
+ public boolean isPrimeiraVezLicenca(){
+
+ Criteria c = makeCriteria();
+ c.setProjection(Projections.rowCount());
+ c.add(Restrictions.eq("activo", Boolean.TRUE));
+ c.add(Restrictions.ne("empresaId", -1));
+
+ Long cantEmpresasBaseDados = HibernateFix.count(c.list());
+
+ c = makeCriteria();
+ c.setProjection(Projections.rowCount());
+ c.add(Restrictions.eq("activo", Boolean.TRUE));
+ c.add(Restrictions.ne("empresaId", -1));
+ c.add(Restrictions.isNull("licenca"));
+
+ Long cantEmpresasSemLicenca = HibernateFix.count(c.list());
+
+ return (cantEmpresasBaseDados.equals(cantEmpresasSemLicenca));
+ }
+
+ public List listarEmpresasSemLicenca(){
+
+ return null;
+ }
@SuppressWarnings("unchecked")
public List obtenerIndExternoFalse() {
Criteria c = getSession().createCriteria(getPersistentClass());
diff --git a/src/com/rjconsultores/ventaboletos/entidad/Empresa.java b/src/com/rjconsultores/ventaboletos/entidad/Empresa.java
index a9632ead3..841e3baaa 100644
--- a/src/com/rjconsultores/ventaboletos/entidad/Empresa.java
+++ b/src/com/rjconsultores/ventaboletos/entidad/Empresa.java
@@ -421,6 +421,9 @@ public class Empresa implements Serializable, Auditavel {
@Column(name = "INDTAXACONVENIENCIASOVENDA")
private Boolean indTaxaConvenienciaSoVenda;
+ @Column(name = "LICENCA")
+ private String licenca;
+
@Column(name = "HORAINICIOEMBARQUE")
@Temporal(TemporalType.TIME)
@AuditarAtributo(pattern = "HH:mm")
@@ -434,6 +437,10 @@ public class Empresa implements Serializable, Auditavel {
@Transient
@NaoAuditar
private Empresa empresaClone;
+
+ @Transient
+ @NaoAuditar
+ private String token;
public Empresa() {
super();
@@ -1586,4 +1593,22 @@ public class Empresa implements Serializable, Auditavel {
public void setHoraFimEmbarque(Date horaFimEmbarque) {
this.horaFimEmbarque = horaFimEmbarque;
}
+
+ public String getToken() {
+ return token;
+ }
+
+ public void setToken(String token) {
+ this.token = token;
+ }
+
+ public String getLicenca() {
+ return licenca;
+ }
+
+ public void setLicenca(String licenca) {
+ this.licenca = licenca;
+ }
+
+
}
diff --git a/src/com/rjconsultores/ventaboletos/entidad/Usuario.java b/src/com/rjconsultores/ventaboletos/entidad/Usuario.java
index eabc61af5..c1b3310a1 100644
--- a/src/com/rjconsultores/ventaboletos/entidad/Usuario.java
+++ b/src/com/rjconsultores/ventaboletos/entidad/Usuario.java
@@ -30,15 +30,18 @@ import javax.persistence.Transient;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.rjconsultores.ventaboletos.service.ConstanteService;
+import com.rjconsultores.ventaboletos.service.impl.EmpresaServiceImpl;
import com.rjconsultores.ventaboletos.utilerias.ApplicationProperties;
import com.rjconsultores.ventaboletos.utilerias.CustomEnum;
import com.rjconsultores.ventaboletos.utilerias.DateUtil;
+import com.rjconsultores.ventaboletos.web.utilerias.security.SecurityEmpresaToken;
import com.rjconsultores.ventaboletos.web.utilerias.spring.AppContext;
import br.com.rjconsultores.auditador.annotations.AuditarClasse;
@@ -59,6 +62,7 @@ import br.com.rjconsultores.auditador.interfaces.Auditavel;
public class Usuario implements Serializable, UserDetails, Auditavel {
public final static int CANT_DIAS_CONTRASENA = 999;
+ private static Logger log = Logger.getLogger(Usuario.class);
private static final long serialVersionUID = 1L;
@AuditarID
@@ -255,10 +259,25 @@ public class Usuario implements Serializable, UserDetails, Auditavel {
public List getEmpresa() {
List tmp = new ArrayList();
+
+ SecurityEmpresaToken security = new SecurityEmpresaToken();
+
if (usuarioEmpresaList != null) {
for (UsuarioEmpresa cp : this.usuarioEmpresaList) {
if ((cp.getActivo())) {
- tmp.add(cp.getEmpresa());
+ Empresa empresa = cp.getEmpresa();
+ boolean licenseValidate = false;
+
+ try{
+ licenseValidate = security.licenseValidate(empresa.getLicenca(), empresa.getEmpresaId(), empresa.getCnpj());
+ }catch(Throwable th){
+ log.error(String.format("Licença não validada para a empresaId: %s e cnpj: %s", empresa.getEmpresaId(),empresa.getCnpj()), th);
+ }
+
+
+ if (licenseValidate){
+ tmp.add(cp.getEmpresa());
+ }
}
}
}
diff --git a/src/com/rjconsultores/ventaboletos/service/EmpresaService.java b/src/com/rjconsultores/ventaboletos/service/EmpresaService.java
index 5f9119b8d..8f89ebfe3 100644
--- a/src/com/rjconsultores/ventaboletos/service/EmpresaService.java
+++ b/src/com/rjconsultores/ventaboletos/service/EmpresaService.java
@@ -63,5 +63,18 @@ public interface EmpresaService {
public ComEmpConferencia suscribirOrActualizacion(ComEmpConferencia comEmpConferencia);
public List buscarEmpresaPtoVtaComissao();
+
+ /**
+ * Atualiza se necessário as licenças no primeiro acesso
+ *
+ * @return A quantidade de empresas atualizadas
+ */
+ public Integer atualizarLicencaEmpresasPrimeiraVez();
+
+ public List filtrarApenasEmpresasLicencaValida(List lsEmpresa);
+
+ public String token(Empresa empresa);
+
+ public String validarTokenLicensa(Empresa empresa, String tokenLicenca);
}
diff --git a/src/com/rjconsultores/ventaboletos/service/impl/EmpresaServiceImpl.java b/src/com/rjconsultores/ventaboletos/service/impl/EmpresaServiceImpl.java
index 352ed5e62..413220e8a 100644
--- a/src/com/rjconsultores/ventaboletos/service/impl/EmpresaServiceImpl.java
+++ b/src/com/rjconsultores/ventaboletos/service/impl/EmpresaServiceImpl.java
@@ -4,6 +4,7 @@
*/
package com.rjconsultores.ventaboletos.service.impl;
+import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
@@ -29,6 +30,7 @@ import com.rjconsultores.ventaboletos.service.LogAuditoriaService;
import com.rjconsultores.ventaboletos.service.MarcaService;
import com.rjconsultores.ventaboletos.utilerias.RegistroConDependenciaException;
import com.rjconsultores.ventaboletos.utilerias.UsuarioLogado;
+import com.rjconsultores.ventaboletos.web.utilerias.security.SecurityEmpresaToken;
/**
*
@@ -60,6 +62,8 @@ public class EmpresaServiceImpl implements EmpresaService {
public Empresa obtenerID(Integer id) {
Empresa empresa = empresaDAO.obtenerID(id);
+ empresa.setToken(this.token(empresa));
+
try {
empresa.clonar();
} catch (Exception e) {
@@ -85,6 +89,7 @@ public class EmpresaServiceImpl implements EmpresaService {
entidad = empresaDAO.suscribir(entidad);
logAuditoriaService.auditar(null, entidad, null);
+ entidad.setToken(this.token(entidad));
gerarMarca(entidad);
@@ -138,7 +143,7 @@ public class EmpresaServiceImpl implements EmpresaService {
}
public List buscarTodosExceto(List empresa, Integer... idEmpresa) {
- return empresaDAO.buscarTodosExceto(empresa, idEmpresa);
+ return this.filtrarApenasEmpresasLicencaValida(empresaDAO.buscarTodosExceto(empresa, idEmpresa));
}
public List obtenerIndExternoFalse() {
@@ -170,9 +175,31 @@ public class EmpresaServiceImpl implements EmpresaService {
empresaDAO.actualizaInscEstadual(inscricaoEstadual);
}
+ @Override
+ public List filtrarApenasEmpresasLicencaValida(List lsEmpresa){
+ SecurityEmpresaToken security = new SecurityEmpresaToken();
+ List lsRetorno = new ArrayList<>();
+
+ if (lsEmpresa == null || lsEmpresa.isEmpty()){
+ return lsEmpresa;
+ }
+
+ for(Empresa empresa:lsEmpresa){
+ boolean licenseValidate = security.licenseValidate(empresa.getLicenca(), empresa.getEmpresaId(), empresa.getCnpj());
+ if (!licenseValidate){
+ log.info(String.format("Empresa sem licença válida", empresa.getEmpresaId()));
+
+ continue;
+ }
+ lsRetorno.add(empresa);
+ }
+ return lsRetorno;
+ }
@Override
public List buscaLike(String nombempresa) {
- return empresaDAO.buscaLike(nombempresa);
+ List lsEmpresa = empresaDAO.buscaLike(nombempresa);
+
+ return this.filtrarApenasEmpresasLicencaValida(lsEmpresa);
}
@Override
@@ -240,9 +267,65 @@ public class EmpresaServiceImpl implements EmpresaService {
return empresaDAO.actualizacion(comEmpConferencia);
}
}
+
+ @Override
+ public String validarTokenLicensa(Empresa empresa,String tokenLicenca){
+ if (tokenLicenca == null){
+ return null;
+ }
+ try{
+ SecurityEmpresaToken security = new SecurityEmpresaToken();
+
+ final String license = security.tokenValidate(tokenLicenca);
+
+ return license;
+ }catch(Throwable th){
+ log.error("Erro ao validar token",th);
+ }
+
+ return null;
+ }
+
+ @Override
+ public String token(Empresa empresa){
+
+ SecurityEmpresaToken security = new SecurityEmpresaToken();
+ final String bodyRequest = security.bodyRequestGenerate(empresa.getEmpresaId(), empresa.getCnpj());
+ final String request = security.requestGenerate(bodyRequest);
+
+ return request;
+ }
@Override
public List buscarEmpresaPtoVtaComissao() {
return empresaDAO.buscarEmpresaPtoVtaComissao();
}
+
+ @Override
+ @Transactional
+ public Integer atualizarLicencaEmpresasPrimeiraVez(){
+ boolean primeiraVezLicenca = empresaDAO.isPrimeiraVezLicenca();
+ int cantEmpresasAtualizadas = 0;
+
+ log.info(String.format("primeiraVezLicenca: %s", primeiraVezLicenca));
+
+ if (primeiraVezLicenca){
+ SecurityEmpresaToken security = new SecurityEmpresaToken();
+ List lsEmpresas = empresaDAO.obtenerTodos();
+
+ for(Empresa empresa:lsEmpresas){
+ String licenseDefaultGenerate = security.licenseDefaultGenerate(empresa.getEmpresaId(), empresa.getCnpj());
+
+ log.info(String.format("licenseDefaultGenerate: %s", licenseDefaultGenerate));
+
+ empresa.setLicenca(licenseDefaultGenerate);
+
+ empresaDAO.actualizacion(empresa);
+ cantEmpresasAtualizadas++;
+ }
+
+ }
+
+ return cantEmpresasAtualizadas;
+ }
}
diff --git a/src/com/rjconsultores/ventaboletos/web/utilerias/security/AESGSMHelper.java b/src/com/rjconsultores/ventaboletos/web/utilerias/security/AESGSMHelper.java
new file mode 100644
index 000000000..bc7f43653
--- /dev/null
+++ b/src/com/rjconsultores/ventaboletos/web/utilerias/security/AESGSMHelper.java
@@ -0,0 +1,106 @@
+package com.rjconsultores.ventaboletos.web.utilerias.security;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Hex;
+
+public class AESGSMHelper {
+ private final String SECRET_KEY = "RJ@2019#c0n5ul10r35";
+ private final String SALT = "HrqoFr44GtkAhhYN+jP8Ag==";
+ private final String ENCRYPT_ALGO = "AES/GCM/NoPadding";
+ private final int TAG_LENGTH_BIT = 128;
+ private final int IV_LENGTH_BYTE = 12;
+
+ private final Charset UTF_8 = StandardCharsets.UTF_8;
+
+ public String encrypt(String value) throws Exception {
+ SecretKey secret = getAESKeyFromPassword(SECRET_KEY.toCharArray());
+
+ byte[] pText = value.getBytes(StandardCharsets.UTF_8);
+ byte[] iv = getRandomNonce(12);
+ byte[] cipherText = encrypt(pText, secret, iv);
+
+ byte[] cipherTextWithIv = ByteBuffer.allocate(iv.length + cipherText.length)
+ .put(iv)
+ .put(cipherText)
+ .array();
+
+ return hex(cipherTextWithIv);
+ }
+
+ private byte[] encrypt(byte[] pText, SecretKey secret, byte[] iv) throws Exception {
+ Cipher cipher = Cipher.getInstance(ENCRYPT_ALGO);
+ cipher.init(Cipher.ENCRYPT_MODE, secret, new GCMParameterSpec(TAG_LENGTH_BIT, iv));
+
+ byte[] encryptedText = cipher.doFinal(pText);
+
+ return encryptedText;
+
+ }
+
+ public String decrypt(String value) throws Exception {
+ SecretKey secret = getAESKeyFromPassword(SECRET_KEY.toCharArray());
+
+ byte[] cText = unhex(value);
+
+ ByteBuffer bb = ByteBuffer.wrap(cText);
+
+ byte[] iv = new byte[IV_LENGTH_BYTE];
+ bb.get(iv);
+
+ byte[] cipherText = new byte[bb.remaining()];
+ bb.get(cipherText);
+
+ String plainText = decrypt(cipherText, secret, iv);
+
+ return plainText;
+ }
+
+ private String decrypt(byte[] cText, SecretKey secret, byte[] iv) throws Exception {
+ Cipher cipher = Cipher.getInstance(ENCRYPT_ALGO);
+ cipher.init(Cipher.DECRYPT_MODE, secret, new GCMParameterSpec(TAG_LENGTH_BIT, iv));
+
+ byte[] plainText = cipher.doFinal(cText);
+
+ return new String(plainText, UTF_8);
+ }
+
+ private byte[] getRandomNonce(int numBytes) {
+ byte[] nonce = new byte[numBytes];
+ new SecureRandom().nextBytes(nonce);
+
+ return nonce;
+ }
+
+ private SecretKey getAESKeyFromPassword(char[] password) throws NoSuchAlgorithmException, InvalidKeySpecException {
+ SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
+
+ KeySpec spec = new PBEKeySpec(password, SALT.getBytes(), 65536, 256);
+ SecretKeySpec secret = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
+
+ return secret;
+ }
+
+ private String hex(byte[] bytes) {
+ char[] result = Hex.encodeHex(bytes);
+ return new String(result);
+ }
+
+ private byte[] unhex(String hex) throws DecoderException {
+ return Hex.decodeHex(hex.toCharArray());
+ }
+}
diff --git a/src/com/rjconsultores/ventaboletos/web/utilerias/security/SecurityEmpresaToken.java b/src/com/rjconsultores/ventaboletos/web/utilerias/security/SecurityEmpresaToken.java
new file mode 100644
index 000000000..738bcacef
--- /dev/null
+++ b/src/com/rjconsultores/ventaboletos/web/utilerias/security/SecurityEmpresaToken.java
@@ -0,0 +1,145 @@
+package com.rjconsultores.ventaboletos.web.utilerias.security;
+
+import java.text.ParseException;
+import java.time.Duration;
+import java.util.Calendar;
+
+import javax.xml.bind.DatatypeConverter;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.JWSHeader;
+import com.nimbusds.jose.JWSObject;
+import com.nimbusds.jose.Payload;
+import com.nimbusds.jose.crypto.MACSigner;
+import com.nimbusds.jwt.JWTClaimsSet;
+
+import net.minidev.json.JSONObject;
+
+public class SecurityEmpresaToken {
+ private static Logger log = Logger.getLogger(SecurityEmpresaToken.class);
+
+ private String secret = "#KO&Fm4_k.sU9M8`6Mx'F\\\"H:*Qxu]6F4r,)JmZ2Jwafd)I.2[RET'1:)VQ6mG9,";
+ private static final Duration ttl = Duration.ofDays(7);
+
+ private Gson gson = new Gson();
+
+ public String bodyRequestGenerate(final Integer empresaId, final String cnpj) throws SecurityException {
+ try {
+ AESGSMHelper crypto = new AESGSMHelper();
+
+ JsonObject json = new JsonObject();
+ json.addProperty("empresaId", empresaId);
+ json.addProperty("CNPJ", cnpj);
+
+ return crypto.encrypt(json.toString());
+
+ } catch (Exception e) {
+ log.error("Erro ao gerar o body usado no request da licença: " + e.getMessage(), e);
+
+ throw new SecurityException(e);
+ }
+ }
+
+ public String licenseDefaultGenerate(final Integer empresaId, final String cnpj) throws SecurityException {
+ try {
+ AESGSMHelper crypto = new AESGSMHelper();
+
+ JsonObject json = new JsonObject();
+ json.addProperty("empresaId", empresaId);
+ json.addProperty("CNPJ", cnpj);
+ json.addProperty("aprovado", 1);
+
+ return crypto.encrypt(json.toString());
+
+ } catch (Exception e) {
+ log.error("Erro ao gerar a licença padrão para as empresas existentes: " + e.getMessage(), e);
+
+ throw new SecurityException(e);
+ }
+ }
+
+ public boolean licenseValidate(final String license, final Integer empresaId, final String cnpj) {
+ try {
+ if (StringUtils.isBlank(license)){
+ return false;
+ }
+
+ AESGSMHelper crypto = new AESGSMHelper();
+
+ final String value = crypto.decrypt(license);
+ final JsonObject json = gson.fromJson(value, JsonObject.class);
+
+ if (json.has("empresaId") && json.get("empresaId").getAsInt() == empresaId.intValue()
+ && json.has("CNPJ") && json.get("CNPJ").getAsString().equals(cnpj)
+ && json.has("aprovado")) {
+ log.debug("[empresaId=" + json.get("empresaId").getAsString() + ", CNPJ=" + json.get("CNPJ").getAsString() + ", aprovado=" + json.get("aprovado").getAsString() + "]");
+
+ return json.get("aprovado").getAsString().equals("1");
+ }
+ } catch (Exception e) {
+ log.error("Erro ao gerar o body usado no request da licença: " + e.getMessage(), e);
+ }
+
+ return false;
+ }
+
+ public String requestGenerate(String licenseRequest) throws SecurityException {
+ return requestGenerate(licenseRequest, ttl);
+ }
+
+ public String requestGenerate(String licenseRequest, Duration ttl) throws SecurityException {
+ try {
+ Calendar cal = Calendar.getInstance();
+ cal.add(Calendar.MILLISECOND, (int) ttl.toMillis());
+
+ JWTClaimsSet claims = new JWTClaimsSet.Builder()
+ .expirationTime(cal.getTime())
+ .claim("sub", licenseRequest)
+ .claim("userId", "adm")
+ .claim("role", "ROLE_TOKEN")
+ .build();
+
+ JWSObject jwsObject = new JWSObject(new JWSHeader(JWSAlgorithm.HS256), new Payload(claims.toJSONObject()));
+
+ jwsObject.sign(new MACSigner(DatatypeConverter.parseBase64Binary(secret)));
+
+ return jwsObject.serialize();
+ } catch (Exception e) {
+ log.error("Erro ao gerar a request: " + e.getMessage(), e);
+
+ throw new SecurityException(e);
+ }
+ }
+
+ public String tokenValidate(final String token) throws SecurityException {
+ try {
+ JWSObject jwsObject = JWSObject.parse(token);
+ JSONObject jsonPayload = jwsObject.getPayload().toJSONObject();
+ JWTClaimsSet claims = JWTClaimsSet.parse(jsonPayload);
+
+ if (claims.getExpirationTime().compareTo(Calendar.getInstance().getTime()) < 0) {
+ throw new SecurityException("Token expirado");
+ }
+
+ return claims.getSubject();
+
+ } catch (SecurityException e) {
+ throw e;
+
+ } catch (ParseException e) {
+ log.error("Erro no parser do token: " + e.getMessage(), e);
+
+ throw new SecurityException(e);
+
+ } catch (Exception e) {
+ log.error("Erro ao validar o token: " + e.getMessage(), e);
+
+ throw new SecurityException(e);
+ }
+ }
+}