File Coverage

blib/lib/Net/OpenID/VerifiedIdentity.pm
Criterion Covered Total %
statement 12 140 8.5
branch 0 74 0.0
condition 0 10 0.0
subroutine 4 28 14.2
pod 11 15 73.3
total 27 267 10.1


line stmt bran cond sub pod time code
1 6     6   31 use strict;
  6         9  
  6         141  
2 6     6   30 use Carp ();
  6         9  
  6         322  
3              
4             ############################################################################
5             package Net::OpenID::VerifiedIdentity;
6             {
7             $Net::OpenID::VerifiedIdentity::VERSION = '1.16';
8             }
9             use fields (
10 6         41 'identity', # the verified identity URL
11             'id_uri', # the verified identity's URI object
12              
13             'claimed_identity', # The ClaimedIdentity object that we've verified
14             'semantic_info', # The "semantic info" (RSS URLs, etc) at the verified identity URL
15              
16             'consumer', # The Net::OpenID::Consumer module which created us
17              
18             'signed_fields' , # hashref of key->value of things that were signed. without "openid." prefix
19             'signed_message', # the signed fields as an IndirectMessage object. Created when needed.
20 6     6   29 );
  6         7  
21 6     6   5304 use URI;
  6         49547  
  6         12577  
22              
23             sub new {
24 0     0 0   my Net::OpenID::VerifiedIdentity $self = shift;
25 0 0         $self = fields::new( $self ) unless ref $self;
26 0           my %opts = @_;
27              
28 0           $self->{'consumer'} = delete $opts{'consumer'};
29              
30 0 0         if ($self->{'claimed_identity'} = delete $opts{'claimed_identity'}) {
31 0           $self->{identity} = $self->{claimed_identity}->claimed_url;
32 0 0         unless ($self->{'id_uri'} = URI->new($self->{identity})) {
33 0           return $self->{'consumer'}->_fail("invalid_uri");
34             }
35             }
36              
37 0           for my $par (qw(signed_fields)) {
38 0           $self->$par(delete $opts{$par});
39             }
40              
41 0 0         Carp::croak("Unknown options: " . join(", ", keys %opts)) if %opts;
42 0           return $self;
43             }
44              
45             sub url {
46 0     0 1   my Net::OpenID::VerifiedIdentity $self = shift;
47 0           return $self->{'identity'};
48             }
49              
50             sub display {
51 0     0 1   my Net::OpenID::VerifiedIdentity $self = shift;
52 0           return DisplayOfURL($self->{'identity'});
53             }
54              
55             sub _semantic_info_hash {
56 0     0     my ($self) = @_;
57 0 0         return $self->{semantic_info} if $self->{semantic_info};
58 0           my $sem_info = $self->{claimed_identity}->semantic_info;
59             $self->{semantic_info} = {
60             'foaf' => $self->_identity_relative_uri($sem_info->{"foaf"}),
61             'foafmaker' => $sem_info->{"foaf.maker"},
62             'rss' => $self->_identity_relative_uri($sem_info->{"rss"}),
63 0           'atom' => $self->_identity_relative_uri($sem_info->{"atom"}),
64             };
65 0           return $self->{semantic_info};
66             }
67              
68             sub _identity_relative_uri {
69 0     0     my $self = shift;
70 0           my $url = shift;
71              
72 0 0         return $url if ref $url;
73 0 0         return undef unless $url;
74 0           return URI->new_abs($url, $self->{'id_uri'});
75             }
76              
77 0     0 0   sub signed_fields { &_getset; }
78              
79 0     0 1   sub foaf { &_getset_semurl; }
80 0     0 1   sub rss { &_getset_semurl; }
81 0     0 1   sub atom { &_getset_semurl; }
82 0     0 1   sub foafmaker { &_getset_sem; }
83              
84 0     0 1   sub declared_foaf { &_dec_semurl; }
85 0     0 1   sub declared_rss { &_dec_semurl; }
86 0     0 1   sub declared_atom { &_dec_semurl; }
87              
88             sub extension_fields {
89 0     0 1   my ($self, $ns_uri) = @_;
90 0           return $self->_extension_fields($ns_uri, $self->{consumer}->message);
91             }
92              
93             sub signed_extension_fields {
94 0     0 1   my ($self, $ns_uri) = @_;
95              
96 0           return $self->_extension_fields($ns_uri, $self->signed_message);
97             }
98              
99             sub _extension_fields {
100 0     0     my ($self, $ns_uri, $args) = @_;
101              
102 0           return $args->get_ext($ns_uri);
103             }
104              
105             sub signed_message {
106 0     0 0   my ($self) = @_;
107              
108 0 0         return $self->{signed_message} if $self->{signed_message};
109              
110             # This is maybe a bit hacky.
111             # We need to synthesize an IndirectMessage object
112             # representing the signed fields, which means
113             # that we need to fake up the mandatory message
114             # arguments that probably weren't signed.
115              
116 0           my %args = map { 'openid.'.$_ => $self->{signed_fields}{$_} } keys %{$self->{signed_fields}};
  0            
  0            
117              
118 0           my $real_message = $self->{consumer}->message;
119 0 0         if ($real_message->protocol_version == 1) {
120             # OpenID 1.1 just needs a mode.
121 0           $args{'openid.mode'} = 'id_res';
122             }
123             else {
124             # OpenID 2.2 needs the namespace URI as well
125 0           $args{'openid.ns'} = 'http://specs.openid.net/auth/2.0';
126 0           $args{'openid.mode'} = 'id_res';
127             }
128              
129 0           my $message = Net::OpenID::IndirectMessage->new(\%args);
130              
131 0           return $self->{signed_message} = $message;
132             }
133              
134             sub _getset {
135 0     0     my $self = shift;
136 0           my $param = (caller(1))[3];
137 0           $param =~ s/.+:://;
138              
139 0 0         if (@_) {
140 0           my $val = shift;
141 0 0         Carp::croak("Too many parameters") if @_;
142 0           $self->{$param} = $val;
143             }
144 0           return $self->{$param};
145             }
146              
147             sub _getset_sem {
148 0     0     my $self = shift;
149 0           my $param = (caller(1))[3];
150 0           $param =~ s/.+:://;
151              
152 0           my $info = $self->_semantic_info_hash;
153              
154 0 0         if (my $value = shift) {
155 0 0         Carp::croak("Too many parameters") if @_;
156 0           $info->{$param} = $value;
157             }
158 0           return $info->{$param};
159             }
160              
161             sub _getset_semurl {
162 0     0     my $self = shift;
163 0           my $param = (caller(1))[3];
164 0           $param =~ s/.+:://;
165              
166 0           my $info = $self->_semantic_info_hash;
167              
168 0 0         if (my $surl = shift) {
169 0 0         Carp::croak("Too many parameters") if @_;
170              
171             # TODO: make absolute URL from possibly relative one
172 0           my $abs = URI->new_abs($surl, $self->{'id_uri'});
173 0           $info->{$param} = $abs;
174             }
175              
176 0           my $uri = $info->{$param};
177 0 0 0       return $uri && _url_is_under($self->{'id_uri'}, $uri) ? $uri->as_string : undef;
178             }
179              
180             sub _dec_semurl {
181 0     0     my $self = shift;
182 0           my $param = (caller(1))[3];
183 0           $param =~ s/.+::declared_//;
184              
185 0           my $info = $self->_semantic_info_hash;
186              
187 0           my $uri = $info->{$param};
188 0 0         return $uri ? $uri->as_string : undef;
189             }
190              
191             sub DisplayOfURL {
192 0     0 0   my $url = shift;
193 0           my $dev_mode = shift;
194              
195 0 0         return $url unless
196             $url =~ m!^https?://([^/]+)(/.*)?$!;
197              
198 0           my ($host, $path) = ($1, $2);
199 0           $host = lc($host);
200              
201 0 0         if ($dev_mode) {
202 0           $host =~ s!^dev\.!!;
203 0           $host =~ s!:\d+!!;
204             }
205              
206 0           $host =~ s/:.+//;
207 0           $host =~ s/^www\.//i;
208              
209 0 0         if (length($path) <= 1) {
210 0           return $host;
211             }
212              
213             # obvious username
214 0 0 0       if ($path =~ m!^/~([^/]+)/?$! ||
215             $path =~ m!^/(?:users?|members?)/([^/]+)/?$!) {
216 0           return "$1 [$host]";
217             }
218              
219 0 0         if ($host =~ m!^profile\.(.+)!i) {
220 0           my $site = $1;
221 0 0         if ($path =~ m!^/([^/]+)/?$!) {
222 0           return "$1 [$site]";
223             }
224             }
225              
226 0           return $url;
227             }
228              
229             # FIXME: duplicated in Net::OpenID::Server
230             sub _url_is_under {
231 0     0     my ($root, $test, $err_ref) = @_;
232              
233             my $err = sub {
234 0 0   0     $$err_ref = shift if $err_ref;
235 0           return undef;
236 0           };
237              
238 0 0         my $ru = ref $root ? $root : URI->new($root);
239 0 0         return $err->("invalid root scheme") unless $ru->scheme =~ /^https?$/;
240 0 0         my $tu = ref $test ? $test : URI->new($test);
241 0 0         return $err->("invalid test scheme") unless $tu->scheme =~ /^https?$/;
242 0 0         return $err->("schemes don't match") unless $ru->scheme eq $tu->scheme;
243 0 0         return $err->("ports don't match") unless $ru->port == $tu->port;
244              
245             # check hostnames
246 0           my $ru_host = $ru->host;
247 0           my $tu_host = $tu->host;
248 0           my $wildcard_host = 0;
249 0 0         if ($ru_host =~ s!^\*\.!!) {
250 0           $wildcard_host = 1;
251             }
252 0 0         unless ($ru_host eq $tu_host) {
253 0 0         if ($wildcard_host) {
254 0 0         return $err->("host names don't match") unless
255             $tu_host =~ /\.\Q$ru_host\E$/;
256             } else {
257 0           return $err->("host names don't match");
258             }
259             }
260              
261             # check paths
262 0   0       my $ru_path = $ru->path || "/";
263 0   0       my $tu_path = $tu->path || "/";
264 0 0         $ru_path .= "/" unless $ru_path =~ m!/$!;
265 0 0         $tu_path .= "/" unless $tu_path =~ m!/$!;
266 0 0         return $err->("path not a subpath") unless $tu_path =~ m!^\Q$ru_path\E!;
267              
268 0           return 1;
269             }
270              
271             1;
272              
273             __END__