Capítulo 3. Modelo de Segurança do JBoss

Assim como o resto da arquitetura do JBoss, a segurança no nível mais inferior é definida como um conjunto de interfaces pelas quais implementações alternadas podem ser fornecidas.
  • org.jboss.security.AuthenticationManager
  • org.jboss.security.RealmMapping
  • org.jboss.security.SecurityProxy
  • org.jboss.security.AuthorizationManager
  • org.jboss.security.AuditManager
  • org.jboss.security.MappingManager
A Figura 3.1, “Relações da Interface do Modelo de Segurança para os Elementos do Recipiente EJB do Servidor JBoss. ” apresenta o diagrama de classe das interfaces de segurança e sua relação à arquitetura do recipiente EJB.
Relações da Interface do Modelo de Segurança para os Elementos do Recipiente EJB do Servidor JBoss.

Figura 3.1. Relações da Interface do Modelo de Segurança para os Elementos do Recipiente EJB do Servidor JBoss.

A camada do Recipiente EJB é representada pelas classes - org.jboss.ejb.Container, org.jboss.SecurityInterceptor e org.jboss.SecurityProxyInterceptor. As demais classes são interfaces e classes fornecidas pelo subsistema de segurança.
As duas interfaces solicitadas para a implementação do modelo de segurança J2EE são:
  • org.jboss.security.AuthenticationManager
  • org.jboss.security.AuthorizationManager
As funções das interface de segurança apresentadas na Figura 3.1, “Relações da Interface do Modelo de Segurança para os Elementos do Recipiente EJB do Servidor JBoss. ” encontram-se resumidas abaixo.

Funções da Interface de Segurança

AuthenticationManager
Esta interface é responsável pela validação de credenciais associados com os Principals. Os Principais são identidades, tais como nomes de usuários, números de funcionário e números de segurança social. Os Credentials são prova de identidade, tais como senhas, teclas de sessão e assinaturas digitais. O método isValid é invocado para determinar se é que uma identidade de usuário e as credenciais associadas conhecidas conforme conhecidas no ambiente operacional são prova válida da identidade do usuário.
AuthorizationManager
Esta interface é responsável pelo controle de acesso mandatório pelas especificações do Java EE. A implementação desta interface fornece a habilidade de empilhar um conjunto de Fornecedores de Política úteis para a autorização conectável.
SecurityProxy
Esta interface descreve as solicitações para um plugin SecurityProxyInterceptor personalizado. O SecurityProxy permite que a externalização de segurança personalizada realize checagem baseada em métodos para ambos os métodos de página principal EJB e interface remota.
AuditManager
Esta interface é responsável em fornecer um atalho de auditoria para os eventos de segurança.
MappingManager
Esta interface é responsável em fornecer o mapeamento do Principal, Função e Atributos. A implementação do AuthorizationManager pode chamar internamente o gerenciador do mapeamento para mapear as funções antes de executar o controle de acesso.
SecurityDomain
Esta é uma extensão das interfaces AuthenticationManager, RealmMapping e SubjectSecurityManager. O SecurityDomain é a maneira recomendada para implementar segurança nos componentes, devido às vantagens oferecidas pelo JAAS Subject e o aumento de suporte oferecido ao aplicativo de estilo ASP e implementações de recurso. O java.security.KeyStore e as interfaces com.sun.net.ssl.KeyManagerFactory e com.sun.net.ssl.TrustManagerFactory estão incluídos nesta classe.
RealmMapping
Esta interface é responsável pelo mapeamento principal e função. O método getPrincipal leva uma identidade de usuário conforme conhecida no ambiente operacional e retorna a identidade do domínio do aplicativo. O método doesUserHaveRole que valida aquela identidade do usuário no ambiente de operação, é determinado para indicar a função daquele domínio do aplicativo.
Perceba que as interfaces AuthenticationManager, RealmMapping e SecurityProxy não possuem associações às classes relacionadas ao JAAS. Embora o framework do JBossSX seja inteiramente dependente no JAAS, as interfaces de segurança básicas requeridas para implementação do modelo de segurança do Java EE não o são. O framework do JBossSX é simplesmente uma implementação das interfaces do plug-in de segurança baseadas no JAAS.
O diagrama do componente na Figura 3.2, “Classes de Implementação do Framework do JBossSX e Camada do Recipiente EJB do Servidor do JBoss.” ilustra esta situação. O problema desta arquitetura de plug-in é que você está livre para substituir o JAAS baseado nas classes de implementação do JBossSX com sua própria implementação de gerenciador de segurança baseado no não-JAAS. Você poderá verificar como isto funciona quando observando o JBossSX MBeans disponível para a configuração do JBossSX na Figura 3.2, “Classes de Implementação do Framework do JBossSX e Camada do Recipiente EJB do Servidor do JBoss.”.
Classes de Implementação do Framework do JBossSX e Camada do Recipiente EJB do Servidor do JBoss.

Figura 3.2. Classes de Implementação do Framework do JBossSX e Camada do Recipiente EJB do Servidor do JBoss.

3.1. Ativação de Segurança Declarativa Revisitada

Anteriormente neste capítulo, a discussão do modelo de segurança padrão do Java EE terminava com uma solicitação de uso do descritor de implementação específico do servidor para ativar a segurança. Os destalhes desta configuração são apresentados aqui. A Figura 3.3, “jboss.xml and jboss-web.xml Security Element Subsets.” apresenta o EJB específico do JBoss e os elementos relacionados à segurança do descritor de implantação do aplicativo da web.
jboss.xml and jboss-web.xml Security Element Subsets.

Figura 3.3. jboss.xml and jboss-web.xml Security Element Subsets.

O valor de um elemento <security-domain> especifica o nome JNDI da implementação da interface de segurança que o JBoss usa para o EJB e os recipientes da web. Este é um objeto que implementa ambas as interfaces AuthenticationManager e RealmMapping. Ele define qual domínio de segurança é especificado para todas as unidades de implantação, quando especificado como um elemento de nível superior. Este é o uso típico uma vez que a mistura dos gerenciadores de segurança com uma unidade de implantação complica a operação entre componentes e administração.
Você precisa especificar o <security-domain> à nível de configuração do recipiente, com o objetivo de especificar o domínio de segurança para um EJB individual. Isto substituirá qualquer elemento <security-domain> de nível superior.
O elemento <unauthenticated-principal> especifica o nome em uso para o objeto Principal retornado pelo método EJBContext.getUserPrincipal quando um usuário não-autenticado invoca um EJB. Perceba que isto não requer permissões especiais a um chamador não-autenticado. O seu propósito inicial é permitir servlets desprotegidos e páginas JSP para invocar EJBs desprotegidos e permitir que o EJB de destino obtenha um Principal não nulo para o chamador usando o método getUserPrincipal. Este é um requerimento da especificação do J2EE.
O elemento <security-proxy> identifica uma implementação de proxy de segurança personalizada. Ele permite as checagens de segurança por solicitação fora do escopo do modelo de segurança declarativo EJB, sem a incorporação da lógica de segurança na implementação EJB. Você pode usar uma implementação da interface org.jboss.security.SecurityProxy. Alternativamente, você pode usar uma interface comum que usa um objeto para implementar métodos na página principal, remota, página principal local ou interfaces locais do EJB. A instância deve ser quebrada automaticamente numa implementação que delega as invocações de métodos ao objeto, caso a classe gerada não implementar a interface SecurityProxy. O org.jboss.security.SubjectSecurityProxy é um exemplo de implementação SecurityProxy usado pela instalação padrão.
Observe um exemplo simples do SecurityProxy personalizado no contexto de um bean de sessão sem estado trivial. O SecurityProxy personalizado valida que ninguém invoque o método echo do bean com quatro letras como seu argumento. Esta checagem não é possível com a segurança baseada na função. Neste caso, você não pode definir uma função FourLetterEchoInvoker, uma vez que o contexto de segurança é um argumento de método e não uma propriedade do chamador. O código para o SecurityProxy personalizado é gerado no Exemplo 3.1, “Implementação EchoSecurityProxy Personalizada. ”

Exemplo 3.1. Implementação EchoSecurityProxy Personalizada.

package org.jboss.book.security.ex1;

import java.lang.reflect.Method;
import javax.ejb.EJBContext;

import org.apache.log4j.Category;

import org.jboss.security.SecurityProxy;

/** A simple example of a custom SecurityProxy implementation
* that demonstrates method argument based security checks.
* @author Scott.Stark@jboss.org
* @version $Revision: 1.4 $
*/
public class EchoSecurityProxy implements SecurityProxy
{
Category log = Category.getInstance(EchoSecurityProxy.class);
Method echo;

public void init(Class beanHome, Class beanRemote,
Object securityMgr)
throws InstantiationException
{
log.debug("init, beanHome="+beanHome
+ ", beanRemote="+beanRemote
+ ", securityMgr="+securityMgr);
// Get the echo method for equality testing in invoke
try {
Class[] params = {String.class};
echo = beanRemote.getDeclaredMethod("echo", params);
} catch(Exception e) {
String msg = "Failed to find an echo(String) method";
log.error(msg, e);
throw new InstantiationException(msg);
}
}

public void setEJBContext(EJBContext ctx)
{
log.debug("setEJBContext, ctx="+ctx);
}

public void invokeHome(Method m, Object[] args)
throws SecurityException
{
// We don't validate access to home methods
}

public void invoke(Method m, Object[] args, Object bean)
throws SecurityException
{
log.debug("invoke, m="+m);
// Check for the echo method
if (m.equals(echo)) {
// Validate that the msg arg is not 4 letter word
String arg = (String) args[0];
if (arg == null || arg.length() == 4)
throw new SecurityException("No 4 letter words");
}
// We are not responsible for doing the invoke
}
}
O EchoSecurityProxy confere se o método a ser invocado na instância do bean corresponde ao método echo(String) carregado no método init. Caso haja um correspondente, o argumento do método é obtido e seu comprimento comparado com 4 ou nulo. Ambos os casos resultam num SecurityException sendo lançado.
Não há dúvida de que isto é um exemplo planejado, mas apenas em seu próprio aplicativo. Uma solicitação comum é que aplicativos devem executar checagens de segurança baseadas no valor dos argumentos do método. O motivo do exemplo é demonstrar como a segurança personalizada acima do escopo do modelo de segurança declarativo padrão pode ser introduzido independente de uma implementação de bean. Isto permite que a especificação e a codificação das solicitações de segurança sejam delegadas às especificações de segurança. Uma vez que a camada proxy pode ser realizada independente da implementação do bean, a segurança pode ser alterada para combinar as solicitações do ambiente de implementação.
O descritor jboss.xml associado que instala o EchoSecurityProxy como um proxy personalizado para o EchoBean é gerado no Exemplo 3.2, “descritor jboss.xml ”.

Exemplo 3.2. descritor jboss.xml

<jboss>
<security-domain>java:/jaas/other</security-domain>

<enterprise-beans>
<session>
<ejb-name>EchoBean</ejb-name>
<security-proxy>org.jboss.book.security.ex1.EchoSecurityProxy</security-proxy>
</session>
</enterprise-beans>
</jboss>
Agora teste o proxy personalizado pela rodagem de um cliente que tenta invocar o método EchoBean.echo com os argumentos Hello e Four, conforme ilustrado no seguinte fragmento:
public class ExClient
{
public static void main(String args[])
throws Exception
{
Logger log = Logger.getLogger("ExClient");
log.info("Looking up EchoBean");

InitialContext iniCtx = new InitialContext();
Object ref = iniCtx.lookup("EchoBean");
EchoHome home = (EchoHome) ref;
Echo echo = home.create();

log.info("Created Echo");
log.info("Echo.echo('Hello') = "+echo.echo("Hello"));
log.info("Echo.echo('Four') = "+echo.echo("Four"));
}
}
A primeira chamada deve ser bem sucedida, enquanto que a segunda deve falhar uma vez que Four é uma palavra de quatro letras. Execute o cliente usando Ant a partir do diretório das amostras:
[examples]$ ant -Dchap=security -Dex=1 run-example
run-example1:
...
[echo] Waiting for 5 seconds for deploy...
[java] [INFO,ExClient] Looking up EchoBean
[java] [INFO,ExClient] Created Echo
[java] [INFO,ExClient] Echo.echo('Hello') = Hello
[java] Exception in thread "main" java.rmi.AccessException: SecurityException; nested exception is:
[java] java.lang.SecurityException: No 4 letter words
...
[java] Caused by: java.lang.SecurityException: No 4 letter words
...
\t
O resultado é a chamada do método echo('Hello') bem sucedida e a chamada do método echo('Four')\tresultando numa exceção confusa, também esperada. O resultado acima está truncado para adaptação neste livro. A parte principal da exceção é que o SecurityException("No 4 letter words") gerado pelo EchoSecurityProxy foi lançado para abortar a tentativa de invocação, conforme o desejado.