File Coverage

blib/lib/OpenID/Lite/Realm.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package OpenID::Lite::Realm;
2              
3 2     2   2886 use Any::Moose;
  2         44714  
  2         17  
4 2     2   2067 use URI;
  2         8282  
  2         63  
5 2     2   1065 use List::MoreUtils qw(any none);
  2         1277  
  2         142  
6              
7 2     2   1039 use OpenID::Lite::Provider::Discover;
  0            
  0            
8             use OpenID::Lite::Util::URI;
9              
10             has 'origin' => (
11             is => 'ro',
12             isa => 'Str',
13             required => 1,
14             );
15              
16             has 'scheme' => (
17             is => 'ro',
18             isa => 'Str',
19             required => 1,
20             );
21              
22             has 'host' => (
23             is => 'ro',
24             isa => 'Str',
25             default => '',
26             );
27              
28             has 'port' => (
29             is => 'ro',
30             isa => 'Int',
31             );
32              
33             has 'path' => (
34             is => 'ro',
35             isa => 'Str',
36             default => '/',
37             );
38              
39             has 'has_wildcard' => (
40             is => 'ro',
41             isa => 'Bool',
42             default => 0,
43             );
44              
45             my @TLDs = qw(
46             ac ad ae aero af ag ai al am an ao aq ar arpa as asia at
47             au aw ax az ba bb bd be bf bg bh bi biz bj bm bn bo br bs bt
48             bv bw by bz ca cat cc cd cf cg ch ci ck cl cm cn co com coop
49             cr cu cv cx cy cz de dj dk dm do dz ec edu ee eg er es et eu
50             fi fj fk fm fo fr ga gb gd ge gf gg gh gi gl gm gn gov gp gq
51             gr gs gt gu gw gy hk hm hn hr ht hu id ie il im in info int
52             io iq ir is it je jm jo jobs jp ke kg kh ki km kn kp kr kw
53             ky kz la lb lc li lk lr ls lt lu lv ly ma mc md me mg mh mil
54             mk ml mm mn mo mobi mp mq mr ms mt mu museum mv mw mx my mz
55             na name nc ne net nf ng ni nl no np nr nu nz om org pa pe pf
56             pg ph pk pl pm pn pr pro ps pt pw py qa re ro rs ru rw sa sb
57             sc sd se sg sh si sj sk sl sm sn so sr st su sv sy sz tc td
58             tel tf tg th tj tk tl tm tn to tp tr travel tt tv tw tz ua
59             ug uk us uy uz va vc ve vg vi vn vu wf ws xn--0zwm56d
60             xn--11b5bs3a9aj6g xn--80akhbyknj4f xn--9t4b11yi5a
61             xn--deba0ad xn--g6w251d xn--hgbk6aj7f53bba
62             xn--hlcj6aya9esc7a xn--jxalpdlp xn--kgbechtv xn--zckzah ye
63             yt yu za zm zw
64             );
65              
66             sub return_to_matches {
67             my ( $class, $urls, $return_to ) = @_;
68             $return_to ||= '';
69             for my $url (@$urls) {
70             my $r = $class->parse($url);
71             return 1
72             if ( $r
73             && !$r->has_wildcard
74             && $r->validate_url($return_to) );
75             }
76             return 0;
77             }
78              
79             sub get_allowed_return_urls {
80             my ( $self, $url ) = @_;
81             my $disco = OpenID::Lite::Provider::Discover->new();
82             my $urls = $disco->discover($url, 1)
83             or return;
84             }
85              
86             sub verify_return_to {
87             my ( $class, $realm, $return_to ) = @_;
88             my $r = $class->parse($realm);
89             return unless $r;
90             my $disco_url = $r->build_discovery_url();
91             my $allowable_urls = $class->get_allowed_return_urls($disco_url);
92             if ( $class->return_to_matches( $allowable_urls, $return_to ) ) {
93             return 1;
94             }
95             return 0;
96             }
97              
98             sub parse {
99             my ( $class, $realm ) = @_;
100             my $origin = $realm;
101             my $found_wildcard = ( index( $realm, q{://*.} ) >= 0 ) ? 1 : 0;
102             $realm =~ s/\*\.// if $found_wildcard;
103             if ( !$found_wildcard && $realm =~ m|^https?\://\*/$| ) {
104             my $scheme = ( split( /\:/, $realm ) )[0];
105             my $port = $scheme eq 'http' ? 80 : 443;
106             return $class->new(
107             origin => $origin,
108             scheme => $scheme,
109             host => '',
110             port => $port,
111             has_wildcard => 1,
112             path => '/',
113             );
114             }
115             my $parts = $class->_parse($realm);
116             return unless $parts;
117             my ( $scheme, $host, $port, $path ) = @$parts;
118             if ( $path && index( $path, q{#} ) >= 0 ) {
119             return;
120             }
121             return if ( none { $_ eq $scheme } qw(http https) );
122             return $class->new(
123             origin => $origin,
124             scheme => $scheme,
125             host => $host,
126             port => $port,
127             path => $path,
128             has_wildcard => $found_wildcard,
129             );
130             }
131              
132             sub _parse {
133             my ( $class, $url ) = @_;
134             $url = OpenID::Lite::Util::URI->normalize($url)
135             or return;
136             return unless OpenID::Lite::Util::URI->is_uri($url);
137             my $u = URI->new($url);
138             my $path = $u->path;
139             $path .= sprintf q{?%s}, $u->query if $u->query;
140             $path .= sprintf q{#%s}, $u->fragment if $u->fragment;
141             return [ $u->scheme || '', $u->host || '', $u->port || '', $path ];
142             }
143              
144             sub check_url {
145             my ( $class, $realm, $url ) = @_;
146             my $r = $class->parse($realm);
147             return ( $r && $r->validate_url($url) ) ? 1 : 0;
148             }
149              
150             sub check_sanity {
151             my ( $class, $realm ) = @_;
152             my $r = $class->parse($realm);
153             return ( $r && $r->is_sane() ) ? 1 : 0;
154             }
155              
156             sub build_discovery_url {
157             my $self = shift;
158             if ( $self->has_wildcard ) {
159             my $port
160             = ( $self->port && $self->port != 80 && $self->port != 443 )
161             ? sprintf(":%d", $self->port)
162             : '';
163             return sprintf q{%s://www.%s%s%s},
164             $self->scheme,
165             $self->host,
166             $port,
167             $self->path;
168             }
169             else {
170             return $self->origin;
171             }
172             }
173              
174             sub is_sane {
175             my $self = shift;
176             return 1 if $self->host eq 'localhost';
177             my @host_parts = split( /\./, $self->host );
178             return 0 if scalar(@host_parts) == 0;
179             return 0 if ( any { $_ eq '' } @host_parts );
180              
181             my $tld = $host_parts[-1];
182             return 0 if ( none { $tld eq $_ } @TLDs );
183             return 0 if scalar(@host_parts) == 1;
184              
185             if ( $self->has_wildcard ) {
186             if ( length($tld) == 2 && length( $host_parts[-2] ) <= 3 ) {
187             return @host_parts > 2 ? 1 : 0;
188             }
189             }
190              
191             return 1;
192             }
193              
194             sub validate_url {
195             my ( $self, $url ) = @_;
196             my $parts = ref($self)->_parse($url)
197             or return 0;
198             my ( $scheme, $host, $port, $path ) = @$parts;
199              
200             return 0 unless $self->scheme eq $scheme;
201             return 0 unless $self->port == $port;
202             return 0 if ( index( $host, q{*} ) >= 0 );
203              
204             my $s_host = $self->host;
205             if ( !$self->has_wildcard ) {
206             return 0 if $s_host ne $host;
207             }
208             elsif ($s_host ne ''
209             && $host !~ /\.$s_host$/
210             && $host ne $s_host )
211             {
212             return 0;
213             }
214              
215             if ( $path ne $self->path ) {
216             my $path_length = length( $self->path );
217             my $prefix = substr( $path, 0, $path_length );
218              
219             return 0 if $self->path ne $prefix;
220             my $allowed = ( index( $self->path, q{?} ) >= 0 ) ? q{&} : q{?/};
221              
222             return (
223             index( $allowed, substr( $self->path, -1 ) ) >= 0
224             || index( $allowed, substr( $path, $path_length, 1 ) ) >= 0
225             ) ? 1 : 0;
226             }
227              
228             return 1;
229             }
230              
231             no Any::Moose;
232             __PACKAGE__->meta->make_immutable;
233             1;
234