Capítulo 2. Visão Geral da Segurança

2.1. Segurança Declarativa

O Declarative security é o método de separar as questões de segurança de seu código de aplicativo pelo uso do contêiner para gerenciar a segurança. O contêiner usa um sistema de autorização baseado tanto nas permissões de arquivo ou usuários, grupos e funções. Essa abordagem é normalmente superior à segurança programmatic, que fornece ao próprio aplicativo toda a responsabilidade de segurança.
O JBoss EAP 6 fornece uma segurança declarativa através dos security domains.

2.1.1. Visão Geral do Java EE Declarative Security

O modelo de segurança J2EE é declarativo na forma que você descreve as funções de segurança e permissões num descritor XML padrão ao invés de incorporar segurança em seu componente comercial. Isto isola a segurança do código de nível comercial uma vez que a segurança tende a ser uma função onde o componente é implantado de um aspecto hereditário da lógica comercial do componente. Por exemplo, considere um Automated Teller Machine (ATM - Caixa Eletrônico) que é usado para acessar uma conta bancária. As solicitações de segurança, funções e permissões irão variar independente de como você acessa a conta bancária, baseado em qual banco você está gerenciando sua conta, onde o caixa eletrônico está localizado, entre outros.
O fornecimento de segurança ao aplicativo J2EE é baseado na especificação das solicitações de segurança do aplicativo pelo uso dos descritores de implantação ejb-jar.xml e web.xml.

2.1.2. Referências de Segurança

Ambos Enterprise Java Beans (EJBs) e servlets podem declarar um ou mais elementos <security-role-ref>.
Ilustração do Modelo de Referência de Segurança

Figura 2.1. Modelo de Referência das Funções de Segurança

Este elemento declara que o componente está usando o valor do atributo role-nameType do elemento <role-name> como um argumento ao método isCallerInRole(String). Com o uso do método isCallerInRole, um componente pode verificar se é que o chamador está em uma função que foi declarada com um elemento <security-role-ref> ou <role-name>. O valor do elemento <role-name> deve ser ligado ao elemento <security-role> através do elemento <role-link>. O uso típico do isCallerInRole é executar uma verificação de segurança que não pode ser definida usando os elementos de função baseada no <method-permissions>.

Exemplo 2.1. Fragmento do descritor ejb-jar.xml

  
  <!-- A sample ejb-jar.xml fragment -->
    <ejb-jar>
      <enterprise-beans>
        <session>
          <ejb-name>ASessionBean</ejb-name>
          ...
          <security-role-ref>
            <role-name>TheRoleICheck<role-name>
              <role-link>TheApplicationRole</role-link>
          </security-role-ref>
        </session>
      </enterprise-beans>
    ...
    </ejb-jar>

Nota

Este fragmento é uma amostra apenas. Nas implantações, os elementos desta seção devem conter nomes de função e links à implantação EJB.

Exemplo 2.2. Fragmento do descritor web.xml


<web-app>
  <servlet>
    <servlet-name>AServlet</servlet-name>
    ...
    <security-role-ref>
      <role-name>TheServletRole</role-name>
      <role-link>TheApplicationRole</role-link>
    </security-role-ref>
  </servlet>
    ...
</web-app>

2.1.3. Identidade de Segurança

O Enterprise Java Bean (EJB) pode especificar a identidade que outro EJB deve usar quando invoca métodos em componentes usando o elemento <security-identity>.
Ilustração do Modelo de Identidade de Segurança J2EE

Figura 2.2. Modelo de Dados da Identidade de Segurança J2EE

A identidade da invocação pode ser o chamador atual ou pode ser uma função específica. O assembler do aplicativo usa o elemento <security-identity> com um elemento filho <use-caller-identity>. Isto indica que a identidade do chamador atual deve ser propagada como a identidade de segurança para invocações do método feitas pelo EJB. A propagação da identidade de segurança é o default usado na ausência de uma declaração do elemento <security-identity> explícito.
Alternativamente, o assembler do aplicativo pode usar o elemento filho <run-as> ou <role-name> para especificar que a função de segurança específica fornecida pelo valor do elemento <role-name> deve ser usada como identidade de segurança para as invocações do método realizadas pelo EJB.
Perceba que isto não altera a identidade do chamador conforme visto pelo método EJBContext.getCallerPrincipal(). Ao invés disto, as funções de segurança do chamador são configuradas à função única especificada pelo valor do elemento <run-as> ou <role-name>.
Um caso de uso para o elemento <run-as> é prevenir que clientes externos de acessarem os EJBs internos. Você configura este comportamento pela determinação dos elementos <method-permission> EJB internos, que restringem o acesso à função nunca determinada a um cliente externo. Os EJBs que em troca usam os EJBs internos são então configurados a um <run-as> ou <role-name> igual à função restringida. O seguinte fragmento do descritor descreve uma amostra de uso do elemento <security-identity>.

<ejb-jar>
    <enterprise-beans>
        <session>
            <ejb-name>ASessionBean</ejb-name>
            <!-- ... -->
            <security-identity>
                <use-caller-identity/>
            </security-identity>
        </session>
        <session>
            <ejb-name>RunAsBean</ejb-name>
            <!-- ... -->
            <security-identity>
                <run-as>
                    <description>A private internal role</description>
                    <role-name>InternalRole</role-name>
                </run-as>
            </security-identity>
        </session>
    </enterprise-beans>
    <!-- ... -->
</ejb-jar>

Quando você usa <run-as> para determinar uma função específica para chamadas de saída, um principal nomeado anonymous é determinado a todas as chamadas de saída. Caso você deseje que outro principal seja associado com a chamada, você deve associar um <run-as-principal> com o bean no arquivo jboss.xml. O seguinte fragmento associa um principal nomeado internal com o RunAsBean a partir da amostra anterior.

<session>
    <ejb-name>RunAsBean</ejb-name>
    <security-identity>
        <run-as-principal>internal</run-as-principal>
    </security-identity>
</session>

O elemento <run-as> também está disponível em definições servlet no arquivo web.xml. A seguinte amostra apresenta como determinar a função InternalRole a um servlet:

  <servlet>
    <servlet-name>AServlet</servlet-name>
    <!-- ... -->
    <run-as> 
        <role-name>InternalRole</role-name>
    </run-as>
  </servlet>

As chamadas a partir deste servlet são associadas com o principal anônimo. O elemento <run-as-principal> está disponível no arquivo jboss-web.xml para determinar um principal específico para ir junto com a função run-as. O seguinte fragmento apresenta com associar um principal nomeado internal para o servlet acima.

  <servlet>
    <servlet-name>AServlet</servlet-name>
    <run-as-principal>internal</run-as-principal>
  </servlet>

2.1.4. Funções de Segurança

O nome de função de segurança referenciado tanto pelo elemento security-role-ref ou security-identity precisa mapear uma das funções declaradas do aplicativo. Um assembler do aplicativo define as funções de segurança lógica pela declaração dos elementos security-role. O valor role-name é um nome de função do aplicativo lógico como Administrador, Arquiteto, Gerente de Vendas, etc.
A nota importante a ser lembrada sobre as especificações J2EE é que as funções de segurança no descritor de implantação são usadas para definir a visualização de segurança de um aplicativo. As funções definidas nos descritores de implantação não devem ser confundidas com os grupos de usuários, usuários, principais e outros conceitos que existem no ambiente operacional enterprise de destino. As funções do descritor de implantação são construções com os nomes de domain específicos do aplicativo. Por exemplo, um aplicativo de banco pode usar nomes de função tais como Gerente de Banco, Caixa ou Cliente.
No JBoss EAP, um elemento security-role é apenas usado para mapear os valores security-role-ref/role-name à função lógica que a função do componente referencia. As funções determinadas do usuário são uma função dinâmica do gerenciador de segurança do aplicativo. O JBoss não requer a definição dos elementos security-role com o objetivo de declarar as permissões do método. No entanto, a especificação dos elementos security-role continua uma prática de garantia de portabilidade pelos servidores e para a manutenção do descritor da implantação.

Exemplo 2.3. Um fragmento do descritor ejb-jar.xml que ilustra o uso do elemento security-role.

<!-- A sample ejb-jar.xml fragment --><ejb-jar><assembly-descriptor><security-role><description>The single application role</description><role-name>TheApplicationRole</role-name></security-role></assembly-descriptor></ejb-jar>

    
        
            
            
        
    

Exemplo 2.4. Uma amostra do fragmento do descritor ejb-jar.xml que ilustra o uso do elemento security-role.

<!-- A sample web.xml fragment --><web-app><security-role><description>The single application role</description><role-name>TheApplicationRole</role-name></security-role></web-app>

  
    
    
  

2.1.5. Permissões de Método EJB

Um assembler do aplicativo pode determinar as funções que são permitidas para invocar a página principal do EJB e os métodos de interface remota através das declarações do elemento method-permission.
Ilustração do elemento de permissões do método J2EE

Figura 2.3. Elemento de Permissões do Método J2EE

Cada elemento method-permission contém um ou mais elementos filho role-name que definem as funções lógicas que são permitidas para acessar os métodos EJB conforme identificado pelos elementos filho do método. Você também pode especificar o elemento unchecked ao invés do elemento role-name para declarar que qualquer usuário autenticado pode acessar os métodos indentificados pelos elementos filho do método. Além disso, você pode declarar que ninguém deve acessar um método que possui o elemento exclude-list. Caso um EJB possu métodos que não foram declarados por uma função usando um elemento method-permission, os métods EJB possuem o default para serem excluídos do uso. Isto é equivalente ao default dos métodos no exclude-list.
Ilustração do elemento do método J2EE

Figura 2.4. Elemento do Método J2EE

Existem três estilos suportados das declarações do elemento do método.
A primeira é usada para referência a todos os métodos da interface do componente e da página principal do bean enterprise nomeado:
<method><ejb-name>EJBNAME</ejb-name><method-name>*</method-name></method>
  
  

O segundo estilo é usado para referenciar o método especificado da interface do componente ou página principal do bean enterprise nomeado:
  <method><ejb-name>EJBNAME</ejb-name><method-name>METHOD</method-name></method>
    
    

Caso exista múltiplos métodos com o mesmo nomes sobrecarregado, este estilo refere-se a todos os dos métodos sobrecarregados.
O terceiro estilo é usado para referir-se a um método com um conjunto de método com o nome sobrecarregado:
<method><ejb-name>EJBNAME</ejb-name><method-name>METHOD</method-name><method-params><method-param>PARAMETER_1</method-param><!-- ... --><method-param>PARAMETER_N</method-param></method-params></method>
    
    
    
        
        
        
    

O método deve ser definido na página principal do bean enterprise ou interface remota. Os valores do elemento method-param são o nome inteiramente qualificado do tipo de parâmetro do método correspondente. Caso hajam múltiplos métodos com a mesma assinatura sobrecarregada, a permissão é aplicada a todos os métodos sobrecarregados coincidentes.
O elemento method-intf opcional pode ser usado para diferenciar métodos com o mesmo nome e assinatura que são definidos em ambas interfaces remota e da página principal de um bean enterprise.

Exemplo 2.5. Um fragmento do descritor ejb-jar.xml que ilustra o uso do elemento method-permission.

<ejb-jar><assembly-descriptor><method-permission><description>The employee and temp-employee roles may access any
                method of the EmployeeService bean </description><role-name>employee</role-name><role-name>temp-employee</role-name><method><ejb-name>EmployeeService</ejb-name><method-name>*</method-name></method></method-permission><method-permission><description>The employee role may access the findByPrimaryKey,
                getEmployeeInfo, and the updateEmployeeInfo(String) method of
                the AardvarkPayroll bean </description><role-name>employee</role-name><method><ejb-name>AardvarkPayroll</ejb-name><method-name>findByPrimaryKey</method-name></method><method><ejb-name>AardvarkPayroll</ejb-name><method-name>getEmployeeInfo</method-name></method><method><ejb-name>AardvarkPayroll</ejb-name><method-name>updateEmployeeInfo</method-name><method-params><method-param>java.lang.String</method-param></method-params></method></method-permission><method-permission><description>The admin role may access any method of the
                EmployeeServiceAdmin bean </description><role-name>admin</role-name><method><ejb-name>EmployeeServiceAdmin</ejb-name><method-name>*</method-name></method></method-permission><method-permission><description>Any authenticated user may access any method of the
                EmployeeServiceHelp bean</description><unchecked/><method><ejb-name>EmployeeServiceHelp</ejb-name><method-name>*</method-name></method></method-permission><exclude-list><description>No fireTheCTO methods of the EmployeeFiring bean may be
                used in this deployment</description><method><ejb-name>EmployeeFiring</ejb-name><method-name>fireTheCTO</method-name></method></exclude-list></assembly-descriptor></ejb-jar>
    
        
            
            
            
            
                
                
            
        
        
            
            
            
                
                
            
            
                
                
            
            
                
                
                
                    
                
            
        
        
            
            
            
                
                
            
        
        
            
            
            
                
                
            
        
        
            
            
                
                
            
        
    

2.1.6. Anotações de Segurança de Beans Enterprise

Os beans enterprise usam Anotações para passar informação ao implantador sobre a segurança e outros aspectos do aplicativo. O implantador pode configurar a política de segurança do bean enterprise para o aplicativo caso especificado nas anotações ou no descritor de implantação.
Quaisquer valores de métodos explicitamente especificados no descritor da implantação substitui os valores da anotação. Caso o valor do método não for especificado no descritor da implantação, aqueles valores determinados usando anotações serão usados. A granularidade é baseada por método.
Essas anotações que endereçam segurança e podem ser usadas nos beans enterprise incluem o seguinte:
@DeclareRoles
Declara cada função de segurança declarada no código. Por favor consulte Java EE 5 Tutorial Declaring Security Roles Using Annotations para maiores informações sobre as funções de configuração.
@RolesAllowed, @PermitAll e @DenyAll
Especifica permissões de método para anotações. Refira-se ao Java EE 5 TutorialSpecifying Method Permissions Using Annotations para maiores informações sobre a configuração das permissões do método de anotação.
@RunAs
Configura a identidade de segurança propagada de um componente. Por favor consulte Java EE 5 TutorialConfiguring a Component’s Propagated Security Identity para maiores informações sobre a configuração das identidades de segurança propagadas usando anotações.

2.1.7. Restrições de Segurança do Conteúdo da Web

Num aplicativo da web, a segurança é definida pelas funções que possuem permissão de acesso ao conteúdo por um URL default que identifica o conteúdo protegido. Este conjunto de informações é declarado pelo uso do elemento web.xmlsecurity-constraint.
Ilustração das Restrições de Segurança do Conteúdo da Web

Figura 2.5. Restrições de Segurança do Conteúdo da Web

O conteúdo a ser protegido é declarado usando um ou mais elementos <web-resource-collection>. Cada elemento <web-resource-collection> contém séries opcionais de elementos <url-pattern> seguidos por uma série opcional de elementos <http-method>. O valor do elemento <url-pattern> especifica um URL default referente a solicitação de combinação de URL para que a solicitação corresponda a uma tentativa de acesso ao conteúdo protegido. O valor do elemento <http-method> especifica o tipo de solicitação HTTP a ser permitido.
O elemento <user-data-constraint> opcional especifica as solicitações para a camada de transporte do cliente à conexão do servidor. A solicitação pode ser para a integridade do conteúdo (prevenindo dados interferindo no processo de comunicação) ou para confidencialidade (prevenindo a leitura enquanto em trânsito). O valor do elemento <transport-guarantee> especifica o grau pelo qual a comunicação entre o cliente e o servidor devem ser protegida. Os seus valores são NONE, INTEGRAL e CONFIDENTIAL. Um valor NONE significa que o aplicativo não requer qualquer garantia de transporte. Um valor INTEGRAL significa que o aplicativo requer que os dados sejam enviados entre o cliente e o servidor. O valor CONFIDENTIAL significa que o aplicativo requer que os dados sejam transmitidos numa maneira que previne outras entidades de observarem os conteúdos da transmissão. Na maioria das vezes, a presença do aviso INTEGRAL ou CONFIDENTIAL indica que o uso do SSL é solicitado.
O elemento <login-config> opcional é usado para configurar o método de autenticação que deve ser usado, o nome realm que deve ser usado para o aplicativo e os atributos que são necessários pelo mecanismo de login de formulário.
Ilustração da Configuração de Login da Web

Figura 2.6. Configuração de Login da Web

O elemento filho <auth-method> especifica o mecanismo de autenticação para o aplicativo da web. O usuário deve autenticar usando o mecanismo configurado, como pré-requisito para ganhar acesso a quaisquer recursos da web que são protegidos por uma restrição de autorização. Os valores <auth-method> legais são BASIC, DIGEST, FORM, e CLIENT-CERT. O elemento filho <realm-name> especifica o nome realm a ser usado no HTTP básico e autorização de resumo. O elemento filho <form-login-config> especifica o login assim como as páginas de erro que devem ser usadas no login baseado em formulário. Caso o valor <auth-method> não for FORM, então o form-login-config e seus elementos filhos serão ignorados.
A seguinte amostra de configuração indica que qualquer URL no caminho /restricted do aplicativo da web requer uma função AuthorizedUser. Não há garantia de transporte requerido e o método de autenticação usado para obtenção da identidade do usuário é a autenticação HTTP BÁSICO.

Exemplo 2.6. Fragmento Descritor web.xml

<web-app>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Secure Content</web-resource-name>
            <url-pattern>/restricted/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>AuthorizedUser</role-name>
        </auth-constraint>
        <user-data-constraint>
            <transport-guarantee>NONE</transport-guarantee>
        </user-data-constraint>
    </security-constraint>
    <!-- ... -->
    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>The Restricted Zone</realm-name>
    </login-config>
    <!-- ... -->
    <security-role>
        <description>The role required to access restricted content </description>
        <role-name>AuthorizedUser</role-name>
    </security-role>
</web-app>

2.1.8. Habilitação da Autenticação baseada no Formulário

A autenticação baseada no formulário fornece flexibilidade na definição de uma página JSP/HTML personalizada para login e uma página separada pela qual usuários são direcionados caso um erro ocorrer durante o login.
A autenticação baseada no formulário é definida pela inclusão do <auth-method>FORM</auth-method> no elemento <login-config> do descritor de implantação, web.xml. As páginas de login e erro estão definidas no <login-config>, conforme abaixo:
<login-config>
  <auth-method>FORM</auth-method>
  <form-login-config>
    <form-login-page>/login.html</form-login-page>
    <form-error-page>/error.html</form-error-page>
  </form-login-config>
</login-config>
Quando um aplicativo da web com a autenticação baseada no formulário é implantado, o contêiner da web usa o FormAuthenticator para direcionar os usuários à página apropriada. O JBoss EAP mantém um pool de sessão do qual a informação de autenticação não precisa estar presente para cada solicitação. Quando o FormAuthenticator recebe uma solicitação, isto solicita ao org.apache.catalina.session.Manager por uma sessão existente. Caso a sessão não existir, uma nova sessão é criada. O FormAuthenticator verifica então os credenciais da sessão.

Nota

Cada sessão é identificada pela ID de sessão, uma sequência de 16 bites gerada de valores diferenciados. Esses valores são recuperados a partir do /dev/urandom (Linux) por default e aplicados hash com o MD5. As checagens são executadas na criação da ID da sessão para certificar-se de que a ID criada é única.
Uma vez verificada, a ID de sessão é determinada como parte de uma cookie e, então retornada ao cliente. Esta cookie é esperada nas solicitações de cliente subsequentes e é usada para identificar a sessão do usuário.
A cookie é passada ao cliente é o par de valor do nome com diversos atributos opcionais. O atributo identificador é chamado JSESSIONID. O seu valor é uma sexagésima sequência da ID de sessão. Esta cookie é configurada a ser não persistente. Isto significa que no lado do cliente, ela continua a ser excluída quando o navegador existir. No lado do servidor, as sessões expiram após 60 segundos de inatividade, pelas quais os objetos de sessão e a informação de credencial das mesmas são excluídas.
Vamos dizer que um usuário tenta acessar um aplicativo da web que está protegido com a autenticação baseada no formulário. O FormAuthenticator efetua o cache na solicitação, cria uma nova sessão se necessário e redireciona o usuário à página de login definida no login-config. (Nos códigos de amostra anteriores, a página de login é login.html.) O usuário então insere seu nome de usuário e senha no formulário HTML fornecido. O nome de usuário e senha são passados ao FormAuthenticator através da ação do formulário j_security_check.
O FormAuthenticator então autentica o nome de usuário e senha em relação ao realm anexado ao contexto do aplicativo da web. No JBoss Enterprise Application Platform, o realm é JBossWebRealm. Quando a autenticação é bem sucedida, o FormAuthenticator recupera a solicitação salva do cache e redireciona o usuário a sua solicitação original.

Nota

O servidor reconhece as solicitações de autenticação do formulário apenas quando o URI finaliza com /j_security_check e pelo menos os parâmetros j_username e j_password existirem.

2.1.9. Habilitação da Segurança Declarativa

Os elementos de segurança do Java EE que foram cobertos até agora, descrevem as solicitações de segurança apenas da perspectiva do aplicativo. O implantador do aplicativo mapeia as funções a partir do domain no ambiente de implantação, uma vez que os elementos de segurança do Java EE declaram funções lógicas. As especificações do Java EE omitem esse aplicativo dos detalhes específicos do servidor.
Com o objetivo de mapear as funções do aplicativo no ambiente implantado, você deve especificar um gerenciador de segurança que implementa o modelo de segurança Java EE usando os descritores de implantação específicos do JBoss EAP. Refira-se à amostra do modelo de login personalizado para maiores detalhes sobre a configuração de segurança.