通过Perl和Net::OpenID::Consumer进行OpenID身份验证到Google应用程序失败

3
我在Google的应用集成支持论坛上提出了这个问题,但是没有得到任何回复。也许这里有人可以帮助我找到正确的方向。
我正在尝试将Perl应用程序与Google应用集成,并且在OpenID身份验证方面遇到了一些问题。由于我找不到Perl示例,因此一直在使用Google的PHP教程作为参考。
我的初始文件index.cgi(由manifest.xml引用,并且是OpenID事务的起点)如下:
use Net::OpenID::Consumer;
use CGI;
# ...

my $q = CGI->new();

my $domain = $q->param('domain');
if (!$domain) {
    print $q->header(), 'Provide domain please.';
    exit 0;
}
# my website
my $root = 'http://www.example.com/';

my $csr = Net::OpenID::Consumer->new(
     # The user agent which sends the openid off to the server
     ua => LWP::UserAgent->new,
     # Who we are
     required_root => $root,
     # Consumer Key Secret from Google Apps Marketplace
     consumer_secret => 'Zzzzzz9zzAAAAA....'
);

my $claimed_id = $csr->claimed_identity(
    'https://www.google.com/accounts/o8/site-xrds?hd=' . $domain);

if ($claimed_id) {
    my $check_url = $claimed_id->check_url(
        # Upon validation, the user will be returned here, and real
        # work may begin
        return_to => $root . '/return.cgi',
        trust_root => $root
    );
    print $q->redirect($check_url);
}
else {
    print $q->header(), "Error";
}

这部分似乎是有效的。也就是说,我被重定向到带有一堆openid.*参数的return.cgi。然而,在此时我收到以下错误信息:

no_identity_server 提供的URL未声明其OpenID身份验证服务器

我正在使用Net::OpenID::Consumer模块的最新版本。

以下是return.cgi的重要部分:

my $q = CGI->new();
my $csr = Net::OpenID::Consumer->new(
     ua => LWP::UserAgent->new,
     # The root of our URL
     required_root => 'http://www.example.com/',
     # Our password.
     consumer_secret => 'Zzzzzz9zzAAAAA....',
     # Where to get the information from.
     args  => $q
);

print $q->header();
$csr->handle_server_response(
     not_openid => sub {
         print "That's not an OpenID message. Did you just type in the URL?";
     },
     setup_required => sub {
         my $setup_url = shift;
         print 'You need to do something <a href="#">here</a>.';
     },
     cancelled => sub {
         print 'You cancelled your login.';
     },
     verified => sub {
         my $vident = shift;
         my $url = $vident->url;
         print "You are verified as '$url'. ** FIN **";
     },
     error => sub { die "Can't figure it out: ", @_; }
);

你可以想象,我希望verified子程序能够运行,但是出现了错误。我有没有漏掉什么明显的问题?任何帮助都将不胜感激。

4个回答

3
所以解决方案是切换模块。我改用文档不太详细的Net::Google::FederatedLogin,现在一切正常。代码如下(将下面的example.com替换为您实际开发者的域名)。
在您的Google应用市场供应商配置文件中,将URL添加到应用程序清单中的index.cgi
...
<Url>http://www.example.com/index.cgi?from=google&amp;domain=${DOMAIN_NAME}</Url>
...

然后将以下代码添加到您的服务器。

index.cgi

use CGI;
use Net::Google::FederatedLogin;

my $q = CGI->new();

my $domain = $q->param('domain');
if (!$domain) {
    print $q->header(), 'Provide domain please.';
    exit 0;
}

my $fl = Net::Google::FederatedLogin->new(
    claimed_id => 
        'https://www.google.com/accounts/o8/site-xrds?hd=' . $domain,
    return_to =>
        'http://www.example.com/return.cgi',
    extensions => [
        {
            ns          => 'ax',
            uri         => 'http://openid.net/srv/ax/1.0',
            attributes  => {
                mode        => 'fetch_request',
                required    => 'email',
                type        => {
                    email => 'http://axschema.org/contact/email'
                }
            }
        }
    ] );

print $q->redirect($fl->get_auth_url());

return.cgi

use CGI;
use Net::Google::FederatedLogin;

my $q = CGI->new();
print $q->header();

my $fl = Net::Google::FederatedLogin->new(  
    cgi => $q,
    return_to =>
        'http://www.example.com/return.cgi' );

eval { $fl->verify_auth(); };
if ($@) {
    print 'Error: ' . $@;
}
else {
    # we've authenticated and gotten attributes --
    my $ext = $fl->get_extension('http://openid.net/srv/ax/1.0');
    print $ext->get_parameter('value.email'); 
}

(对于完整的示例,以及OAuth访问用户数据,请参阅我博客上的文章。)

2
在某些情况下,据报道,这是由于Perl缺少Net::SSL而导致的,使其在Google的SSL URL上失败。

谢谢,系统上的Net::SSL版本为2.84,所以非常新。我还在系统中使用LWP来执行其他应用程序中的https查询,从未遇到过问题。 - jar

2

出现故障的步骤是它对Google服务器所断言的标识符进行发现的地方。由于某种原因,该标识符URL的发现失败了。知道Google服务器所断言的OpenID标识符将有助于我们调试为什么无法对其进行发现。


return.cgi 正在接收以下参数 -- openid.identity=http: //apps.example.com/openid?id=100540411240650753287 -- 这是你所指的吗?实际上,这个 URL 在我的网站中并不存在。 - jar
1
那么Google是在字面上断言http://apps.example.com/openid?id=100540411240650753287吗?OpenID消费者代码将尝试获取此URL以查找其OpenID服务器,如果该URL无效,则会失败。你需要想办法说服Google应用程序断言一个有效的URL,但我对Google应用程序OpenID了解不够,无法提出解决方案。 - Martin Atkins
是的,看起来是这样。我不确定谷歌在OpenID方面是否完全按照正常流程进行。我找到了一个适用于谷歌的特定模块,所以现在我正在使用它(见下文)。感谢您的回复。 - jar

0

我不确定$domain是什么,但你可能需要对它进行转义:

use URI::Escape 'uri_escape';
....
my $claimed_id = $csr->claimed_identity(
    'https://www.google.com/accounts/o8/site-xrds?hd=' . uri_escape($domain) );

此外,Net::OpenID::Consumer使用的consumer_secret与任何其他密钥都没有关系。


我尝试了uri_escape(),但好像没有什么用。$domain类似于“apps.example.com”。我想我误解了consumer_secret的用法,但由于它只用于nonce,我不认为它应该影响结果,因为它在index.cgi和return.cgi中都匹配。感谢您的指导。 - jar
uri_escape()有多个版本。 - kagali-san
@mhambra:但如果域名都是单词字符和.,则不需要任何内容。 - ysth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接