NAME
OpenID::Lite::RelyingParty - OpenID RelyingParty support module
SYNOPSIS
my $openid = OpenID::Lite::RelyingParty->new();
sub login {
my $self = shift;
my $user_suplied_identifier = $self->req->param('openid_identifier');
return unless $self->validate( $user_suplied_identifier );
my $checkid_request = $openid->begin( $user_suplied_identifier )
or $self->show_error( $openid->errstr );
my $sreg = OpenID::Lite::Extension::SREG::Request->new;
$sreg->request_fields(qw(nickname));
$checkid_request->add_extension($sreg);
my $redirect_url = $checkid_request->redirect_url(
return_to => q{http://example.com/return_to},
realm => q{http://example.com/},
);
return $self->redirect_to( $redirect_url );
}
sub return_to {
my $self = shift;
my $openid = OpenID::Lite::RelyingParty->new;
my $res = $openid->complete( $self->request, q{http://myapp/return_to} );
if ( $res->is_success ) {
# openid login successfully completed.
# you should save the verified identifier.
my $display_identifier = $res->display_identifier;
my $identity_url = $res->identity_url;
} elsif ( $res->is_canceled ) {
# user canceled openid-login.
#
# redirect back to top-page or login-page.
return $your_app->redirect('http://yourapp.com/');
} elsif ( $res->is_setup_needed ) {
# you requested as immediate-mode.
# but OP requires setup.
# so, then redirect to the indicated url
return $your_app->redirect( $res->url );
# if you accept OP with white-list,
# You can know whether the OP accepts immedate mode or not.
# So, it's better to change not to use immediate-mode.
} elsif ( $res->is_not_openid ) {
return $your_app->error('request is not for openid.');
} elsif ( $res->is_invalid ) {
# failed to verify returned assertion
$your_app->log( $res->message );
$your_app->error('Failed to verify assertion.');
} elsif ( $res->is_error ) {
# error response.
$your_app->log( $res->message );
$your_app->log( $res->contact );
$your_app->log( $res->referrence );
$your_app->error('Got error response from OP');
}
}
DESCRIPTION
This module allows you to make OpenID RelyingParty easily. This supports OpenID 2.0. Most of these interface is borrowd from ruby-openid which is provided by OpenID Enabled.
You only have to execute 'begin' and 'complete'. These methods automatically and properly execute each OpenID communication.
But if you want to customize behavior in detail, You alco can use rower API of this module, for example, 'discover', 'associate', 'idres', and so on.
'Lite' means nothing. It's to escape namespace confliction.
PREPARE
You should start with preparing OpenID::Lite::RelyingParty object with defualt set.
my $openid_rp = OpenID::Lite::RelyingParty->new();
Or set options.
use OpenID::Lite::Constants::AssocType qw(HMAC_SHA256);
use OpenID::Lite::Constants::SessionType qw(DH_SHA256);
my $openid_rp = OpenID::Lite::RelyingParty->new(
assoc_type => HMAC_SHA256,
session_type => DH_SHA256,
session => $myapp->session, # HTTP::Session object or other object which has same interface.
agent => $agent,
store => OpenID::Lite::RelyingParty::Store::Cache->new,
);
new
- assoc_type
-
HMAC_SHA1 is set by default. OpenID::Lite::Constants::AssocType
- session_type
-
NO_ENCRYPTION is set by default. OpenID::Lite::Constants::SessionType
- agent
-
If you omit, LWP::UserAgent is set by default.
To keep your application secure, you'd better set agent with more-secure one. like LWPx::ParanoidAgent or OpenID::Lite::Agent::Paranoid.
OpenID::Lite::Agent::Dump dump the request and response object for debug.
- session
-
To reduce the cost on 'idres', you can set session object. This object must behaves as same as HTTP:Session object. (Just requires only 'get' and 'set' methods.)
If session is set and discovery is executed by claimed-id, On 'idres' process, it need'nt execute re-discovery to verify returned information.
See Also HTTP::Session
- store
-
This if for saving associations which is established between RP and OP. If this is undef, OpenID process is carried out as 'stateless mode'. In stateless case, check_authentication http request is required to verify signature included in checkid-response.
You had better to set this to reduce networking cost. If your RP site allows OP with white-list (maybe this is a standard way now), Not so much associations are build. So Hash object on memory is enough to store them. OpenID::Lite::RelyingParty::Store::OnMemory fits for this case.
But your site accepts all the OpenID Providers, More assocations will be established with them. Then you may need another solution.
If you omit, OpenID::Lite::RelyingParty::Store::OnMemory is set by default. In future OpenID::Lite::RelyingParty::Store::Cache will be pushed into this package.
BEGIN
You should
1. normalize user suplied identifier 2. execute discovery with identifier ( if arleady you obtained OP's information, you can omit this phase ) 3. established association with OP ( if stateless mode, this phase is omitted ) 4. make check-id request 5. redirect user to OP's endpoint as checkid-request.
There are methods corresponding to each phase. You can use them or simple 'begin' methods that execute most of these process automatically.
simple API example
sub login {
my $your_app = shift;
my $identifier = $your_app->req->param('openid_identifier');
# $your_app->validate_identifier( $identifier );
my $checkid_request = $openid_rp->begin( $identifier )
or $your_app->show_error( $your_app->openid->errstr );
my $endpoint_url = $checkid_request->redirect_url(
return_to => q{http://myapp.com/return_to},
realm => q{http://myapp.com/},
);
return $your_app->redirect( $endpoint_url );
}
simple API and limiting OP and reducing discovery-cost.
use OpenID::Lite::Constants::Namespace qw(SERVER_2_0);
sub login {
my $your_app = shift;
my $service = OpenID::Lite::RelyingParty::Discover::Service->new;
$service->add_type( SERVER_2_0 );
$service->add_uri( q{http://example.com/op/endpoint} );
my $checkid_request = $openid_rp->begin_without_discovery( $service );
my $endpoint_url = $checkid_request->redirect_url(
return_to => q{http://myapp.com/return_to},
realm => q{http://myapp.com/},
);
return $your_app->redirect( $endpoint_url );
}
raw API example
sub login {
my $your_app = shift;
my $identifier = $your_app->req->param('openid_identifier');
# $your_app->validate_identifier( $identifier );
$identifier = $openid_rp->normalize_identifier( $identifier )
or return $your_app->error( $openid_rp->errstr );
my $services = $openid_rp->discover( $identifier )
or return $your_app->error( $openid_rp->errstr );
unless ( @$services > 0 ) {
return $your_app->error('No proper OpenID Provider found.');
}
my $service = $services->[0];
my $association = $openid_rp->associate( $services->[0] )
or return $your_app->error( $openid_rp->errstr );
$your_app->save_association( $service, $association );
$your_app->session->set( 'openid.last_requested_endpoint', $service );
my $checkid_request = OpenID::Lite::RelyingParty::CheckID::Request->new(
service => $service,
association => $association,
);
my $endpoint_url = $checkid_request->redirect_url(
return_to => q{http://myapp.com/return_to},
realm => q{http://myapp.com/},
);
return $your_app->redirect( $endpoint_url );
}
normalize_identifier($identifier)
Normalize user suplied identifier, and return OpenID::Lite::Identifier object.
my $normalized_identifier = $openid_rp->normalized_identifier($user_suplied_identifier)
or die $openid_rp->errstr;
discover($normalized_identifier)
Do discovery and return found service informations(Array of OpenID::Lite::RelyingParty::Discover::Service)
$services = $openid_rp->discover( $normalized_identifier )
or die $openid_rp->errstr;
associate($service)
Establish association with OP. Returns <OpenID::Lite::Association> object.
my $association = $openid_rp->associate( $service )
or die $openid_rp->errstr;
begin($user_suplied_identifier)
Return <OpenID::Lite::relyingParty::CheckID::Request> object.
my $checkid_req = $openid_rp->begin( $identifier )
or die $openid_rp->errstr;
begin_without_discovery($service)
Return <OpenID::Lite::relyingParty::CheckID::Request> object.
my $checkid_req = $openid_rp->begin_without_discovery( $service )
or die $openid_rp->errstr;
APPEND EXTENSION
You can add extension request onto checkid request.
my $chekid_req = $openid_rp->begin(...);
my $sreg_req = OpenID::Lite::Extension::SREG::Request->new;
$sreg_req->request_field('nickname');
$sreg_req->request_field('fullname');
$checkid_req->add_extension( $sreg_req );
my $ui_req = OpenID::Lite::Extension::UI::Request->new;
$ui_req->mode('popup');
$checkid_req->add_extension( $ui_req );
my $url = $checkid_req->redirect_url(
...
);
COMPLETE
When OP redirect back user to the return_to url you defined on checkid-request, you should execute 'idres'. You can choose row API and simple wrapper here too.
row API example
sub complete {
my $your_app = shift;
my $params = OpenID::Lite::Message->from_request( $your_app->request );
my $service = $your_app->session->get('openid.last_requested_endpoint');
my $association = $your_app->load_association_for( $service );
my $res = $openid_rp->idres(
service => $service,
association => $association,
params => $params,
current_url => q{http://yourapp.com/return_to},
);
if ( $res->is_success ) {
# openid login successfully completed.
# you should save the verified identifier.
my $display_identifier = $res->display_identifier;
my $identity_url = $res->identity_url;
} elsif ( $res->is_canceled ) {
# user canceled openid-login.
#
# redirect back to top-page or login-page.
return $your_app->redirect('http://yourapp.com/');
} elsif ( $res->is_setup_needed ) {
# you requested as immediate-mode.
# but OP requires setup.
# so, then redirect to the indicated url
return $your_app->redirect( $res->url );
# if you accept OP with white-list,
# You can know whether the OP accepts immedate mode or not.
# So, it's better to change not to use immediate-mode.
} elsif ( $res->is_not_openid ) {
return $your_app->error('request is not for openid.');
} elsif ( $res->is_invalid ) {
# failed to verify returned assertion
$your_app->log( $res->message );
$your_app->error('Failed to verify assertion.');
} elsif ( $res->is_error ) {
# error response.
$your_app->log( $res->message );
$your_app->log( $res->contact );
$your_app->log( $res->referrence );
$your_app->error('Got error response from OP');
}
}
simple API example
sub complete {
my $your_app = shift;
my $current_url = q{http://yourapp.com/return_to};
my $res = $openid_rp->complete( $your_app->request, $current_url );
# same as row API example above
if ( $res->is_success ) {
...
} elsif ( $res->is_canceled ) {
...
} elsif ( $res->is_setup_needed ) {
...
} elsif ( $res->is_not_openid ) {
...
} elsif ( $res->is_invalid ) {
...
} elsif ( $res->is_error ) {
...
}
}
idres(%args)
Returns OpenID::Lite::RelyingParty::CheckID::Result object.
- params(required)
-
OpenID::Lite::Message object. You should encode your request to OpenID::Lite::Message.
- current_url(required)
-
URL string that represents the endpoint you indicate as return_to on checkid-request.
- services(optional)
- association(optional)
complete($request, $current_url)
Returns OpenID::Lite::RelyingParty::CheckID::Result object.
EXTRACT EXTENSION RESPONSE
In successfull response, You can extract extension data you requested.
} elsif ( $res->is_success ) {
my $sreg_res = OpenID::Lite::Extension::SREG::Response->from_success_response($res);
my $data = $sreg_res->data;
my $nickname = $data->{nickname}||'';
my $fullname = $data->{fullname}||'';
...
}
SEE ALSO
http://openid.net/specs/openid-authentication-2_0.html http://openidenabled.com/
TODO
AUTHOR
Lyo Kato, <lyo.kato@gmail.com>
COPYRIGHT AND LICENSE
Copyright (C) 2009 by Lyo Kato
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available.
2 POD Errors
The following errors were encountered while parsing the POD:
- Around line 324:
Unknown directive: =over4
- Around line 326:
'=item' outside of any '=over'