Arquivo

Archive for the ‘Segurança’ Category

Criptografia Assimétrica com OpenSSL

O OpenSSL é um projeto open source que ajuda a aumentar a segurança na comunicação entre aplicações e garante a autenticidade da identidade de uma das partes comunicantes. Em outro artigo, mostrei como gerar um arquivo p7b. Nesse artigo, vou mostrar como utilizar o OpenSSL para trabalhar com chaves públicas e privadas (criptografia assimétrica).

Criação das Chaves

Vamos utilizar o algoritmo RSA para gerar a chave privada:

$openssl genrsa -out privkey.kp 2048

Esse comando produziu um arquivo chamado privkey.kp cujo conteúdo é:

—–BEGIN RSA PRIVATE KEY—–
MIIEpQIBAAKCAQEA0s2xwy0/awWsYBSTWV+C4MwgBgGw3lj6WiLiXD6oRdhVgEFQ
2PjUJPF0r90McWXmFvVyTlQIFqATtsI7XeMxaI8mecHZpaZWkuWwn9P5Y/oaEfnd
SwzdpugY1yveho39PBKBipuypcPhPEee/fHTeoQiua4FXiCUWhKMSqGBWN830sOw
fZwzKVw5N0JS0HFjiB/PO8TTy5hJ2p+Wb6S2uUwQdo8fwvvD1hNeJiJVH22s+fDh
mG9PDMpOrzXpRkiC9YzzXTRZwOn6oRtXTKIF5LdvpxwKSi641Yl2yCnUW7A7V9zY
UVIOh4m9blP+XGJvW22+l3dAd7gfyXyxZB0v9QIDAQABAoIBADhG4aYRdlTD9vjP
hWbesLoCxKnV2boCVxOpLHUj5RiAYJMU3NiP1VLngxdQE/pSEdMfQ5zVojMoGRs5
T1AJTy9yx/rJXalzdrlQyI5isLmYE02pPwLCNIpSfA81jvqs/WYEKsEuP8sxN/g3
xqJU5PhYPk0DwDsYx4IkYX+rDjUDJmKc6A35LRlCFrBOn46ABW7s5SZYm2dvJqY8
5DJYK1j/jmpO52Ua0nnL/jVxXtwZA/2Y83D34XxHVEaIekG9uKGL0xdoovNEfblB
by2b4A6TT3fkhwlZskAE/b4nX/udWvvkPtVWwTXqZqutdBGKy8MY7hggog4lmt0C
e1CkCQECgYEA8wE2vL2SjQfmDBHM9ipeChWGiObNPq2jIbcrzPAZz5PQJRR892oU
rzgiVwYam4bzj9WYvKVsOLAud3cMiDzmFJ+0MJSbj+vEv5zxuzCqLuURbde8eGth
NMf+I3vkhBp6Vp+T9mnnKDIkbqH3zwvu7Q6z2Rkjidjn0YEbpbSoNMkCgYEA3hOj
gTpXrg4K1l+Opdm0AkHAqaoZYshaUhUepvpjBVRheToTxX5x6g7sHIZ1saxC3Mgm
Q3j95qjMwwAFyF0ySVtIexkxgtcGyBnUgRVeTCKZRtNpawn8SQgruVL8LmHKdQfk
wqCEcGP5jL+oZDzrab+5D0RJQ3Stwnr8X5GAE80CgYEA35NJUkO0ty8COC6UfhQi
63I8km6PfdBx285UbTym8rXTdpowE8608zVZWunRxzBVnQtveHlWZZ2rUtzkWeB1
65m4Rk4kBjlsjsMOISS4H2dALuijjcN17wLmTq1pZSWbU2GE190+AVyI6oT4o7Ue
AVtamy6m5Of8+WOpFT9u1wkCgYEA3A3Bus/BCivH+Vx+0UDD6miVLIns1cGKHkPn
N7ZsYF+YprMx3ETLRA69UBa8kO4M4xFBOSKvFNy26ZMgJ8aRibb2P2Rbdzby9V0D
AVXXNsIh99iNYQ9n+kYqbV0ZniwwnX7Q4zqDgYrPQPS5O3pSG1trWQFlR35an5eW
dGyM6RECgYEA0NoXZz+u6kpcqvB2cH/8g3HmZ8Q8qCQnnn4SZM19XuyUQUkXv0wa
g+nqhWDNFygTcSiWbw3lk/07QRVXvuxOJbGr9CuLA+F0d06wcqEdlKCnZ/Vq0SGV
skwwsPsG8xdUGyX2Bg5mPM5X5NVEamR4oSrlTj0iTPMwLhMeUWVO1s0=
—–END RSA PRIVATE KEY—–

À partir da chave privada criada, criaremos uma chave pública. Lembre-se de armazenar a chave privada, pois ela não pode ser compartilhada. Nos certificados digitais, a chaves privada, dependendo do tipo do certificado, é gerada dentro de um dispositivo criptográfico entregue ao solicitante e a chave pública é armazenada em um hardware mantido pela Autoridade Certificadora. Esses são alguns dos conceitos da Infraestrutura de Chaves Públicas.

$openssl rsa -in privkey.kp -pubout -out pubkey.kp

Esse comando produziu um arquivo chamado pubkey.kp cujo conteúdo é:

—–BEGIN PUBLIC KEY—–
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0s2xwy0/awWsYBSTWV+C
4MwgBgGw3lj6WiLiXD6oRdhVgEFQ2PjUJPF0r90McWXmFvVyTlQIFqATtsI7XeMx
aI8mecHZpaZWkuWwn9P5Y/oaEfndSwzdpugY1yveho39PBKBipuypcPhPEee/fHT
eoQiua4FXiCUWhKMSqGBWN830sOwfZwzKVw5N0JS0HFjiB/PO8TTy5hJ2p+Wb6S2
uUwQdo8fwvvD1hNeJiJVH22s+fDhmG9PDMpOrzXpRkiC9YzzXTRZwOn6oRtXTKIF
5LdvpxwKSi641Yl2yCnUW7A7V9zYUVIOh4m9blP+XGJvW22+l3dAd7gfyXyxZB0v
9QIDAQAB
—–END PUBLIC KEY—–

Chaves Pública e Privada em um Mesmo Arquivo

Adicionalmente, suponha que você já tenha um arquivo, que chamaremos de keypair.kp, cujo conteúdo seja a concatenação das chaves privada e pública:

—–BEGIN RSA PRIVATE KEY—–
MIIEowIBAAKCAQEAzupZUuiV9mS1i1KRQKFyYeo6fwFZB1GumwPnkHi6xNgX3YgK
kZPN1agIKFuII795lP+GnB2/+mxbszXZx7Q2VjwaqZMiOBHCXJjZZe6lYRumbMUD
cEex1tcUhufpSsSXcxglNwYEPOeAeC96x4QLTpDNCf4fyY6IdZHQINEnKJdxT1Rv
7i00d8OeF2pk8z3Y1QJDrZQghjHEvpxqBqVBkPYrqtjAhMHwKZo5Zi7bcBM5vmJ3
b5iDs1MjvHYLgd0TPBQPiz3bKQ5CbDAuMFHw0XPTWz0luHbcsvKVK0PBSt0ciWeZ
TGeQs+xnaYmQpS/d5HPk8t2ygKuZdukBtSwVGQIDAQABAoIBABXPZfLzSTtbijdR
ULY7Tk873Uad4cB/v6PfWX1E/IrbLEjRmiuWJNAskg+O9l6uRCaMeKfkCuRen5vY
RUhjmoakdzsAo069sHsKMYApE42U2IoGikI/jGNU8Hj34QNcjYo4NVQDclbpIAWL
G6oEJRz27mXrP3aDa6bY49NRuIrymumsCksMT+jR1fW7sYMmDr8drdSyMn4LROSN
ntiSBG2Ab3ltiZPhGI/YTxru+C8xzU9htqVwvKqVtcEfNZ17g6fd/W29mTGB+B5S
zDjFmm5fTJW2iiEPpZ8hFYlo4lqXtTtALdJndMk4f8vbs8mfgRAB9qbuYqv2ijY/
EoSNFAECgYEA/EE+TtN8zoYf6LLE7FXIXKZX6VHrbbyQhFyrhJ8UC8vhemtTcli2
2nKzaJN4Vv5voXkKMlp4J3NL45VIIx6kupWMqEls3a6HLhZ5AnegVlNeK/kQFFaH
7Q9lpnntpFIHOQe4FrH8maEs1you2fvJafgRzpVUlmKPgVCsOnl5K3kCgYEA0fzI
KNig3044lKZAszXb/iPUHq4TdPcSiqeEjzMPd+Zmxx4hbrsjYPuAbMsTfiNMRC2p
3yECCuUSpuwlgVbf9Ol4PEd8PWaMDyLDYT/2tcS6YWErvVlFG9uhgyF1sh1fdNB+
Z61YK1/uOC7rQTYZt2NNiFL495CmUOTRk6loLqECgYBSr2gnGneskpZfBko6VZwJ
kpT6a9nJ7KdKW731CNffTgMox4lgz+eQD0zzmHM3wMsCmNRY0QLVm5tijApLSL4i
Uub6OqcuuwigeMlNn7y0zzrtGwTEReDkOcnOGeVlmWW4sekLt2ffS8+Q78jPtxK8
Y44isxw49zGm57SsriijsQKBgQCAP1yX5cZK2+EemHNHgIt9qbAxlKt5cjS2zhzd
wJef6O24iqRslorC/peu2lBrZ2967FClX+l5cfJ0VCGL3t0lHTo7xoUQkwLTc63U
RVaOKTqTot8t48mbfAYmqlbRk7LrCzNIasxAoXRCiBVSXJJUOKfvrI011fhdy4Jc
JsjkQQKBgEZsXhqYO+BK7IbOlVRwiN2kC6XlZl7lClpkjGPw7JVt0OZ/7EUni59O
e1UPHwflzdInOrog8UpVqJJp6Xp9hK14gIdtFMFIncak8DspCYdviYnaUJALXhO2
HjG1eqrp1E701fGJKHKFSonWogKa+7ecBgm9FaDHJcULfJorYeRf
—–END RSA PRIVATE KEY—–
—–BEGIN PUBLIC KEY—–
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzupZUuiV9mS1i1KRQKFy
Yeo6fwFZB1GumwPnkHi6xNgX3YgKkZPN1agIKFuII795lP+GnB2/+mxbszXZx7Q2
VjwaqZMiOBHCXJjZZe6lYRumbMUDcEex1tcUhufpSsSXcxglNwYEPOeAeC96x4QL
TpDNCf4fyY6IdZHQINEnKJdxT1Rv7i00d8OeF2pk8z3Y1QJDrZQghjHEvpxqBqVB
kPYrqtjAhMHwKZo5Zi7bcBM5vmJ3b5iDs1MjvHYLgd0TPBQPiz3bKQ5CbDAuMFHw
0XPTWz0luHbcsvKVK0PBSt0ciWeZTGeQs+xnaYmQpS/d5HPk8t2ygKuZdukBtSwV
GQIDAQAB
—–END PUBLIC KEY—–

Nesse caso, rode o openssl com os parâmetros abaixo para extrair a chave privada desse arquivo, remova o trecho referente à chave privada daquele arquivo e o renomeie para “pubkey.kp”:

$openssl rsa -in keypair.kp -out privkey.kp
$mv keypair.kp pubkey.kp

O conteúdo desse arquivo ficará assim:

—–BEGIN RSA PRIVATE KEY—–
MIIEowIBAAKCAQEAzupZUuiV9mS1i1KRQKFyYeo6fwFZB1GumwPnkHi6xNgX3YgK
kZPN1agIKFuII795lP+GnB2/+mxbszXZx7Q2VjwaqZMiOBHCXJjZZe6lYRumbMUD
cEex1tcUhufpSsSXcxglNwYEPOeAeC96x4QLTpDNCf4fyY6IdZHQINEnKJdxT1Rv
7i00d8OeF2pk8z3Y1QJDrZQghjHEvpxqBqVBkPYrqtjAhMHwKZo5Zi7bcBM5vmJ3
b5iDs1MjvHYLgd0TPBQPiz3bKQ5CbDAuMFHw0XPTWz0luHbcsvKVK0PBSt0ciWeZ
TGeQs+xnaYmQpS/d5HPk8t2ygKuZdukBtSwVGQIDAQABAoIBABXPZfLzSTtbijdR
ULY7Tk873Uad4cB/v6PfWX1E/IrbLEjRmiuWJNAskg+O9l6uRCaMeKfkCuRen5vY
RUhjmoakdzsAo069sHsKMYApE42U2IoGikI/jGNU8Hj34QNcjYo4NVQDclbpIAWL
G6oEJRz27mXrP3aDa6bY49NRuIrymumsCksMT+jR1fW7sYMmDr8drdSyMn4LROSN
ntiSBG2Ab3ltiZPhGI/YTxru+C8xzU9htqVwvKqVtcEfNZ17g6fd/W29mTGB+B5S
zDjFmm5fTJW2iiEPpZ8hFYlo4lqXtTtALdJndMk4f8vbs8mfgRAB9qbuYqv2ijY/
EoSNFAECgYEA/EE+TtN8zoYf6LLE7FXIXKZX6VHrbbyQhFyrhJ8UC8vhemtTcli2
2nKzaJN4Vv5voXkKMlp4J3NL45VIIx6kupWMqEls3a6HLhZ5AnegVlNeK/kQFFaH
7Q9lpnntpFIHOQe4FrH8maEs1you2fvJafgRzpVUlmKPgVCsOnl5K3kCgYEA0fzI
KNig3044lKZAszXb/iPUHq4TdPcSiqeEjzMPd+Zmxx4hbrsjYPuAbMsTfiNMRC2p
3yECCuUSpuwlgVbf9Ol4PEd8PWaMDyLDYT/2tcS6YWErvVlFG9uhgyF1sh1fdNB+
Z61YK1/uOC7rQTYZt2NNiFL495CmUOTRk6loLqECgYBSr2gnGneskpZfBko6VZwJ
kpT6a9nJ7KdKW731CNffTgMox4lgz+eQD0zzmHM3wMsCmNRY0QLVm5tijApLSL4i
Uub6OqcuuwigeMlNn7y0zzrtGwTEReDkOcnOGeVlmWW4sekLt2ffS8+Q78jPtxK8
Y44isxw49zGm57SsriijsQKBgQCAP1yX5cZK2+EemHNHgIt9qbAxlKt5cjS2zhzd
wJef6O24iqRslorC/peu2lBrZ2967FClX+l5cfJ0VCGL3t0lHTo7xoUQkwLTc63U
RVaOKTqTot8t48mbfAYmqlbRk7LrCzNIasxAoXRCiBVSXJJUOKfvrI011fhdy4Jc
JsjkQQKBgEZsXhqYO+BK7IbOlVRwiN2kC6XlZl7lClpkjGPw7JVt0OZ/7EUni59O
e1UPHwflzdInOrog8UpVqJJp6Xp9hK14gIdtFMFIncak8DspCYdviYnaUJALXhO2
HjG1eqrp1E701fGJKHKFSonWogKa+7ecBgm9FaDHJcULfJorYeRf
—–END RSA PRIVATE KEY—–

Se você quiser, pode acrescentar uma senha para proteção da chave privada:

$openssl rsa -in keypair.kp -out privkey.kp -des3 -passout pass:Teste123

Renomeie o arquivo “keypair.kp” para “pubkey.kp”. Abra o arquivo “pubkey.kp” e remova o trecho referente à chave privada. O arquivo se parecerá com esse:

—–BEGIN PUBLIC KEY—–
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzupZUuiV9mS1i1KRQKFy
Yeo6fwFZB1GumwPnkHi6xNgX3YgKkZPN1agIKFuII795lP+GnB2/+mxbszXZx7Q2
VjwaqZMiOBHCXJjZZe6lYRumbMUDcEex1tcUhufpSsSXcxglNwYEPOeAeC96x4QL
TpDNCf4fyY6IdZHQINEnKJdxT1Rv7i00d8OeF2pk8z3Y1QJDrZQghjHEvpxqBqVB
kPYrqtjAhMHwKZo5Zi7bcBM5vmJ3b5iDs1MjvHYLgd0TPBQPiz3bKQ5CbDAuMFHw
0XPTWz0luHbcsvKVK0PBSt0ciWeZTGeQs+xnaYmQpS/d5HPk8t2ygKuZdukBtSwV
GQIDAQAB
—–END PUBLIC KEY—–

Verificação

Vamos simular o envio de uma mensagem criptografada de um remetente para um receptor. O remetente possui a chave pública do receptor e a utilizará para criptografar a mensagem. Crie um arquivo qualquer e insira um pequeno texto nele. Criei o arquivo arquivo.txt:

$openssl rsautl -encrypt -inkey pubkey.kp -pubin -in arquivo.txt -out encriptado.ssl

Esse comando produziu o arquivo encriptado.ssl, que está criptografado e só poderá ser lido por quem detiver a chave privada relacionada à chave pública. É importante lembrar que na criptografia assimétrica, uma mensagem pode ser criptografada ou descriptografada com ambas as chaves, mas se uma for utilizada para criptografar, apenas a outra poderá ser utilizada para descriptografar:

$openssl rsautl -decrypt -inkey privkey.kp -in encriptado.ssl -out decripatado.txt

O arquivo decripatado.txt possui o texto original enviado pelo remetente.

Referências

1. [https://stackoverflow.com/questions/5244129/use-rsa-private-key-to-generate-public-key]
2. [https://rietta.com/blog/2012/01/27/openssl-generating-rsa-key-from-command/]
3. [https://blog.sleeplessbeastie.eu/2017/12/28/how-to-generate-private-key/]
4. [https://www.mkssoftware.com/docs/man1/openssl_genrsa.1.asp]
5. [https://www.devco.net/archives/2006/02/13/public_-_private_key_encryption_using_openssl.php]
6. [https://unix.stackexchange.com/questions/296697/how-to-encrypt-a-file-with-private-key]

Anúncios

Assinando E-mail Digitalmente com o Bouncy Castle

O Bouncy Castle é uma coleção de APIs usadas em criptografia para Java. O código abaixo é um exemplo de como assinar um e-mail digitalmente com essa API.

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.cms.AttributeTable;
import org.bouncycastle.asn1.cms.IssuerAndSerialNumber;
import org.bouncycastle.asn1.smime.SMIMECapabilitiesAttribute;
import org.bouncycastle.asn1.smime.SMIMECapability;
import org.bouncycastle.asn1.smime.SMIMECapabilityVector;
import org.bouncycastle.asn1.smime.SMIMEEncryptionKeyPreferenceAttribute;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.SignerInfoGenerator;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.mail.smime.SMIMESignedGenerator;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.util.Store;

public class MailSigner {

   private static final String BOUNCE_CASTLE_PROVIDER = "BC";
   private static final String CRYPT_FILE_FORMAT = "PKCS12";
   private static final String CRYPT_ALGORITH = "RSA";
   private static final String SHA1_PKCS_PROVIDER = "SHA1withRSA";
   private static final String MD5_PKCS_PROVIDER = "MD5withRSA";

   private SMIMECapabilityVector capabilities;

   public MailSigner() {
      load();
   }

   private void load() {
      capabilities = new SMIMECapabilityVector();
      capabilities.addCapability(SMIMECapability.dES_EDE3_CBC);
      capabilities.addCapability(SMIMECapability.rC2_CBC, 128);
      capabilities.addCapability(SMIMECapability.dES_CBC);
      /* Adiciona o provider do BouncyCastle */
      Security.addProvider(new BouncyCastleProvider());
   }

   public Message sign(MimeMessage message) throws Exception {
      String password = "SENHA_CERTIFICADO";
      KeyStore keystore = loadKeyStore(password);
      String alias = findAlias(keystore, password);
      if (alias == null) {
         throw new UnrecoverableKeyException("cannot find alias for certificate");
      }

      PrivateKey privateKey = (PrivateKey) keystore.getKey(alias, password.toCharArray());
      Certificate certificate = keystore.getCertificate(alias);
      SMIMESignedGenerator signer = configSigner(certificate, privateKey);
      MimeMessage signedMessage = new MimeMessage(message.getSession());

		/*
		 * Copia todos os MIME header da mensagem original para a mensagem assinada
		 */
		copyHeader(message, signedMessage);

		/* Assina a mensagem */
		MimeMultipart mimeMultipart = signer.generate(message, BOUNCE_CASTLE_PROVIDER);

		/* Insere o conteudo da mensagem original na mensagem assinada */
		signedMessage.setContent(mimeMultipart);
		signedMessage.saveChanges();

		return signedMessage;
	}


	@SuppressWarnings("rawtypes")
	private void copyHeader(MimeMessage message, MimeMessage signedMessage) throws MessagingException {
		Enumeration headers = message.getAllHeaderLines();
		while (headers.hasMoreElements()) {
			signedMessage.addHeaderLine((String) headers.nextElement());
		}
	}

	private String findAlias(KeyStore keystore, String password) throws KeyStoreException, UnrecoverableKeyException,
			NoSuchAlgorithmException {
		Enumeration<String> aliases = keystore.aliases();
		while (aliases.hasMoreElements()) {
			String alias = (String) aliases.nextElement();
			/* Obtem a chave privada do certificado */
			PrivateKey privateKey = (PrivateKey) keystore.getKey(alias, password.toCharArray());
			if (privateKey != null) {
			   return alias;
			}
		}
		return null;
	}

	private KeyStore loadKeyStore(String password) throws KeyStoreException, NoSuchProviderException,
			FileNotFoundException, IOException, NoSuchAlgorithmException, CertificateException {
		File certFile = new File("CAMINHO_ARQUIVO_PFX_ASSINATURA");
		FileInputStream fis = new FileInputStream(certFile);

		/* Carrega o keystore */
		KeyStore keystore = KeyStore.getInstance(CRYPT_FILE_FORMAT, BOUNCE_CASTLE_PROVIDER);
		keystore.load(fis, password.toCharArray());

		return keystore;
	}

	private SMIMESignedGenerator configSigner(Certificate certificate, PrivateKey privateKey)
			throws OperatorCreationException, CertificateEncodingException {
		ASN1EncodableVector attributes = new ASN1EncodableVector();
		attributes.add(new SMIMEEncryptionKeyPreferenceAttribute(new IssuerAndSerialNumber(new X500Name(
				((X509Certificate) certificate).getIssuerDN().getName()), ((X509Certificate) certificate)
				.getSerialNumber())));
		attributes.add(new SMIMECapabilitiesAttribute(capabilities));

		JcaSimpleSignerInfoGeneratorBuilder signerInfoBuilder = new JcaSimpleSignerInfoGeneratorBuilder();
		signerInfoBuilder.setProvider(BOUNCE_CASTLE_PROVIDER);
		signerInfoBuilder.setSignedAttributeGenerator(new AttributeTable(attributes));
		SignerInfoGenerator signerInfoGenerator = signerInfoBuilder.build(
				CRYPT_ALGORITH.equals(privateKey.getAlgorithm()) ? SHA1_PKCS_PROVIDER : MD5_PKCS_PROVIDER, privateKey,
				(X509Certificate) certificate);

		SMIMESignedGenerator signer = new SMIMESignedGenerator();
		signer.addSignerInfoGenerator(signerInfoGenerator);

		/* Adiciona a lista de certificados no Bouncy Castle */
		List<Certificate> certList = new ArrayList<Certificate>();
		certList.add(certificate);
		Store certs = new JcaCertStore(certList);
		signer.addCertificates(certs);
		return signer;
	}
}

Referências

1. [http://www.docjar.org/src/api/org/bouncycastle/mail/smime/examples/CreateSignedMail.java]
2. [http://grepcode.com/file/repo1.maven.org/maven2/org.bouncycastle/bcmail-jdk16/1.46/org/bouncycastle/mail/smime/examples/SendSignedAndEncryptedMail.java#SendSignedAndEncryptedMail.main%28java.lang.String%5B%5D%29]
3. [http://www.thehecklers.org/tag/bouncycastle/]
4. [http://www.thehecklers.org/2013/01/14/secure-email-from-java/]
5. [http://www.docjar.org/html/api/org/bouncycastle/mail/smime/examples/SendSignedAndEncryptedMail.java.html]
6. [http://answer.techwikihow.com/1060825/encrypted-smime-issue.html]
7. [http://fastpicket.com/blog/2012/05/14/easy-pgp-in-java-bouncy-castle/]

Uma Declaração de Independência do Ciberespaço

Aqui e ali lemos noticias de que governos querem controlar a Internet, apresentam iniciativas próprias para podar parte da liberdade inerente à rede, como a tal cripto moeda russa, a ex-presidente Dilma não sabia onde ficava a nuvem e queria que o Google trouxesse sua base de dados para o Brasil, fala-se em bloqueio de acesso à Internet global, e outros mimos de pensamento autoritário.

Em um momento histórico em que a Internet corre o risco de se submeter à sanha autoritária das grandes nações e da ONU, que se outorga o direito de ditar os rumos da humanidade, o blog AnchisesLandia compartilhou uma “Declaração de Independência do Ciberespaço”, um texto redigido em 1996 que continua atual.

A Declaration of the Independence of Cyberspace

por John Perry Barlow

Governments of the Industrial World, you weary giants of flesh and steel, I come from Cyberspace, the new home of Mind. On behalf of the future, I ask you of the past to leave us alone. You are not welcome among us. You have no sovereignty where we gather.

We have no elected government, nor are we likely to have one, so I address you with no greater authority than that with which liberty itself always speaks. I declare the global social space we are building to be naturally independent of the tyrannies you seek to impose on us. You have no moral right to rule us nor do you possess any methods of enforcement we have true reason to fear.

Governments derive their just powers from the consent of the governed. You have neither solicited nor received ours. We did not invite you. You do not know us, nor do you know our world. Cyberspace does not lie within your borders. Do not think that you can build it, as though it were a public construction project. You cannot. It is an act of nature and it grows itself through our collective actions.

You have not engaged in our great and gathering conversation, nor did you create the wealth of our marketplaces. You do not know our culture, our ethics, or the unwritten codes that already provide our society more order than could be obtained by any of your impositions.

You claim there are problems among us that you need to solve. You use this claim as an excuse to invade our precincts. Many of these problems don’t exist. Where there are real conflicts, where there are wrongs, we will identify them and address them by our means. We are forming our own Social Contract. This governance will arise according to the conditions of our world, not yours. Our world is different.

Cyberspace consists of transactions, relationships, and thought itself, arrayed like a standing wave in the web of our communications. Ours is a world that is both everywhere and nowhere, but it is not where bodies live.

We are creating a world that all may enter without privilege or prejudice accorded by race, economic power, military force, or station of birth.

We are creating a world where anyone, anywhere may express his or her beliefs, no matter how singular, without fear of being coerced into silence or conformity.

Your legal concepts of property, expression, identity, movement, and context do not apply to us. They are all based on matter, and there is no matter here.

Our identities have no bodies, so, unlike you, we cannot obtain order by physical coercion. We believe that from ethics, enlightened self-interest, and the commonweal, our governance will emerge. Our identities may be distributed across many of your jurisdictions. The only law that all our constituent cultures would generally recognize is the Golden Rule. We hope we will be able to build our particular solutions on that basis. But we cannot accept the solutions you are attempting to impose.

In the United States, you have today created a law, the Telecommunications Reform Act, which repudiates your own Constitution and insults the dreams of Jefferson, Washington, Mill, Madison, DeToqueville, and Brandeis. These dreams must now be born anew in us.

You are terrified of your own children, since they are natives in a world where you will always be immigrants. Because you fear them, you entrust your bureaucracies with the parental responsibilities you are too cowardly to confront yourselves. In our world, all the sentiments and expressions of humanity, from the debasing to the angelic, are parts of a seamless whole, the global conversation of bits. We cannot separate the air that chokes from the air upon which wings beat.

In China, Germany, France, Russia, Singapore, Italy and the United States, you are trying to ward off the virus of liberty by erecting guard posts at the frontiers of Cyberspace. These may keep out the contagion for a small time, but they will not work in a world that will soon be blanketed in bit-bearing media.

Your increasingly obsolete information industries would perpetuate themselves by proposing laws, in America and elsewhere, that claim to own speech itself throughout the world. These laws would declare ideas to be another industrial product, no more noble than pig iron. In our world, whatever the human mind may create can be reproduced and distributed infinitely at no cost. The global conveyance of thought no longer requires your factories to accomplish.

These increasingly hostile and colonial measures place us in the same position as those previous lovers of freedom and self-determination who had to reject the authorities of distant, uninformed powers. We must declare our virtual selves immune to your sovereignty, even as we continue to consent to your rule over our bodies. We will spread ourselves across the Planet so that no one can arrest our thoughts.

We will create a civilization of the Mind in Cyberspace. May it be more humane and fair than the world your governments have made before.

Davos, Suiça. 8 de fevereiro de 1996

Categorias:Segurança Tags:,

O Problema da Galeria de Arte

Figura 1 – Visibilidade de uma câmera em uma galeria de arte [1]

A Geometria Computacional [2] é um ramo da Matemática que busca soluções computacionais para problemas geométricos. Galeria de Arte é um problema derivado da Geometria Computacional proposto originalmente por Victor Klee em 1973 [1] que oferece uma resposta matemática para a pergunta: qual é a quantidade mínima de câmeras de vigilância necessárias para monitorar inteiramente uma Galeria de Arte? Essa é a forma mais comum de formular esse problema, mas ele se aplica a qualquer cenário em que exista um ambiente delimitado por paredes e que precisa ser monitorado – seja por câmeras de segurança, vigias armados com posição fixa, unidades ED-209, etc – de forma que não sobrem quaisquer partes do ambiente sem monitoramento.

Figura 2 – Onde as câmeras devem ser posicionadas?

Para tornar as coisas um pouco mais simples, vamos trabalhar em duas dimensões (2D) assumindo que a planta baixa da galeria de arte é um polígono simples: uma forma geométrica delimitada por seguimentos de linhas retas que não cruzam umas as outras – não tem paredes internas – e que não contém “buracos” (polígonos dentro de um polígono maior ou o possível resultado da intersecção interna de pelo menos três linhas). Sendo uma câmera um ponto, um conjunto de câmeras cobre o polígono se todo ponto do polígono é monitorado por alguma câmera [1]. Se fossem vigilantes e não câmeras, assumiríamos que eles ficam fixos nos vértices (ponto de encontro de dois segmentos laterais).

Isso normalmente é válido nas galerias de arte, pois as obras de arte ficam nas paredes (arestas ou seguimentos de reta do polígono) e teoricamente uma câmera deveria filmar a máxima extensão de uma parede e a máxima quantidade de paredes possível, o que só se consegue posicionando as câmeras nos vértices. As obras raras não se enquadram nessa regra, pois devido ao seus valores às vezes inestimáveis, como no caso da Mona Lisa, é necessária vigilância exclusiva independente de quanto isso custe.

Figura 3 – Mona Lisa – obra insubstituível

Matematicamente, dado um conjunto de câmeras C, uma câmera cn vigia um polígono P se existe um segmento de reta que liga a câmera ao ponto p e tanto o segmento de reta quanto o ponto p são internos ao polígono:

C{c1, c2, c3, …, cn} → p ∀ p ∈ C | cp ∈ P

Como a planta baixa da galeria é um polígono, o problema consiste em colocar pontos nesse polígono e à partir deles traçar linhas para as paredes opostas sem sair do polígono, que pode ser convexo (aquele em que dois pontos quaisquer, quando unidos, nunca passam pelo lado de fora do polígono) ou não convexo. Um polígono convexo precisa apenas de uma câmera, pois sua simetria permite que de um dos vértices se possa enxergar todos os outros vértices:

Figura 4 – Octógono – um polígono convexo regular (todos os lados e ângulos têm a mesma medida) de oito lados

Para que o problema se apresente de forma mais genérica, vamos trabalhar com polígonos não convexos, como o da figura abaixo, pois são mais comuns de encontrar do que os convexos:

Figura 5 – Um polígono não convexo

O Teorema de Chvátal diz que para todo polígono de n vértices, n/3 câmeras são sempre suficientes e ocasionalmente necessárias. Para o Pente de Chvátal, n/3 câmeras são necessárias. Como o pente abaixo tem 15 vértices, 5 câmeras são necessárias para monitorar sua área interna:

Figura 6 – Pente de Chvátal com 15 vértices

Além do Teorema de Chvátal, os teoremas abaixo serão utilizados no exemplo que apresentaremos a seguir:

  • Todo polígono possui pelo menos um vértice estritamente convexo.
  • Teorema de Jordan: toda curva plana fechada simples divide o plano em duas regiões: o interior e o exterior da curva.
  • Teorema de Meister: Todo polígono com n ≥ 4 vértices possui uma diagonal.
  • Teorema da Triangularização: Todo polígono n vértices pode ser particionado em triângulos pela adição de (zero ou mais) diagonais.
  • Toda triangularização de um polígono P de n vértices usa n − 3 diagonais e consiste de n − 2 triângulos.

Demonstração

Para fazer uma demonstração, vou utilizar o exemplo do canal Derivando e a didática do prof. Eduardo Sáenz de Cabezón, PhD em Matemática e também professor de Matemática Discreta e Álgebra pela Universidad de La Rioja, na Espanha.

O exemplo do prof. Eduardo faz triangularização por adição de diagonais para dividir o polígono internamente em n triângulos – essa é a Prova de Suficiência de Fisk. O problema seria um pouco mais complexo se o prof. tentasse remover as “orelhas” com triangularização por remoção de orelhas [1], o que é possível pelo teorema de Meister, mas vamos ficar no caso mais simples – adição de diagonais -, que vale para qualquer polígono com mais de 3 lados, pois o triângulo (3 lados) é o único polígono que não possui diagonais (N<4) e uma câmera colocada em qualquer um dos vértices pode monitorar todo o perímetro interno, uma vez que ele respeita a regra das n/3 câmeras – como ele tem 3 lados, uma câmera é suficiente e no caso necessária.

Nossa demonstração partirá de um polígono não convexo com 10 lados e 10 vértices:

Vamos triangular esse polígono, pois sabemos que todo polígono com mais de três lados pode ser triangulado pela adição de diagonais. Necessariamente, encontraremos 8 triângulos, pois para triangular um polígono de 10 lados, precisamos de (10-2) triângulos:

Agora, vamos construir um grafo dual colocando um vértice em cada face de cada triângulo e unindo todos esses vértices. Esse grafo serve apenas para verificar se os triângulos inscritos no polígono podem ser 3-colorados. Só haverá 3-coloração se o grafo for do tipo árvore e não cíclico:

Por último, vamos aplicar a 3-coloração aos triângulos inscritos. O processo consiste em escolher três cores diferentes e pintar cada vértice com uma cor sem que dois vértices adjacentes tenham a mesma cor:

Enfim, onde serão instaladas as câmeras? Vamos fazer algumas considerações. O Teorema de Chvátal afirma que (n/3) câmeras são suficientes e ocasionalmente necessárias para cobrir a área interna do polígono. No nosso caso, 3 câmeras (10/3) são suficientes, mas ainda não sabemos se as 3 são necessárias.

As câmeras serão posicionadas em todos os vértices de mesma cor. Podemos instalar 4 câmeras nos vértices vermelhos, 4 câmeras nos vértices azuis ou apenas 2 câmeras nos vértices verdes. 2 é o mínimo de câmeras que precisamos para monitorar toda a área interna do polígono. Sendo assim, precisamos de apenas 2 câmeras e essas serão instaladas nos vértices verdes:

Essa é uma prova de que sempre podemos economizar recursos utilizando matemática. Dificilmente conseguiríamos um resultado melhor no chute, como provei em outro artigo.

Referências

1. [https://www.ime.usp.br/~cpq/main/arquivos/teoremadagaleriadearteetriangularizacaodepoligonos.pdf]
2. [http://webserver2.tecgraf.puc-rio.br/ftp_pub/lfm/CIV2802-GeometriaComputacional.pdf]
3. [https://brilliant.org/wiki/guarding-a-museum/]
4. [https://plus.maths.org/content/art-gallery-problem]
5. [https://www.youtube.com/watch?v=nEFYpwofbbk]
6. [http://sweet.ua.pt/leslie/GeoCom/Slides/GC_0708_6_Galeria_Arte.pdf]
7. [http://www.ic.unicamp.br/~rezende/ensino/mo619/ArtGallery-PJR-Handout.pdf]
8. [http://www.inf.ufrgs.br/~comba/cmp189-files/class03.pdf]
9. [https://www.inf.ufrgs.br/~prestes/Courses/Graph%20Theory/GrafosA10.pdf]
10. [https://www.ime.usp.br/~cris/aulas/09_2_331/slides/aula3.pdf]

Como Habilitar o Ehcache no Shiro

O Shiro oferece um mecanismo de cache para diminuir o tempo de respostas das operações de segurança, mas as implementações disponibilizadas podem ser utilizadas para propósitos fora do escopo do framework de segurança.

Figura 1 – Arquitetura do Shiro

Várias implementações do CacheManager estão disponíveis. Nesse artigo, mostraremos como habilitar o EhCacheManager, o que permite utilizar o Ehcache. Antes de continuar, sugiro que você veja o artigo de introdução ao Shiro que escrevi e um outro artigo sobre a integração do Ehcache ao Spring, onde faço algumas considerações sobre o cache em si.

Comecemos pela configuração das dependências do Maven:

   <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.3.2</version>
   </dependency>
   <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-web</artifactId>
      <version>1.3.2</version>
    </dependency>
    <dependency>
      <groupId>org.ehcache</groupId>
      <artifactId>ehcache</artifactId>
      <version>3.3.1</version>
    </dependency>  
    <dependency>
      <groupId>javax.cache</groupId>
      <artifactId>cache-api</artifactId>
      <version>1.0.0</version>
    </dependency>

Em seguida, vamos configurar o arquivo shiro.ini

[main]
[main]
apprealm = br.com.app.autorizacao.AppRealm
securityManager.realms = $apprealm
cacheManager = org.apache.shiro.cache.ehcache.EhCacheManager
securityManager.cacheManager = $cacheManager

Uma vez definido um CacheManager, o Shiro o entrega para as classes que implementam a interface CacheManagerAware. Nosso AppRealm é um SimpleAccountRealm. Sendo assim, já estamos implementando aquela interface.

Referências

1. [https://shiro.apache.org/caching.html]
2. [https://shiro.apache.org/static/1.3.0/apidocs/org/apache/shiro/cache/Cache.html]
3. [https://shiro.apache.org/static/1.3.0/apidocs/org/apache/shiro/cache/ehcache/EhCacheManager.html]
4. [http://www.ehcache.org/]

Criando sua Própria Tag Library do Shiro

Se você precisa de mais granularidade na checagem de permissões em uma página web, como por exemplo determinar se um botão deve ou não ser exibido, o Shiro oferece uma API que te permite fazer sua implementação nos métodos do seu controller/managed bean – não faça scriplets! No exemplo do botão, você poderia condicionar sua exibição assim:

<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:p="http://primefaces.org/ui">
   <body>
      <p:commandLink action="#{appMB.executar()}" 
          rendered="#{appMB.podeExecutar()}">Executar</p:commandLink>
   </body>
</html>

A implementação do método podeExecutar() utiliza a API do Shiro para verificar se o usuário tem determinada permissão:

public boolean podeExecutar() throws IOException {
   Subject subject = SecurityUtils.getSubject();
   return subject.isPermitted("PERMISSAO_EXECUCAO");
}

O problema é que você tende a reescrever esse mesmo código ou um muito parecido em cada managed bean que precisar de autorização. Felizmente, o Shiro possui uma tag library útil para quem trabalha com arquivos JSP, mas se você trabalha com JSF, não há nada pronto para utilizar. Porém, é possível criar sua própria biblioteca reutilizável à partir daquele código de checagem que você inseriu no managed bean. Vamos definir a assinatura de uma tag chamada “hasPermissao” que receba como parâmetro uma permissao:

<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib 
   version="2.2"
   xmlns="http://xmlns.jcp.org/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
   http://xmlns.jcp.org/xml/ns/javaee/web-facelettaglibrary_2_2.xsd">
   <namespace>http://app.com.br/security</namespace>
   <tag>
      <description><![CDATA[Verifica a permissao do usuario]]></description>
      <tag-name>hasPermissao</tag-name>
      <component>
         <component-type>permitido</component-type>
      </component>
      <attribute>
         <description><![CDATA[Permissao a ser verificada.]]></description>
         <name>permissao</name>
         <required>true</required>
         <type>java.lang.String</type>
      </attribute>
   </tag>
</facelet-taglib>

Uma vez criada a biblioteca, ela deve ser cadastrada no web.xml:

<context-param>
   <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
   <param-value>/WEB-INF/app.taglib.xml</param-value>
</context-param>

Em seguida, vamos criar uma classe que extende UIComponentBase e é anotada como @FacesComponent. Essa implementação “esconde” todos os componentes visuais delimitados pela tag caso o usuário não esteja autorizado:

@FacesComponent(createTag = true, 
   namespace = "http://app.com.br/security", 
   tagName = "hasPermissao", 
   value = "hasPermissao")
public class PermissaoTag extends UIComponentBase {

   @Override
   public String getFamily() {
      return "app";
   }

   @Override
   public void encodeBegin(FacesContext context)
      throws IOException {
      String permissao = (String)getAttributes().get("permissao");
      Subject subject = SecurityUtils.getSubject();
      if (!subject.isPermitted(permissao)) {
         getChildren().stream().forEach(
            s -> s.setRendered(false));
      }
   }
}

Por último, importe a tag em seu arquivo xhtml e utilize no trecho de código sujeito à autorização:

<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:p="http://primefaces.org/ui"
   xmlns:app="http://app.com.br/security">
   <body>
     <app:hasPermissao permissao="PERMISSAO_EXECUCAO">
       <p:commandLink action="#{appMB.executar()}">Executar</p:commandLink>
     </app:hasPermissao>
   </body>
</html>

Referências

1. [https://www.mkyong.com/jsf2/custom-tags-in-jsf-2-0/]
2. [https://shiro.apache.org/web.html#Web-taglibrary]
3. [https://shiro.apache.org/java-authorization-guide.html#programmatic-authorization]

Como Integrar o Apache Shiro a uma Aplicação JSF

O Shiro é um framework de segurança da Apache escrito em Java que permite a criação de soluções para autenticação, autorização, criptografia, gerenciamento de sessão e ainda fornece várias implementações de cache. Ele é simples de configurar e tem vários pontos de extensão que nos permitem intervir sobre seu funcionamento – são características de um framework bem projetado -, mas as configurações padrão já são suficientes para uma aplicação de pequeno porte.

Figura 1 – Arquitetura do Shiro

Nesse artigo, vou mostrar um exemplo de como integrar o Shiro a uma aplicação JSF. Nosso modelo será composto por uma enum chamada Permissao, uma enum Perfil para agrupar as permissões, e a entidade Usuario, que possui um Perfil:

public enum Permissao {
   CRIAR_PEDIDO, 
   LISTAR_PEDIDOS;
}

public enum Perfil {
   ADMINISTRADOR(Permissao.CRIAR_PEDIDO, Permissao.LISTAR_PEDIDOS);
   private List<Permissao> permissoes;
   private Perfil(Permissao... permissoes) {
      this.permissoes = Arrays.stream(permissoes).
         collect(Collectors.toList());
   }
}

@Entity
@Table(name = "TBL_USUARIO")
@TypeDefs(value = {@TypeDef(name = "TIPO_PERFIL" ...)})
public class Usuario {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "PK_USUARIO")
   private Long id;
   @Column(name = "NM_USUARIO")
   private String nome;
   @Column(name = "COD_PERFIL")
   @Type(type = "TIPO_PERFIL")
   private Perfil perfil;
}

Há várias formas de configurar o Shiro. Vou mostrar como configurá-lo à partir do arquivo de configuração shiro.ini. Precisamos incluir duas dependências no arquivo pom.xml – isso é o básico para o Shiro ser integrado a uma aplicação web:

<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-core</artifactId>
   <version>1.3.2</version>
</dependency>
<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-web</artifactId>
   <version>1.3.2</version>
</dependency>

Em seguida, vamos configurar o arquivo shiro.ini, que deve ficar no classpath – eu costumo colocar em /src/main/resources. As seções desse arquivo agrupam propriedades que determinam o comportamento do Shiro. Basicamente, informamos qual é o Realm utilizado (será explicado mais adiante), qual é a página de autenticação para a qual o Shiro redirecionará o usuário não autenticado, para onde o usuário será redirecionado após o logout e também permite que informemos que há páginas privadas que só podem ser acessadas por usuários que tenham determinadas permissões. No nosso exemplo, a página “criarpedido.xhtml” só pode ser acessada por usuários que contenham a permissão “CRIAR_PEDIDO”.

[main]
apprealm = br.com.app.autorizacao.AppRealm
securityManager.realms = $apprealm
authc.loginUrl = /publico/index.xhtml
logout.redirectUrl = /publico/index.xhtml

[users]

[roles]
ADMINISTRADOR = *

[urls]
/privado/criarpedido.xhtml =  authc, perms["CRIAR_PEDIDO"]

No arquivo web.xml, configuraremos os filtros e listeners do Shiro e também informaremos quais são as páginas que responderão pelos códigos de erro HTTP.

<filter>
   <filter-name>ShiroFilter</filter-name>
   <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>

<filter-mapping>
   <filter-name>ShiroFilter</filter-name>
   <url-pattern>/*</url-pattern>
   <dispatcher>REQUEST</dispatcher>
   <dispatcher>FORWARD</dispatcher>
   <dispatcher>INCLUDE</dispatcher>
   <dispatcher>ERROR</dispatcher>
</filter-mapping>

<listener>
   <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener
</listener-class>
</listener>
	
<error-page>
   <error-code>401</error-code>
   <location>/publico/acessonegado.xhtml</location>
</error-page>

<error-page>
   <error-code>403</error-code>
   <location>/publico/acessonegado.xhtml</location>
</error-page>

<error-page>
   <error-code>404</error-code>
   <location>/publico/paginanaoencontrada.xhtml</location>
</error-page>

<error-page>
   <error-code>500</error-code>
   <location>/publico/erro.xhtml</location>
</error-page>

Essa é toda a configuração básica que qualquer aplicação web precisa para ser integrada ao Shiro. De agora em diante, começaremos a implementação do nosso mecanismo de autenticação e autorização. Só então você verá como é simples trabalhar com o Shiro. Uma peça importante do mecanismo de autenticação é o AuthenticationToken, que é a classe que mantém as credenciais do usuário. Você pode escolher uma das implementações dessa interface disponíveis, mas vamos criar uma implementação dela que recebe o ID do usuário:

public class IdAuthenticationToken implements AuthenticationToken {
   private Integer userId;

   public IdAuthenticationToken(Integer userId) {
      this.userId= userId;
   }

   @Override
   public Object getPrincipal() {
      return this.id;
   }

   @Override
   public Object getCredentials() {
      return this.id;
   }
}

Você precisará informar ao Shiro que um usuário está se autenticando. Você pode fazer isso à partir de um servlet, campos de input em um formulário de uma tela que é tratada por um ManagedBean, etc. Eu fiz através de um servlet porque antes que o usuário se autenticasse na minha aplicação era feita client authentication contra um Apache Server para validar o certificado digital. Modifiquei um pouco o código para indicar que as credenciais do usuário estão vindo pela request, que no meu caso era um post realizado pela aplicação que rodava em um JBoss debaixo daquele Apache. A credencial é apenas o atributo “userId”, que foi fornecido pela aplicação que validou o certificado digital.

@WebServlet(displayName = "AutenticacaoServlet", 
   name = "AutenticacaoServlet", urlPatterns = "/autenticar")
public class AutenticacaoServlet extends HttpServlet {

protected void doPost(HttpServletRequest request, 
      HttpServletResponse response)
     throws ServletException, IOException {
   Integer userId = (Integer) request.getAttribute("userId");
   Subject subject = SecurityUtils.getSubject();
   subject.login(new IdAuthenticationToken(token, userId));
   subject.checkPermission("CRIAR_PEDIDO");

   response.sendRedirect(request.getContextPath() + 
      "/private/criarpedido.xhtml?faces-redirect=true";

O Realm é um componente que interpreta os artefatos de segurança da aplicação – como usuários, regras e permissões – para o Shiro. Sendo o Realm a fonte de dados para autorização, podemos dizer, grosso modo, que ele é o DAO, ou melhor, um repository, que serve um modelo de autorização e autenticação.

Figura 2 – Sequência Simples de Autenticação

public class AppRealm extends SimpleAccountRealm {

   @Override
   protected AuthenticationInfo doGetAuthenticationInfo(
       AuthenticationToken token) throws AuthenticationException {
      IdAuthenticationToken authToken = (IdAuthenticationToken) token;
      Optional<Usuario> usuario = usuarioDao.buscar(token.getUserId());
      return new SimpleAuthenticationInfo(
         usuario.get(), usuario.get().getId(), getName());
   }

   @Override
   protected AuthorizationInfo doGetAuthorizationInfo(
        PrincipalCollection principals) {
      Set<String> roles = new HashSet<>();
      Set<String> permissions = new HashSet<>();

      Usuario usuario = (Usuario) SecurityUtils.getSubject().getPrincipal();
      Perfil perfil = usuario.getPerfil();

      roles.add(perfil.name());

      perfil.getPermissoes().forEach(a -> {
         permissions.add(a.nome());
      });

      SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
      info.setRoles(roles);
      info.setStringPermissions(permissions);
      return info;
   }

   @Override
   public String getName() {
      return getClass().getName();
   }

   @Override
   public boolean supports(AuthenticationToken token) {
      return IdAuthenticationToken.class.equals(token.getClass());
   }
}

Utilizamos a implementação SimpleAccountRealm, que é suficiente para o que nos propusemos a fazer. Se você quiser que o Shiro fique automaticamente consultando o banco de dados para carregar as permissões, basta utilizar um JdbcRealm e adicionar a consulta que o Shiro deve utilizar no arquivo shiro.ini.

Nesse momento, já temos um mecanismo que gerencia as credenciais do usuário e autoriza o acesso às páginas informadas na configuração inicial. Se você precisar fazer checagens de permissão ou verificar se o usuário está autenticado programaticamente, você deve acessar o Subject através do SecurityUtils ou utilizar as anotações do Shiro nos métodos das suas classes que devem ser autorizados.

Recomendações para Migração de Aplicações JSF “Puras”

Se você tem uma implementação de PhaseListener que de alguma forma toma decisões com base na URL acessada em sua aplicação JSF, remova-a. Na verdade, você deveria remover filtros, servlets e quaisquer outras implementações interessadas em autorização. Quem cuidará disso é o Shiro – mais especificamente a sua implementação de Realm.

É comum que aplicações JSF tenham uma ExceptionHandlerFactory para interceptar e tratar exceções nas páginas. Isso também não será necessário, pois o Shiro contém a ShiroException e suas variantes. Você também pode definir páginas específicas para tratar os códigos de erro HTTP mapeadas no seu arquivo web.xml.

Referências

1. [http://shiro.apache.org/reference.html]
2. [https://shiro.apache.org/java-authorization-guide.html]
3. [https://shiro.apache.org/authorization.html]
4. [https://shiro.apache.org/architecture.html]
5. [https://shiro.apache.org/configuration.html]
6. [http://galluzzo.com.br/?p=698]
7. [https://dzone.com/articles/java-security-framework-apache]
8. [http://czetsuya-tech.blogspot.com/2012/10/how-to-integrate-apache-shiro-with.html]
9. [http://www.javastutorial.com/2016/03/how-to-use-apache-shiroauthentication.html]