DotNetOpenAuth: подпись сообщения неверна - PullRequest
10 голосов
/ 24 марта 2010

Я получаю исключение "Подпись сообщения неверна" при попытке аутентификации с 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

Есть ли у кого-нибудь обходной путь?

Ответы [ 3 ]

6 голосов
/ 24 марта 2010

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

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

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

var openIdRelyingParty = new OpenIdRelyingParty(null);
5 голосов
/ 30 сентября 2010

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

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

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

  1. Запрос пользователя поступает к отвечающей стороне (RP), нашему сайту в нашем случае
  2. Приложение сохраняет уникальную подпись, соответствующую этому пользователю, в локальном хранилище подписей (LSS), а затем встраивает эту подпись в Сообщение и пересылает это Сообщение поставщику OpenId (OP)
  3. Пользователь вводит свои учетные данные, и OP аутентифицирует свое Сообщение, а затем пересылает это Сообщение, в котором еще есть подпись, обратно на RP
  4. RP сравнивает подпись, встроенную в Сообщение, с подписью, которая находится в LSS, и, если они совпадают с RP, аутентифицирует пользователя

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

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

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

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

  1. Обороты RP в тупом режиме

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

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

  2. Реализация собственного хранилища сохраняемости, которое не исчезает, независимо от того, что ASP.net делает с процессом, подобно использованию SQL для хранения состояния сеанса.

4 голосов
/ 25 марта 2010

Мы исправили эту проблему, реализовав 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
{
}

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

...