DotNetOpenAuth: подпись сообщения неверна

При попытке аутентификации с помощью MyOpenID и Yahoo я получаю сообщение об ошибке "Сообщение было неправильным".

Я использую код ASP.NET MVC, который поставляется с 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();
}

Работает отлично с Google, AOL и другими. Однако Yahoo и MyOpenID попадают в файл AuthenticationStatus.Failed со следующим исключением:

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

Появляется тот факт, что другие проблемы имеют такую ​​же проблему: http://trac.dotnetopenauth.net:8000/ticket/172

У кого-нибудь есть обход?

Ответ 1

Оказывается, это была проблема с использованием DotNetOpenAuth в среде веб-фермы.

При создании OpenIdRelyingParty убедитесь, что вы передали null в конструкторе.

Это помещает ваш веб-сайт в автономный режим OpenID или "немой". Это немного медленнее для пользователей, чтобы войти в систему (если вы даже заметили), но вы не должны писать IRelyingPartyApplicationStore, чтобы позволить DotNetOpenAuth работать в вашей ферме;

var openIdRelyingParty = new OpenIdRelyingParty(null);

Ответ 2

Все это обсуждение вращается вокруг следующего вопроса:

Как Relying Party (RP) гарантирует, что запрос, содержащий токен аутентификации, поступает от OP (поставщик OpenId), на который он отправил запрос пользователям?

Следующие шаги объясняют, как это происходит

  • Пользовательский запрос поступает в ответную партию (RP), наш веб-сайт в нашем случае
  • Приложение хранит уникальную подпись, соответствующую этому пользователю в локальном хранилище подписи (LSS), а затем вставляет эту подпись в сообщение и передает это сообщение поставщику OpenId (OP)
  • Пользователь вводит свои учетные данные, и OP аутентифицирует свое сообщение, а затем перенаправляет это сообщение, которое имеет подпись, все еще встроенную в него, обратно в RP
  • RP сравнивает подпись, которая встроена в сообщение в подпись, которая находится в LSS, и если они соответствуют RP, аутентифицируют пользователя

Если LSS исчезает (каким-то образом) до того, как сообщение возвращается из OP, для сравнения с сигнатурой RP нет ничего, поэтому он не может аутентифицировать пользователя и бросает ошибку: подпись сообщения была неправильной.

Как LSS может исчезнуть:

  • ASP.net обновляет пул приложений.
  • IIS перезагружен
  • В веб-ферме сообщение обслуживается приложением, размещенным на другом сервере

Два решения этой проблемы:

  • RP работает в немой режиме

    a.. Он не хранит и не подписывает локально и, таким образом, не использует сравнение подписи, чтобы удостовериться, что сообщение отправлено из OP, на который он перенаправил пользователя для аутентификации.

    b. Вместо этого, как только RP получит сообщение об аутентификации из OP, он отправит сообщение обратно в OP и попросит его проверить, является ли он тем, кто аутентифицировал этого пользователя и является создателем сообщение. Если OP отвечает Да, я являюсь создателем этого сообщения, и я создал это сообщение, тогда пользователь аутентифицируется RP

  • Внедрите свой собственный хранилище персистентности, который не исчезнет, ​​неважно, что делает ASP.net для процесса, подобно использованию SQL для хранения состояния сеанса.

Ответ 3

Мы исправили эту проблему, выполнив IRelyingPartyApplicationStore (IOpenIdApplicationStore в новых версиях DotNetOpenAuth) и добавив имя класса хранилища в .config

<dotNetOpenAuth>
  <openid ...>
    <relyingParty>
      ...
      <store type="some.name.space.MyRelyingPartyApplicationStore, some.assembly"/>
    </relyingParty>
  </openid>
  ...
</dotNetOpenAuth>

Интерфейс представляет собой композицию из двух других интерфейсов с пятью членами вместе.

/// <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
{
}

Мы использовали немой режим в качестве быстрого исправления для запуска работы, но, в конце концов, вы, вероятно, захотите что-то вроде этого.