Skip to content
mobius1qwe edited this page Nov 8, 2026 · 1 revision

Home > Servidor SOAP > WS-Security

WS-Security (UsernameToken)

Important

Em desenvolvimento (2.0). Ainda não está numa versão lançada e pode mudar.

Delphi e Lazarus · Nível: intermediário

Em uma frase: o login dentro do envelope SOAP, como pedem os serviços de governo, bancos e sistemas legados em .NET e Java: usuário e senha (em texto ou em resumo) no cabeçalho wsse:Security, pelo perfil UsernameToken 1.1 da OASIS.

Você vai precisar: o Servidor SOAP ou o Cliente SOAP (pacote RALModuleSOAPPackage). A senha em texto viaja legível: use HTTPS, ou a senha em resumo (digest).

O que é

O WS-Security põe as credenciais no envelope, não no HTTP:

<soap:Header>
  <wsse:Security soap:mustUnderstand="1" xmlns:wsse="..." xmlns:wsu="...">
    <wsse:UsernameToken>
      <wsse:Username>alice</wsse:Username>
      <wsse:Password Type="...#PasswordDigest">7nB0...=</wsse:Password>
      <wsse:Nonce>q9Fh...==</wsse:Nonce>
      <wsu:Created>2026-11-08T12:00:00.000Z</wsu:Created>
    </wsse:UsernameToken>
  </wsse:Security>
</soap:Header>
Senha O que viaja Quando
texto (wptText) a própria senha sob HTTPS; o servidor pode guardar só um hash
resumo (wptDigest) Base64(SHA-1(nonce + Created + senha)) sem HTTPS, ou quando o parceiro pede; o servidor precisa da senha em si

O Nonce (aleatório) e o Created (hora UTC) impedem que alguém que gravou um pedido o repita: o servidor recusa um Created velho e um nonce já visto.

No servidor

Solte um TRALServerWSSecurityAuth (paleta RAL - Server) e ligue-o em Servidor.Authentication, como qualquer autenticação:

uses RALWSSecurity, RALWSSecurityAuth;

Auth := TRALServerWSSecurityAuth.Create(Self);
Auth.UserName := 'alice';
Auth.Password := 's3cret';
Servidor.Authentication := Auth;

Vários usuários: o evento OnGetPassword devolve a senha de quem chegou (vale para texto e resumo). Senha guardada como hash: OnValidate decide a senha em texto (com ele, o OnGetPassword não é perguntado para texto).

procedure TForm1.AuthGetPassword(ARequest: TRALRequest; const AUserName: StringRAL;
  var APassword: StringRAL; var AFound: boolean);
begin
  AFound := Usuarios.Locate('login', AUserName, []);
  if AFound then
    APassword := Usuarios.FieldByName('senha').AsString;
end;
Propriedade O que faz
UserName, Password o usuário único, sem OnGetPassword
PasswordTypes tipos aceitos (padrão: texto e resumo)
MaxAge segundos que um token vale depois do Created (padrão 300; 0 não confere a idade)
ClockSkew folga entre os relógios do cliente e do servidor (padrão 60 s)
ReplayProtection recusa nonce repetido e resumo sem nonce ou sem Created (padrão ligado)
ReplayStore onde os nonces vistos ficam; vários servidores atrás de um balanceador dividem um TRALFileStore
OnGetRoles preenche os papéis de quem entrou (Papéis e políticas)

O que ele faz em cada pedido:

  • lê o envelope que o módulo SOAP já analisou (uma vez só: a operação usa o mesmo documento);
  • confere o tipo da senha, o Created (nem velho, nem do futuro), o wsu:Timestamp quando vem, a senha e o nonce;
  • marca o bloco wsse:Security como entendido: o mustUnderstand="1" que os clientes mandam não vira falha;
  • aceito, ARequest.Identity.Name é o usuário; a força bruta conta as senhas erradas.

Recusado, o cliente recebe a falha que a norma pede, wsse:FailedAuthentication, na versão do envelope (HTTP 500 no SOAP 1.1; 400 com Subcode no 1.2), e não um 401 HTTP. Um cliente que mandou credenciais HTTP (Basic, por exemplo) continua recebendo o 401 do esquema dele.

O WSDL (GET) segue a regra do módulo: livre, ou com WSDLRequireAuth.

No cliente

O TRALSOAPClient tem a propriedade Security; com UserName preenchido, todo envelope sai com o bloco:

Cliente.Security.UserName := 'alice';
Cliente.Security.Password := 's3cret';
Cliente.Security.PasswordType := wptDigest;
Cliente.Execute('Somar');
Security. O que faz
UserName, Password as credenciais; UserName vazio não manda nada
PasswordType wptText (padrão) ou wptDigest
AddNonce, AddCreated mandam Nonce e Created (o resumo manda sempre)
Timestamp, TimestampTTL mandam um wsu:Timestamp com Created e Expires
MustUnderstand marca o bloco: um servidor que não confere WS-Security recusa em vez de ignorar (padrão ligado)

Outros blocos de cabeçalho do parceiro (um token de sessão, um rastreio): o evento OnBuildHeader recebe o soap:Header de cada envelope, na thread que envia.

procedure TForm1.ClienteBuildHeader(Sender: TObject; AHeader: TRALXMLNode);
begin
  AHeader.AddChild('t:Sessao').AddNamespace('t', 'urn:parceiro').WithText(FSessao);
end;

Erros comuns

O que acontece Causa O que fazer
FailedAuthentication com a senha certa relógio do cliente adiantado ou atrasado além de ClockSkew acerte o relógio (NTP) ou aumente ClockSkew
FailedAuthentication só no resumo o servidor guarda hash, e o resumo precisa da senha use texto sob HTTPS, ou guarde a senha de modo recuperável
FailedAuthentication na segunda vez do mesmo pedido nonce repetido (um pedido gravado e reenviado) é a proteção funcionando; cada envio leva nonce novo
falha MustUnderstand no Security o servidor não tem o TRALServerWSSecurityAuth, ou a operação pula a autenticação (SkipAuth) ligue o autenticador, ou ponha Security em Headers da operação
o parceiro .NET/Java recusa o login ele pede só um tipo de senha, ou Created sem milissegundos ajuste PasswordType; o RAL lê Created com ou sem frações

Assinatura e cifra de XML (XMLDSig, XMLEnc) ainda não existem; a forma canônica que elas usam já existe.

Veja também

Clone this wiki locally