Dotnetopenauth: a assinatura da mensagem estava incorreta
-
22-09-2019 - |
Pergunta
Estou recebendo uma exceção "assinatura da mensagem estava incorreta" ao tentar autenticar com miopenid e yahoo.
Estou usando praticamente o código de amostra ASP.NET MVC que acompanha o Dotnetopenauth 3.4.2
public ActionResult Authenticate(string openid)
{
var openIdRelyingParty = new OpenIdRelyingParty();
var authenticationResponse = openIdRelyingParty.GetResponse();
if (authenticationResponse == null)
{
// Stage 2: User submitting identifier
Identifier identifier;
if (Identifier.TryParse(openid, out identifier))
{
var realm = new Realm(Request.Url.Root() + "openid");
var authenticationRequest = openIdRelyingParty.CreateRequest(openid, realm);
authenticationRequest.RedirectToProvider();
}
else
{
return RedirectToAction("login", "home");
}
}
else
{
// Stage 3: OpenID provider sending assertion response
switch (authenticationResponse.Status)
{
case AuthenticationStatus.Authenticated:
{
// TODO
}
case AuthenticationStatus.Failed:
{
throw authenticationResponse.Exception;
}
}
}
return new EmptyResult();
}
Trabalhando bem com o Google, AOL e outros. No entanto, o Yahoo e o Myopenid se enquadram no caso AuthenticationStatus.Failed com a seguinte exceção:
DotNetOpenAuth.Messaging.Bindings.InvalidSignatureException: Message signature was incorrect.
at DotNetOpenAuth.OpenId.ChannelElements.SigningBindingElement.ProcessIncomingMessage(IProtocolMessage message) in c:\Users\andarno\git\dotnetopenid\src\DotNetOpenAuth\OpenId\ChannelElements\SigningBindingElement.cs:line 139
at DotNetOpenAuth.Messaging.Channel.ProcessIncomingMessage(IProtocolMessage message) in c:\Users\andarno\git\dotnetopenid\src\DotNetOpenAuth\Messaging\Channel.cs:line 992
at DotNetOpenAuth.OpenId.ChannelElements.OpenIdChannel.ProcessIncomingMessage(IProtocolMessage message) in c:\Users\andarno\git\dotnetopenid\src\DotNetOpenAuth\OpenId\ChannelElements\OpenIdChannel.cs:line 172
at DotNetOpenAuth.Messaging.Channel.ReadFromRequest(HttpRequestInfo httpRequest) in c:\Users\andarno\git\dotnetopenid\src\DotNetOpenAuth\Messaging\Channel.cs:line 386
at DotNetOpenAuth.OpenId.RelyingParty.OpenIdRelyingParty.GetResponse(HttpRequestInfo httpRequestInfo) in c:\Users\andarno\git\dotnetopenid\src\DotNetOpenAuth\OpenId\RelyingParty\OpenIdRelyingParty.cs:line 540
Parece que outros estão tendo o mesmo problema: http://trac.dotnetopenauth.net:8000/ticket/172
Alguém tem uma solução alternativa?
Solução
Acontece que isso foi um problema no uso do Dotnetopenauth em um ambiente agrícola na web.
Quando você cria seu OpenidrelyingParty, certifique -se de passar nulo no construtor.
Isso coloca seu site no modo apátrido ou 'burro' OpenID. É um pouco mais lento para os usuários fazer login (se você notar), mas evita ter que escrever um IrlyingPartyApplicationStore para permitir que o Dotnetopenauth trabalhe em sua fazenda;
var openIdRelyingParty = new OpenIdRelyingParty(null);
Outras dicas
Toda essa discussão gira em torno da seguinte pergunta:
Como a Parte de Confiar (RP) garante que a solicitação que contém o token de autenticação esteja proveniente do OP (OpenID Provedor) para o qual ele encaminhou a solicitação do usuário?
As etapas seguintes explica como isso acontece
- A solicitação do usuário chega à festa de resposta (RP), nosso site em nosso caso
- O aplicativo armazena uma assinatura exclusiva correspondente a esse usuário em um armazenamento de assinatura local (LSS) e, em seguida, incorpora essa assinatura na mensagem e encaminhe esta mensagem ao OpenID Proves (OP)
- O usuário digita suas credenciais e o OP autentica sua mensagem e depois encaminha esta mensagem, que tem a assinatura ainda incorporada, de volta ao RP
- RP Compare a assinatura que está incorporada na mensagem à assinatura que está no LSS e se eles corresponderem ao RP autenticar o usuário
Se o LSS desaparecer (de alguma forma) antes que a mensagem volte do OP, não há nada para o RP comparar a assinatura com o fato de não autenticar o usuário e lança erro: a assinatura da mensagem estava incorreta.
Como o LSS pode desaparecer:
- Asp.net atualiza o pool de aplicativos
- IIS é reiniciado
- Na Web Farm, a mensagem é servida por aplicativos hospedados em diferentes servidores
Duas soluções para esta questão:
RP Run's no modo idiota
uma. Ele não armazena e assinatura localmente e, portanto, não usa comparação de assinatura para garantir que a mensagem esteja proveniente do OP para o qual ele encaminhou o usuário para autenticação
b. Em vez disso, uma vez que o RP recebeu a mensagem de autenticação do OP, ele envia a mensagem de volta ao OP e peça que ele verifique se ele é quem tem autenticar esse usuário e é o criador da mensagem. Se o OP responde sim, eu sou o criador desta mensagem e criei esta mensagem, o usuário é autenticado por RP
Implemente seu próprio armazenamento de persistência que não desaparece, não importa o que o ASP.NET faz com o processo, assim como o uso do SQL para armazenar o estado da sessão.
Corrigimos esse problema implementando IRelyingPartyApplicationStore
(IOpenIdApplicationStore
em versões mais recentes do Dotnetopenauth) e adicionando o nome da classe da loja ao .config
<dotNetOpenAuth>
<openid ...>
<relyingParty>
...
<store type="some.name.space.MyRelyingPartyApplicationStore, some.assembly"/>
</relyingParty>
</openid>
...
</dotNetOpenAuth>
A interface é uma composição de duas outras interfaces com cinco membros juntos.
/// <summary>
/// A hybrid of the store interfaces that an OpenID Provider must implement, and
/// an OpenID Relying Party may implement to operate in stateful (smart) mode.
/// </summary>
public interface IOpenIdApplicationStore : ICryptoKeyStore, INonceStore
{
}
Usamos o modo idiota como uma correção rápida para acumular uma corrida, mas no final você provavelmente vai querer algo assim.