1 package Catalyst::Authentication::Credential::OpenID;
2 use base "Class::Accessor::Fast";
5 __PACKAGE__->mk_accessors(qw/ _config realm debug secret /);
10 our $VERSION = '0.01';
12 use Net::OpenID::Consumer;
13 use LWPx::ParanoidAgent;
14 use UNIVERSAL::require;
15 use Catalyst::Exception ();
20 my ( $class, $config, $c, $realm ) = @_;
21 my $self = { _config => { %{ $config },
28 $self->_config->{openid_field} ||= "openid_identifier"; # 2.0 SHOULD
30 $self->debug( $self->_config->{debug} );
32 my $secret = $self->_config->{consumer_secret} ||= join("+",
37 $c->log->debug("Setting consumer secret: " . $secret) if $self->debug;
38 $self->secret( $secret );
43 my ( $self, $c, $realm, $authinfo ) = @_;
45 $c->log->debug("authenticate() called from " . $c->request->uri) if $self->debug;
47 my $field = $self->{_config}->{openid_field};
49 my $claimed_uri = $authinfo->{ $field };
50 $claimed_uri ||= $c->req->params->{ $field };
52 $c->log->debug(Dumper $self->_config->{ua_args});
54 my $csr = Net::OpenID::Consumer->new(
55 ua => ($self->_config->{ua} || "LWPx::ParanoidAgent")->new(%{$self->_config->{ua_args} || {}}),
56 args => $c->req->params,
57 consumer_secret => sub { $self->secret },
62 my $current = $c->req->uri;
63 $current->query(undef); # no query
64 my $identity = $csr->claimed_identity($claimed_uri)
65 or Catalyst::Exception->throw($csr->err);
66 my $check_url = $identity->check_url(
67 return_to => $current . '?openid-check=1',
68 trust_root => $current,
71 $c->res->redirect($check_url);
74 elsif ( $c->req->params->{'openid-check'} )
76 if ( my $setup_url = $csr->user_setup_url )
78 $c->res->redirect($setup_url);
81 elsif ( $csr->user_cancel )
85 elsif ( my $identity = $csr->verified_identity )
87 my $user = +{ map { $_ => scalar $identity->$_ }
88 qw( url display rss atom foaf declared_rss declared_atom declared_foaf foafmaker ) };
90 my $user_obj = $realm->find_user($user, $c);
98 $c->log->debug("Verified OpenID identity failed to load with find_user; bad user_class? Try 'Null.'") if $c->debug;
104 Catalyst::Exception->throw("Error validating identity: " .
121 my $config = $c->config->{authentication}->{openid} ||= {};
122 ( $config->{user_class}
123 ||= "Catalyst::Plugin::Authentication::User::Hash" )->require;
127 sub authenticate_openid {
130 my $config = $c->config->{authentication}->{openid};
132 my $csr = Net::OpenID::Consumer->new(
133 ua => LWPx::ParanoidAgent->new,
134 args => $c->req->params,
135 consumer_secret => sub { $_[0] },
138 my @try_params = qw( openid_url openid_identifier claimed_uri );
139 if ($uri ||= (grep defined, @{$c->req->params}{@try_params})[0]) {
140 my $current = $c->req->uri;
141 $current->query(undef); # no query
142 my $identity = $csr->claimed_identity($uri)
143 or Catalyst::Exception->throw($csr->err);
144 my $check_url = $identity->check_url(
145 return_to => $current . '?openid-check=1',
146 trust_root => $current,
149 $c->res->redirect($check_url);
151 } elsif ($c->req->param('openid-check')) {
152 if (my $setup_url = $csr->user_setup_url) {
153 $c->res->redirect($setup_url);
155 } elsif ($csr->user_cancel) {
157 } elsif (my $identity = $csr->verified_identity) {
158 my $user = +{ map { $_ => scalar $identity->$_ }
159 qw( url display rss atom foaf declared_rss declared_atom declared_foaf foafmaker ) };
161 my $store = $config->{store} || $c->default_auth_store;
164 = $store->get_user( $user->{url}, $user ) ) {
165 $c->set_authenticated($store_user);
167 $user = $config->{user_class}->new($user);
168 $c->set_authenticated($user);
172 Catalyst::Exception->throw("Error validating identity: " .
199 Catalyst::Plugin::Authentication::Credential::OpenID - OpenID credential for Catalyst::Auth framework
205 Authentication::Credential::OpenID
207 Session::Store::FastMmap
208 Session::State::Cookie
211 # MyApp.yaml -- optional
215 user_class: MyApp::M::User::OpenID
217 # whatever in your Controller pm
218 sub default : Private {
220 if ($c->user_exists) { ... }
223 sub signin_openid : Local {
226 if ($c->authenticate_openid) {
227 $c->res->redirect( $c->uri_for('/') );
232 <form action="[% c.uri_for('/signin_openid') %]" method="GET">
233 <input type="text" name="openid_url" class="openid" />
234 <input type="submit" value="Sign in with OpenID" />
239 Catalyst::Plugin::Authentication::Credential::OpenID is an OpenID
240 credential for Catalyst::Plugin::Authentication framework.
246 =item authenticate_openid
248 $c->authenticate_openid;
250 Call this method in the action you'd like to authenticate the user via
251 OpenID. Returns 0 if auth is not successful, and 1 if user is
254 User class specified with I<user_class> config, which defaults to
255 Catalyst::Plugin::Authentication::User::Hash, will be instantiated
256 with the following parameters.
258 By default, L<authenticate_openid> method looks for claimed URI
259 parameter from the form field named C<openid_url>,
260 C<openid_identifier> or C<claimed_uri>. If you want to use another
261 form field name, call it like:
263 $c->authenticate_openid( $c->req->param('myopenid_param') );
287 See L<Net::OpenID::VerifiedIdentity> for details.
291 =head1 DIFFERENCE WITH Authentication::OpenID
293 There's already Catalyst::Plugin::Authentication::OpenID
294 (Auth::OpenID) and this plugin tries to deprecate it.
300 Don't use this plugin with Auth::OpenID since method names will
301 conflict and your app won't work.
305 Auth::OpenID uses your root path (/) as an authentication callback but
306 this plugin uses the current path, which means you can use this plugin
307 with other Credential plugins, like Flickr or TypeKey.
311 This plugin is NOT a drop-in replacement for Auth::OpenID, but your
312 app needs only slight modifications to work with this one.
316 This plugin is based on Catalyst authentication framework, which means
317 you can specify I<user_class> or I<auth_store> in your app config and
318 this modules does the right thing, like other Credential modules. This
319 crates new User object if authentication is successful, and works with
326 Six Apart, Ltd. E<lt>cpan@sixapart.comE<gt>
330 This library is free software; you can redistribute it and/or modify
331 it under the same terms as Perl itself.
335 L<Catalyst::Plugin::Authentication::OpenID>, L<Catalyst::Plugin::Authentication::Credential::Flickr>