Rotinas para gerar a liberação da utilização da empresa no sistema
parent
9cf79e7bcc
commit
482261845e
9
pom.xml
9
pom.xml
|
@ -32,6 +32,15 @@
|
|||
</excludes>
|
||||
</resource>
|
||||
</resources>
|
||||
<testSourceDirectory>tests</testSourceDirectory>
|
||||
<testResources>
|
||||
<testResource>
|
||||
<directory>tests</directory>
|
||||
<excludes>
|
||||
<exclude>**/*.java</exclude>
|
||||
</excludes>
|
||||
</testResource>
|
||||
</testResources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
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.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.ofHours(24);
|
||||
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.rjconsultores.ventaboletos.web.utilerias.security.exception;
|
||||
|
||||
public class SecurityException extends Exception {
|
||||
private static final long serialVersionUID = 1801174850577435303L;
|
||||
|
||||
public SecurityException(String arg0, Throwable arg1) {
|
||||
super(arg0, arg1);
|
||||
}
|
||||
|
||||
public SecurityException(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package com.rjconsultores.tests;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.rjconsultores.ventaboletos.web.utilerias.security.SecurityEmpresaToken;
|
||||
|
||||
public class SecurityEmpresaTokenTest {
|
||||
private static final Logger log = LoggerFactory.getLogger(SecurityEmpresaTokenTest.class);
|
||||
|
||||
@Before
|
||||
public void initApplicationContext() {
|
||||
log.info("[ BEGIN ]");
|
||||
}
|
||||
|
||||
@After
|
||||
public void closeApplicationContext() {
|
||||
log.info("[ END ]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_EmpresaNova() throws Exception {
|
||||
// license request -> token request -> token response -> license
|
||||
|
||||
Integer empresaId = 1313;
|
||||
String cnpj = "00073778000120";
|
||||
|
||||
SecurityEmpresaToken security = new SecurityEmpresaToken();
|
||||
|
||||
final String bodyRequest = security.bodyRequestGenerate(empresaId, cnpj);
|
||||
final String request = security.requestGenerate(bodyRequest);
|
||||
|
||||
final String license = security.tokenValidate(request);
|
||||
final boolean valid = security.licenseValidate(license, empresaId, cnpj);
|
||||
|
||||
log.info("Body Request: " + bodyRequest);
|
||||
log.info("Request: " + request);
|
||||
log.info("License: " + license);
|
||||
log.info("Valid: " + Boolean.toString(valid));
|
||||
|
||||
if (valid) fail("Licença válida");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Licenca() throws Exception {
|
||||
Integer empresaId = 1313;
|
||||
String cnpj = "00073778000120";
|
||||
|
||||
SecurityEmpresaToken security = new SecurityEmpresaToken();
|
||||
|
||||
final String license = security.licenseDefaultGenerate(empresaId, cnpj);
|
||||
final boolean valid = security.licenseValidate(license, empresaId, cnpj);
|
||||
|
||||
log.info("License: " + license);
|
||||
log.info("Valid: " + Boolean.toString(valid));
|
||||
|
||||
if (!valid) fail("Licença inválida");
|
||||
}
|
||||
|
||||
@Test(expected = SecurityException.class)
|
||||
public void test_TTL_expired() throws Exception {
|
||||
Duration ttl = Duration.ofSeconds(5);
|
||||
|
||||
Integer empresaId = 1313;
|
||||
String cnpj = "00073778000120";
|
||||
|
||||
SecurityEmpresaToken security = new SecurityEmpresaToken();
|
||||
|
||||
final String bodyRequest = security.bodyRequestGenerate(empresaId, cnpj);
|
||||
final String request = security.requestGenerate(bodyRequest, ttl);
|
||||
|
||||
Thread.sleep(Duration.ofSeconds(10).toMillis());
|
||||
|
||||
final String license = security.tokenValidate(request);
|
||||
final boolean valid = security.licenseValidate(license, empresaId, cnpj);
|
||||
|
||||
log.info("Body Request: " + bodyRequest);
|
||||
log.info("Request: " + request);
|
||||
log.info("License: " + license);
|
||||
log.info("Valid: " + Boolean.toString(valid));
|
||||
|
||||
if (valid) fail("Licença válida");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue