Java Web Services: Assinatura e criptografia de WS-Security no Axis2

Aprenda como utilizar Axis2 e Rampart para assinar e criptografar mensagens

Obtenha uma introdução sobre os princípios de criptografia de chave pública. Em seguida, veja como a WS-Security os aplica para assinar e criptografar mensagens SOAP usando pares de chaves público-privados em combinação com chaves secretas. Dennis Sosnoski continua a sua série de Java Web Services com uma discussão sobre os recursos de assinatura e criptografia da WS-Security e WS-SecurityPolicy, assim como código de exemplo usando Axis2 e Rampart.

Dennis Sosnoski, Consultant, Sosnoski Software Solutions, Inc.

Author photoDennis Sosnoski é consultor e instrutor especializado em serviços de XML e Web baseados em Java. Possui experiência profissional de mais de 30 anos como desenvolvedor de software, tendo focado seu trabalho nos últimos 10 anos em tecnologias XML e Java no lado do servidor. Dennis é o desenvolvedor principal da estrutura de software livre JiBX XML Data Binding e da estrutura de serviços da Web associada JiBX/WS. Também é "committer" (pessoa autorizada a modificar o código fonte de um determinado software) na estrutura de serviços Web Apache Axis2. Também foi um dos membros do Expert Group para as especificações JAX-WS 2.0 e JAXB 2.0.



16/Jun/2009

A segurança é crucial quando os serviços da Web trocam dados de negócios. Podem haver consequências financeiras ou legais negativas se dados forem interceptados por terceiros ou se dados fraudulentos forem aceitos como válidos. Sempre é possível projetar e implementar os procedimentos de segurança próprios de um aplicativo para serviços da Web — para qualquer tipo de troca de dados —. Contudo, essa é uma abordagem arriscada, pois mesmo pequenas distrações podem resultar em vulnerabilidades graves. Um dos principais benefícios da SOAP, se comparada a outras formas de troca de dados, é que a mesma permite extensões modulares. Desde o lançamento da SOAP, as extensões têm focado muito na segurança, o que resultou na padronização da WS-Security e das tecnologias relacionadas que permitem que a segurança seja configurada de forma apropriada para cada serviço.

Os requisitos para a segurança relacionada à troca de informações geralmente envolvem três aspectos:

  • Confidencialidade: Apenas o destinatário-alvo para quem uma certa mensagem é destinada tem acesso ao seu conteúdo.
  • Integridade: A mensagem é recebida sem modificações.
  • Autenticidade: A origem da mensagem pode ser verificada.

A WS-Security permite atender esses três aspectos facilmente. Neste artigo, você verá como fazer isso usando Axis2 e a extensão WS-Security Rampart. Em primeiro lugar, irei apresentar uma breve descrição dos princípios da criptografia de chave pública — a base para a maioria dos recursos de criptografia e assinatura da WS-Security.

Sobre esta série

Os serviços da Web são uma parte crucial do papel desempenhado pela tecnologia Java™ na computação empresarial. Nesta série de artigos, o consultor de serviços de XML e Web Dennis Sosnoski cobre as principais estruturas e tecnologias importantes para desenvolvedores Java que utilizam serviços da Web. Acompanhe a série para se manter informado com relação aos mais recentes desenvolvimentos da área e saber como utilizá-los para auxiliá-lo em seus projetos de programação.

Criptografia de chave pública

Ao longo de toda a história, a troca de mensagem tem se baseado em algum tipo de segredo compartilhado. O segredo pode ter a forma de um código, no qual as partes envolvidas na troca de mensagem possuem um conjunto em comum de substituições para frases ou ações. Ou pode ser um código no qual texto é convertido em outro tipo de texto usando algum algoritmo. O segredo também pode tomar outras formas, como por exemplo uma língua desconhecida para pessoas que possam vir a ter acesso às mensagens. O segredo compartilhado tornava a troca de mensagens segura. Contudo, se outra pessoa descobrisse o segredo, a troca de mensagem seria comprometida, com resultados potencialmente devastadores para as partes envolvidas na troca. (é só lembrar, por exemplo, do Enigma e das comunicações militares alemãs na Segunda Guerra Mundial).

A criptografia de chave pública é uma abordagem de segurança inerentemente diferente que não requer um segredo compartilhado. Ela baseia-se na idéia das funções matemáticas "trap-door", as quais são facilmente computáveis em uma direção, mas muito dificilmente computáveis na direção reversa. Por exemplo, é fácil encontrar o produto de dois números primos (mesmo números primos muito altos, caso se esteja trabalhando em um computador), mas é muito mais difícil analisar o produto para encontrar os dois fatores originais. Quando se constrói um algoritmo de criptografia baseado na direção fácil de uma função, alguém que queira quebrar sua criptografia precisa trabalhar a partir do lado difícil. Com um algoritmo bem escolhido, a tarefa de quebrar a criptografia é dificultada em um nível que a torna impraticável de ser executada em um espaço de tempo que chegue a ameaçar a troca de mensagens (pelo menos até que alguém desenvolva um computador quantum utilizável ou capacidades muito boas em física).

Na criptografia de chave pública, uma pessoa que deseje receber mensagens criptografadas cria um par de valores de chave. Cada um dos valores de chave pode ser utilizado separadamente para criptografar mensagens, mas não pode ser usado para decriptografar mensagens da forma que foi utilizado para criptografá-las. Ao invés disso, a outra chave do par deve ser utilizada para fazer a decriptografia. Desde que o proprietário das chaves mantenha uma delas em segredo, a outra pode ser tornada pública. Qualquer pessoa que tenha acesso à chave pública pode utilizar a mesma para criptografar mensagens, as quais só poderão ser decriptografadas pelo proprietário. Uma vez que são utilizadas chaves diferentes para criptografar e decriptografar mensagens, essa forma de criptografia é conhecida como criptografia assimétrica.

Assinatura de mensagens

Quando sua chave pública é utilizada para criptografar a mensagem, apenas você, o proprietário da chave privada, pode decriptografar a mensagem. Isso garante a confidencialidade, um dos três aspectos da troca de mensagens segura. contudo, também é possível utilizar sua chave privada para criptografar uma mensagem. quando isso é feito, qualquer pessoa que possuir uma cópia de sua chave pública pode decriptografar essa mensagem. Isso não parece muito útil, pois — para que serve uma mensagem criptografada que qualquer um pode ler? — mas é uma boa maneira de verificar a autenticidade de mensagens. Uma pessoa que receba uma mensagem criptografada supostamente enviada por você pode utilizar sua chave pública para decriptografar a mensagem e compará-la a um determinado valor esperado. Se o resultado bater, a pessoa tem a certeza de que foi você que enviou a mensagem.

Na prática, existem mais fatores envolvidos na assinatura de mensagens do que simplesmente a criptografia com uma chave privada. Em primeiro lugar, você precisa de algum meio de estabelecer o valor esperado para a mensagem decriptografada. Isso geralmente é feito usando uma outra variação da função "trap-door": uma função hash é fácil de ser computada, mas difícil de ser duplicada (o que significa que é difícil realizar alterações na mensagem sem alterar o valor do hash para a mensagem, ou encontrar outra mensagem com o mesmo valor do hash que uma mensagem fornecida). Com uma função hash desse tipo, é possível gerar o valor do hash (geralmente chamado de resumo em assuntos relacionados à segurança) para a mensagem que deseja assinar e depois criptografar esse resumo usando sua chave privada e enviar o valor criptografado do resumo com a mensagem. Qualquer um que receba a mensagem pode utilizar o mesmo algoritmo hash na mesma e, em seguida, decriptografar o resumo criptografado fornecido usando sua chave pública e comparar os dois valores. Se os valores baterem, o destinatário terá certeza (dentro dos limites tecnológicos atuais e considerando que você manteve sua chave privada em segredo) de que a mensagem foi enviada por você.

No caso de XML, há mais uma etapa envolvida na assinatura de mensagens. As mensagens XML são expressas em forma de texto, mas alguns aspectos da representação do texto são considerados irrelevantes pelo XML (como a ordem dos atributos em um elemento ou espaço em branco utilizado no interior da tag inicial ou final de um elemento). Devido a essas questões relativas a representações de textos, o W3c (proprietário da especificação XML) decidiu converter mensagens XML em um texto canônico antes de computar um valor de resumo (consulte Recursos). São definidos vários algoritmos de canonização que podem ser utilizados com mensagens XML. Geralmente, o algoritmo particular utilizado não importa muito, desde o utilizado por ambas as partes envolvidas em uma troca de mensagem seja o mesmo.

A utilização de um resumo de mensagem assinado garante a integridade da mensagem (uma vez que alterações na mensagem modificam o valor do resumo), bem como sua autenticidade (uma vez que a sua chave privada é utilizada para criptografar o resumo). Uma vez que a confidencialidade é assegurada em mensagens enviadas para você por meio de uma criptografia que utiliza sua chave pública, todos os aspectos principais da segurança de troca de mensagem são cobertos ao se utilizar um par de chaves público-privado. Obviamente, com apenas um par de chaves, somente uma direção de uma troca de mensagens é assegurada — mas, se a outra pessoa envolvida na troca também possuir seu par de chaves público-privado, é possível obter segurança total para mensagens indo em ambas as direções.

Certificados

Assim, pares de chaves público-privados podem ser utilizados tanto para a criptografia quanto para a assinatura de mensagens trocadas entre duas partes, desde que cada uma das partes tenha acesso à chave pública da outra parte. Assim, só nos resta a questão de como obter a chave pública de uma forma segura. Dentre as diversas maneiras de se fazer isso, a mais utilizada é fazer com que uma ou mais entidades confiáveis garantam a autenticidade da chave pública. Os Certificados Digitais são o mecanismo de fornecimento de chaves públicas nesse modelo de garantia.

Um certificado digital é basicamente uma etiqueta que acompanha uma chave pública e inclui informações de identificação para o proprietário da chave. Essa etiqueta é então assinada por uma terceira entidade confiável e a assinatura é incluída no certificado. A terceira entidade confiável garante a autenticidade da chave pública e das informações de identificação ao emitir o certificado com sua assinatura. É claro que ainda permanece a questão de como estabelecer a identidade de entidades confiáveis. Isso geralmente é feito fixando certificados para determinados terceiros confiáveis chamados autoridades de emissão no código de softwares (como o JVM).

Há muito mais por trás dos certificados digitais além dos fundamentos descritos aqui, como maneiras de anular certificados emitidos acidentalmente (o que pode acontecer, infelizmente) ou com chaves privadas, períodos de validade do certificado e extensões para especificar o uso pretendido de um certificado. Consulte Recursos para encontrar links para mais informações a respeito de certificados digitais e criptografia de chave pública em geral. Você também pode consultar a documentação da ferramenta de segurança keytool incluída em sua instalação JDK. A documentação keytool fornece uma boa introdução sobre estrutura e manuseio de certificados, acompanhada de keystores (discutido a seguir) e outros aspectos de segurança. Você também verá o exemplo mais à frente neste artigo do trabalho com a keytool.

Keystores

A maioria dos códigos de segurança de Java trabalha com chaves privadas e certificados digitais usando keystores. Um keystore é simplesmente um arquivo que contém uma chave, bem como entradas de certificado em forma criptografada. É necessária uma senha para acessar o keystore. Cada chave privada no keystore também é criptografada, exigindo uma senha adicional para manter a segurança das chaves. Qualquer software que utilizar o keystore e a chave privada precisa ter tanto a senha do keystore quanto a da chave privada durante o tempo de execução. Isso limita a segurança oferecida por essas senhas (porque qualquer pessoa com acesso ao código fonte pode descobrir como as senhas são carregadas). Assim, é necessário que você mantenha a segurança física do sistema que esteja hospedando o software e quaisquer backups desse sistema. E você deve manter o keystore e a senha apenas nesse sistema e nesses backups para preservar a segurança de suas chaves privadas.

Chaves secretas e criptografia simétrica

Embora a criptografia de chave pública usando criptografia simétrica seja a base de vários dos recursos úteis da WS-Security, a tradicional criptografia de chave secreta também desempenha um papel importante. Os algoritmos de criptografia assimétrica costumam envolver uma computação mais intensa que algoritmos simétricos baseados em chaves secretas (sendo que a mesma chave é utilizada tanto para criptografar quanto para decriptografar, ou seja, a chave deve sempre ser mantida em segredo) para garantir os mesmos níveis de proteção. Por isso, as duas técnicas são geralmente combinadas: a criptografia assimétrica de alto custo é utilizada para proteger a troca de uma chave secreta, que pode então ser utilizada para criptografia simétrica de baixo custo. Você verá um exemplo dessa abordagem mais adiante neste artigo, quando estiver lendo sobre criptografia WS-Security de uma mensagem.


Configuração

Este artigo utiliza o mesmo exemplo de aplicativo que o "Fundamentos da WS-Security no Axis2," que mostra como implementar a WS-Security UsernameToken usando Axis2 e Rampart. Contudo, são necessárias alguma mudanças para suportar o uso dos recursos de criptografia de chave pública da WS-Security, por isso, um pacote de código separado acompanha este artigo (consulte Download).

O diretório-raiz do código de exemplo é jws05code. Dentro desse diretório, você irá encontrar:

  • Um arquivo Ant build.xml
  • Um arquivo Ant build.properties, que configura a operação do aplicativo exemplo
  • O arquivo library.wsdl, fornecendo a definição do serviço para o aplicativo exemplo
  • Um arquivo de log4j.properties usado para configurar o registro no lado do cliente
  • Diversos arquivos XML de definição de propriedade (todos chamados XXX-policy-client.xml ou XXX-policy-server.xml)

Antes de utilizar o código de exemplo, você precisa:

  1. Editar o arquivo build.properties para configurar o caminho para a sua instalação do Axis2.
  2. Certificar-se de que sua instalação do Axis2 seja atualizada com o código Rampart, como mencionado na seção Instalando o Rampart do "Fundamentos da WS-Security no Axis2." (uma boa forma de checar é procurar no diretório repositório/módulos por um arquivo de módulo rampart-x.y.mar.)
  3. Adicionar o provedor de segurança Bouncy Castle org.bouncycastle.jce.provider.BouncyCastleProvider (necessário para os recursos de criptografia de chave pública utilizados no código de exemplo) à sua configuração de segurança JVM (o arquivo lib/security/java.security file) (consulte Recursos).
  4. Adicionar o JAR Bouncy Castle (nomeado de bcprov-jdkxx-vvv.jar, onde xx é sua versão de Java e vvv é a versão do código Bouncy Castle) tanto ao diretório lib de instalação do seu Axis2 quanto ao diretório WEB-INF/lib de seu aplicativo de servidor Axis2.

Agora você está pronto para compilar o aplicativo exemplo e experimentar os exemplos de segurança descritos nas seções seguintes.


Assinatura de mensagens

A assinatura requer muito mais especificações que o exemplo UsernameToken em "Fundamentos da WS-Security no Axis2." Você precisa:

  • Identificar o par de chaves público-privado usado para criar a assinatura em cada direção e fornecer as senhas utilizadas para acessar o keystore e a chave privada.
  • Especificar o conjunto de algoritmos utilizado para a canonização XML, geração do resumo e a assinatura em si.
  • Especificar quais partes da mensagem devem ser incluídas na assinatura.

Parte dessas informações é tratada como dados de configuração, integrada ao documento WS-SecurityPolicy para o serviço. Outras partes são incluídas na troca de mensagem em tempo de execução.

A Listagem 1 mostra um documento WS-Policy utilizado para configurar o cliente de Axis2 para assinar mensagens. (a Listagem 1 foi adaptada à largura da página. Veja o texto completo em sign-policy-client.xml no código de exemplo.)

Listagem 1.WS-Policy/WS-SecurityPolicy para assinatura (cliente)
<!-- Política do cliente para assinar todas as mensagens, com certificados incluídos em 
cada mensagem--> <wsp:Policy wsu:Id="SignOnly"
    xmlns:wsu="http://.../oasis-200401-wss-wssecurity-utility-1.0.xsd"
    xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
  <wsp:ExactlyOne>
    <wsp:All>
      <sp:AsymmetricBinding
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
        <wsp:Policy>
          <sp:InitiatorToken>
            <wsp:Policy>
              <sp:X509Token
                  sp:IncludeToken="http://.../IncludeToken/AlwaysToRecipient"/>
            </wsp:Policy>
          </sp:InitiatorToken>
          <sp:RecipientToken>
            <wsp:Policy>
              <sp:X509Token
                  sp:IncludeToken="http://.../IncludeToken/AlwaysToInitiator"/>
            </wsp:Policy>
          </sp:RecipientToken>
          <sp:AlgorithmSuite>
            <wsp:Policy>
              <sp:TripleDesRsa15/>
            </wsp:Policy>
          </sp:AlgorithmSuite>
          <sp:Layout>
            <wsp:Policy>
              <sp:Strict/>
            </wsp:Policy>
          </sp:Layout>
          <sp:IncludeTimestamp/>
          <sp:OnlySignEntireHeadersAndBody/>
        </wsp:Policy>
      </sp:AsymmetricBinding>
      <sp:SignedParts xmlns:sp="http://.../ws-securitypolicy/200702">
        <sp:Body/>
      </sp:SignedParts>

      <ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy">
        <ramp:user>clientkey</ramp:user>
        <ramp:passwordCallbackClass
            >com.sosnoski.ws.library.adb.PWCBHandler</ramp:passwordCallbackClass>

        <ramp:signatureCrypto>
          <ramp:crypto provider="org.apache.ws.security.components.crypto.Merlin">
            <ramp:property name="org.apache.ws.security.crypto.merlin.keystore.type"
                >JKS</ramp:property>
            <ramp:property name="org.apache.ws.security.crypto.merlin.file"
                >client.keystore</ramp:property>
            <ramp:property
                name="org.apache.ws.security.crypto.merlin.keystore.password"
                >nosecret</ramp:property>
          </ramp:crypto>
        </ramp:signatureCrypto>

      </ramp:RampartConfig>

    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

Na Listagem 1, o elemento <sp:AsymmetricBinding> na política fornece a informação de configuração básica para a utilização de criptografia de chave pública na troca de mensagem. Dentro desse elemento, vários elementos aninhados são utilizados para as especificidades da configuração. O <sp:InitiatorToken> identifica o par de chaves utilizado para assinar mensagens do cliente (o iniciador) para o servidor (o destinatário), nesse caso informando que a chave pública irá vir na forma de um certificado X.509 e será enviada com cada mensagem do cliente (sp:IncludeToken=".../AlwaysToRecipient"). O <sp:RecipientToken> identifica o par de chaves utilizado para assinar mensagens no caminho de resposta do servidor para o cliente, mais uma vez, usando um certificado X.509 e com o certificado incluído em cada mensagem do servidor (sp:IncludeToken=".../AlwaysToInitiator").

O elemento <sp:AlgorithmSuite> identifica o conjunto de algoritmos utilizado para a assinatura. O <sp:IncludeTimestamp> diz que um registro de data e hora será usado com cada mensagem (útil para prevenir ataques tipo repetição em um servidor, nos quais uma mensagem é capturada em trânsito e re-enviada na tentativa de confundir ou interromper o serviço). O elemento <sp:OnlySignEntireHeadersAndBody> diz que a assinatura será realizada em todo o cabeçalho ou corpo da mensagem, ao invés de em alguns elementos aninhados (outra medida de segurança, a qual previne certos tipos de ataque que reescrevem a mensagem). O elemento <sp:SignedParts> identifica as partes da mensagem que devem ser assinadas — nesse caso, o Corpo da mensagem SOAP.

A última parte do documento de WS-Policy da Listagem 1 fornece informações de configuração específicas de Rampart. Trata-se de uma versão mais complexa da configuração de Rampart utilizada em "Fundamentos da WS-Security no Axis2," dessa vez incluindo um elemento <ramp:user> para identificar a chave que será utilizada para assinar mensagens e um elemento <ramp:signatureCrypto> para configurar o keystore contendo a chave privada do cliente e o certificado do servidor. O arquivo keystore de referência deve estar presente no caminho de classe durante o tempo de execução. No aplicativo exemplo, o arquivo keystore é copiado para o diretório cliente/bin durante a compilação.

As classes de retorno de senha são um pouco diferentes das usadas no "Fundamentos de WS-Security no Axis2." Nesse artigo, o retorno de senha só era necessário no servidor e só era necessário para verificar (para um texto simples UsernameToken) ou configurar (para um hash UsernameToken) a senha correspondente a um determinado nome de usuário. Para a criptografia de chave pública utilizada neste artigo, o retorno deve fornecer a senha utilizada para proteger uma chave privada dentro do keystore. São necessários retornos separados para o cliente (para fornecer a senha para a chave privada do cliente) e servidor (para fornecer a senha para a chave privada do servidor). A Listagem 2 mostra a versão do retorno do lado do cliente:

Listagem2: Retorno de senha do cliente
/** * Manipulador de retorno de senha simples. Isso simplesmente verifica se a senha 
para a chave privada * está sendo requisitada e, caso esteja, configura esse 
valor. */ public class PWCBHandler implements CallbackHandler
{
    public void handle(Callback[] callbacks) throws IOException {
        for (int i = 0; i < callbacks.length; i++) {
            WSPasswordCallback pwcb = (WSPasswordCallback)callbacks[i];
            String id = pwcb.getIdentifer();
            int usage = pwcb.getUsage();
            if (usage == WSPasswordCallback.DECRYPT ||
                usage == WSPasswordCallback.SIGNATURE) {

                // used to retrieve password for private key
                if ("clientkey".equals(id)) {
                    pwcb.setPassword("clientpass");
                }

            }
        }
    }
}

O retorno na Lista 2 é projetado para suportar tanto a assinatura quanto a de criptografia usando o mesmo par de chaves público-privado, assim, ele checa a existência dos dois casos e retorna a mesma senha em ambos os casos.

Além da WS-Policy da Listagem 1 usada para o cliente, existe uma correspondente para o servidor (sign-policy-server.xml, no código de exemplo), a qual se diferencia apenas quanto aos detalhes da configuração Rampart. De forma semelhante, a versão do servidor da classe de retorno de senha da Listagem 2 se diferencia apenas quanto ao valor e senha identificadores retornados.

Executando o aplicativo exemplo

O arquivo build.properties possui linhas que fazem referência aos arquivos client.policy e server.policy a serem utilizados pelo aplicativo exemplo. Os mesmos estão configurados, respectivamente, para sign-policy-client.xml e sign-policy-server.xml na versão fornecida do arquivo. Assim, você só precisará compilar o aplicativo. É possível fazer isso com Ant, abrindo um console para o diretório jws05code e inserindo ant. Caso tudo esteja configurado corretamente, no final você deve ter um archive Axis2 library-signencr.aar no diretório jws05code. Implemente o serviço na instalação de seu servidor Axis2 carregando o arquivo .aar através da página de administração do Axis2 e depois teste o cliente, inserindo ant run no console. Se tudo estiver configurado corretamente você deverá ver as informações de saída exibidas na Figura 1:

Figura 1. Saída de console para o aplicativo em execução
Console output when running application

Para visualizar a informação de WS-Security nas mensagens, você precisa utilizar uma ferramenta como TCPMon (consulte Recursos). Primeiro, obtenha do cliente as conexões de configuração e aceitação do TCPMon em uma porta, as quais são em seguida encaminhadas ao servidor executado em uma porta diferente (ou host diferente). Então é possível editar o arquivo build.properties e mudar o valor do host-port para a porta de escuta para o TCPMon. Ao entrar mais uma vez com ant run no console, você deverá ver as mensagens sendo trocadas. A Listagem 3 mostra uma captura de mensagem de cliente como exemplo:

Listagem 3: Primeira mensagem do cliente para o servidor
 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <wsse:Security xmlns:wsse=".../oasis-200401-wss-wssecurity-secext-1.0.xsd"
        soapenv:mustUnderstand="1">
      <wsu:Timestamp xmlns:wsu=".../oasis-200401-wss-wssecurity-utility-1.0.xsd"
          wsu:Id="Timestamp-3753023">
        <wsu:Created>2009-04-18T19:26:14.779Z</wsu:Created>
        <wsu:Expires>2009-04-18T19:31:14.779Z</wsu:Expires>
      </wsu:Timestamp>
      <wsse:BinarySecurityToken
          xmlns:wsu=".../oasis-200401-wss-wssecurity-utility-1.0.xsd"
          EncodingType=".../oasis-200401-wss-soap-message-security-1.0#Base64Binary"
          ValueType=".../oasis-200401-wss-x509-token-profile-1.0#X509v1"
          wsu:Id="CertId-2650016">MIICoDC...0n33w==</wsse:BinarySecurityToken>
      <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
          Id="Signature-29086271">
        <ds:SignedInfo>
          <ds:CanonicalizationMethod
              Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
          <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
          <ds:Reference URI="#Id-14306161">
            <ds:Transforms>
              <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
            <ds:DigestValue>SiU8LTnBL10/mDCPTFETs+ZNL3c=</ds:DigestValue>
          </ds:Reference>
          <ds:Reference URI="#Timestamp-3753023">
            <ds:Transforms>
              <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
            <ds:DigestValue>2YopLipLgBFJi5Xdgz+harM9hO0=</ds:DigestValue>
          </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>TnUQtz...VUpZcm3Nk=</ds:SignatureValue>
        <ds:KeyInfo Id="KeyId-3932167">
          <wsse:SecurityTokenReference
              xmlns:wsu=".../oasis-200401-wss-wssecurity-utility-1.0.xsd"
              wsu:Id="STRId-25616143">
            <wsse:Reference URI="#CertId-2650016"
              ValueType=".../oasis-200401-wss-x509-token-profile-1.0#X509v1"/>
          </wsse:SecurityTokenReference>
        </ds:KeyInfo>
      </ds:Signature>
    </wsse:Security>
  </soapenv:Header>
  <soapenv:Body
      xmlns:wsu=".../oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Id-14306161">
    <ns2:getBook xmlns:ns2="http://ws.sosnoski.com/library/wsdl">
      <ns2:isbn>0061020052</ns2:isbn>
    </ns2:getBook>
  </soapenv:Body>
</soapenv:Envelope>

O cabeçalho <wsse:Security> com a mensagem SOAP possui todas as informações de configuração de segurança de tempo de execução e dados de assinatura. O primeiro item presente é um <wsu:Timestamp>, como requerido pela configuração da WS-SecurityPolicy. O registro de data e hora inclui dois valores de tempo: o tempo no qual ele foi criado e o tempo no qual expira. Esses dois valores diferem em cinco minutos nesse caso, que é o padrão para Rampart. (É possível alterar os valores como parte da configuração de política do Rampart.) A quantidade de tempo entre os dois é arbitrária de certa forma, mas cinco minutos é um valor razoável — é suficiente para compensar uma quantidade razoável de distorção de relógio (diferença nos tempos de relógio de sistema) entre o cliente e o servidor e ao mesmo tempo curto o bastante para limitar o potencial de ataques de repetição usando a mensagem. Após o registro de data e hora, o próximo item no cabeçalho de segurança é um <wsse:BinarySecurityToken>. Esse token de segurança é o certificado de cliente em formato binário codificado base64.

O terceiro item no cabeçalho de segurança é um bloco <ds:Signature> com três elementos filhos. O primeiro elemento filho, <ds:SignedInfo>, é a única parte da mensagem que é diretamente assinada. Os primeiros elementos filhos em <ds:SignedInfo> identificam os algoritmos utilizados para sua própria canonização e assinatura. Eles são acompanhados de um elemento filho <ds:Reference> para cada componente de mensagem incluído na assinatura. Cada elemento filho <ds:Reference> faz referência a um determinado componente de mensagem através de identificador e fornece os algoritmos de canonização e resumo aplicados a esse componente, acompanhado do valor de resumo resultante. Os elementos filhos restantes de <ds:SignedInfo> fornecem o valor da assinatura e uma referência à chave pública usada para verificar a assinatura (nesse caso, o certificado incluído no <wsse:BinarySecurityToken> antes no cabeçalho, como identificado por wsu:Id="CertId-2650016").


Criptografando e assinando mensagens

Adicionar criptografia à troca de mensagens assinada é simples e requer apenas a adição de um elemento <sp:EncryptedParts> à política para identificar o(s) componente(s) a serem assinados e algumas informações de configuração Rampart adicionais. A Listagem 4 mostra a versão do cliente de uma política com esse propósito (novamente editada de acordo com a largura da página — consulte o arquivo signencr-policy-client.xml no código de exemplo para ter acesso ao texto completo), com as adições à política da Listagem 1 em negrito:

Listagem 4: WS-Policy/WS-SecurityPolicy para assinatura e posterior criptografia (cliente)
<!-- Política de cliente para primeiro assinar e depois criptografar todas as mensagens,
com o certificado incluído na mensagem do cliente para o servidor, mas apenas uma 
impressão digital em mensagens do servidor para o 
cliente. -->  <wsp:Policy wsu:Id="SignEncr"
    xmlns:wsu="http://.../oasis-200401-wss-wssecurity-utility-1.0.xsd"
    xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
  <wsp:ExactlyOne>
    <wsp:All>
      <sp:AsymmetricBinding
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
        <wsp:Policy>
          <sp:InitiatorToken>
            <wsp:Policy>
              <sp:X509Token
                  sp:IncludeToken="http://.../IncludeToken/AlwaysToRecipient"/>
            </wsp:Policy>
          </sp:InitiatorToken>
          <sp:RecipientToken>
            <wsp:Policy>
              <sp:X509Token
                  sp:IncludeToken="http://.../IncludeToken/Never">
                <wsp:Policy>
                  <sp:RequireThumbprintReference/>
                </wsp:Policy>
              </sp:X509Token>
            </wsp:Policy>
          </sp:RecipientToken>
          <sp:AlgorithmSuite>
            <wsp:Policy>
              <sp:TripleDesRsa15/>
            </wsp:Policy>
          </sp:AlgorithmSuite>
          <sp:Layout>
            <wsp:Policy>
              <sp:Strict/>
            </wsp:Policy>
          </sp:Layout>
          <sp:IncludeTimestamp/>
          <sp:OnlySignEntireHeadersAndBody/>
        </wsp:Policy>
      </sp:AsymmetricBinding>
      <sp:SignedParts xmlns:sp="http://.../200702">
        <sp:Body/>
      </sp:SignedParts>
      <sp:EncryptedParts xmlns:sp="http://.../200702">
        <sp:Body/>
      </sp:EncryptedParts>

      <ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy">
        <ramp:user>clientkey</ramp:user>
        <ramp:encryptionUser>serverkey</ramp:encryptionUser>
        <ramp:passwordCallbackClass
            >com.sosnoski.ws.library.adb.PWCBHandler</ramp:passwordCallbackClass>

        <ramp:signatureCrypto>
          <ramp:crypto provider="org.apache.ws.security.components.crypto.Merlin">
            <ramp:property name="org.apache.ws.security.crypto.merlin.keystore.type"
                >JKS</ramp:property>
            <ramp:property name="org.apache.ws.security.crypto.merlin.file"
                >client.keystore</ramp:property>
            <ramp:property
                name="org.apache.ws.security.crypto.merlin.keystore.password"
                >nosecret</ramp:property>
          </ramp:crypto>
        </ramp:signatureCrypto>

        <ramp:encryptionCrypto>
          <ramp:crypto provider="org.apache.ws.security.components.crypto.Merlin">
            <ramp:property name="org.apache.ws.security.crypto.merlin.keystore.type"
                >JKS</ramp:property>
            <ramp:property name="org.apache.ws.security.crypto.merlin.file"
                >client.keystore</ramp:property>
            <ramp:property
                name="org.apache.ws.security.crypto.merlin.keystore.password"
                >nosecret</ramp:property>
          </ramp:crypto>
        </ramp:encryptionCrypto>

      </ramp:RampartConfig>

    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

Por que não apenas criptografia?

Seria bom fornecer um exemplo da utilização de apenas criptografia com Axis2 e Rampart, mas essa funcionalidade foi interrompida no Axis2 1.4 (e versões anteriores). Existe uma correção do código para a versão 1.5. Caso esteja usando Axis2 1.5 ou versões posteriores (junto com uma versão correspondente do Rampart), tente utilizar os arquivos de política encr-policy-client.xml e encr-policy-server.xml para criptografar o corpo de cada mensagem sem utilizar assinaturas.

A primeira alteração na política da Listagem 4 não é necessária para utilizar criptografia, mas é uma boa idéia. Ao utilizar criptografia, o cliente precisa possuir o certificado do servidor disponível ao enviar a solicitação inicial (porque a chave pública do servidor do certificado é utilizada para a criptografia). Uma vez que o cliente precisa possuir o certificado do servidor de qualquer forma, nunca há motivo para enviar o certificado do servidor para o cliente. O <sp:RecipientToken> alterado na política da Listagem 4 reflete esse tipo de utilização, dizendo que não deve ser enviado um certificado (sp:IncludeToken=".../Never") e que uma referência de impressão digital (basicamente um hash do certificado) deve ser utilizada no lugar do mesmo. A referência da impressão digital é muito mais compacta que um certificado completo. Por isso, a utilização da referência reduz o tamanho da mensagem e os gastos adicionais com processamento.

A mudança que realmente implementa a criptografia é o elemento <sp:EncryptedParts> adicionado. Esse elemento diz que a criptografia deve ser utilizada, e o elemento de conteúdo <sp:Body> diz que o corpo da mensagem SOAP é a parte da mensagem que deve ser criptografada.

A informação de configuração Rampart adicionada na Listagem 4 consiste em um elemento <ramp:encryptionUser> fornecendo o alias para a chave pública (ou seja, certificado) a ser utilizado para criptografar a mensagem, e em um elemento <ramp:encryptionCrypto> dizendo como acessar o keystore contendo o certificado. No aplicativo exemplo, o mesmo keystore é utilizado para a chave privada utilizada para assinar e a chave pública, utilizada para criptografar, assim, o elemento <ramp:encryptionCrypto> é apenas uma duplicata renomeada do elemento <ramp:signatureCrypto> existente.

Durante o tempo de execução, o Rampart precisa obter a senha utilizada para proteger a chave privada que será utilizada para decriptografar os dados criptografados. O retorno de senha utilizado anteriormente para obter a senha de chave privada para assinar, exibido na Listagem 2, também fornece a senha para decriptografia. Assim, não são necessárias alterações nesse ponto.

Executando o aplicativo exemplo

Para testar o aplicativo exemplo usando assinatura seguida de criptografia, você primeiro precisa editar o arquivo build.properties. Altere a linha de política do cliente para client.policy=signencr-policy-client.xml e a política do servidor para server-policy=signencr-policy-server.xml. Em seguida, é possível recompilar o aplicativo, executando ant, implementar o arquivo library-signencr.aar gerado em sua instalação do Axis2 e executar ant run para testar.

A Listagem 5 exibe uma captura de mensagem de solicitação quando é utilizada assinatura seguida de criptografia, com as diferenças significativas com relação à versão de apenas assinatura da Listagem 3 em negrito:

Listagem 5. Mensagem usando assinatura e criptografia
  <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
  <soapenv:Header>
    <wsse:Security xmlns:wsse=".../oasis-200401-wss-wssecurity-secext-1.0.xsd"
        soapenv:mustUnderstand="1">
      <wsu:Timestamp xmlns:wsu=".../oasis-200401-wss-wssecurity-utility-1.0.xsd"
          wsu:Id="Timestamp-4067003">
        <wsu:Created>2009-04-21T23:15:47.701Z</wsu:Created>
        <wsu:Expires>2009-04-21T23:20:47.701Z</wsu:Expires>
      </wsu:Timestamp>
      <xenc:EncryptedKey Id="EncKeyId-urn:uuid:6E12E251E439C034FA12403557497352">
        <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
        <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
          <wsse:SecurityTokenReference>
            <wsse:KeyIdentifier
                EncodingType="http://...-wss-soap-message-security-1.0#Base64Binary"
                ValueType="http://.../oasis-wss-soap-message-security-1.1#ThumbprintSHA1"
                >uYn3PK2wXheN2lLZr4n2mJjoWE0=</wsse:KeyIdentifier>
          </wsse:SecurityTokenReference>
        </ds:KeyInfo>
        <xenc:CipherData>
          <xenc:CipherValue>OBUcMI...OIPQEUQaxkZps=</xenc:CipherValue>
        </xenc:CipherData>
        <xenc:ReferenceList>
          <xenc:DataReference URI="#EncDataId-28290629"/>
        </xenc:ReferenceList>
      </xenc:EncryptedKey>
      <wsse:BinarySecurityToken
          xmlns:wsu="http://.../oasis-200401-wss-wssecurity-utility-1.0.xsd"
          EncodingType="http://...-wss-soap-message-security-1.0#Base64Binary"
          ValueType="http://.../oasis-200401-wss-x509-token-profile-1.0#X509v1"
          wsu:Id="CertId-2650016">MIICo...QUBCPx+m8/0n33w==</wsse:BinarySecurityToken>
      <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
          Id="Signature-12818976">
        <ds:SignedInfo>
          <ds:CanonicalizationMethod
              Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
          <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
          <ds:Reference URI="#Id-28290629">
            <ds:Transforms>
              <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
            <ds:DigestValue>5RQy7La+tL2kyz/ae1Z8Eqw2qiI=</ds:DigestValue>
          </ds:Reference>
          <ds:Reference URI="#Timestamp-4067003">
            <ds:Transforms>
              <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
            <ds:DigestValue>GAt/gC/4mPbnKcfahUW0aWE43Y0=</ds:DigestValue>
          </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>DhamMx...+Umrnims=</ds:SignatureValue>
        <ds:KeyInfo Id="KeyId-31999426">
          <wsse:SecurityTokenReference
              xmlns:wsu=".../oasis-200401-wss-wssecurity-utility-1.0.xsd"
              wsu:Id="STRId-19267322">
            <wsse:Reference URI="#CertId-2650016"
                ValueType=".../oasis-200401-wss-x509-token-profile-1.0#X509v1"/>
          </wsse:SecurityTokenReference>
        </ds:KeyInfo>
      </ds:Signature>
    </wsse:Security>
  </soapenv:Header>
  <soapenv:Body
      xmlns:wsu=".../oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Id-28290629">
    <xenc:EncryptedData Id="EncDataId-28290629"
        Type="http://www.w3.org/2001/04/xmlenc#Content">
      <xenc:EncryptionMethod
          Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
      <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <wsse:SecurityTokenReference
            xmlns:wsse="http://.../oasis-200401-wss-wssecurity-secext-1.0.xsd">
          <wsse:Reference URI="#EncKeyId-urn:uuid:6E12E251E439C034FA12403557497352"/>
        </wsse:SecurityTokenReference>
      </ds:KeyInfo>
      <xenc:CipherData>
        <xenc:CipherValue>k9IzAEG...3jBmonCsk=</xenc:CipherValue>
      </xenc:CipherData>
    </xenc:EncryptedData>
  </soapenv:Body>
</soapenv:Envelope>

A primeira diferença é a presença de um elemento <xenc:EncryptedKey> no cabeçalho de segurança. O conteúdo desse elemento fornece uma chave secreta em formato criptografado, usando a chave pública do servidor para realizar a criptografia. A segunda diferença é o conteúdo Body SOAP em si, que foi substituído por um elemento <xenc:EncryptedData>. Esse elemento de dados criptografado faz referência ao valor <xenc:EncryptedKey> do cabeçalho de segurança como chave para a criptografia simétrica utilizada no conteúdo Body.


Usando seus próprios certificados autoassinados

Para obter um certificado digital oficial assinado por uma autoridade de certificados reconhecida, você deve gerar um par de chaves público-privado e utilizar a chave pública para criar uma solicitação por certificado. Em seguida, a solicitação por certificado deve ser enviada para a autoridade selecionada e paga. A autoridade verifica sua identidade (um passo importante para a integridade do processo como um todo, embora às vezes esteja sujeito a falhas embaraçosas) e emite o certificado com sua assinatura.

Para testes ou uso interno, é possível, ao invés disso, gerar os seus próprios certificados autoassinados. O código de exemplo utilizado neste artigo utiliza dois certificados autoassinados: um para o cliente e um para o servidor. O keystore client.keystore utilizado no lado do cliente contém a chave e o certificado privados do cliente, assim como o certificado do servidor (que deve ser armazenado no cliente, de forma que seja aceito como válido sem a aprovação de uma autoridade de certificado ao ser utilizado para assinar, e também de forma que possa ser usado diretamente para criptografia). O keystore server.keystore utilizado no lado do servidor contém a chave e o certificado privados do servidor, além do certificado do cliente (novamente necessário para que o certificado seja aceito como válido).

É possível gerar suas próprias chaves privadas e certificados autoassinados e substituir os seus pares de chave-certificado gerados pelos fornecidos no download. Para fazer isso usando o programa keytool incluído no JDK, abra um console e, primeiramente, entre com essa linha de comando (aqui dividida para se adequar à largura da página: o comando deve ser inserido como uma linha única):

keytool -genkey -alias serverkey -keypass serverpass -keyalg RSA -sigalg SHA1withRSA 
  -keystore server.keystore -storepass nosecret

O comando anterior gera a chave e o certificado do servidor com o alias serverkey em um novo keystore, chamado server.keystore (caso já possua um server.keystore nesse diretório, primeiro é necessário excluir o par de chaves existente usando esse alias.) O keytool avisa sobre alguns itens de informação utilizados para a geração do certificado (nenhum deles importa realmente para a utilização em testes) e, em seguida, pede que você aprove a informação. Após isso ter sido feito, através da digitação do comando yes, o keytool cria o keystorecom a chave e o certificado privados e depois sai.

Em seguida, siga o mesmo procedimento para criar o par de chaves e o keystore do cliente. Dessa vez, utilize a linha de comando (inserida em uma só linha):

keytool -genkey -alias clientkey -keypass clientpass -keyalg RSA -sigalg SHA1withRSA 
  -keystore client.keystore -storepass nosecret

O próximo passo é exportar o certificado a partir do keystore de servidor e importar o mesmo para o keystore do cliente. Para exportar, utilize essa linha de comando (aqui dividida para se adequar à largura da página; deve ser inserida como uma só linha):

keytool -export -alias serverkey -keystore server.keystore -storepass nosecret -file 
  servercert.cer

A exportação cria um arquivo de certificado chamado servercert.cer, o qual pode ser importado em seguida para o keystore do cliente usando essa linha de comando (inserida como linha única):

keytool -import -alias serverkey -keystore client.keystore -storepass nosecret -file 
  servercert.cer

Quando você executa o comando de importação, o keytool imprime os detalhes do certificado e pergunta se você confia no mesmo. Após você aceitar a chave, digitando yes, ele adiciona o certificado ao keystore e sai.

Para finalizar, exporte o certificado de cliente e importe para o keystore do servidor, executando (em uma só linha):

keytool -export -alias clientkey -keystore client.keystore -storepass nosecret -file 
  clientcert.cer

Depois, execute (aqui dividido para se adequar à largura da página; deve ser inserido como uma só linha):

keytool -import -alias clientkey -keystore server.keystore -storepass nosecret -file 
   clientcert.cer

Por que exportar/importar ambos os certificados?

O texto pede que você exporte um certificado para cada parte envolvida e, em seguida, importe o certificado para o keystore para a outra parte envolvida. você precisaria fazer isso para o certificado do servidor, caso esteja usando criptografia, mesmo se os certificados fossem assinados por uma autoridade reconhecida, pois a criptografia exige o acesso à chave pública da outra parte envolvida. Para o certificado do cliente, por outro lado, a importação para o keystore do servidor somente é necessária porque o certificado é autoassinado e não pode ser validado de outra forma. Ao importar o certificado para o keystore, você já o está aprovando, de forma que a validação por uma autoridade não é necessária.

É possível utilizar a mesma abordagem para trabalhar com clientes múltiplos usando certificados autoassinados, simplesmente importando o certificado de cada cliente para o keystore do servidor. Uma outra alternativa é, ao invés de trabalhar com certificados autoassinados, é possível implementar sua própria autoridade de certificado (com uma ferramenta como o OpenSSL) e solicitar a cada cliente que obtenha um certificado assinado por essa autoridade. Dessa forma, é possível adicionar a autoridade de certificado ao seu keystore de servidor e os clientes que apresentem um certificado assinado por aquela autoridade serão aceitos. Ou é possível simplesmente pagar para utilizar certificados assinados por uma autoridade reconhecida.

Para utilizar as novas chaves e certificados, o arquivo client.keystore deve ser copiado no diretório cliente/src do código de exemplo antes da execução da compilação do cliente (ou simplesmente copie-o para o diretório cliente/bin para efeito imediato) e o arquivo server.keystore deve ser copiado no diretório servidor/src do código de exemplo antes de executar a compilação do servidor.

As linhas de comando de exemplo nesta seção utilizam os mesmos nomes de arquivo e senhas que no código de exemplo fornecido. Você também pode alterar esses valores ao gerar suas próprias chaves e certificados, mas precisa alterar o código de exemplo para que haja correspondência. a senha do keystore e o nome do arquivo são parâmetros contidos na seção RampartConfig do arquivo de política de cada parte envolvida. A senha da chave do cliente é codificada permanentemente na versão do cliente da classe com.sosnoski.ws.library.adb.PWCBHandler, e a senha da chave do servidor na versão do servidor da mesma classe.


Resumindo

Neste artigo, você viu como utilizar Axis2 e Rampart para criptografia e assinatura WS-Security baseado em políticas. Esses eficientes recursos de segurança são essenciais para diversos tipos de troca de dados de negócios, mas envolvem um custo em termos de processamento adicional. No próximo artigo Serviços Web Java, você verá uma comparação entre os custos de performance relativos a diferentes tipos de segurança, podendo decidir melhor como utilizar a segurança em seus aplicativos.


Download

DescriçãoNomeTamanho
Source code for this articlej-jws5.zip36KB

Recursos

Aprender

Obter produtos e tecnologias

  • Apache Axis2: Baixe a mais nova versão do Axis2.
  • Rampart: Baixe o módulo Rampart para o Axis2.
  • A Legião de Bouncy Castle: Baixe o .jar do Bouncy Castle correto para o seu ambiente de execução.
  • TCPMon: Baixe esse software utilitário livre para monitorar conexões TCP.

Discutir

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Tecnologia Java, Software livre
ArticleID=404862
ArticleTitle=Java Web Services: Assinatura e criptografia de WS-Security no Axis2
publish-date=06162009