root/trunk/extlib/Net/OpenID/IndirectMessage.pm @ 3531

Revision 3531, 7.9 kB (checked in by fumiakiy, 9 months ago)

Merged sockfish to trunk. "svn merge -r3114:3527 http://code.sixapart.com/svn/movabletype/branches/sockfish/ ."

Line 
1
2package Net::OpenID::IndirectMessage;
3
4use strict;
5use Carp;
6use Net::OpenID::Consumer;
7
8sub new {
9    my $class = shift;
10    my $what = shift;
11    my %opts = @_;
12
13    my $self = bless {}, $class;
14
15    $self->{minimum_version} = delete $opts{minimum_version};
16
17    Carp::croak("Unknown options: " . join(", ", keys %opts)) if %opts;
18
19    my $getter;
20    my $enumer;
21    if (ref $what eq "HASH") {
22        # In this case it's the caller's responsibility to determine
23        # whether the method is GET or POST.
24        $getter = sub { $what->{$_[0]}; };
25        $enumer = sub { keys(%$what); };
26    }
27    elsif (UNIVERSAL::isa($what, "CGI")) {
28        # CGI automatically does what we need when method is POST
29        $getter = sub { scalar $what->param($_[0]); };
30        $enumer = sub { $what->param; };
31    }
32    elsif (ref $what eq "Apache") {
33        my %get;
34        if ($what->method eq 'POST') {
35            %get = $what->content;
36        }
37        else {
38            %get = $what->args;
39        }
40        $getter = sub { $get{$_[0]}; };
41        $enumer = sub { keys(%get); };
42    }
43    elsif (ref $what eq "Apache::Request") {
44        # Apache::Request includes the POST and GET arguments in ->param
45        # when doing a POST request, which is close enough to what
46        # the spec requires.
47        $getter = sub { scalar $what->param($_[0]); };
48        $enumer = sub { $what->param; };
49    }
50    elsif (ref $what eq "CODE") {
51        $getter = $what;
52        # We can't enumerate with just a coderef.
53        # OpenID 2 spec only requires enumeration to support
54        # extension namespaces, so we don't care too much.
55        $enumer = sub { return (); };
56    }
57    else {
58        $what = 'undef' if !defined $what;
59        Carp::croak("Unknown parameter type ($what)");
60    }
61    $self->{getter} = $getter;
62    $self->{enumer} = $enumer;
63
64    # Now some quick pre-configuration of a few bits
65
66    # Is this an OpenID message at all?
67    # All OpenID messages have an openid.mode value...
68    return undef unless $self->get('mode');
69
70    # Is this an OpenID 2.0 message?
71    my $ns = $self->get('ns');
72
73
74    # The 2.0 spec section 4.1.2 requires that we support these namespace values
75    # but act like it's a normal 1.1 request.
76    # We do this by just pretending that ns wasn't set at all.
77    if ($ns && ($ns eq 'http://openid.net/signon/1.1' || $ns eq 'http://openid.net/signon/1.0')) {
78        $ns = undef;
79    }
80
81    if (defined($ns) && $ns eq OpenID::util::version_2_namespace()) {
82        $self->{protocol_version} = 2;
83    }
84    elsif (! defined($ns)) {
85        # No namespace at all means a 1.1 message
86        if (($self->{minimum_version}||0) <= 1) {
87            $self->{protocol_version} = 1;
88        }
89        else {
90            # Pretend we don't understand the message.
91            return undef;
92        }
93    }
94    else {
95        # Unknown version is the same as not being an OpenID message at all
96        return undef;
97    }
98
99    # This will be populated in on demand
100    $self->{extension_prefixes} = undef;
101
102    return $self;
103}
104
105sub protocol_version {
106    return $_[0]->{protocol_version};
107}
108
109sub mode {
110    my $self = shift;
111    return $self->get('mode');
112}
113
114sub get {
115    my $self = shift;
116    my $key = shift or Carp::croak("No argument name supplied to get method");
117
118    # NOTE: There is intentionally no way to get all of the keys in the core
119    # namespace because that means we don't need to be able to enumerate
120    # to support the core protocol, and there is no requirement to enumerate
121    # anyway.
122
123    # Arguments can only contain letters, numbers, underscores and dashes
124    Carp::croak("Invalid argument key $key") unless $key =~ /^[\w\-]+$/;
125    Carp::croak("Too many arguments") if scalar(@_);
126
127    return $self->{getter}->("openid.$key");
128}
129
130sub raw_get {
131    my $self = shift;
132    my $key = shift or Carp::croak("No argument name supplied to raw_get method");
133
134    return $self->{getter}->($key);
135}
136
137sub getter {
138    my $self = shift;
139
140    return $self->{getter};
141}
142
143sub get_ext {
144    my $self = shift;
145    my $namespace = shift or Carp::croak("No namespace URI supplied to get_ext method");
146    my $key = shift;
147
148    Carp::croak("Too many arguments") if scalar(@_);
149
150    $self->_compute_extension_prefixes() unless defined($self->{extension_prefixes});
151
152    my $alias = $self->{extension_prefixes}{$namespace};
153    return $key ? undef : {} unless $alias;
154
155    if ($key) {
156        return $self->{getter}->("openid.$alias.$key");
157    }
158    else {
159        my $prefix = "openid.$alias.";
160        my $prefixlen = length($prefix);
161        my $ret = {};
162        foreach my $key ($self->{enumer}->()) {
163            next unless substr($key, 0, $prefixlen) eq $prefix;
164            $ret->{substr($key, $prefixlen)} = $self->{getter}->($key);
165        }
166        return $ret;
167    }
168}
169
170sub has_ext {
171    my $self = shift;
172    my $namespace = shift or Carp::croak("No namespace URI supplied to get_ext method");
173
174    Carp::croak("Too many arguments") if scalar(@_);
175
176    $self->_compute_extension_prefixes() unless defined($self->{extension_prefixes});
177
178    return defined($self->{extension_prefixes}{$namespace}) ? 1 : 0;
179}
180
181sub _compute_extension_prefixes {
182    my ($self) = @_;
183
184    return unless $self->{enumer};
185
186    $self->{extension_prefixes} = {};
187    if ($self->protocol_version != 1) {
188        foreach my $key ($self->{enumer}->()) {
189            next unless $key =~ /^openid\.ns\.(\w+)$/;
190            my $alias = $1;
191            my $uri = $self->{getter}->($key);
192            $self->{extension_prefixes}{$uri} = $alias;
193        }
194    }
195    else {
196        # Synthesize the SREG namespace as it was used in OpenID 1.1
197        $self->{extension_prefixes}{"http://openid.net/extensions/sreg/1.1"} = "sreg";
198    }
199}
200
2011;
202
203=head1 NAME
204
205Net::OpenID::IndirectMessage - Class representing a collection of namespaced arguments
206
207=head1 DESCRIPTION
208
209This class acts as an abstraction layer over a collection of flat URL arguments
210which supports namespaces as defined by the OpenID Auth 2.0 specification.
211
212It also recognises when its is given OpenID 1.1 non-namespaced arguments and
213acts as if the relevant namespaces were present. In this case, it only
214supports the basic OpenID 1.1 arguments and the extension arguments
215for Simple Registration.
216
217This class can operate on a normal hashref, a L<CGI> object, an L<Apache>
218object, an L<Apache::Request> object or an arbitrary C<CODE> ref that takes
219a key name as its first parameter and returns a value. However,
220if you use a coderef then extension arguments are not supported.
221
222If you pass in a hashref or a coderef it is your responsibility as the caller
223to check the HTTP request method and pass in the correct set of arguments. If
224you use an Apache, Apache::Request or CGI object then this module will do
225the right thing automatically.
226
227=head1 SYNOPSIS
228
229    use Net::OpenID::IndirectMessage;
230   
231    # Pass in something suitable for the underlying flat dictionary.
232    # Will return an instance if the request arguments can be understood
233    # as a supported OpenID Message format.
234    # Will return undef if this doesn't seem to be an OpenID Auth message.
235    # Will croak if the $argumenty_thing is not of a suitable type.
236    my $args = Net::OpenID::IndirectMessage->new($argumenty_thing);
237   
238    # Determine which protocol version the message is using.
239    # Currently this can be either 1 for 1.1 or 2 for 2.0.
240    # Expect larger numbers for other versions in future.
241    # Most callers don't really need to care about this.
242    my $version = $args->protocol_version();
243   
244    # Get a core argument value ("openid.mode")
245    my $mode = $args->get("mode");
246   
247    # Get an extension argument value
248    my $nickname = $args->get_ext("http://openid.net/extensions/sreg/1.1", "nickname");
249   
250    # Get hashref of all arguments in a given namespace
251    my $sreg = $args->get_ext("http://openid.net/extensions/sreg/1.1");
252
253Most of the time callers won't need to use this class directly, but will instead
254access it through a L<Net::OpenID::Consumer> instance.
255
Note: See TracBrowser for help on using the browser.