FailureResponse при успешном входе в систему OpenID: серверу отказано в check_authentication - PullRequest
1 голос
/ 08 октября 2010

Я тестирую аутентификацию OpenID с использованием python-openid на веб-сервере разработки webpy. Через Yahoo! и myOpenID, я продолжаю получать сообщение об ошибке с сообщением Сервер отклонен check_authentication . Странная часть, я также получаю правильный openid.identity.

Тот же тип аутентификации прекрасно работает с Google (@ https://www.google.com/accounts/o8/ud...). С одной стороны, это дает мне уверенность, что я что-то делаю правильно, но с другой стороны, несоответствие меня смущает.

return_to & trust_root оба являются localhost: 8080, которые могут иметь к этому какое-то отношение.

Вот код, который я использую для отправки пользователя в Yahoo! аутентифицировать:

  def POST(self):
    post_data = web.input()
    if post_data.has_key('openid_identifier'):
      openid_identifier = post_data.get('openid_identifier')
      c = Consumer(session, openid.store.memstore.MemoryStore())
      auth = c.begin(openid_identifier)
      auth_url = auth.redirectURL('http://localhost:8080', return_to='http://localhost:8080/authenticate')
      raise web.seeother(auth_url)
    return post_data

auth_url в этом случае установлено (отформатировано для удобства чтения):

https://open.login.yahooapis.com/openid/op/auth?
openid.assoc_handle=cYSO3wJSjQa3ewmRpaQz3YodzqjosP1ta.4TVzumqlLpAFM7oWci6K9bMKG4uuqZ.5m.fY7Wp8BWfQ1eR_soHWpJ6gCsKtxi_7Bqi22T5RUcMIuQBVjpGFSjc_kRY2k-&
openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&
openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&
openid.mode=checkid_setup&
openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.realm=http%3A%2F%2Flocalhost%3A8080&
openid.return_to=http%3A%2F%2Flocalhost%3A8080%2Fauthenticate%3Fjanrain_nonce%3D2010-10-08T02%253A56%253A04ZrxAI

Вот как выглядит обработчик на обратном URL:

  def GET(self):
    data = web.input()
    c = Consumer(session, openid.store.memstore.MemoryStore())
    result = c.complete(dict(data), current_url='http://localhost:8080/authenticate')
    if result.status == SUCCESS:
      openid_identity = data.get('openid.identity')
      ...
    render = web.template.render('templates/', base='layout')
    return render.error(...)

result устанавливается на <openid.consumer.consumer.FailureResponse id=None message='Server denied check_authentication'>, а data (параметры запроса при возврате) устанавливаются так:

<Storage {'openid.op_endpoint': u'https://open.login.yahooapis.com/openid/op/auth', 
'openid.sig': u'yCHffpHs2Whtw9p1gPzC+ToQJ0k=', 
'openid.ns': u'http://specs.openid.net/auth/2.0', 
'janrain_nonce': u'2010-10-08T02:56:04ZrxAIWh', 
'openid.return_to': u'http://localhost:8080/authenticate?janrain_nonce=2010-10-08T02%3A56%3A04ZrxAIWh', 
'openid.pape.auth_level.nist': u'0', 
'openid.claimed_id': u'https://me.yahoo.com/a/d3eEQZAWydfmtDwaGB2vBEVU4vIMLsez#1ac56', 
'openid.mode': u'id_res', 
'openid.realm': u'http://localhost:8080', 
'openid.response_nonce': u'2010-10-08T02:55:52ZRLNmEd7aWiaGWjHfhqEQs2Fxj3.nXdwciA--', 
'openid.signed': u'assoc_handle,claimed_id,identity,mode,ns,op_endpoint,response_nonce,return_to,signed,pape.auth_level.nist', 
'openid.identity': u'https://me.yahoo.com/a/d3eEQZAWydfmtDwaGB2vBEVU4vIMLsez', 
'openid.assoc_handle': u'cYSO3wJSjQa3ewmRpaQz3YodzqjosP1ta.4TVzumqlLpAFM7oWci6K9bMKG4uuqZ.5m.fY7Wp8BWfQ1eR_soHWpJ6gCsKtxi_7Bqi22T5RUcMIuQBVjpGFSjc_kRY2k-'}>

Это точно не похоже на неудачную реакцию для меня. Обратите внимание, что openid.identity установлено. И да, это мой идентификатор OpenID на Yahoo!.

Я не уверен, где взять это отсюда. Любые слова совета?

1 Ответ

3 голосов
/ 10 октября 2010

Потребителю необходимо хранилище данных для поддержания состояния между обнаружением и аутентификацией.Хранилище, которое я использовал, openid.store.memstore.MemoryStore(), фактически не поддерживало состояние между запросами.Он поддерживает состояние только внутри процесса - как и следовало ожидать от «памяти» (дух).Бит, который должен был измениться, - это создание потребителя в обработчиках GET и POST.

Вот неправильный способ создания потребителя:

# BAD: MemoryStore() has a short memory -- within the process only
c = Consumer(session, openid.store.memstore.MemoryStore())

И вот правильный путь ксоздать потребителя:

# GOOD: MySQL has a long memory -- across processes
db = web.database(dbn='mysql', db='somedb', user='someuser', pw='')
conn = db._db_cursor().connection
cstore = sqlstore.MySQLStore(conn, 'openid_associations', 'openid_nonces')
c = Consumer(session, cstore)

Полагаю, это помогает запомнить ваши дескрипторы и одноразовые номера.Должно быть, я застрял здесь на 10 часов, поэтому я надеюсь, что это поможет следующему парню (или девочке) избежать того же.

Это будет первая награда, которую я когда-либо выиграл - моя собственная.Woot!

Замечание по расставанию: предполагается, что вы настроили таблицы OpenID в своей базе данных, которые должны выглядеть следующим образом в MySQL:

create table openid_nonces (
  server_url blob not null,
  timestamp integer not null,
  salt char(40) not null,
  primary key (server_url(255), timestamp, salt)
) engine=InnoDB;

create table openid_associations (
  server_url blob not null,
  handle varchar(255) not null,
  secret blob not null,
  issued integer not null,
  lifetime integer not null,
  assoc_type varchar(64) not null,
  primary key (server_url(255), handle)
) engine=InnoDB;

Проверьте раздел openid.store.sqlstore документация для связанных операторов SQL для вашего конкретного хранилища.

...