File Coverage

blib/lib/OpenID/Login/Extension.pm
Criterion Covered Total %
statement 63 69 91.3
branch 9 18 50.0
condition 1 3 33.3
subroutine 10 10 100.0
pod 3 3 100.0
total 86 103 83.5


line stmt bran cond sub pod time code
1             package OpenID::Login::Extension;
2             {
3             $OpenID::Login::Extension::VERSION = '0.1.2';
4             }
5              
6             # ABSTRACT: Storage and methods for OpenId extensions, both requesting information and receiving data.
7              
8 4     4   21 use Moose 0.51;
  4         114  
  4         35  
9              
10              
11             has ns => (
12             is => 'rw',
13             isa => 'Str',
14             required => 1,
15             );
16              
17              
18             has uri => (
19             is => 'rw',
20             isa => 'Str',
21             required => 1,
22             );
23              
24              
25             has attributes => (
26             is => 'rw',
27             isa => 'HashRef',
28             required => 1,
29             trigger => \&_flatten_attributes,
30             );
31              
32             around BUILDARGS => sub {
33             my $orig = shift;
34             my $class = shift;
35              
36             my $args;
37             if ( @_ == 1 && ref $_[0] eq 'HASH' ) {
38             $args = $_[0];
39             } else {
40             $args = {@_};
41             }
42             if ( $args->{cgi} or $args->{cgi_params} ) {
43             my $new_args;
44             if ( $args->{uri} ) {
45             $new_args = _extract_attributes_by_uri($args);
46             } elsif ( $args->{ns} ) {
47             $new_args = _extract_attributes_by_ns($args);
48             } else {
49             die 'Unable to determine extension details';
50             }
51             return $class->$orig($new_args);
52             } else {
53             return $class->$orig(@_);
54             }
55             };
56              
57             sub _extract_attributes_by_uri {
58 1     1   1 my $args = shift;
59              
60 1         5 my $cgi = $args->{cgi};
61 1         2 my $cgi_params = $args->{cgi_params};
62 1         4 my $uri = $args->{uri};
63              
64 1 50       7 my @openid_params = grep {/^openid\./} $cgi ? $cgi->param() : keys %$cgi_params;
  18         57  
65 1 50       4 ( my $ns_param ) = grep { ( $cgi ? $cgi->param($_) : $cgi_params->{$_} ) eq $uri } grep {/^openid\.ns\./} @openid_params;
  1         8  
  18         31  
66 1 50       29 if ($ns_param) {
67 1         5 $args->{ns} = substr( $ns_param, 10 );
68 1         4 return _extract_attributes_by_ns($args);
69             }
70              
71 0         0 return $args;
72             }
73              
74             sub _extract_attributes_by_ns {
75 1     1   2 my $args = shift;
76              
77 1         3 my $cgi = $args->{cgi};
78 1         3 my $cgi_params = $args->{cgi_params};
79 1         2 my $ns = $args->{ns};
80              
81 1 0 33     4 $args->{uri} ||= $cgi ? $cgi->param("openid.ns.$ns") : $cgi_params->{"openid.ns.$ns"};
82              
83 1         4 my $prefix = "openid.$ns.";
84 1         1 my $prefix_len = length($prefix);
85 1         3 my %attributes;
86 1 50       4 if ($cgi) {
87 1         82 my %signed_params = map { ( "openid.$_" => 1 ) } split /,/, $cgi->param('openid.signed');
  14         53  
88 1 100       8 %attributes = ( map { substr( $_, $prefix_len ) => scalar $cgi->param($_) } grep { /^\Q$prefix\E/ and $signed_params{$_} } $cgi->param() );
  7         114  
  18         96  
89             } else {
90 0         0 my %signed_params = map { ( "openid.$_" => 1 ) } split /,/, $cgi_params->{'openid.signed'};
  0         0  
91 0 0       0 %attributes = ( map { substr( $_, $prefix_len ) => $cgi_params->{$_} } grep { /^\Q$prefix\E/ and $signed_params{$_} } keys %$cgi_params );
  0         0  
  0         0  
92             }
93 1         23 $args->{attributes} = \%attributes;
94              
95 1         5 return $args;
96             }
97              
98              
99             sub get_parameter_string {
100 6     6 1 9 my $self = shift;
101 6         224 my $ns = $self->ns;
102              
103 6         249 my $params = sprintf 'openid.ns.%s=%s', $ns, $self->uri;
104              
105 6         227 my $attributes = $self->attributes;
106 6         21 $params .= _parameterise_hash( "openid.$ns", $attributes );
107              
108 6         34 return $params;
109             }
110              
111             sub _parameterise_hash {
112 6     6   9 my $prefix = shift;
113 6         8 my $hash = shift;
114              
115 6         8 my $params = '';
116 6         61 $params .= sprintf '&%s.%s=%s', $prefix, $_, $hash->{$_} foreach ( sort keys %$hash );
117 6         21 return $params;
118             }
119              
120              
121             sub get_parameter {
122 3     3 1 11 my $self = shift;
123 3         4 my $param = shift;
124              
125 3 50       114 die "$param is not an available parameter" unless exists $self->attributes->{$param};
126 3         113 return $self->attributes->{$param};
127             }
128              
129              
130             sub set_parameter {
131 3     3 1 7 my $self = shift;
132 3         12 my %params = @_;
133              
134 3         12 _flatten_hash( \%params );
135              
136 3         131 $self->attributes->{$_} = $params{$_} foreach keys %params;
137             }
138              
139             sub _flatten_attributes {
140 3     3   5 my $self = shift;
141 3         4 my $attributes = shift;
142              
143 3         9 _flatten_hash($attributes);
144             }
145              
146             sub _flatten_hash {
147 8     8   11 my $hash = shift;
148              
149 8         29 foreach my $key ( keys %$hash ) {
150 18         23 my $value = $hash->{$key};
151 18 100       166 if ( ref $value eq 'HASH' ) {
152 2         10 _flatten_hash($value);
153 2         21 $hash->{"$key.$_"} = $value->{$_} foreach keys %$value;
154 2         9 delete $hash->{$key};
155             }
156             }
157             }
158              
159 4     4   33189 no Moose;
  4         9  
  4         40  
160             __PACKAGE__->meta->make_immutable;
161             1;
162              
163              
164              
165             =pod
166              
167             =head1 NAME
168              
169             OpenID::Login::Extension - Storage and methods for OpenId extensions, both requesting information and receiving data.
170              
171             =head1 VERSION
172              
173             version 0.1.2
174              
175             =head1 ATTRIBUTES
176              
177             =head2 ns
178              
179             The namespace to use for this extension (eg 'ax' is the one usually used in documentation about attribute exchange).
180              
181             =head2 uri
182              
183             The type URI for the extension (eg attribute exchange has L<http://openid.net/srv/ax/1.0>).
184              
185             =head2 attributes
186              
187             The attributes for the extension (everything under openid.[ns].*), stored as a hashref. Internally this
188             is flattened to a single hashref, but a tree structure can be passed in, and intermediate keys will be
189             linked together with '.'.
190              
191             =head1 METHODS
192              
193             =head2 get_parameter_string
194              
195             Collect the internal attributes, and create a single string representing the query of this extension object,
196             usable for an OpenID request.
197              
198             =head2 get_parameter
199              
200             Get a single extension parameter, this is most likely to be used for extensions that are
201             the result of a request (rather than when creating a request).
202              
203             =head2 set_parameter
204              
205             Set an extension parameter (or several parameters). Nested parameters are allowed, i.e.
206              
207             C<< $extension->set_parameter(type => {firstname => 'q1', lastname => 'q2'}); >>
208              
209             is equivalent to:
210              
211             C<< $extension->set_parameter('type.firstname' => 'q1', 'type.lastname' => 'q2'); >>
212              
213             and neither approach will clear any other C<type.*> values that may already be set.
214              
215             =head1 AUTHOR
216              
217             Holger Eiboeck <realholgi@cpan.org>
218              
219             =head1 COPYRIGHT AND LICENSE
220              
221             This software is copyright (c) 2013 by Holger Eiboeck.
222              
223             This is free software; you can redistribute it and/or modify it under
224             the same terms as the Perl 5 programming language system itself.
225              
226             =cut
227              
228              
229             __END__
230              
231