FailureResponse при успешном входе в систему OpenID: серверу отказано в check_authentication
Я тестирую аутентификацию OpenID с помощью python-openid на веб-сервере разработки webpy. Через Yahoo! и myOpenID, я продолжаю получать сообщение об ошибке с сообщением Server denied 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 ответ
Потребителю необходимо хранилище данных для поддержания состояния между обнаружением и аутентификацией. Магазин, который я использовал, 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 для вашего конкретного хранилища.