Merge lp:ubuntu-uy-website into lp:ubuntu-uy-website/trunk

Proposed by Pablo Rubianes
Status: Merged
Merged at revision: 33
Proposed branch: lp:ubuntu-uy-website
Merge into: lp:ubuntu-uy-website/trunk
Diff against target: 101482 lines (+82070/-17446)
270 files modified
Auth/OpenID.php (+563/-0)
Auth/OpenID/AX.php (+1022/-0)
Auth/OpenID/Association.php (+610/-0)
Auth/OpenID/BigMath.php (+452/-0)
Auth/OpenID/Consumer.php (+2230/-0)
Auth/OpenID/CryptUtil.php (+108/-0)
Auth/OpenID/DatabaseConnection.php (+130/-0)
Auth/OpenID/DiffieHellman.php (+113/-0)
Auth/OpenID/Discover.php (+606/-0)
Auth/OpenID/DumbStore.php (+99/-0)
Auth/OpenID/Extension.php (+61/-0)
Auth/OpenID/FileStore.php (+618/-0)
Auth/OpenID/HMAC.php (+98/-0)
Auth/OpenID/Interface.php (+196/-0)
Auth/OpenID/KVForm.php (+111/-0)
Auth/OpenID/MDB2Store.php (+413/-0)
Auth/OpenID/MemcachedStore.php (+207/-0)
Auth/OpenID/Message.php (+920/-0)
Auth/OpenID/MySQLStore.php (+77/-0)
Auth/OpenID/Nonce.php (+108/-0)
Auth/OpenID/PAPE.php (+300/-0)
Auth/OpenID/Parse.php (+377/-0)
Auth/OpenID/PostgreSQLStore.php (+112/-0)
Auth/OpenID/SQLStore.php (+557/-0)
Auth/OpenID/SQLiteStore.php (+70/-0)
Auth/OpenID/SReg.php (+521/-0)
Auth/OpenID/Server.php (+1765/-0)
Auth/OpenID/ServerRequest.php (+36/-0)
Auth/OpenID/TrustRoot.php (+461/-0)
Auth/OpenID/URINorm.php (+249/-0)
Auth/Yadis/HTTPFetcher.php (+174/-0)
Auth/Yadis/Manager.php (+521/-0)
Auth/Yadis/Misc.php (+58/-0)
Auth/Yadis/ParanoidHTTPFetcher.php (+245/-0)
Auth/Yadis/ParseHTML.php (+258/-0)
Auth/Yadis/PlainHTTPFetcher.php (+248/-0)
Auth/Yadis/XML.php (+352/-0)
Auth/Yadis/XRDS.php (+478/-0)
Auth/Yadis/XRI.php (+234/-0)
Auth/Yadis/XRIRes.php (+72/-0)
Auth/Yadis/Yadis.php (+382/-0)
Doc/BluePrints.txt (+14/-0)
Doc/COPYRIGHT.txt (+22/-0)
Doc/LICENCE.txt (+133/-0)
Doc/LICENCIA.txt (+117/-0)
Doc/Launchpad.txt (+7/-0)
Doc/Readme.txt (+86/-0)
Doc/openid/Auth/OpenID.php (+552/-0)
Doc/openid/Auth/OpenID/AX.php (+1023/-0)
Doc/openid/Auth/OpenID/Association.php (+613/-0)
Doc/openid/Auth/OpenID/BigMath.php (+471/-0)
Doc/openid/Auth/OpenID/Consumer.php (+2227/-0)
Doc/openid/Auth/OpenID/CryptUtil.php (+109/-0)
Doc/openid/Auth/OpenID/DatabaseConnection.php (+131/-0)
Doc/openid/Auth/OpenID/DiffieHellman.php (+113/-0)
Doc/openid/Auth/OpenID/Discover.php (+548/-0)
Doc/openid/Auth/OpenID/DumbStore.php (+100/-0)
Doc/openid/Auth/OpenID/Extension.php (+62/-0)
Doc/openid/Auth/OpenID/FileStore.php (+618/-0)
Doc/openid/Auth/OpenID/HMAC.php (+99/-0)
Doc/openid/Auth/OpenID/Interface.php (+197/-0)
Doc/openid/Auth/OpenID/KVForm.php (+112/-0)
Doc/openid/Auth/OpenID/MemcachedStore.php (+208/-0)
Doc/openid/Auth/OpenID/Message.php (+915/-0)
Doc/openid/Auth/OpenID/MySQLStore.php (+78/-0)
Doc/openid/Auth/OpenID/Nonce.php (+109/-0)
Doc/openid/Auth/OpenID/PAPE.php (+301/-0)
Doc/openid/Auth/OpenID/Parse.php (+352/-0)
Doc/openid/Auth/OpenID/PostgreSQLStore.php (+113/-0)
Doc/openid/Auth/OpenID/SQLStore.php (+569/-0)
Doc/openid/Auth/OpenID/SQLiteStore.php (+71/-0)
Doc/openid/Auth/OpenID/SReg.php (+521/-0)
Doc/openid/Auth/OpenID/Server.php (+1754/-0)
Doc/openid/Auth/OpenID/ServerRequest.php (+37/-0)
Doc/openid/Auth/OpenID/TrustRoot.php (+462/-0)
Doc/openid/Auth/OpenID/URINorm.php (+249/-0)
Doc/openid/Auth/Yadis/HTTPFetcher.php (+147/-0)
Doc/openid/Auth/Yadis/Manager.php (+529/-0)
Doc/openid/Auth/Yadis/Misc.php (+59/-0)
Doc/openid/Auth/Yadis/ParanoidHTTPFetcher.php (+228/-0)
Doc/openid/Auth/Yadis/ParseHTML.php (+259/-0)
Doc/openid/Auth/Yadis/PlainHTTPFetcher.php (+251/-0)
Doc/openid/Auth/Yadis/XML.php (+374/-0)
Doc/openid/Auth/Yadis/XRDS.php (+478/-0)
Doc/openid/Auth/Yadis/XRI.php (+234/-0)
Doc/openid/Auth/Yadis/XRIRes.php (+72/-0)
Doc/openid/Auth/Yadis/Yadis.php (+382/-0)
Doc/openid/conectar.html (+28/-0)
Doc/openid/conectar.php (+28/-0)
Doc/openid/config.php (+12/-0)
Doc/openid/formulario-registro.php (+114/-0)
Doc/openid/index.html (+44/-0)
Doc/openid/login.php (+42/-0)
Doc/openid/logout.php (+7/-0)
Doc/openid/openid.php (+40/-0)
Doc/openid/openid_return.php (+64/-0)
Doc/openid/usuarios.sql (+8/-0)
Doc/openid/zona-restringida.php (+10/-0)
Readme.txt (+0/-18)
SQL/locoportal.sql (+103/-0)
admin/css/UnitySlide.css (+313/-0)
admin/css/Unityslide.css (+311/-0)
admin/css/default.css (+334/-0)
admin/css/ie.css (+299/-0)
admin/css/ie6.css (+301/-0)
admin/css/lightbox.css (+27/-0)
admin/css/wireframe-default.css (+120/-0)
admin/css/wireframe-ie.css (+123/-0)
admin/css/wireframe-ie6.css (+123/-0)
admin/highslide/highslide-full.js (+3302/-0)
admin/highslide/highslide-full.min.js (+9/-0)
admin/highslide/highslide-full.packed.js (+9/-0)
admin/highslide/highslide-ie6.css (+76/-0)
admin/highslide/highslide-with-gallery.js (+2639/-0)
admin/highslide/highslide-with-gallery.min.js (+9/-0)
admin/highslide/highslide-with-gallery.packed.js (+9/-0)
admin/highslide/highslide-with-html.js (+2477/-0)
admin/highslide/highslide-with-html.min.js (+9/-0)
admin/highslide/highslide-with-html.packed.js (+9/-0)
admin/highslide/highslide.css (+886/-0)
admin/highslide/highslide.js (+1886/-0)
admin/highslide/highslide.min.js (+9/-0)
admin/highslide/highslide.packed.js (+9/-0)
admin/index.php (+84/-0)
admin/js/builder.js (+136/-0)
admin/js/effects.js (+1123/-0)
admin/js/lightbox-web.js (+497/-0)
admin/js/lightbox.js (+496/-0)
admin/js/main.js (+43/-0)
admin/js/pngFix.js (+13/-0)
admin/js/prototype.js (+6081/-0)
admin/js/scriptaculous.js (+68/-0)
admin/js/ventanas.js (+20/-0)
admin/template.php (+61/-0)
auth.php (+84/-0)
calendario.php (+82/-115)
cerrar.php (+11/-0)
common.php (+97/-0)
conex.php (+14/-14)
css/default.css (+23/-5)
css/lightbox.css (+27/-0)
enviarPedido.php (+107/-0)
estadisticas.php (+42/-45)
examples/ajax.html (+51/-0)
examples/flash.html (+61/-0)
examples/gallery-controls-in-heading.html (+89/-0)
examples/gallery-dark.html (+93/-0)
examples/gallery-floating-caption.html (+91/-0)
examples/gallery-floating-thumbs.html (+144/-0)
examples/gallery-horizontal-strip.html (+147/-0)
examples/gallery-in-box.html (+95/-0)
examples/gallery-in-page.html (+221/-0)
examples/gallery-thumbstrip-above.html (+142/-0)
examples/gallery-vertical-strip.html (+178/-0)
examples/gallery-white.html (+90/-0)
examples/headline.html (+49/-0)
examples/html.html (+67/-0)
examples/iframe.html (+44/-0)
examples/image-map.html (+49/-0)
examples/includes/ajax.htm (+45/-0)
examples/includes/include-short.htm (+40/-0)
examples/inline.html (+50/-0)
examples/mini-galleries.html (+135/-0)
examples/mini-gallery.html (+89/-0)
examples/no-border.html (+62/-0)
examples/no-outline.html (+52/-0)
examples/outer-glow.html (+53/-0)
examples/white-10px.html (+51/-0)
examples/white-rounded-outline.html (+51/-0)
examples/youtube.html (+62/-0)
finish_auth.php (+97/-0)
footer.php (+90/-93)
highslide/highslide-full.js (+3302/-0)
highslide/highslide-full.min.js (+9/-0)
highslide/highslide-full.packed.js (+9/-0)
highslide/highslide-ie6.css (+76/-0)
highslide/highslide-with-gallery.js (+2639/-0)
highslide/highslide-with-gallery.min.js (+9/-0)
highslide/highslide-with-gallery.packed.js (+9/-0)
highslide/highslide-with-html.js (+2477/-0)
highslide/highslide-with-html.min.js (+9/-0)
highslide/highslide-with-html.packed.js (+9/-0)
highslide/highslide.css (+886/-0)
highslide/highslide.js (+1886/-0)
highslide/highslide.min.js (+9/-0)
highslide/highslide.packed.js (+9/-0)
index.php (+193/-157)
irc.php (+57/-51)
js/builder.js (+136/-0)
js/effects.js (+1123/-0)
js/lightbox-web.js (+497/-0)
js/lightbox.js (+496/-0)
js/prototype.js (+6081/-0)
js/scriptaculous.js (+68/-0)
live.php (+3/-2)
login/Auth/OpenID.php (+0/-563)
login/Auth/OpenID/AX.php (+0/-1022)
login/Auth/OpenID/Association.php (+0/-610)
login/Auth/OpenID/BigMath.php (+0/-452)
login/Auth/OpenID/Consumer.php (+0/-2230)
login/Auth/OpenID/CryptUtil.php (+0/-108)
login/Auth/OpenID/DatabaseConnection.php (+0/-130)
login/Auth/OpenID/DiffieHellman.php (+0/-113)
login/Auth/OpenID/Discover.php (+0/-606)
login/Auth/OpenID/DumbStore.php (+0/-99)
login/Auth/OpenID/Extension.php (+0/-61)
login/Auth/OpenID/FileStore.php (+0/-618)
login/Auth/OpenID/HMAC.php (+0/-98)
login/Auth/OpenID/Interface.php (+0/-196)
login/Auth/OpenID/KVForm.php (+0/-111)
login/Auth/OpenID/MDB2Store.php (+0/-413)
login/Auth/OpenID/MemcachedStore.php (+0/-207)
login/Auth/OpenID/Message.php (+0/-920)
login/Auth/OpenID/MySQLStore.php (+0/-77)
login/Auth/OpenID/Nonce.php (+0/-108)
login/Auth/OpenID/PAPE.php (+0/-300)
login/Auth/OpenID/Parse.php (+0/-377)
login/Auth/OpenID/PostgreSQLStore.php (+0/-112)
login/Auth/OpenID/SQLStore.php (+0/-557)
login/Auth/OpenID/SQLiteStore.php (+0/-70)
login/Auth/OpenID/SReg.php (+0/-521)
login/Auth/OpenID/Server.php (+0/-1765)
login/Auth/OpenID/ServerRequest.php (+0/-36)
login/Auth/OpenID/TrustRoot.php (+0/-461)
login/Auth/OpenID/URINorm.php (+0/-249)
login/Auth/Yadis/HTTPFetcher.php (+0/-174)
login/Auth/Yadis/Manager.php (+0/-521)
login/Auth/Yadis/Misc.php (+0/-58)
login/Auth/Yadis/ParanoidHTTPFetcher.php (+0/-245)
login/Auth/Yadis/ParseHTML.php (+0/-258)
login/Auth/Yadis/PlainHTTPFetcher.php (+0/-248)
login/Auth/Yadis/XML.php (+0/-352)
login/Auth/Yadis/XRDS.php (+0/-478)
login/Auth/Yadis/XRI.php (+0/-234)
login/Auth/Yadis/XRIRes.php (+0/-72)
login/Auth/Yadis/Yadis.php (+0/-382)
login/conectar.php (+0/-28)
login/config.php (+0/-12)
login/formulario-registro.php (+0/-114)
login/index.html (+0/-44)
login/login.php (+0/-42)
login/logout.php (+0/-7)
login/openid.php (+0/-42)
login/openid_return.php (+0/-72)
login/usuarios.sql (+0/-8)
login/zona-restringida.php (+0/-10)
menu.php (+37/-16)
planet/uyplanet/config.php (+66/-0)
planet/uyplanet/css/2c-r-fixed.css (+68/-0)
planet/uyplanet/css/images.css (+64/-0)
planet/uyplanet/css/reset.css (+64/-0)
planet/uyplanet/css/typography.css (+141/-0)
planet/uyplanet/index.php (+169/-0)
planet/uyplanet/magpierss/extlib/Snoopy.class.inc (+900/-0)
planet/uyplanet/magpierss/rss_cache.inc (+200/-0)
planet/uyplanet/magpierss/rss_fetch.inc (+458/-0)
planet/uyplanet/magpierss/rss_parse.inc (+605/-0)
planet/uyplanet/magpierss/rss_utils.inc (+67/-0)
planet/uyplanet/planet.php (+57/-0)
planet/uyplanet/style.css (+274/-0)
shipituy.php (+275/-0)
shipituypopup.php (+264/-0)
slide/fotos-uy.html (+14/-11)
slide/novedades.html (+1/-0)
slide/webdevel.html (+1/-0)
template.php (+82/-78)
ubuntu.php (+120/-123)
unity.php (+95/-127)
webdevel.php (+222/-0)
webdevel/website.xhtml (+130/-0)
To merge this branch: bzr merge lp:ubuntu-uy-website
Reviewer Review Type Date Requested Status
Pablo Rubianes Approve
Review via email: mp+65112@code.launchpad.net

This proposal has been superseded by a proposal from 2011-06-20.

Commit message

Se aprueba el merge de la version 1.0

Description of the change

Pasar a trunk todo el desarollo de la version 1.0

To post a comment you must log in.
Revision history for this message
Pablo Rubianes (pablorubianes-uy) wrote :

Se aprueba

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'Auth'
2=== added directory 'Auth/OpenID'
3=== added file 'Auth/OpenID.php'
4--- Auth/OpenID.php 1970-01-01 00:00:00 +0000
5+++ Auth/OpenID.php 2011-06-19 04:48:34 +0000
6@@ -0,0 +1,563 @@
7+<?php
8+
9+/**
10+ * This is the PHP OpenID library by JanRain, Inc.
11+ *
12+ * This module contains core utility functionality used by the
13+ * library. See Consumer.php and Server.php for the consumer and
14+ * server implementations.
15+ *
16+ * PHP versions 4 and 5
17+ *
18+ * LICENSE: See the COPYING file included in this distribution.
19+ *
20+ * @package OpenID
21+ * @author JanRain, Inc. <openid@janrain.com>
22+ * @copyright 2005-2008 Janrain, Inc.
23+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
24+ */
25+
26+/**
27+ * The library version string
28+ */
29+define('Auth_OpenID_VERSION', '2.2.2');
30+
31+/**
32+ * Require the fetcher code.
33+ */
34+require_once "Auth/Yadis/PlainHTTPFetcher.php";
35+require_once "Auth/Yadis/ParanoidHTTPFetcher.php";
36+require_once "Auth/OpenID/BigMath.php";
37+require_once "Auth/OpenID/URINorm.php";
38+
39+/**
40+ * Status code returned by the server when the only option is to show
41+ * an error page, since we do not have enough information to redirect
42+ * back to the consumer. The associated value is an error message that
43+ * should be displayed on an HTML error page.
44+ *
45+ * @see Auth_OpenID_Server
46+ */
47+define('Auth_OpenID_LOCAL_ERROR', 'local_error');
48+
49+/**
50+ * Status code returned when there is an error to return in key-value
51+ * form to the consumer. The caller should return a 400 Bad Request
52+ * response with content-type text/plain and the value as the body.
53+ *
54+ * @see Auth_OpenID_Server
55+ */
56+define('Auth_OpenID_REMOTE_ERROR', 'remote_error');
57+
58+/**
59+ * Status code returned when there is a key-value form OK response to
60+ * the consumer. The value associated with this code is the
61+ * response. The caller should return a 200 OK response with
62+ * content-type text/plain and the value as the body.
63+ *
64+ * @see Auth_OpenID_Server
65+ */
66+define('Auth_OpenID_REMOTE_OK', 'remote_ok');
67+
68+/**
69+ * Status code returned when there is a redirect back to the
70+ * consumer. The value is the URL to redirect back to. The caller
71+ * should return a 302 Found redirect with a Location: header
72+ * containing the URL.
73+ *
74+ * @see Auth_OpenID_Server
75+ */
76+define('Auth_OpenID_REDIRECT', 'redirect');
77+
78+/**
79+ * Status code returned when the caller needs to authenticate the
80+ * user. The associated value is a {@link Auth_OpenID_ServerRequest}
81+ * object that can be used to complete the authentication. If the user
82+ * has taken some authentication action, use the retry() method of the
83+ * {@link Auth_OpenID_ServerRequest} object to complete the request.
84+ *
85+ * @see Auth_OpenID_Server
86+ */
87+define('Auth_OpenID_DO_AUTH', 'do_auth');
88+
89+/**
90+ * Status code returned when there were no OpenID arguments
91+ * passed. This code indicates that the caller should return a 200 OK
92+ * response and display an HTML page that says that this is an OpenID
93+ * server endpoint.
94+ *
95+ * @see Auth_OpenID_Server
96+ */
97+define('Auth_OpenID_DO_ABOUT', 'do_about');
98+
99+/**
100+ * Defines for regexes and format checking.
101+ */
102+define('Auth_OpenID_letters',
103+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
104+
105+define('Auth_OpenID_digits',
106+ "0123456789");
107+
108+define('Auth_OpenID_punct',
109+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~");
110+
111+Auth_OpenID_include_init();
112+
113+/**
114+ * The OpenID utility function class.
115+ *
116+ * @package OpenID
117+ * @access private
118+ */
119+class Auth_OpenID {
120+
121+ /**
122+ * Return true if $thing is an Auth_OpenID_FailureResponse object;
123+ * false if not.
124+ *
125+ * @access private
126+ */
127+ static function isFailure($thing)
128+ {
129+ return is_a($thing, 'Auth_OpenID_FailureResponse');
130+ }
131+
132+ /**
133+ * Gets the query data from the server environment based on the
134+ * request method used. If GET was used, this looks at
135+ * $_SERVER['QUERY_STRING'] directly. If POST was used, this
136+ * fetches data from the special php://input file stream.
137+ *
138+ * Returns an associative array of the query arguments.
139+ *
140+ * Skips invalid key/value pairs (i.e. keys with no '=value'
141+ * portion).
142+ *
143+ * Returns an empty array if neither GET nor POST was used, or if
144+ * POST was used but php://input cannot be opened.
145+ *
146+ * See background:
147+ * http://lists.openidenabled.com/pipermail/dev/2007-March/000395.html
148+ *
149+ * @access private
150+ */
151+ static function getQuery($query_str=null)
152+ {
153+ $data = array();
154+
155+ if ($query_str !== null) {
156+ $data = Auth_OpenID::params_from_string($query_str);
157+ } else if (!array_key_exists('REQUEST_METHOD', $_SERVER)) {
158+ // Do nothing.
159+ } else {
160+ // XXX HACK FIXME HORRIBLE.
161+ //
162+ // POSTing to a URL with query parameters is acceptable, but
163+ // we don't have a clean way to distinguish those parameters
164+ // when we need to do things like return_to verification
165+ // which only want to look at one kind of parameter. We're
166+ // going to emulate the behavior of some other environments
167+ // by defaulting to GET and overwriting with POST if POST
168+ // data is available.
169+ $data = Auth_OpenID::params_from_string($_SERVER['QUERY_STRING']);
170+
171+ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
172+ $str = file_get_contents('php://input');
173+
174+ if ($str === false) {
175+ $post = array();
176+ } else {
177+ $post = Auth_OpenID::params_from_string($str);
178+ }
179+
180+ $data = array_merge($data, $post);
181+ }
182+ }
183+
184+ return $data;
185+ }
186+
187+ static function params_from_string($str)
188+ {
189+ $chunks = explode("&", $str);
190+
191+ $data = array();
192+ foreach ($chunks as $chunk) {
193+ $parts = explode("=", $chunk, 2);
194+
195+ if (count($parts) != 2) {
196+ continue;
197+ }
198+
199+ list($k, $v) = $parts;
200+ $data[urldecode($k)] = urldecode($v);
201+ }
202+
203+ return $data;
204+ }
205+
206+ /**
207+ * Create dir_name as a directory if it does not exist. If it
208+ * exists, make sure that it is, in fact, a directory. Returns
209+ * true if the operation succeeded; false if not.
210+ *
211+ * @access private
212+ */
213+ static function ensureDir($dir_name)
214+ {
215+ if (is_dir($dir_name) || @mkdir($dir_name)) {
216+ return true;
217+ } else {
218+ $parent_dir = dirname($dir_name);
219+
220+ // Terminal case; there is no parent directory to create.
221+ if ($parent_dir == $dir_name) {
222+ return true;
223+ }
224+
225+ return (Auth_OpenID::ensureDir($parent_dir) && @mkdir($dir_name));
226+ }
227+ }
228+
229+ /**
230+ * Adds a string prefix to all values of an array. Returns a new
231+ * array containing the prefixed values.
232+ *
233+ * @access private
234+ */
235+ static function addPrefix($values, $prefix)
236+ {
237+ $new_values = array();
238+ foreach ($values as $s) {
239+ $new_values[] = $prefix . $s;
240+ }
241+ return $new_values;
242+ }
243+
244+ /**
245+ * Convenience function for getting array values. Given an array
246+ * $arr and a key $key, get the corresponding value from the array
247+ * or return $default if the key is absent.
248+ *
249+ * @access private
250+ */
251+ static function arrayGet($arr, $key, $fallback = null)
252+ {
253+ if (is_array($arr)) {
254+ if (array_key_exists($key, $arr)) {
255+ return $arr[$key];
256+ } else {
257+ return $fallback;
258+ }
259+ } else {
260+ trigger_error("Auth_OpenID::arrayGet (key = ".$key.") expected " .
261+ "array as first parameter, got " .
262+ gettype($arr), E_USER_WARNING);
263+
264+ return false;
265+ }
266+ }
267+
268+ /**
269+ * Replacement for PHP's broken parse_str.
270+ */
271+ static function parse_str($query)
272+ {
273+ if ($query === null) {
274+ return null;
275+ }
276+
277+ $parts = explode('&', $query);
278+
279+ $new_parts = array();
280+ for ($i = 0; $i < count($parts); $i++) {
281+ $pair = explode('=', $parts[$i]);
282+
283+ if (count($pair) != 2) {
284+ continue;
285+ }
286+
287+ list($key, $value) = $pair;
288+ $new_parts[urldecode($key)] = urldecode($value);
289+ }
290+
291+ return $new_parts;
292+ }
293+
294+ /**
295+ * Implements the PHP 5 'http_build_query' functionality.
296+ *
297+ * @access private
298+ * @param array $data Either an array key/value pairs or an array
299+ * of arrays, each of which holding two values: a key and a value,
300+ * sequentially.
301+ * @return string $result The result of url-encoding the key/value
302+ * pairs from $data into a URL query string
303+ * (e.g. "username=bob&id=56").
304+ */
305+ static function httpBuildQuery($data)
306+ {
307+ $pairs = array();
308+ foreach ($data as $key => $value) {
309+ if (is_array($value)) {
310+ $pairs[] = urlencode($value[0])."=".urlencode($value[1]);
311+ } else {
312+ $pairs[] = urlencode($key)."=".urlencode($value);
313+ }
314+ }
315+ return implode("&", $pairs);
316+ }
317+
318+ /**
319+ * "Appends" query arguments onto a URL. The URL may or may not
320+ * already have arguments (following a question mark).
321+ *
322+ * @access private
323+ * @param string $url A URL, which may or may not already have
324+ * arguments.
325+ * @param array $args Either an array key/value pairs or an array of
326+ * arrays, each of which holding two values: a key and a value,
327+ * sequentially. If $args is an ordinary key/value array, the
328+ * parameters will be added to the URL in sorted alphabetical order;
329+ * if $args is an array of arrays, their order will be preserved.
330+ * @return string $url The original URL with the new parameters added.
331+ *
332+ */
333+ static function appendArgs($url, $args)
334+ {
335+ if (count($args) == 0) {
336+ return $url;
337+ }
338+
339+ // Non-empty array; if it is an array of arrays, use
340+ // multisort; otherwise use sort.
341+ if (array_key_exists(0, $args) &&
342+ is_array($args[0])) {
343+ // Do nothing here.
344+ } else {
345+ $keys = array_keys($args);
346+ sort($keys);
347+ $new_args = array();
348+ foreach ($keys as $key) {
349+ $new_args[] = array($key, $args[$key]);
350+ }
351+ $args = $new_args;
352+ }
353+
354+ $sep = '?';
355+ if (strpos($url, '?') !== false) {
356+ $sep = '&';
357+ }
358+
359+ return $url . $sep . Auth_OpenID::httpBuildQuery($args);
360+ }
361+
362+ /**
363+ * Implements python's urlunparse, which is not available in PHP.
364+ * Given the specified components of a URL, this function rebuilds
365+ * and returns the URL.
366+ *
367+ * @access private
368+ * @param string $scheme The scheme (e.g. 'http'). Defaults to 'http'.
369+ * @param string $host The host. Required.
370+ * @param string $port The port.
371+ * @param string $path The path.
372+ * @param string $query The query.
373+ * @param string $fragment The fragment.
374+ * @return string $url The URL resulting from assembling the
375+ * specified components.
376+ */
377+ static function urlunparse($scheme, $host, $port = null, $path = '/',
378+ $query = '', $fragment = '')
379+ {
380+
381+ if (!$scheme) {
382+ $scheme = 'http';
383+ }
384+
385+ if (!$host) {
386+ return false;
387+ }
388+
389+ if (!$path) {
390+ $path = '';
391+ }
392+
393+ $result = $scheme . "://" . $host;
394+
395+ if ($port) {
396+ $result .= ":" . $port;
397+ }
398+
399+ $result .= $path;
400+
401+ if ($query) {
402+ $result .= "?" . $query;
403+ }
404+
405+ if ($fragment) {
406+ $result .= "#" . $fragment;
407+ }
408+
409+ return $result;
410+ }
411+
412+ /**
413+ * Given a URL, this "normalizes" it by adding a trailing slash
414+ * and / or a leading http:// scheme where necessary. Returns
415+ * null if the original URL is malformed and cannot be normalized.
416+ *
417+ * @access private
418+ * @param string $url The URL to be normalized.
419+ * @return mixed $new_url The URL after normalization, or null if
420+ * $url was malformed.
421+ */
422+ static function normalizeUrl($url)
423+ {
424+ @$parsed = parse_url($url);
425+
426+ if (!$parsed) {
427+ return null;
428+ }
429+
430+ if (isset($parsed['scheme']) &&
431+ isset($parsed['host'])) {
432+ $scheme = strtolower($parsed['scheme']);
433+ if (!in_array($scheme, array('http', 'https'))) {
434+ return null;
435+ }
436+ } else {
437+ $url = 'http://' . $url;
438+ }
439+
440+ $normalized = Auth_OpenID_urinorm($url);
441+ if ($normalized === null) {
442+ return null;
443+ }
444+ list($defragged, $frag) = Auth_OpenID::urldefrag($normalized);
445+ return $defragged;
446+ }
447+
448+ /**
449+ * Replacement (wrapper) for PHP's intval() because it's broken.
450+ *
451+ * @access private
452+ */
453+ static function intval($value)
454+ {
455+ $re = "/^\\d+$/";
456+
457+ if (!preg_match($re, $value)) {
458+ return false;
459+ }
460+
461+ return intval($value);
462+ }
463+
464+ /**
465+ * Count the number of bytes in a string independently of
466+ * multibyte support conditions.
467+ *
468+ * @param string $str The string of bytes to count.
469+ * @return int The number of bytes in $str.
470+ */
471+ static function bytes($str)
472+ {
473+ return strlen(bin2hex($str)) / 2;
474+ }
475+
476+ /**
477+ * Get the bytes in a string independently of multibyte support
478+ * conditions.
479+ */
480+ static function toBytes($str)
481+ {
482+ $hex = bin2hex($str);
483+
484+ if (!$hex) {
485+ return array();
486+ }
487+
488+ $b = array();
489+ for ($i = 0; $i < strlen($hex); $i += 2) {
490+ $b[] = chr(base_convert(substr($hex, $i, 2), 16, 10));
491+ }
492+
493+ return $b;
494+ }
495+
496+ static function urldefrag($url)
497+ {
498+ $parts = explode("#", $url, 2);
499+
500+ if (count($parts) == 1) {
501+ return array($parts[0], "");
502+ } else {
503+ return $parts;
504+ }
505+ }
506+
507+ static function filter($callback, &$sequence)
508+ {
509+ $result = array();
510+
511+ foreach ($sequence as $item) {
512+ if (call_user_func_array($callback, array($item))) {
513+ $result[] = $item;
514+ }
515+ }
516+
517+ return $result;
518+ }
519+
520+ static function update(&$dest, &$src)
521+ {
522+ foreach ($src as $k => $v) {
523+ $dest[$k] = $v;
524+ }
525+ }
526+
527+ /**
528+ * Wrap PHP's standard error_log functionality. Use this to
529+ * perform all logging. It will interpolate any additional
530+ * arguments into the format string before logging.
531+ *
532+ * @param string $format_string The sprintf format for the message
533+ */
534+ static function log($format_string)
535+ {
536+ $args = func_get_args();
537+ $message = call_user_func_array('sprintf', $args);
538+ error_log($message);
539+ }
540+
541+ static function autoSubmitHTML($form, $title="OpenId transaction in progress")
542+ {
543+ return("<html>".
544+ "<head><title>".
545+ $title .
546+ "</title></head>".
547+ "<body onload='document.forms[0].submit();'>".
548+ $form .
549+ "<script>".
550+ "var elements = document.forms[0].elements;".
551+ "for (var i = 0; i < elements.length; i++) {".
552+ " elements[i].style.display = \"none\";".
553+ "}".
554+ "</script>".
555+ "</body>".
556+ "</html>");
557+ }
558+}
559+
560+/*
561+ * Function to run when this file is included.
562+ * Abstracted to a function to make life easier
563+ * for some PHP optimizers.
564+ */
565+function Auth_OpenID_include_init() {
566+ if (Auth_OpenID_getMathLib() === null) {
567+ Auth_OpenID_setNoMathSupport();
568+ }
569+}
570
571=== added file 'Auth/OpenID/AX.php'
572--- Auth/OpenID/AX.php 1970-01-01 00:00:00 +0000
573+++ Auth/OpenID/AX.php 2011-06-19 04:48:34 +0000
574@@ -0,0 +1,1022 @@
575+<?php
576+
577+/**
578+ * Implements the OpenID attribute exchange specification, version 1.0
579+ * as of svn revision 370 from openid.net svn.
580+ *
581+ * @package OpenID
582+ */
583+
584+/**
585+ * Require utility classes and functions for the consumer.
586+ */
587+require_once "Auth/OpenID/Extension.php";
588+require_once "Auth/OpenID/Message.php";
589+require_once "Auth/OpenID/TrustRoot.php";
590+
591+define('Auth_OpenID_AX_NS_URI',
592+ 'http://openid.net/srv/ax/1.0');
593+
594+// Use this as the 'count' value for an attribute in a FetchRequest to
595+// ask for as many values as the OP can provide.
596+define('Auth_OpenID_AX_UNLIMITED_VALUES', 'unlimited');
597+
598+// Minimum supported alias length in characters. Here for
599+// completeness.
600+define('Auth_OpenID_AX_MINIMUM_SUPPORTED_ALIAS_LENGTH', 32);
601+
602+/**
603+ * AX utility class.
604+ *
605+ * @package OpenID
606+ */
607+class Auth_OpenID_AX {
608+ /**
609+ * @param mixed $thing Any object which may be an
610+ * Auth_OpenID_AX_Error object.
611+ *
612+ * @return bool true if $thing is an Auth_OpenID_AX_Error; false
613+ * if not.
614+ */
615+ static function isError($thing)
616+ {
617+ return is_a($thing, 'Auth_OpenID_AX_Error');
618+ }
619+}
620+
621+/**
622+ * Check an alias for invalid characters; raise AXError if any are
623+ * found. Return None if the alias is valid.
624+ */
625+function Auth_OpenID_AX_checkAlias($alias)
626+{
627+ if (strpos($alias, ',') !== false) {
628+ return new Auth_OpenID_AX_Error(sprintf(
629+ "Alias %s must not contain comma", $alias));
630+ }
631+ if (strpos($alias, '.') !== false) {
632+ return new Auth_OpenID_AX_Error(sprintf(
633+ "Alias %s must not contain period", $alias));
634+ }
635+
636+ return true;
637+}
638+
639+/**
640+ * Results from data that does not meet the attribute exchange 1.0
641+ * specification
642+ *
643+ * @package OpenID
644+ */
645+class Auth_OpenID_AX_Error {
646+ function Auth_OpenID_AX_Error($message=null)
647+ {
648+ $this->message = $message;
649+ }
650+}
651+
652+/**
653+ * Abstract class containing common code for attribute exchange
654+ * messages.
655+ *
656+ * @package OpenID
657+ */
658+class Auth_OpenID_AX_Message extends Auth_OpenID_Extension {
659+ /**
660+ * ns_alias: The preferred namespace alias for attribute exchange
661+ * messages
662+ */
663+ var $ns_alias = 'ax';
664+
665+ /**
666+ * mode: The type of this attribute exchange message. This must be
667+ * overridden in subclasses.
668+ */
669+ var $mode = null;
670+
671+ var $ns_uri = Auth_OpenID_AX_NS_URI;
672+
673+ /**
674+ * Return Auth_OpenID_AX_Error if the mode in the attribute
675+ * exchange arguments does not match what is expected for this
676+ * class; true otherwise.
677+ *
678+ * @access private
679+ */
680+ function _checkMode($ax_args)
681+ {
682+ $mode = Auth_OpenID::arrayGet($ax_args, 'mode');
683+ if ($mode != $this->mode) {
684+ return new Auth_OpenID_AX_Error(
685+ sprintf(
686+ "Expected mode '%s'; got '%s'",
687+ $this->mode, $mode));
688+ }
689+
690+ return true;
691+ }
692+
693+ /**
694+ * Return a set of attribute exchange arguments containing the
695+ * basic information that must be in every attribute exchange
696+ * message.
697+ *
698+ * @access private
699+ */
700+ function _newArgs()
701+ {
702+ return array('mode' => $this->mode);
703+ }
704+}
705+
706+/**
707+ * Represents a single attribute in an attribute exchange
708+ * request. This should be added to an AXRequest object in order to
709+ * request the attribute.
710+ *
711+ * @package OpenID
712+ */
713+class Auth_OpenID_AX_AttrInfo {
714+ /**
715+ * Construct an attribute information object. Do not call this
716+ * directly; call make(...) instead.
717+ *
718+ * @param string $type_uri The type URI for this attribute.
719+ *
720+ * @param int $count The number of values of this type to request.
721+ *
722+ * @param bool $required Whether the attribute will be marked as
723+ * required in the request.
724+ *
725+ * @param string $alias The name that should be given to this
726+ * attribute in the request.
727+ */
728+ function Auth_OpenID_AX_AttrInfo($type_uri, $count, $required,
729+ $alias)
730+ {
731+ /**
732+ * required: Whether the attribute will be marked as required
733+ * when presented to the subject of the attribute exchange
734+ * request.
735+ */
736+ $this->required = $required;
737+
738+ /**
739+ * count: How many values of this type to request from the
740+ * subject. Defaults to one.
741+ */
742+ $this->count = $count;
743+
744+ /**
745+ * type_uri: The identifier that determines what the attribute
746+ * represents and how it is serialized. For example, one type
747+ * URI representing dates could represent a Unix timestamp in
748+ * base 10 and another could represent a human-readable
749+ * string.
750+ */
751+ $this->type_uri = $type_uri;
752+
753+ /**
754+ * alias: The name that should be given to this attribute in
755+ * the request. If it is not supplied, a generic name will be
756+ * assigned. For example, if you want to call a Unix timestamp
757+ * value 'tstamp', set its alias to that value. If two
758+ * attributes in the same message request to use the same
759+ * alias, the request will fail to be generated.
760+ */
761+ $this->alias = $alias;
762+ }
763+
764+ /**
765+ * Construct an attribute information object. For parameter
766+ * details, see the constructor.
767+ */
768+ static function make($type_uri, $count=1, $required=false,
769+ $alias=null)
770+ {
771+ if ($alias !== null) {
772+ $result = Auth_OpenID_AX_checkAlias($alias);
773+
774+ if (Auth_OpenID_AX::isError($result)) {
775+ return $result;
776+ }
777+ }
778+
779+ return new Auth_OpenID_AX_AttrInfo($type_uri, $count, $required,
780+ $alias);
781+ }
782+
783+ /**
784+ * When processing a request for this attribute, the OP should
785+ * call this method to determine whether all available attribute
786+ * values were requested. If self.count == UNLIMITED_VALUES, this
787+ * returns True. Otherwise this returns False, in which case
788+ * self.count is an integer.
789+ */
790+ function wantsUnlimitedValues()
791+ {
792+ return $this->count === Auth_OpenID_AX_UNLIMITED_VALUES;
793+ }
794+}
795+
796+/**
797+ * Given a namespace mapping and a string containing a comma-separated
798+ * list of namespace aliases, return a list of type URIs that
799+ * correspond to those aliases.
800+ *
801+ * @param $namespace_map The mapping from namespace URI to alias
802+ * @param $alias_list_s The string containing the comma-separated
803+ * list of aliases. May also be None for convenience.
804+ *
805+ * @return $seq The list of namespace URIs that corresponds to the
806+ * supplied list of aliases. If the string was zero-length or None, an
807+ * empty list will be returned.
808+ *
809+ * return null If an alias is present in the list of aliases but
810+ * is not present in the namespace map.
811+ */
812+function Auth_OpenID_AX_toTypeURIs($namespace_map, $alias_list_s)
813+{
814+ $uris = array();
815+
816+ if ($alias_list_s) {
817+ foreach (explode(',', $alias_list_s) as $alias) {
818+ $type_uri = $namespace_map->getNamespaceURI($alias);
819+ if ($type_uri === null) {
820+ // raise KeyError(
821+ // 'No type is defined for attribute name %r' % (alias,))
822+ return new Auth_OpenID_AX_Error(
823+ sprintf('No type is defined for attribute name %s',
824+ $alias)
825+ );
826+ } else {
827+ $uris[] = $type_uri;
828+ }
829+ }
830+ }
831+
832+ return $uris;
833+}
834+
835+/**
836+ * An attribute exchange 'fetch_request' message. This message is sent
837+ * by a relying party when it wishes to obtain attributes about the
838+ * subject of an OpenID authentication request.
839+ *
840+ * @package OpenID
841+ */
842+class Auth_OpenID_AX_FetchRequest extends Auth_OpenID_AX_Message {
843+
844+ var $mode = 'fetch_request';
845+
846+ function Auth_OpenID_AX_FetchRequest($update_url=null)
847+ {
848+ /**
849+ * requested_attributes: The attributes that have been
850+ * requested thus far, indexed by the type URI.
851+ */
852+ $this->requested_attributes = array();
853+
854+ /**
855+ * update_url: A URL that will accept responses for this
856+ * attribute exchange request, even in the absence of the user
857+ * who made this request.
858+ */
859+ $this->update_url = $update_url;
860+ }
861+
862+ /**
863+ * Add an attribute to this attribute exchange request.
864+ *
865+ * @param attribute: The attribute that is being requested
866+ * @return true on success, false when the requested attribute is
867+ * already present in this fetch request.
868+ */
869+ function add($attribute)
870+ {
871+ if ($this->contains($attribute->type_uri)) {
872+ return new Auth_OpenID_AX_Error(
873+ sprintf("The attribute %s has already been requested",
874+ $attribute->type_uri));
875+ }
876+
877+ $this->requested_attributes[$attribute->type_uri] = $attribute;
878+
879+ return true;
880+ }
881+
882+ /**
883+ * Get the serialized form of this attribute fetch request.
884+ *
885+ * @returns Auth_OpenID_AX_FetchRequest The fetch request message parameters
886+ */
887+ function getExtensionArgs()
888+ {
889+ $aliases = new Auth_OpenID_NamespaceMap();
890+
891+ $required = array();
892+ $if_available = array();
893+
894+ $ax_args = $this->_newArgs();
895+
896+ foreach ($this->requested_attributes as $type_uri => $attribute) {
897+ if ($attribute->alias === null) {
898+ $alias = $aliases->add($type_uri);
899+ } else {
900+ $alias = $aliases->addAlias($type_uri, $attribute->alias);
901+
902+ if ($alias === null) {
903+ return new Auth_OpenID_AX_Error(
904+ sprintf("Could not add alias %s for URI %s",
905+ $attribute->alias, $type_uri
906+ ));
907+ }
908+ }
909+
910+ if ($attribute->required) {
911+ $required[] = $alias;
912+ } else {
913+ $if_available[] = $alias;
914+ }
915+
916+ if ($attribute->count != 1) {
917+ $ax_args['count.' . $alias] = strval($attribute->count);
918+ }
919+
920+ $ax_args['type.' . $alias] = $type_uri;
921+ }
922+
923+ if ($required) {
924+ $ax_args['required'] = implode(',', $required);
925+ }
926+
927+ if ($if_available) {
928+ $ax_args['if_available'] = implode(',', $if_available);
929+ }
930+
931+ return $ax_args;
932+ }
933+
934+ /**
935+ * Get the type URIs for all attributes that have been marked as
936+ * required.
937+ *
938+ * @return A list of the type URIs for attributes that have been
939+ * marked as required.
940+ */
941+ function getRequiredAttrs()
942+ {
943+ $required = array();
944+ foreach ($this->requested_attributes as $type_uri => $attribute) {
945+ if ($attribute->required) {
946+ $required[] = $type_uri;
947+ }
948+ }
949+
950+ return $required;
951+ }
952+
953+ /**
954+ * Extract a FetchRequest from an OpenID message
955+ *
956+ * @param request: The OpenID request containing the attribute
957+ * fetch request
958+ *
959+ * @returns mixed An Auth_OpenID_AX_Error or the
960+ * Auth_OpenID_AX_FetchRequest extracted from the request message if
961+ * successful
962+ */
963+ static function fromOpenIDRequest($request)
964+ {
965+ $m = $request->message;
966+ $obj = new Auth_OpenID_AX_FetchRequest();
967+ $ax_args = $m->getArgs($obj->ns_uri);
968+
969+ $result = $obj->parseExtensionArgs($ax_args);
970+
971+ if (Auth_OpenID_AX::isError($result)) {
972+ return $result;
973+ }
974+
975+ if ($obj->update_url) {
976+ // Update URL must match the openid.realm of the
977+ // underlying OpenID 2 message.
978+ $realm = $m->getArg(Auth_OpenID_OPENID_NS, 'realm',
979+ $m->getArg(
980+ Auth_OpenID_OPENID_NS,
981+ 'return_to'));
982+
983+ if (!$realm) {
984+ $obj = new Auth_OpenID_AX_Error(
985+ sprintf("Cannot validate update_url %s " .
986+ "against absent realm", $obj->update_url));
987+ } else if (!Auth_OpenID_TrustRoot::match($realm,
988+ $obj->update_url)) {
989+ $obj = new Auth_OpenID_AX_Error(
990+ sprintf("Update URL %s failed validation against realm %s",
991+ $obj->update_url, $realm));
992+ }
993+ }
994+
995+ return $obj;
996+ }
997+
998+ /**
999+ * Given attribute exchange arguments, populate this FetchRequest.
1000+ *
1001+ * @return $result Auth_OpenID_AX_Error if the data to be parsed
1002+ * does not follow the attribute exchange specification. At least
1003+ * when 'if_available' or 'required' is not specified for a
1004+ * particular attribute type. Returns true otherwise.
1005+ */
1006+ function parseExtensionArgs($ax_args)
1007+ {
1008+ $result = $this->_checkMode($ax_args);
1009+ if (Auth_OpenID_AX::isError($result)) {
1010+ return $result;
1011+ }
1012+
1013+ $aliases = new Auth_OpenID_NamespaceMap();
1014+
1015+ foreach ($ax_args as $key => $value) {
1016+ if (strpos($key, 'type.') === 0) {
1017+ $alias = substr($key, 5);
1018+ $type_uri = $value;
1019+
1020+ $alias = $aliases->addAlias($type_uri, $alias);
1021+
1022+ if ($alias === null) {
1023+ return new Auth_OpenID_AX_Error(
1024+ sprintf("Could not add alias %s for URI %s",
1025+ $alias, $type_uri)
1026+ );
1027+ }
1028+
1029+ $count_s = Auth_OpenID::arrayGet($ax_args, 'count.' . $alias);
1030+ if ($count_s) {
1031+ $count = Auth_OpenID::intval($count_s);
1032+ if (($count === false) &&
1033+ ($count_s === Auth_OpenID_AX_UNLIMITED_VALUES)) {
1034+ $count = $count_s;
1035+ }
1036+ } else {
1037+ $count = 1;
1038+ }
1039+
1040+ if ($count === false) {
1041+ return new Auth_OpenID_AX_Error(
1042+ sprintf("Integer value expected for %s, got %s",
1043+ 'count.' . $alias, $count_s));
1044+ }
1045+
1046+ $attrinfo = Auth_OpenID_AX_AttrInfo::make($type_uri, $count,
1047+ false, $alias);
1048+
1049+ if (Auth_OpenID_AX::isError($attrinfo)) {
1050+ return $attrinfo;
1051+ }
1052+
1053+ $this->add($attrinfo);
1054+ }
1055+ }
1056+
1057+ $required = Auth_OpenID_AX_toTypeURIs($aliases,
1058+ Auth_OpenID::arrayGet($ax_args, 'required'));
1059+
1060+ foreach ($required as $type_uri) {
1061+ $attrib = $this->requested_attributes[$type_uri];
1062+ $attrib->required = true;
1063+ }
1064+
1065+ $if_available = Auth_OpenID_AX_toTypeURIs($aliases,
1066+ Auth_OpenID::arrayGet($ax_args, 'if_available'));
1067+
1068+ $all_type_uris = array_merge($required, $if_available);
1069+
1070+ foreach ($aliases->iterNamespaceURIs() as $type_uri) {
1071+ if (!in_array($type_uri, $all_type_uris)) {
1072+ return new Auth_OpenID_AX_Error(
1073+ sprintf('Type URI %s was in the request but not ' .
1074+ 'present in "required" or "if_available"',
1075+ $type_uri));
1076+
1077+ }
1078+ }
1079+
1080+ $this->update_url = Auth_OpenID::arrayGet($ax_args, 'update_url');
1081+
1082+ return true;
1083+ }
1084+
1085+ /**
1086+ * Iterate over the AttrInfo objects that are contained in this
1087+ * fetch_request.
1088+ */
1089+ function iterAttrs()
1090+ {
1091+ return array_values($this->requested_attributes);
1092+ }
1093+
1094+ function iterTypes()
1095+ {
1096+ return array_keys($this->requested_attributes);
1097+ }
1098+
1099+ /**
1100+ * Is the given type URI present in this fetch_request?
1101+ */
1102+ function contains($type_uri)
1103+ {
1104+ return in_array($type_uri, $this->iterTypes());
1105+ }
1106+}
1107+
1108+/**
1109+ * An abstract class that implements a message that has attribute keys
1110+ * and values. It contains the common code between fetch_response and
1111+ * store_request.
1112+ *
1113+ * @package OpenID
1114+ */
1115+class Auth_OpenID_AX_KeyValueMessage extends Auth_OpenID_AX_Message {
1116+
1117+ function Auth_OpenID_AX_KeyValueMessage()
1118+ {
1119+ $this->data = array();
1120+ }
1121+
1122+ /**
1123+ * Add a single value for the given attribute type to the
1124+ * message. If there are already values specified for this type,
1125+ * this value will be sent in addition to the values already
1126+ * specified.
1127+ *
1128+ * @param type_uri: The URI for the attribute
1129+ * @param value: The value to add to the response to the relying
1130+ * party for this attribute
1131+ * @return null
1132+ */
1133+ function addValue($type_uri, $value)
1134+ {
1135+ if (!array_key_exists($type_uri, $this->data)) {
1136+ $this->data[$type_uri] = array();
1137+ }
1138+
1139+ $values =& $this->data[$type_uri];
1140+ $values[] = $value;
1141+ }
1142+
1143+ /**
1144+ * Set the values for the given attribute type. This replaces any
1145+ * values that have already been set for this attribute.
1146+ *
1147+ * @param type_uri: The URI for the attribute
1148+ * @param values: A list of values to send for this attribute.
1149+ */
1150+ function setValues($type_uri, &$values)
1151+ {
1152+ $this->data[$type_uri] =& $values;
1153+ }
1154+
1155+ /**
1156+ * Get the extension arguments for the key/value pairs contained
1157+ * in this message.
1158+ *
1159+ * @param aliases: An alias mapping. Set to None if you don't care
1160+ * about the aliases for this request.
1161+ *
1162+ * @access private
1163+ */
1164+ function _getExtensionKVArgs($aliases)
1165+ {
1166+ if ($aliases === null) {
1167+ $aliases = new Auth_OpenID_NamespaceMap();
1168+ }
1169+
1170+ $ax_args = array();
1171+
1172+ foreach ($this->data as $type_uri => $values) {
1173+ $alias = $aliases->add($type_uri);
1174+
1175+ $ax_args['type.' . $alias] = $type_uri;
1176+ $ax_args['count.' . $alias] = strval(count($values));
1177+
1178+ foreach ($values as $i => $value) {
1179+ $key = sprintf('value.%s.%d', $alias, $i + 1);
1180+ $ax_args[$key] = $value;
1181+ }
1182+ }
1183+
1184+ return $ax_args;
1185+ }
1186+
1187+ /**
1188+ * Parse attribute exchange key/value arguments into this object.
1189+ *
1190+ * @param ax_args: The attribute exchange fetch_response
1191+ * arguments, with namespacing removed.
1192+ *
1193+ * @return Auth_OpenID_AX_Error or true
1194+ */
1195+ function parseExtensionArgs($ax_args)
1196+ {
1197+ $result = $this->_checkMode($ax_args);
1198+ if (Auth_OpenID_AX::isError($result)) {
1199+ return $result;
1200+ }
1201+
1202+ $aliases = new Auth_OpenID_NamespaceMap();
1203+
1204+ foreach ($ax_args as $key => $value) {
1205+ if (strpos($key, 'type.') === 0) {
1206+ $type_uri = $value;
1207+ $alias = substr($key, 5);
1208+
1209+ $result = Auth_OpenID_AX_checkAlias($alias);
1210+
1211+ if (Auth_OpenID_AX::isError($result)) {
1212+ return $result;
1213+ }
1214+
1215+ $alias = $aliases->addAlias($type_uri, $alias);
1216+
1217+ if ($alias === null) {
1218+ return new Auth_OpenID_AX_Error(
1219+ sprintf("Could not add alias %s for URI %s",
1220+ $alias, $type_uri)
1221+ );
1222+ }
1223+ }
1224+ }
1225+
1226+ foreach ($aliases->iteritems() as $pair) {
1227+ list($type_uri, $alias) = $pair;
1228+
1229+ if (array_key_exists('count.' . $alias, $ax_args) && ($ax_args['count.' . $alias] !== Auth_OpenID_AX_UNLIMITED_VALUES)) {
1230+
1231+ $count_key = 'count.' . $alias;
1232+ $count_s = $ax_args[$count_key];
1233+
1234+ $count = Auth_OpenID::intval($count_s);
1235+
1236+ if ($count === false) {
1237+ return new Auth_OpenID_AX_Error(
1238+ sprintf("Integer value expected for %s, got %s",
1239+ 'count. %s' . $alias, $count_s,
1240+ Auth_OpenID_AX_UNLIMITED_VALUES)
1241+ );
1242+ }
1243+
1244+ $values = array();
1245+ for ($i = 1; $i < $count + 1; $i++) {
1246+ $value_key = sprintf('value.%s.%d', $alias, $i);
1247+
1248+ if (!array_key_exists($value_key, $ax_args)) {
1249+ return new Auth_OpenID_AX_Error(
1250+ sprintf(
1251+ "No value found for key %s",
1252+ $value_key));
1253+ }
1254+
1255+ $value = $ax_args[$value_key];
1256+ $values[] = $value;
1257+ }
1258+ } else {
1259+ $key = 'value.' . $alias;
1260+
1261+ if (!array_key_exists($key, $ax_args)) {
1262+ return new Auth_OpenID_AX_Error(
1263+ sprintf(
1264+ "No value found for key %s",
1265+ $key));
1266+ }
1267+
1268+ $value = $ax_args['value.' . $alias];
1269+
1270+ if ($value == '') {
1271+ $values = array();
1272+ } else {
1273+ $values = array($value);
1274+ }
1275+ }
1276+
1277+ $this->data[$type_uri] = $values;
1278+ }
1279+
1280+ return true;
1281+ }
1282+
1283+ /**
1284+ * Get a single value for an attribute. If no value was sent for
1285+ * this attribute, use the supplied default. If there is more than
1286+ * one value for this attribute, this method will fail.
1287+ *
1288+ * @param type_uri: The URI for the attribute
1289+ * @param default: The value to return if the attribute was not
1290+ * sent in the fetch_response.
1291+ *
1292+ * @return $value Auth_OpenID_AX_Error on failure or the value of
1293+ * the attribute in the fetch_response message, or the default
1294+ * supplied
1295+ */
1296+ function getSingle($type_uri, $default=null)
1297+ {
1298+ $values = Auth_OpenID::arrayGet($this->data, $type_uri);
1299+ if (!$values) {
1300+ return $default;
1301+ } else if (count($values) == 1) {
1302+ return $values[0];
1303+ } else {
1304+ return new Auth_OpenID_AX_Error(
1305+ sprintf('More than one value present for %s',
1306+ $type_uri)
1307+ );
1308+ }
1309+ }
1310+
1311+ /**
1312+ * Get the list of values for this attribute in the
1313+ * fetch_response.
1314+ *
1315+ * XXX: what to do if the values are not present? default
1316+ * parameter? this is funny because it's always supposed to return
1317+ * a list, so the default may break that, though it's provided by
1318+ * the user's code, so it might be okay. If no default is
1319+ * supplied, should the return be None or []?
1320+ *
1321+ * @param type_uri: The URI of the attribute
1322+ *
1323+ * @return $values The list of values for this attribute in the
1324+ * response. May be an empty list. If the attribute was not sent
1325+ * in the response, returns Auth_OpenID_AX_Error.
1326+ */
1327+ function get($type_uri)
1328+ {
1329+ if (array_key_exists($type_uri, $this->data)) {
1330+ return $this->data[$type_uri];
1331+ } else {
1332+ return new Auth_OpenID_AX_Error(
1333+ sprintf("Type URI %s not found in response",
1334+ $type_uri)
1335+ );
1336+ }
1337+ }
1338+
1339+ /**
1340+ * Get the number of responses for a particular attribute in this
1341+ * fetch_response message.
1342+ *
1343+ * @param type_uri: The URI of the attribute
1344+ *
1345+ * @returns int The number of values sent for this attribute. If
1346+ * the attribute was not sent in the response, returns
1347+ * Auth_OpenID_AX_Error.
1348+ */
1349+ function count($type_uri)
1350+ {
1351+ if (array_key_exists($type_uri, $this->data)) {
1352+ return count($this->get($type_uri));
1353+ } else {
1354+ return new Auth_OpenID_AX_Error(
1355+ sprintf("Type URI %s not found in response",
1356+ $type_uri)
1357+ );
1358+ }
1359+ }
1360+}
1361+
1362+/**
1363+ * A fetch_response attribute exchange message.
1364+ *
1365+ * @package OpenID
1366+ */
1367+class Auth_OpenID_AX_FetchResponse extends Auth_OpenID_AX_KeyValueMessage {
1368+ var $mode = 'fetch_response';
1369+
1370+ function Auth_OpenID_AX_FetchResponse($update_url=null)
1371+ {
1372+ $this->Auth_OpenID_AX_KeyValueMessage();
1373+ $this->update_url = $update_url;
1374+ }
1375+
1376+ /**
1377+ * Serialize this object into arguments in the attribute exchange
1378+ * namespace
1379+ *
1380+ * @return $args The dictionary of unqualified attribute exchange
1381+ * arguments that represent this fetch_response, or
1382+ * Auth_OpenID_AX_Error on error.
1383+ */
1384+ function getExtensionArgs($request=null)
1385+ {
1386+ $aliases = new Auth_OpenID_NamespaceMap();
1387+
1388+ $zero_value_types = array();
1389+
1390+ if ($request !== null) {
1391+ // Validate the data in the context of the request (the
1392+ // same attributes should be present in each, and the
1393+ // counts in the response must be no more than the counts
1394+ // in the request)
1395+
1396+ foreach ($this->data as $type_uri => $unused) {
1397+ if (!$request->contains($type_uri)) {
1398+ return new Auth_OpenID_AX_Error(
1399+ sprintf("Response attribute not present in request: %s",
1400+ $type_uri)
1401+ );
1402+ }
1403+ }
1404+
1405+ foreach ($request->iterAttrs() as $attr_info) {
1406+ // Copy the aliases from the request so that reading
1407+ // the response in light of the request is easier
1408+ if ($attr_info->alias === null) {
1409+ $aliases->add($attr_info->type_uri);
1410+ } else {
1411+ $alias = $aliases->addAlias($attr_info->type_uri,
1412+ $attr_info->alias);
1413+
1414+ if ($alias === null) {
1415+ return new Auth_OpenID_AX_Error(
1416+ sprintf("Could not add alias %s for URI %s",
1417+ $attr_info->alias, $attr_info->type_uri)
1418+ );
1419+ }
1420+ }
1421+
1422+ if (array_key_exists($attr_info->type_uri, $this->data)) {
1423+ $values = $this->data[$attr_info->type_uri];
1424+ } else {
1425+ $values = array();
1426+ $zero_value_types[] = $attr_info;
1427+ }
1428+
1429+ if (($attr_info->count != Auth_OpenID_AX_UNLIMITED_VALUES) &&
1430+ ($attr_info->count < count($values))) {
1431+ return new Auth_OpenID_AX_Error(
1432+ sprintf("More than the number of requested values " .
1433+ "were specified for %s",
1434+ $attr_info->type_uri)
1435+ );
1436+ }
1437+ }
1438+ }
1439+
1440+ $kv_args = $this->_getExtensionKVArgs($aliases);
1441+
1442+ // Add the KV args into the response with the args that are
1443+ // unique to the fetch_response
1444+ $ax_args = $this->_newArgs();
1445+
1446+ // For each requested attribute, put its type/alias and count
1447+ // into the response even if no data were returned.
1448+ foreach ($zero_value_types as $attr_info) {
1449+ $alias = $aliases->getAlias($attr_info->type_uri);
1450+ $kv_args['type.' . $alias] = $attr_info->type_uri;
1451+ $kv_args['count.' . $alias] = '0';
1452+ }
1453+
1454+ $update_url = null;
1455+ if ($request) {
1456+ $update_url = $request->update_url;
1457+ } else {
1458+ $update_url = $this->update_url;
1459+ }
1460+
1461+ if ($update_url) {
1462+ $ax_args['update_url'] = $update_url;
1463+ }
1464+
1465+ Auth_OpenID::update($ax_args, $kv_args);
1466+
1467+ return $ax_args;
1468+ }
1469+
1470+ /**
1471+ * @return $result Auth_OpenID_AX_Error on failure or true on
1472+ * success.
1473+ */
1474+ function parseExtensionArgs($ax_args)
1475+ {
1476+ $result = parent::parseExtensionArgs($ax_args);
1477+
1478+ if (Auth_OpenID_AX::isError($result)) {
1479+ return $result;
1480+ }
1481+
1482+ $this->update_url = Auth_OpenID::arrayGet($ax_args, 'update_url');
1483+
1484+ return true;
1485+ }
1486+
1487+ /**
1488+ * Construct a FetchResponse object from an OpenID library
1489+ * SuccessResponse object.
1490+ *
1491+ * @param success_response: A successful id_res response object
1492+ *
1493+ * @param signed: Whether non-signed args should be processsed. If
1494+ * True (the default), only signed arguments will be processsed.
1495+ *
1496+ * @return $response A FetchResponse containing the data from the
1497+ * OpenID message
1498+ */
1499+ static function fromSuccessResponse($success_response, $signed=true)
1500+ {
1501+ $obj = new Auth_OpenID_AX_FetchResponse();
1502+ if ($signed) {
1503+ $ax_args = $success_response->getSignedNS($obj->ns_uri);
1504+ } else {
1505+ $ax_args = $success_response->message->getArgs($obj->ns_uri);
1506+ }
1507+ if ($ax_args === null || Auth_OpenID::isFailure($ax_args) ||
1508+ sizeof($ax_args) == 0) {
1509+ return null;
1510+ }
1511+
1512+ $result = $obj->parseExtensionArgs($ax_args);
1513+ if (Auth_OpenID_AX::isError($result)) {
1514+ #XXX log me
1515+ return null;
1516+ }
1517+ return $obj;
1518+ }
1519+}
1520+
1521+/**
1522+ * A store request attribute exchange message representation.
1523+ *
1524+ * @package OpenID
1525+ */
1526+class Auth_OpenID_AX_StoreRequest extends Auth_OpenID_AX_KeyValueMessage {
1527+ var $mode = 'store_request';
1528+
1529+ /**
1530+ * @param array $aliases The namespace aliases to use when making
1531+ * this store response. Leave as None to use defaults.
1532+ */
1533+ function getExtensionArgs($aliases=null)
1534+ {
1535+ $ax_args = $this->_newArgs();
1536+ $kv_args = $this->_getExtensionKVArgs($aliases);
1537+ Auth_OpenID::update($ax_args, $kv_args);
1538+ return $ax_args;
1539+ }
1540+}
1541+
1542+/**
1543+ * An indication that the store request was processed along with this
1544+ * OpenID transaction. Use make(), NOT the constructor, to create
1545+ * response objects.
1546+ *
1547+ * @package OpenID
1548+ */
1549+class Auth_OpenID_AX_StoreResponse extends Auth_OpenID_AX_Message {
1550+ var $SUCCESS_MODE = 'store_response_success';
1551+ var $FAILURE_MODE = 'store_response_failure';
1552+
1553+ /**
1554+ * Returns Auth_OpenID_AX_Error on error or an
1555+ * Auth_OpenID_AX_StoreResponse object on success.
1556+ */
1557+ function make($succeeded=true, $error_message=null)
1558+ {
1559+ if (($succeeded) && ($error_message !== null)) {
1560+ return new Auth_OpenID_AX_Error('An error message may only be '.
1561+ 'included in a failing fetch response');
1562+ }
1563+
1564+ return new Auth_OpenID_AX_StoreResponse($succeeded, $error_message);
1565+ }
1566+
1567+ function Auth_OpenID_AX_StoreResponse($succeeded=true, $error_message=null)
1568+ {
1569+ if ($succeeded) {
1570+ $this->mode = $this->SUCCESS_MODE;
1571+ } else {
1572+ $this->mode = $this->FAILURE_MODE;
1573+ }
1574+
1575+ $this->error_message = $error_message;
1576+ }
1577+
1578+ /**
1579+ * Was this response a success response?
1580+ */
1581+ function succeeded()
1582+ {
1583+ return $this->mode == $this->SUCCESS_MODE;
1584+ }
1585+
1586+ function getExtensionArgs()
1587+ {
1588+ $ax_args = $this->_newArgs();
1589+ if ((!$this->succeeded()) && $this->error_message) {
1590+ $ax_args['error'] = $this->error_message;
1591+ }
1592+
1593+ return $ax_args;
1594+ }
1595+}
1596+
1597
1598=== added file 'Auth/OpenID/Association.php'
1599--- Auth/OpenID/Association.php 1970-01-01 00:00:00 +0000
1600+++ Auth/OpenID/Association.php 2011-06-19 04:48:34 +0000
1601@@ -0,0 +1,610 @@
1602+<?php
1603+
1604+/**
1605+ * This module contains code for dealing with associations between
1606+ * consumers and servers.
1607+ *
1608+ * PHP versions 4 and 5
1609+ *
1610+ * LICENSE: See the COPYING file included in this distribution.
1611+ *
1612+ * @package OpenID
1613+ * @author JanRain, Inc. <openid@janrain.com>
1614+ * @copyright 2005-2008 Janrain, Inc.
1615+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
1616+ */
1617+
1618+/**
1619+ * @access private
1620+ */
1621+require_once 'Auth/OpenID/CryptUtil.php';
1622+
1623+/**
1624+ * @access private
1625+ */
1626+require_once 'Auth/OpenID/KVForm.php';
1627+
1628+/**
1629+ * @access private
1630+ */
1631+require_once 'Auth/OpenID/HMAC.php';
1632+
1633+/**
1634+ * This class represents an association between a server and a
1635+ * consumer. In general, users of this library will never see
1636+ * instances of this object. The only exception is if you implement a
1637+ * custom {@link Auth_OpenID_OpenIDStore}.
1638+ *
1639+ * If you do implement such a store, it will need to store the values
1640+ * of the handle, secret, issued, lifetime, and assoc_type instance
1641+ * variables.
1642+ *
1643+ * @package OpenID
1644+ */
1645+class Auth_OpenID_Association {
1646+
1647+ /**
1648+ * This is a HMAC-SHA1 specific value.
1649+ *
1650+ * @access private
1651+ */
1652+ var $SIG_LENGTH = 20;
1653+
1654+ /**
1655+ * The ordering and name of keys as stored by serialize.
1656+ *
1657+ * @access private
1658+ */
1659+ var $assoc_keys = array(
1660+ 'version',
1661+ 'handle',
1662+ 'secret',
1663+ 'issued',
1664+ 'lifetime',
1665+ 'assoc_type'
1666+ );
1667+
1668+ var $_macs = array(
1669+ 'HMAC-SHA1' => 'Auth_OpenID_HMACSHA1',
1670+ 'HMAC-SHA256' => 'Auth_OpenID_HMACSHA256'
1671+ );
1672+
1673+ /**
1674+ * This is an alternate constructor (factory method) used by the
1675+ * OpenID consumer library to create associations. OpenID store
1676+ * implementations shouldn't use this constructor.
1677+ *
1678+ * @access private
1679+ *
1680+ * @param integer $expires_in This is the amount of time this
1681+ * association is good for, measured in seconds since the
1682+ * association was issued.
1683+ *
1684+ * @param string $handle This is the handle the server gave this
1685+ * association.
1686+ *
1687+ * @param string secret This is the shared secret the server
1688+ * generated for this association.
1689+ *
1690+ * @param assoc_type This is the type of association this
1691+ * instance represents. The only valid values of this field at
1692+ * this time is 'HMAC-SHA1' and 'HMAC-SHA256', but new types may
1693+ * be defined in the future.
1694+ *
1695+ * @return association An {@link Auth_OpenID_Association}
1696+ * instance.
1697+ */
1698+ static function fromExpiresIn($expires_in, $handle, $secret, $assoc_type)
1699+ {
1700+ $issued = time();
1701+ $lifetime = $expires_in;
1702+ return new Auth_OpenID_Association($handle, $secret,
1703+ $issued, $lifetime, $assoc_type);
1704+ }
1705+
1706+ /**
1707+ * This is the standard constructor for creating an association.
1708+ * The library should create all of the necessary associations, so
1709+ * this constructor is not part of the external API.
1710+ *
1711+ * @access private
1712+ *
1713+ * @param string $handle This is the handle the server gave this
1714+ * association.
1715+ *
1716+ * @param string $secret This is the shared secret the server
1717+ * generated for this association.
1718+ *
1719+ * @param integer $issued This is the time this association was
1720+ * issued, in seconds since 00:00 GMT, January 1, 1970. (ie, a
1721+ * unix timestamp)
1722+ *
1723+ * @param integer $lifetime This is the amount of time this
1724+ * association is good for, measured in seconds since the
1725+ * association was issued.
1726+ *
1727+ * @param string $assoc_type This is the type of association this
1728+ * instance represents. The only valid values of this field at
1729+ * this time is 'HMAC-SHA1' and 'HMAC-SHA256', but new types may
1730+ * be defined in the future.
1731+ */
1732+ function Auth_OpenID_Association(
1733+ $handle, $secret, $issued, $lifetime, $assoc_type)
1734+ {
1735+ if (!in_array($assoc_type,
1736+ Auth_OpenID_getSupportedAssociationTypes(), true)) {
1737+ $fmt = 'Unsupported association type (%s)';
1738+ trigger_error(sprintf($fmt, $assoc_type), E_USER_ERROR);
1739+ }
1740+
1741+ $this->handle = $handle;
1742+ $this->secret = $secret;
1743+ $this->issued = $issued;
1744+ $this->lifetime = $lifetime;
1745+ $this->assoc_type = $assoc_type;
1746+ }
1747+
1748+ /**
1749+ * This returns the number of seconds this association is still
1750+ * valid for, or 0 if the association is no longer valid.
1751+ *
1752+ * @return integer $seconds The number of seconds this association
1753+ * is still valid for, or 0 if the association is no longer valid.
1754+ */
1755+ function getExpiresIn($now = null)
1756+ {
1757+ if ($now == null) {
1758+ $now = time();
1759+ }
1760+
1761+ return max(0, $this->issued + $this->lifetime - $now);
1762+ }
1763+
1764+ /**
1765+ * This checks to see if two {@link Auth_OpenID_Association}
1766+ * instances represent the same association.
1767+ *
1768+ * @return bool $result true if the two instances represent the
1769+ * same association, false otherwise.
1770+ */
1771+ function equal($other)
1772+ {
1773+ return ((gettype($this) == gettype($other))
1774+ && ($this->handle == $other->handle)
1775+ && ($this->secret == $other->secret)
1776+ && ($this->issued == $other->issued)
1777+ && ($this->lifetime == $other->lifetime)
1778+ && ($this->assoc_type == $other->assoc_type));
1779+ }
1780+
1781+ /**
1782+ * Convert an association to KV form.
1783+ *
1784+ * @return string $result String in KV form suitable for
1785+ * deserialization by deserialize.
1786+ */
1787+ function serialize()
1788+ {
1789+ $data = array(
1790+ 'version' => '2',
1791+ 'handle' => $this->handle,
1792+ 'secret' => base64_encode($this->secret),
1793+ 'issued' => strval(intval($this->issued)),
1794+ 'lifetime' => strval(intval($this->lifetime)),
1795+ 'assoc_type' => $this->assoc_type
1796+ );
1797+
1798+ assert(array_keys($data) == $this->assoc_keys);
1799+
1800+ return Auth_OpenID_KVForm::fromArray($data, $strict = true);
1801+ }
1802+
1803+ /**
1804+ * Parse an association as stored by serialize(). This is the
1805+ * inverse of serialize.
1806+ *
1807+ * @param string $assoc_s Association as serialized by serialize()
1808+ * @return Auth_OpenID_Association $result instance of this class
1809+ */
1810+ static function deserialize($class_name, $assoc_s)
1811+ {
1812+ $pairs = Auth_OpenID_KVForm::toArray($assoc_s, $strict = true);
1813+ $keys = array();
1814+ $values = array();
1815+ foreach ($pairs as $key => $value) {
1816+ if (is_array($value)) {
1817+ list($key, $value) = $value;
1818+ }
1819+ $keys[] = $key;
1820+ $values[] = $value;
1821+ }
1822+
1823+ $class_vars = get_class_vars($class_name);
1824+ $class_assoc_keys = $class_vars['assoc_keys'];
1825+
1826+ sort($keys);
1827+ sort($class_assoc_keys);
1828+
1829+ if ($keys != $class_assoc_keys) {
1830+ trigger_error('Unexpected key values: ' . var_export($keys, true),
1831+ E_USER_WARNING);
1832+ return null;
1833+ }
1834+
1835+ $version = $pairs['version'];
1836+ $handle = $pairs['handle'];
1837+ $secret = $pairs['secret'];
1838+ $issued = $pairs['issued'];
1839+ $lifetime = $pairs['lifetime'];
1840+ $assoc_type = $pairs['assoc_type'];
1841+
1842+ if ($version != '2') {
1843+ trigger_error('Unknown version: ' . $version, E_USER_WARNING);
1844+ return null;
1845+ }
1846+
1847+ $issued = intval($issued);
1848+ $lifetime = intval($lifetime);
1849+ $secret = base64_decode($secret);
1850+
1851+ return new $class_name(
1852+ $handle, $secret, $issued, $lifetime, $assoc_type);
1853+ }
1854+
1855+ /**
1856+ * Generate a signature for a sequence of (key, value) pairs
1857+ *
1858+ * @access private
1859+ * @param array $pairs The pairs to sign, in order. This is an
1860+ * array of two-tuples.
1861+ * @return string $signature The binary signature of this sequence
1862+ * of pairs
1863+ */
1864+ function sign($pairs)
1865+ {
1866+ $kv = Auth_OpenID_KVForm::fromArray($pairs);
1867+
1868+ /* Invalid association types should be caught at constructor */
1869+ $callback = $this->_macs[$this->assoc_type];
1870+
1871+ return call_user_func_array($callback, array($this->secret, $kv));
1872+ }
1873+
1874+ /**
1875+ * Generate a signature for some fields in a dictionary
1876+ *
1877+ * @access private
1878+ * @param array $fields The fields to sign, in order; this is an
1879+ * array of strings.
1880+ * @param array $data Dictionary of values to sign (an array of
1881+ * string => string pairs).
1882+ * @return string $signature The signature, base64 encoded
1883+ */
1884+ function signMessage($message)
1885+ {
1886+ if ($message->hasKey(Auth_OpenID_OPENID_NS, 'sig') ||
1887+ $message->hasKey(Auth_OpenID_OPENID_NS, 'signed')) {
1888+ // Already has a sig
1889+ return null;
1890+ }
1891+
1892+ $extant_handle = $message->getArg(Auth_OpenID_OPENID_NS,
1893+ 'assoc_handle');
1894+
1895+ if ($extant_handle && ($extant_handle != $this->handle)) {
1896+ // raise ValueError("Message has a different association handle")
1897+ return null;
1898+ }
1899+
1900+ $signed_message = $message;
1901+ $signed_message->setArg(Auth_OpenID_OPENID_NS, 'assoc_handle',
1902+ $this->handle);
1903+
1904+ $message_keys = array_keys($signed_message->toPostArgs());
1905+ $signed_list = array();
1906+ $signed_prefix = 'openid.';
1907+
1908+ foreach ($message_keys as $k) {
1909+ if (strpos($k, $signed_prefix) === 0) {
1910+ $signed_list[] = substr($k, strlen($signed_prefix));
1911+ }
1912+ }
1913+
1914+ $signed_list[] = 'signed';
1915+ sort($signed_list);
1916+
1917+ $signed_message->setArg(Auth_OpenID_OPENID_NS, 'signed',
1918+ implode(',', $signed_list));
1919+ $sig = $this->getMessageSignature($signed_message);
1920+ $signed_message->setArg(Auth_OpenID_OPENID_NS, 'sig', $sig);
1921+ return $signed_message;
1922+ }
1923+
1924+ /**
1925+ * Given a {@link Auth_OpenID_Message}, return the key/value pairs
1926+ * to be signed according to the signed list in the message. If
1927+ * the message lacks a signed list, return null.
1928+ *
1929+ * @access private
1930+ */
1931+ function _makePairs($message)
1932+ {
1933+ $signed = $message->getArg(Auth_OpenID_OPENID_NS, 'signed');
1934+ if (!$signed || Auth_OpenID::isFailure($signed)) {
1935+ // raise ValueError('Message has no signed list: %s' % (message,))
1936+ return null;
1937+ }
1938+
1939+ $signed_list = explode(',', $signed);
1940+ $pairs = array();
1941+ $data = $message->toPostArgs();
1942+ foreach ($signed_list as $field) {
1943+ $pairs[] = array($field, Auth_OpenID::arrayGet($data,
1944+ 'openid.' .
1945+ $field, ''));
1946+ }
1947+ return $pairs;
1948+ }
1949+
1950+ /**
1951+ * Given an {@link Auth_OpenID_Message}, return the signature for
1952+ * the signed list in the message.
1953+ *
1954+ * @access private
1955+ */
1956+ function getMessageSignature($message)
1957+ {
1958+ $pairs = $this->_makePairs($message);
1959+ return base64_encode($this->sign($pairs));
1960+ }
1961+
1962+ /**
1963+ * Confirm that the signature of these fields matches the
1964+ * signature contained in the data.
1965+ *
1966+ * @access private
1967+ */
1968+ function checkMessageSignature($message)
1969+ {
1970+ $sig = $message->getArg(Auth_OpenID_OPENID_NS,
1971+ 'sig');
1972+
1973+ if (!$sig || Auth_OpenID::isFailure($sig)) {
1974+ return false;
1975+ }
1976+
1977+ $calculated_sig = $this->getMessageSignature($message);
1978+ return $calculated_sig == $sig;
1979+ }
1980+}
1981+
1982+function Auth_OpenID_getSecretSize($assoc_type)
1983+{
1984+ if ($assoc_type == 'HMAC-SHA1') {
1985+ return 20;
1986+ } else if ($assoc_type == 'HMAC-SHA256') {
1987+ return 32;
1988+ } else {
1989+ return null;
1990+ }
1991+}
1992+
1993+function Auth_OpenID_getAllAssociationTypes()
1994+{
1995+ return array('HMAC-SHA1', 'HMAC-SHA256');
1996+}
1997+
1998+function Auth_OpenID_getSupportedAssociationTypes()
1999+{
2000+ $a = array('HMAC-SHA1');
2001+
2002+ if (Auth_OpenID_HMACSHA256_SUPPORTED) {
2003+ $a[] = 'HMAC-SHA256';
2004+ }
2005+
2006+ return $a;
2007+}
2008+
2009+function Auth_OpenID_getSessionTypes($assoc_type)
2010+{
2011+ $assoc_to_session = array(
2012+ 'HMAC-SHA1' => array('DH-SHA1', 'no-encryption'));
2013+
2014+ if (Auth_OpenID_HMACSHA256_SUPPORTED) {
2015+ $assoc_to_session['HMAC-SHA256'] =
2016+ array('DH-SHA256', 'no-encryption');
2017+ }
2018+
2019+ return Auth_OpenID::arrayGet($assoc_to_session, $assoc_type, array());
2020+}
2021+
2022+function Auth_OpenID_checkSessionType($assoc_type, $session_type)
2023+{
2024+ if (!in_array($session_type,
2025+ Auth_OpenID_getSessionTypes($assoc_type))) {
2026+ return false;
2027+ }
2028+
2029+ return true;
2030+}
2031+
2032+function Auth_OpenID_getDefaultAssociationOrder()
2033+{
2034+ $order = array();
2035+
2036+ if (!Auth_OpenID_noMathSupport()) {
2037+ $order[] = array('HMAC-SHA1', 'DH-SHA1');
2038+
2039+ if (Auth_OpenID_HMACSHA256_SUPPORTED) {
2040+ $order[] = array('HMAC-SHA256', 'DH-SHA256');
2041+ }
2042+ }
2043+
2044+ $order[] = array('HMAC-SHA1', 'no-encryption');
2045+
2046+ if (Auth_OpenID_HMACSHA256_SUPPORTED) {
2047+ $order[] = array('HMAC-SHA256', 'no-encryption');
2048+ }
2049+
2050+ return $order;
2051+}
2052+
2053+function Auth_OpenID_getOnlyEncryptedOrder()
2054+{
2055+ $result = array();
2056+
2057+ foreach (Auth_OpenID_getDefaultAssociationOrder() as $pair) {
2058+ list($assoc, $session) = $pair;
2059+
2060+ if ($session != 'no-encryption') {
2061+ if (Auth_OpenID_HMACSHA256_SUPPORTED &&
2062+ ($assoc == 'HMAC-SHA256')) {
2063+ $result[] = $pair;
2064+ } else if ($assoc != 'HMAC-SHA256') {
2065+ $result[] = $pair;
2066+ }
2067+ }
2068+ }
2069+
2070+ return $result;
2071+}
2072+
2073+function Auth_OpenID_getDefaultNegotiator()
2074+{
2075+ return new Auth_OpenID_SessionNegotiator(
2076+ Auth_OpenID_getDefaultAssociationOrder());
2077+}
2078+
2079+function Auth_OpenID_getEncryptedNegotiator()
2080+{
2081+ return new Auth_OpenID_SessionNegotiator(
2082+ Auth_OpenID_getOnlyEncryptedOrder());
2083+}
2084+
2085+/**
2086+ * A session negotiator controls the allowed and preferred association
2087+ * types and association session types. Both the {@link
2088+ * Auth_OpenID_Consumer} and {@link Auth_OpenID_Server} use
2089+ * negotiators when creating associations.
2090+ *
2091+ * You can create and use negotiators if you:
2092+
2093+ * - Do not want to do Diffie-Hellman key exchange because you use
2094+ * transport-layer encryption (e.g. SSL)
2095+ *
2096+ * - Want to use only SHA-256 associations
2097+ *
2098+ * - Do not want to support plain-text associations over a non-secure
2099+ * channel
2100+ *
2101+ * It is up to you to set a policy for what kinds of associations to
2102+ * accept. By default, the library will make any kind of association
2103+ * that is allowed in the OpenID 2.0 specification.
2104+ *
2105+ * Use of negotiators in the library
2106+ * =================================
2107+ *
2108+ * When a consumer makes an association request, it calls {@link
2109+ * getAllowedType} to get the preferred association type and
2110+ * association session type.
2111+ *
2112+ * The server gets a request for a particular association/session type
2113+ * and calls {@link isAllowed} to determine if it should create an
2114+ * association. If it is supported, negotiation is complete. If it is
2115+ * not, the server calls {@link getAllowedType} to get an allowed
2116+ * association type to return to the consumer.
2117+ *
2118+ * If the consumer gets an error response indicating that the
2119+ * requested association/session type is not supported by the server
2120+ * that contains an assocation/session type to try, it calls {@link
2121+ * isAllowed} to determine if it should try again with the given
2122+ * combination of association/session type.
2123+ *
2124+ * @package OpenID
2125+ */
2126+class Auth_OpenID_SessionNegotiator {
2127+ function Auth_OpenID_SessionNegotiator($allowed_types)
2128+ {
2129+ $this->allowed_types = array();
2130+ $this->setAllowedTypes($allowed_types);
2131+ }
2132+
2133+ /**
2134+ * Set the allowed association types, checking to make sure each
2135+ * combination is valid.
2136+ *
2137+ * @access private
2138+ */
2139+ function setAllowedTypes($allowed_types)
2140+ {
2141+ foreach ($allowed_types as $pair) {
2142+ list($assoc_type, $session_type) = $pair;
2143+ if (!Auth_OpenID_checkSessionType($assoc_type, $session_type)) {
2144+ return false;
2145+ }
2146+ }
2147+
2148+ $this->allowed_types = $allowed_types;
2149+ return true;
2150+ }
2151+
2152+ /**
2153+ * Add an association type and session type to the allowed types
2154+ * list. The assocation/session pairs are tried in the order that
2155+ * they are added.
2156+ *
2157+ * @access private
2158+ */
2159+ function addAllowedType($assoc_type, $session_type = null)
2160+ {
2161+ if ($this->allowed_types === null) {
2162+ $this->allowed_types = array();
2163+ }
2164+
2165+ if ($session_type === null) {
2166+ $available = Auth_OpenID_getSessionTypes($assoc_type);
2167+
2168+ if (!$available) {
2169+ return false;
2170+ }
2171+
2172+ foreach ($available as $session_type) {
2173+ $this->addAllowedType($assoc_type, $session_type);
2174+ }
2175+ } else {
2176+ if (Auth_OpenID_checkSessionType($assoc_type, $session_type)) {
2177+ $this->allowed_types[] = array($assoc_type, $session_type);
2178+ } else {
2179+ return false;
2180+ }
2181+ }
2182+
2183+ return true;
2184+ }
2185+
2186+ // Is this combination of association type and session type allowed?
2187+ function isAllowed($assoc_type, $session_type)
2188+ {
2189+ $assoc_good = in_array(array($assoc_type, $session_type),
2190+ $this->allowed_types);
2191+
2192+ $matches = in_array($session_type,
2193+ Auth_OpenID_getSessionTypes($assoc_type));
2194+
2195+ return ($assoc_good && $matches);
2196+ }
2197+
2198+ /**
2199+ * Get a pair of assocation type and session type that are
2200+ * supported.
2201+ */
2202+ function getAllowedType()
2203+ {
2204+ if (!$this->allowed_types) {
2205+ return array(null, null);
2206+ }
2207+
2208+ return $this->allowed_types[0];
2209+ }
2210+}
2211+
2212
2213=== added file 'Auth/OpenID/BigMath.php'
2214--- Auth/OpenID/BigMath.php 1970-01-01 00:00:00 +0000
2215+++ Auth/OpenID/BigMath.php 2011-06-19 04:48:34 +0000
2216@@ -0,0 +1,452 @@
2217+<?php
2218+
2219+/**
2220+ * BigMath: A math library wrapper that abstracts out the underlying
2221+ * long integer library.
2222+ *
2223+ * PHP versions 4 and 5
2224+ *
2225+ * LICENSE: See the COPYING file included in this distribution.
2226+ *
2227+ * @access private
2228+ * @package OpenID
2229+ * @author JanRain, Inc. <openid@janrain.com>
2230+ * @copyright 2005-2008 Janrain, Inc.
2231+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
2232+ */
2233+
2234+/**
2235+ * Needed for random number generation
2236+ */
2237+require_once 'Auth/OpenID/CryptUtil.php';
2238+
2239+/**
2240+ * Need Auth_OpenID::bytes().
2241+ */
2242+require_once 'Auth/OpenID.php';
2243+
2244+/**
2245+ * The superclass of all big-integer math implementations
2246+ * @access private
2247+ * @package OpenID
2248+ */
2249+class Auth_OpenID_MathLibrary {
2250+ /**
2251+ * Given a long integer, returns the number converted to a binary
2252+ * string. This function accepts long integer values of arbitrary
2253+ * magnitude and uses the local large-number math library when
2254+ * available.
2255+ *
2256+ * @param integer $long The long number (can be a normal PHP
2257+ * integer or a number created by one of the available long number
2258+ * libraries)
2259+ * @return string $binary The binary version of $long
2260+ */
2261+ function longToBinary($long)
2262+ {
2263+ $cmp = $this->cmp($long, 0);
2264+ if ($cmp < 0) {
2265+ $msg = __FUNCTION__ . " takes only positive integers.";
2266+ trigger_error($msg, E_USER_ERROR);
2267+ return null;
2268+ }
2269+
2270+ if ($cmp == 0) {
2271+ return "\x00";
2272+ }
2273+
2274+ $bytes = array();
2275+
2276+ while ($this->cmp($long, 0) > 0) {
2277+ array_unshift($bytes, $this->mod($long, 256));
2278+ $long = $this->div($long, pow(2, 8));
2279+ }
2280+
2281+ if ($bytes && ($bytes[0] > 127)) {
2282+ array_unshift($bytes, 0);
2283+ }
2284+
2285+ $string = '';
2286+ foreach ($bytes as $byte) {
2287+ $string .= pack('C', $byte);
2288+ }
2289+
2290+ return $string;
2291+ }
2292+
2293+ /**
2294+ * Given a binary string, returns the binary string converted to a
2295+ * long number.
2296+ *
2297+ * @param string $binary The binary version of a long number,
2298+ * probably as a result of calling longToBinary
2299+ * @return integer $long The long number equivalent of the binary
2300+ * string $str
2301+ */
2302+ function binaryToLong($str)
2303+ {
2304+ if ($str === null) {
2305+ return null;
2306+ }
2307+
2308+ // Use array_merge to return a zero-indexed array instead of a
2309+ // one-indexed array.
2310+ $bytes = array_merge(unpack('C*', $str));
2311+
2312+ $n = $this->init(0);
2313+
2314+ if ($bytes && ($bytes[0] > 127)) {
2315+ trigger_error("bytesToNum works only for positive integers.",
2316+ E_USER_WARNING);
2317+ return null;
2318+ }
2319+
2320+ foreach ($bytes as $byte) {
2321+ $n = $this->mul($n, pow(2, 8));
2322+ $n = $this->add($n, $byte);
2323+ }
2324+
2325+ return $n;
2326+ }
2327+
2328+ function base64ToLong($str)
2329+ {
2330+ $b64 = base64_decode($str);
2331+
2332+ if ($b64 === false) {
2333+ return false;
2334+ }
2335+
2336+ return $this->binaryToLong($b64);
2337+ }
2338+
2339+ function longToBase64($str)
2340+ {
2341+ return base64_encode($this->longToBinary($str));
2342+ }
2343+
2344+ /**
2345+ * Returns a random number in the specified range. This function
2346+ * accepts $start, $stop, and $step values of arbitrary magnitude
2347+ * and will utilize the local large-number math library when
2348+ * available.
2349+ *
2350+ * @param integer $start The start of the range, or the minimum
2351+ * random number to return
2352+ * @param integer $stop The end of the range, or the maximum
2353+ * random number to return
2354+ * @param integer $step The step size, such that $result - ($step
2355+ * * N) = $start for some N
2356+ * @return integer $result The resulting randomly-generated number
2357+ */
2358+ function rand($stop)
2359+ {
2360+ static $duplicate_cache = array();
2361+
2362+ // Used as the key for the duplicate cache
2363+ $rbytes = $this->longToBinary($stop);
2364+
2365+ if (array_key_exists($rbytes, $duplicate_cache)) {
2366+ list($duplicate, $nbytes) = $duplicate_cache[$rbytes];
2367+ } else {
2368+ if ($rbytes[0] == "\x00") {
2369+ $nbytes = Auth_OpenID::bytes($rbytes) - 1;
2370+ } else {
2371+ $nbytes = Auth_OpenID::bytes($rbytes);
2372+ }
2373+
2374+ $mxrand = $this->pow(256, $nbytes);
2375+
2376+ // If we get a number less than this, then it is in the
2377+ // duplicated range.
2378+ $duplicate = $this->mod($mxrand, $stop);
2379+
2380+ if (count($duplicate_cache) > 10) {
2381+ $duplicate_cache = array();
2382+ }
2383+
2384+ $duplicate_cache[$rbytes] = array($duplicate, $nbytes);
2385+ }
2386+
2387+ do {
2388+ $bytes = "\x00" . Auth_OpenID_CryptUtil::getBytes($nbytes);
2389+ $n = $this->binaryToLong($bytes);
2390+ // Keep looping if this value is in the low duplicated range
2391+ } while ($this->cmp($n, $duplicate) < 0);
2392+
2393+ return $this->mod($n, $stop);
2394+ }
2395+}
2396+
2397+/**
2398+ * Exposes BCmath math library functionality.
2399+ *
2400+ * {@link Auth_OpenID_BcMathWrapper} wraps the functionality provided
2401+ * by the BCMath extension.
2402+ *
2403+ * @access private
2404+ * @package OpenID
2405+ */
2406+class Auth_OpenID_BcMathWrapper extends Auth_OpenID_MathLibrary{
2407+ var $type = 'bcmath';
2408+
2409+ function add($x, $y)
2410+ {
2411+ return bcadd($x, $y);
2412+ }
2413+
2414+ function sub($x, $y)
2415+ {
2416+ return bcsub($x, $y);
2417+ }
2418+
2419+ function pow($base, $exponent)
2420+ {
2421+ return bcpow($base, $exponent);
2422+ }
2423+
2424+ function cmp($x, $y)
2425+ {
2426+ return bccomp($x, $y);
2427+ }
2428+
2429+ function init($number, $base = 10)
2430+ {
2431+ return $number;
2432+ }
2433+
2434+ function mod($base, $modulus)
2435+ {
2436+ return bcmod($base, $modulus);
2437+ }
2438+
2439+ function mul($x, $y)
2440+ {
2441+ return bcmul($x, $y);
2442+ }
2443+
2444+ function div($x, $y)
2445+ {
2446+ return bcdiv($x, $y);
2447+ }
2448+
2449+ /**
2450+ * Same as bcpowmod when bcpowmod is missing
2451+ *
2452+ * @access private
2453+ */
2454+ function _powmod($base, $exponent, $modulus)
2455+ {
2456+ $square = $this->mod($base, $modulus);
2457+ $result = 1;
2458+ while($this->cmp($exponent, 0) > 0) {
2459+ if ($this->mod($exponent, 2)) {
2460+ $result = $this->mod($this->mul($result, $square), $modulus);
2461+ }
2462+ $square = $this->mod($this->mul($square, $square), $modulus);
2463+ $exponent = $this->div($exponent, 2);
2464+ }
2465+ return $result;
2466+ }
2467+
2468+ function powmod($base, $exponent, $modulus)
2469+ {
2470+ if (function_exists('bcpowmod')) {
2471+ return bcpowmod($base, $exponent, $modulus);
2472+ } else {
2473+ return $this->_powmod($base, $exponent, $modulus);
2474+ }
2475+ }
2476+
2477+ function toString($num)
2478+ {
2479+ return $num;
2480+ }
2481+}
2482+
2483+/**
2484+ * Exposes GMP math library functionality.
2485+ *
2486+ * {@link Auth_OpenID_GmpMathWrapper} wraps the functionality provided
2487+ * by the GMP extension.
2488+ *
2489+ * @access private
2490+ * @package OpenID
2491+ */
2492+class Auth_OpenID_GmpMathWrapper extends Auth_OpenID_MathLibrary{
2493+ var $type = 'gmp';
2494+
2495+ function add($x, $y)
2496+ {
2497+ return gmp_add($x, $y);
2498+ }
2499+
2500+ function sub($x, $y)
2501+ {
2502+ return gmp_sub($x, $y);
2503+ }
2504+
2505+ function pow($base, $exponent)
2506+ {
2507+ return gmp_pow($base, $exponent);
2508+ }
2509+
2510+ function cmp($x, $y)
2511+ {
2512+ return gmp_cmp($x, $y);
2513+ }
2514+
2515+ function init($number, $base = 10)
2516+ {
2517+ return gmp_init($number, $base);
2518+ }
2519+
2520+ function mod($base, $modulus)
2521+ {
2522+ return gmp_mod($base, $modulus);
2523+ }
2524+
2525+ function mul($x, $y)
2526+ {
2527+ return gmp_mul($x, $y);
2528+ }
2529+
2530+ function div($x, $y)
2531+ {
2532+ return gmp_div_q($x, $y);
2533+ }
2534+
2535+ function powmod($base, $exponent, $modulus)
2536+ {
2537+ return gmp_powm($base, $exponent, $modulus);
2538+ }
2539+
2540+ function toString($num)
2541+ {
2542+ return gmp_strval($num);
2543+ }
2544+}
2545+
2546+/**
2547+ * Define the supported extensions. An extension array has keys
2548+ * 'modules', 'extension', and 'class'. 'modules' is an array of PHP
2549+ * module names which the loading code will attempt to load. These
2550+ * values will be suffixed with a library file extension (e.g. ".so").
2551+ * 'extension' is the name of a PHP extension which will be tested
2552+ * before 'modules' are loaded. 'class' is the string name of a
2553+ * {@link Auth_OpenID_MathWrapper} subclass which should be
2554+ * instantiated if a given extension is present.
2555+ *
2556+ * You can define new math library implementations and add them to
2557+ * this array.
2558+ */
2559+function Auth_OpenID_math_extensions()
2560+{
2561+ $result = array();
2562+
2563+ if (!defined('Auth_OpenID_BUGGY_GMP')) {
2564+ $result[] =
2565+ array('modules' => array('gmp', 'php_gmp'),
2566+ 'extension' => 'gmp',
2567+ 'class' => 'Auth_OpenID_GmpMathWrapper');
2568+ }
2569+
2570+ $result[] = array('modules' => array('bcmath', 'php_bcmath'),
2571+ 'extension' => 'bcmath',
2572+ 'class' => 'Auth_OpenID_BcMathWrapper');
2573+
2574+ return $result;
2575+}
2576+
2577+/**
2578+ * Detect which (if any) math library is available
2579+ */
2580+function Auth_OpenID_detectMathLibrary($exts)
2581+{
2582+ $loaded = false;
2583+
2584+ $hasDl = function_exists('dl');
2585+ foreach ($exts as $extension) {
2586+ if (extension_loaded($extension['extension'])) {
2587+ return $extension;
2588+ }
2589+ }
2590+
2591+ return false;
2592+}
2593+
2594+/**
2595+ * {@link Auth_OpenID_getMathLib} checks for the presence of long
2596+ * number extension modules and returns an instance of
2597+ * {@link Auth_OpenID_MathWrapper} which exposes the module's
2598+ * functionality.
2599+ *
2600+ * Checks for the existence of an extension module described by the
2601+ * result of {@link Auth_OpenID_math_extensions()} and returns an
2602+ * instance of a wrapper for that extension module. If no extension
2603+ * module is found, an instance of {@link Auth_OpenID_MathWrapper} is
2604+ * returned, which wraps the native PHP integer implementation. The
2605+ * proper calling convention for this method is $lib =
2606+ * Auth_OpenID_getMathLib().
2607+ *
2608+ * This function checks for the existence of specific long number
2609+ * implementations in the following order: GMP followed by BCmath.
2610+ *
2611+ * @return Auth_OpenID_MathWrapper $instance An instance of
2612+ * {@link Auth_OpenID_MathWrapper} or one of its subclasses
2613+ *
2614+ * @package OpenID
2615+ */
2616+function Auth_OpenID_getMathLib()
2617+{
2618+ // The instance of Auth_OpenID_MathWrapper that we choose to
2619+ // supply will be stored here, so that subseqent calls to this
2620+ // method will return a reference to the same object.
2621+ static $lib = null;
2622+
2623+ if (isset($lib)) {
2624+ return $lib;
2625+ }
2626+
2627+ if (Auth_OpenID_noMathSupport()) {
2628+ $null = null;
2629+ return $null;
2630+ }
2631+
2632+ // If this method has not been called before, look at
2633+ // Auth_OpenID_math_extensions and try to find an extension that
2634+ // works.
2635+ $ext = Auth_OpenID_detectMathLibrary(Auth_OpenID_math_extensions());
2636+ if ($ext === false) {
2637+ $tried = array();
2638+ foreach (Auth_OpenID_math_extensions() as $extinfo) {
2639+ $tried[] = $extinfo['extension'];
2640+ }
2641+ $triedstr = implode(", ", $tried);
2642+
2643+ Auth_OpenID_setNoMathSupport();
2644+
2645+ $result = null;
2646+ return $result;
2647+ }
2648+
2649+ // Instantiate a new wrapper
2650+ $class = $ext['class'];
2651+ $lib = new $class();
2652+
2653+ return $lib;
2654+}
2655+
2656+function Auth_OpenID_setNoMathSupport()
2657+{
2658+ if (!defined('Auth_OpenID_NO_MATH_SUPPORT')) {
2659+ define('Auth_OpenID_NO_MATH_SUPPORT', true);
2660+ }
2661+}
2662+
2663+function Auth_OpenID_noMathSupport()
2664+{
2665+ return defined('Auth_OpenID_NO_MATH_SUPPORT');
2666+}
2667+
2668+
2669
2670=== added file 'Auth/OpenID/Consumer.php'
2671--- Auth/OpenID/Consumer.php 1970-01-01 00:00:00 +0000
2672+++ Auth/OpenID/Consumer.php 2011-06-19 04:48:34 +0000
2673@@ -0,0 +1,2230 @@
2674+<?php
2675+
2676+/**
2677+ * This module documents the main interface with the OpenID consumer
2678+ * library. The only part of the library which has to be used and
2679+ * isn't documented in full here is the store required to create an
2680+ * Auth_OpenID_Consumer instance. More on the abstract store type and
2681+ * concrete implementations of it that are provided in the
2682+ * documentation for the Auth_OpenID_Consumer constructor.
2683+ *
2684+ * OVERVIEW
2685+ *
2686+ * The OpenID identity verification process most commonly uses the
2687+ * following steps, as visible to the user of this library:
2688+ *
2689+ * 1. The user enters their OpenID into a field on the consumer's
2690+ * site, and hits a login button.
2691+ * 2. The consumer site discovers the user's OpenID server using the
2692+ * YADIS protocol.
2693+ * 3. The consumer site sends the browser a redirect to the identity
2694+ * server. This is the authentication request as described in
2695+ * the OpenID specification.
2696+ * 4. The identity server's site sends the browser a redirect back
2697+ * to the consumer site. This redirect contains the server's
2698+ * response to the authentication request.
2699+ *
2700+ * The most important part of the flow to note is the consumer's site
2701+ * must handle two separate HTTP requests in order to perform the full
2702+ * identity check.
2703+ *
2704+ * LIBRARY DESIGN
2705+ *
2706+ * This consumer library is designed with that flow in mind. The goal
2707+ * is to make it as easy as possible to perform the above steps
2708+ * securely.
2709+ *
2710+ * At a high level, there are two important parts in the consumer
2711+ * library. The first important part is this module, which contains
2712+ * the interface to actually use this library. The second is the
2713+ * Auth_OpenID_Interface class, which describes the interface to use
2714+ * if you need to create a custom method for storing the state this
2715+ * library needs to maintain between requests.
2716+ *
2717+ * In general, the second part is less important for users of the
2718+ * library to know about, as several implementations are provided
2719+ * which cover a wide variety of situations in which consumers may use
2720+ * the library.
2721+ *
2722+ * This module contains a class, Auth_OpenID_Consumer, with methods
2723+ * corresponding to the actions necessary in each of steps 2, 3, and 4
2724+ * described in the overview. Use of this library should be as easy
2725+ * as creating an Auth_OpenID_Consumer instance and calling the
2726+ * methods appropriate for the action the site wants to take.
2727+ *
2728+ * STORES AND DUMB MODE
2729+ *
2730+ * OpenID is a protocol that works best when the consumer site is able
2731+ * to store some state. This is the normal mode of operation for the
2732+ * protocol, and is sometimes referred to as smart mode. There is
2733+ * also a fallback mode, known as dumb mode, which is available when
2734+ * the consumer site is not able to store state. This mode should be
2735+ * avoided when possible, as it leaves the implementation more
2736+ * vulnerable to replay attacks.
2737+ *
2738+ * The mode the library works in for normal operation is determined by
2739+ * the store that it is given. The store is an abstraction that
2740+ * handles the data that the consumer needs to manage between http
2741+ * requests in order to operate efficiently and securely.
2742+ *
2743+ * Several store implementation are provided, and the interface is
2744+ * fully documented so that custom stores can be used as well. See
2745+ * the documentation for the Auth_OpenID_Consumer class for more
2746+ * information on the interface for stores. The implementations that
2747+ * are provided allow the consumer site to store the necessary data in
2748+ * several different ways, including several SQL databases and normal
2749+ * files on disk.
2750+ *
2751+ * There is an additional concrete store provided that puts the system
2752+ * in dumb mode. This is not recommended, as it removes the library's
2753+ * ability to stop replay attacks reliably. It still uses time-based
2754+ * checking to make replay attacks only possible within a small
2755+ * window, but they remain possible within that window. This store
2756+ * should only be used if the consumer site has no way to retain data
2757+ * between requests at all.
2758+ *
2759+ * IMMEDIATE MODE
2760+ *
2761+ * In the flow described above, the user may need to confirm to the
2762+ * lidentity server that it's ok to authorize his or her identity.
2763+ * The server may draw pages asking for information from the user
2764+ * before it redirects the browser back to the consumer's site. This
2765+ * is generally transparent to the consumer site, so it is typically
2766+ * ignored as an implementation detail.
2767+ *
2768+ * There can be times, however, where the consumer site wants to get a
2769+ * response immediately. When this is the case, the consumer can put
2770+ * the library in immediate mode. In immediate mode, there is an
2771+ * extra response possible from the server, which is essentially the
2772+ * server reporting that it doesn't have enough information to answer
2773+ * the question yet.
2774+ *
2775+ * USING THIS LIBRARY
2776+ *
2777+ * Integrating this library into an application is usually a
2778+ * relatively straightforward process. The process should basically
2779+ * follow this plan:
2780+ *
2781+ * Add an OpenID login field somewhere on your site. When an OpenID
2782+ * is entered in that field and the form is submitted, it should make
2783+ * a request to the your site which includes that OpenID URL.
2784+ *
2785+ * First, the application should instantiate the Auth_OpenID_Consumer
2786+ * class using the store of choice (Auth_OpenID_FileStore or one of
2787+ * the SQL-based stores). If the application has a custom
2788+ * session-management implementation, an object implementing the
2789+ * {@link Auth_Yadis_PHPSession} interface should be passed as the
2790+ * second parameter. Otherwise, the default uses $_SESSION.
2791+ *
2792+ * Next, the application should call the Auth_OpenID_Consumer object's
2793+ * 'begin' method. This method takes the OpenID URL. The 'begin'
2794+ * method returns an Auth_OpenID_AuthRequest object.
2795+ *
2796+ * Next, the application should call the 'redirectURL' method of the
2797+ * Auth_OpenID_AuthRequest object. The 'return_to' URL parameter is
2798+ * the URL that the OpenID server will send the user back to after
2799+ * attempting to verify his or her identity. The 'trust_root' is the
2800+ * URL (or URL pattern) that identifies your web site to the user when
2801+ * he or she is authorizing it. Send a redirect to the resulting URL
2802+ * to the user's browser.
2803+ *
2804+ * That's the first half of the authentication process. The second
2805+ * half of the process is done after the user's ID server sends the
2806+ * user's browser a redirect back to your site to complete their
2807+ * login.
2808+ *
2809+ * When that happens, the user will contact your site at the URL given
2810+ * as the 'return_to' URL to the Auth_OpenID_AuthRequest::redirectURL
2811+ * call made above. The request will have several query parameters
2812+ * added to the URL by the identity server as the information
2813+ * necessary to finish the request.
2814+ *
2815+ * Lastly, instantiate an Auth_OpenID_Consumer instance as above and
2816+ * call its 'complete' method, passing in all the received query
2817+ * arguments.
2818+ *
2819+ * There are multiple possible return types possible from that
2820+ * method. These indicate the whether or not the login was successful,
2821+ * and include any additional information appropriate for their type.
2822+ *
2823+ * PHP versions 4 and 5
2824+ *
2825+ * LICENSE: See the COPYING file included in this distribution.
2826+ *
2827+ * @package OpenID
2828+ * @author JanRain, Inc. <openid@janrain.com>
2829+ * @copyright 2005-2008 Janrain, Inc.
2830+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
2831+ */
2832+
2833+/**
2834+ * Require utility classes and functions for the consumer.
2835+ */
2836+require_once "Auth/OpenID.php";
2837+require_once "Auth/OpenID/Message.php";
2838+require_once "Auth/OpenID/HMAC.php";
2839+require_once "Auth/OpenID/Association.php";
2840+require_once "Auth/OpenID/CryptUtil.php";
2841+require_once "Auth/OpenID/DiffieHellman.php";
2842+require_once "Auth/OpenID/KVForm.php";
2843+require_once "Auth/OpenID/Nonce.php";
2844+require_once "Auth/OpenID/Discover.php";
2845+require_once "Auth/OpenID/URINorm.php";
2846+require_once "Auth/Yadis/Manager.php";
2847+require_once "Auth/Yadis/XRI.php";
2848+
2849+/**
2850+ * This is the status code returned when the complete method returns
2851+ * successfully.
2852+ */
2853+define('Auth_OpenID_SUCCESS', 'success');
2854+
2855+/**
2856+ * Status to indicate cancellation of OpenID authentication.
2857+ */
2858+define('Auth_OpenID_CANCEL', 'cancel');
2859+
2860+/**
2861+ * This is the status code completeAuth returns when the value it
2862+ * received indicated an invalid login.
2863+ */
2864+define('Auth_OpenID_FAILURE', 'failure');
2865+
2866+/**
2867+ * This is the status code completeAuth returns when the
2868+ * {@link Auth_OpenID_Consumer} instance is in immediate mode, and the
2869+ * identity server sends back a URL to send the user to to complete his
2870+ * or her login.
2871+ */
2872+define('Auth_OpenID_SETUP_NEEDED', 'setup needed');
2873+
2874+/**
2875+ * This is the status code beginAuth returns when the page fetched
2876+ * from the entered OpenID URL doesn't contain the necessary link tags
2877+ * to function as an identity page.
2878+ */
2879+define('Auth_OpenID_PARSE_ERROR', 'parse error');
2880+
2881+/**
2882+ * An OpenID consumer implementation that performs discovery and does
2883+ * session management. See the Consumer.php file documentation for
2884+ * more information.
2885+ *
2886+ * @package OpenID
2887+ */
2888+class Auth_OpenID_Consumer {
2889+
2890+ /**
2891+ * @access private
2892+ */
2893+ var $discoverMethod = 'Auth_OpenID_discover';
2894+
2895+ /**
2896+ * @access private
2897+ */
2898+ var $session_key_prefix = "_openid_consumer_";
2899+
2900+ /**
2901+ * @access private
2902+ */
2903+ var $_token_suffix = "last_token";
2904+
2905+ /**
2906+ * Initialize a Consumer instance.
2907+ *
2908+ * You should create a new instance of the Consumer object with
2909+ * every HTTP request that handles OpenID transactions.
2910+ *
2911+ * @param Auth_OpenID_OpenIDStore $store This must be an object
2912+ * that implements the interface in {@link
2913+ * Auth_OpenID_OpenIDStore}. Several concrete implementations are
2914+ * provided, to cover most common use cases. For stores backed by
2915+ * MySQL, PostgreSQL, or SQLite, see the {@link
2916+ * Auth_OpenID_SQLStore} class and its sublcasses. For a
2917+ * filesystem-backed store, see the {@link Auth_OpenID_FileStore}
2918+ * module. As a last resort, if it isn't possible for the server
2919+ * to store state at all, an instance of {@link
2920+ * Auth_OpenID_DumbStore} can be used.
2921+ *
2922+ * @param mixed $session An object which implements the interface
2923+ * of the {@link Auth_Yadis_PHPSession} class. Particularly, this
2924+ * object is expected to have these methods: get($key), set($key),
2925+ * $value), and del($key). This defaults to a session object
2926+ * which wraps PHP's native session machinery. You should only
2927+ * need to pass something here if you have your own sessioning
2928+ * implementation.
2929+ *
2930+ * @param str $consumer_cls The name of the class to instantiate
2931+ * when creating the internal consumer object. This is used for
2932+ * testing.
2933+ */
2934+ function Auth_OpenID_Consumer($store, $session = null,
2935+ $consumer_cls = null)
2936+ {
2937+ if ($session === null) {
2938+ $session = new Auth_Yadis_PHPSession();
2939+ }
2940+
2941+ $this->session = $session;
2942+
2943+ if ($consumer_cls !== null) {
2944+ $this->consumer = new $consumer_cls($store);
2945+ } else {
2946+ $this->consumer = new Auth_OpenID_GenericConsumer($store);
2947+ }
2948+
2949+ $this->_token_key = $this->session_key_prefix . $this->_token_suffix;
2950+ }
2951+
2952+ /**
2953+ * Used in testing to define the discovery mechanism.
2954+ *
2955+ * @access private
2956+ */
2957+ function getDiscoveryObject($session, $openid_url,
2958+ $session_key_prefix)
2959+ {
2960+ return new Auth_Yadis_Discovery($session, $openid_url,
2961+ $session_key_prefix);
2962+ }
2963+
2964+ /**
2965+ * Start the OpenID authentication process. See steps 1-2 in the
2966+ * overview at the top of this file.
2967+ *
2968+ * @param string $user_url Identity URL given by the user. This
2969+ * method performs a textual transformation of the URL to try and
2970+ * make sure it is normalized. For example, a user_url of
2971+ * example.com will be normalized to http://example.com/
2972+ * normalizing and resolving any redirects the server might issue.
2973+ *
2974+ * @param bool $anonymous True if the OpenID request is to be sent
2975+ * to the server without any identifier information. Use this
2976+ * when you want to transport data but don't want to do OpenID
2977+ * authentication with identifiers.
2978+ *
2979+ * @return Auth_OpenID_AuthRequest $auth_request An object
2980+ * containing the discovered information will be returned, with a
2981+ * method for building a redirect URL to the server, as described
2982+ * in step 3 of the overview. This object may also be used to add
2983+ * extension arguments to the request, using its 'addExtensionArg'
2984+ * method.
2985+ */
2986+ function begin($user_url, $anonymous=false)
2987+ {
2988+ $openid_url = $user_url;
2989+
2990+ $disco = $this->getDiscoveryObject($this->session,
2991+ $openid_url,
2992+ $this->session_key_prefix);
2993+
2994+ // Set the 'stale' attribute of the manager. If discovery
2995+ // fails in a fatal way, the stale flag will cause the manager
2996+ // to be cleaned up next time discovery is attempted.
2997+
2998+ $m = $disco->getManager();
2999+ $loader = new Auth_Yadis_ManagerLoader();
3000+
3001+ if ($m) {
3002+ if ($m->stale) {
3003+ $disco->destroyManager();
3004+ } else {
3005+ $m->stale = true;
3006+ $disco->session->set($disco->session_key,
3007+ serialize($loader->toSession($m)));
3008+ }
3009+ }
3010+
3011+ $endpoint = $disco->getNextService($this->discoverMethod,
3012+ $this->consumer->fetcher);
3013+
3014+ // Reset the 'stale' attribute of the manager.
3015+ $m = $disco->getManager();
3016+ if ($m) {
3017+ $m->stale = false;
3018+ $disco->session->set($disco->session_key,
3019+ serialize($loader->toSession($m)));
3020+ }
3021+
3022+ if ($endpoint === null) {
3023+ return null;
3024+ } else {
3025+ return $this->beginWithoutDiscovery($endpoint,
3026+ $anonymous);
3027+ }
3028+ }
3029+
3030+ /**
3031+ * Start OpenID verification without doing OpenID server
3032+ * discovery. This method is used internally by Consumer.begin
3033+ * after discovery is performed, and exists to provide an
3034+ * interface for library users needing to perform their own
3035+ * discovery.
3036+ *
3037+ * @param Auth_OpenID_ServiceEndpoint $endpoint an OpenID service
3038+ * endpoint descriptor.
3039+ *
3040+ * @param bool anonymous Set to true if you want to perform OpenID
3041+ * without identifiers.
3042+ *
3043+ * @return Auth_OpenID_AuthRequest $auth_request An OpenID
3044+ * authentication request object.
3045+ */
3046+ function beginWithoutDiscovery($endpoint, $anonymous=false)
3047+ {
3048+ $loader = new Auth_OpenID_ServiceEndpointLoader();
3049+ $auth_req = $this->consumer->begin($endpoint);
3050+ $this->session->set($this->_token_key,
3051+ $loader->toSession($auth_req->endpoint));
3052+ if (!$auth_req->setAnonymous($anonymous)) {
3053+ return new Auth_OpenID_FailureResponse(null,
3054+ "OpenID 1 requests MUST include the identifier " .
3055+ "in the request.");
3056+ }
3057+ return $auth_req;
3058+ }
3059+
3060+ /**
3061+ * Called to interpret the server's response to an OpenID
3062+ * request. It is called in step 4 of the flow described in the
3063+ * consumer overview.
3064+ *
3065+ * @param string $current_url The URL used to invoke the application.
3066+ * Extract the URL from your application's web
3067+ * request framework and specify it here to have it checked
3068+ * against the openid.current_url value in the response. If
3069+ * the current_url URL check fails, the status of the
3070+ * completion will be FAILURE.
3071+ *
3072+ * @param array $query An array of the query parameters (key =>
3073+ * value pairs) for this HTTP request. Defaults to null. If
3074+ * null, the GET or POST data are automatically gotten from the
3075+ * PHP environment. It is only useful to override $query for
3076+ * testing.
3077+ *
3078+ * @return Auth_OpenID_ConsumerResponse $response A instance of an
3079+ * Auth_OpenID_ConsumerResponse subclass. The type of response is
3080+ * indicated by the status attribute, which will be one of
3081+ * SUCCESS, CANCEL, FAILURE, or SETUP_NEEDED.
3082+ */
3083+ function complete($current_url, $query=null)
3084+ {
3085+ if ($current_url && !is_string($current_url)) {
3086+ // This is ugly, but we need to complain loudly when
3087+ // someone uses the API incorrectly.
3088+ trigger_error("current_url must be a string; see NEWS file " .
3089+ "for upgrading notes.",
3090+ E_USER_ERROR);
3091+ }
3092+
3093+ if ($query === null) {
3094+ $query = Auth_OpenID::getQuery();
3095+ }
3096+
3097+ $loader = new Auth_OpenID_ServiceEndpointLoader();
3098+ $endpoint_data = $this->session->get($this->_token_key);
3099+ $endpoint =
3100+ $loader->fromSession($endpoint_data);
3101+
3102+ $message = Auth_OpenID_Message::fromPostArgs($query);
3103+ $response = $this->consumer->complete($message, $endpoint,
3104+ $current_url);
3105+ $this->session->del($this->_token_key);
3106+
3107+ if (in_array($response->status, array(Auth_OpenID_SUCCESS,
3108+ Auth_OpenID_CANCEL))) {
3109+ if ($response->identity_url !== null) {
3110+ $disco = $this->getDiscoveryObject($this->session,
3111+ $response->identity_url,
3112+ $this->session_key_prefix);
3113+ $disco->cleanup(true);
3114+ }
3115+ }
3116+
3117+ return $response;
3118+ }
3119+}
3120+
3121+/**
3122+ * A class implementing HMAC/DH-SHA1 consumer sessions.
3123+ *
3124+ * @package OpenID
3125+ */
3126+class Auth_OpenID_DiffieHellmanSHA1ConsumerSession {
3127+ var $session_type = 'DH-SHA1';
3128+ var $hash_func = 'Auth_OpenID_SHA1';
3129+ var $secret_size = 20;
3130+ var $allowed_assoc_types = array('HMAC-SHA1');
3131+
3132+ function Auth_OpenID_DiffieHellmanSHA1ConsumerSession($dh = null)
3133+ {
3134+ if ($dh === null) {
3135+ $dh = new Auth_OpenID_DiffieHellman();
3136+ }
3137+
3138+ $this->dh = $dh;
3139+ }
3140+
3141+ function getRequest()
3142+ {
3143+ $math = Auth_OpenID_getMathLib();
3144+
3145+ $cpub = $math->longToBase64($this->dh->public);
3146+
3147+ $args = array('dh_consumer_public' => $cpub);
3148+
3149+ if (!$this->dh->usingDefaultValues()) {
3150+ $args = array_merge($args, array(
3151+ 'dh_modulus' =>
3152+ $math->longToBase64($this->dh->mod),
3153+ 'dh_gen' =>
3154+ $math->longToBase64($this->dh->gen)));
3155+ }
3156+
3157+ return $args;
3158+ }
3159+
3160+ function extractSecret($response)
3161+ {
3162+ if (!$response->hasKey(Auth_OpenID_OPENID_NS,
3163+ 'dh_server_public')) {
3164+ return null;
3165+ }
3166+
3167+ if (!$response->hasKey(Auth_OpenID_OPENID_NS,
3168+ 'enc_mac_key')) {
3169+ return null;
3170+ }
3171+
3172+ $math = Auth_OpenID_getMathLib();
3173+
3174+ $spub = $math->base64ToLong($response->getArg(Auth_OpenID_OPENID_NS,
3175+ 'dh_server_public'));
3176+ $enc_mac_key = base64_decode($response->getArg(Auth_OpenID_OPENID_NS,
3177+ 'enc_mac_key'));
3178+
3179+ return $this->dh->xorSecret($spub, $enc_mac_key, $this->hash_func);
3180+ }
3181+}
3182+
3183+/**
3184+ * A class implementing HMAC/DH-SHA256 consumer sessions.
3185+ *
3186+ * @package OpenID
3187+ */
3188+class Auth_OpenID_DiffieHellmanSHA256ConsumerSession extends
3189+ Auth_OpenID_DiffieHellmanSHA1ConsumerSession {
3190+ var $session_type = 'DH-SHA256';
3191+ var $hash_func = 'Auth_OpenID_SHA256';
3192+ var $secret_size = 32;
3193+ var $allowed_assoc_types = array('HMAC-SHA256');
3194+}
3195+
3196+/**
3197+ * A class implementing plaintext consumer sessions.
3198+ *
3199+ * @package OpenID
3200+ */
3201+class Auth_OpenID_PlainTextConsumerSession {
3202+ var $session_type = 'no-encryption';
3203+ var $allowed_assoc_types = array('HMAC-SHA1', 'HMAC-SHA256');
3204+
3205+ function getRequest()
3206+ {
3207+ return array();
3208+ }
3209+
3210+ function extractSecret($response)
3211+ {
3212+ if (!$response->hasKey(Auth_OpenID_OPENID_NS, 'mac_key')) {
3213+ return null;
3214+ }
3215+
3216+ return base64_decode($response->getArg(Auth_OpenID_OPENID_NS,
3217+ 'mac_key'));
3218+ }
3219+}
3220+
3221+/**
3222+ * Returns available session types.
3223+ */
3224+function Auth_OpenID_getAvailableSessionTypes()
3225+{
3226+ $types = array(
3227+ 'no-encryption' => 'Auth_OpenID_PlainTextConsumerSession',
3228+ 'DH-SHA1' => 'Auth_OpenID_DiffieHellmanSHA1ConsumerSession',
3229+ 'DH-SHA256' => 'Auth_OpenID_DiffieHellmanSHA256ConsumerSession');
3230+
3231+ return $types;
3232+}
3233+
3234+/**
3235+ * This class is the interface to the OpenID consumer logic.
3236+ * Instances of it maintain no per-request state, so they can be
3237+ * reused (or even used by multiple threads concurrently) as needed.
3238+ *
3239+ * @package OpenID
3240+ */
3241+class Auth_OpenID_GenericConsumer {
3242+ /**
3243+ * @access private
3244+ */
3245+ var $discoverMethod = 'Auth_OpenID_discover';
3246+
3247+ /**
3248+ * This consumer's store object.
3249+ */
3250+ var $store;
3251+
3252+ /**
3253+ * @access private
3254+ */
3255+ var $_use_assocs;
3256+
3257+ /**
3258+ * @access private
3259+ */
3260+ var $openid1_nonce_query_arg_name = 'janrain_nonce';
3261+
3262+ /**
3263+ * Another query parameter that gets added to the return_to for
3264+ * OpenID 1; if the user's session state is lost, use this claimed
3265+ * identifier to do discovery when verifying the response.
3266+ */
3267+ var $openid1_return_to_identifier_name = 'openid1_claimed_id';
3268+
3269+ /**
3270+ * This method initializes a new {@link Auth_OpenID_Consumer}
3271+ * instance to access the library.
3272+ *
3273+ * @param Auth_OpenID_OpenIDStore $store This must be an object
3274+ * that implements the interface in {@link Auth_OpenID_OpenIDStore}.
3275+ * Several concrete implementations are provided, to cover most common use
3276+ * cases. For stores backed by MySQL, PostgreSQL, or SQLite, see
3277+ * the {@link Auth_OpenID_SQLStore} class and its sublcasses. For a
3278+ * filesystem-backed store, see the {@link Auth_OpenID_FileStore} module.
3279+ * As a last resort, if it isn't possible for the server to store
3280+ * state at all, an instance of {@link Auth_OpenID_DumbStore} can be used.
3281+ *
3282+ * @param bool $immediate This is an optional boolean value. It
3283+ * controls whether the library uses immediate mode, as explained
3284+ * in the module description. The default value is False, which
3285+ * disables immediate mode.
3286+ */
3287+ function Auth_OpenID_GenericConsumer($store)
3288+ {
3289+ $this->store = $store;
3290+ $this->negotiator = Auth_OpenID_getDefaultNegotiator();
3291+ $this->_use_assocs = (is_null($this->store) ? false : true);
3292+
3293+ $this->fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
3294+
3295+ $this->session_types = Auth_OpenID_getAvailableSessionTypes();
3296+ }
3297+
3298+ /**
3299+ * Called to begin OpenID authentication using the specified
3300+ * {@link Auth_OpenID_ServiceEndpoint}.
3301+ *
3302+ * @access private
3303+ */
3304+ function begin($service_endpoint)
3305+ {
3306+ $assoc = $this->_getAssociation($service_endpoint);
3307+ $r = new Auth_OpenID_AuthRequest($service_endpoint, $assoc);
3308+ $r->return_to_args[$this->openid1_nonce_query_arg_name] =
3309+ Auth_OpenID_mkNonce();
3310+
3311+ if ($r->message->isOpenID1()) {
3312+ $r->return_to_args[$this->openid1_return_to_identifier_name] =
3313+ $r->endpoint->claimed_id;
3314+ }
3315+
3316+ return $r;
3317+ }
3318+
3319+ /**
3320+ * Given an {@link Auth_OpenID_Message}, {@link
3321+ * Auth_OpenID_ServiceEndpoint} and optional return_to URL,
3322+ * complete OpenID authentication.
3323+ *
3324+ * @access private
3325+ */
3326+ function complete($message, $endpoint, $return_to)
3327+ {
3328+ $mode = $message->getArg(Auth_OpenID_OPENID_NS, 'mode',
3329+ '<no mode set>');
3330+
3331+ $mode_methods = array(
3332+ 'cancel' => '_complete_cancel',
3333+ 'error' => '_complete_error',
3334+ 'setup_needed' => '_complete_setup_needed',
3335+ 'id_res' => '_complete_id_res',
3336+ );
3337+
3338+ $method = Auth_OpenID::arrayGet($mode_methods, $mode,
3339+ '_completeInvalid');
3340+
3341+ return call_user_func_array(array($this, $method),
3342+ array($message, &$endpoint, $return_to));
3343+ }
3344+
3345+ /**
3346+ * @access private
3347+ */
3348+ function _completeInvalid($message, $endpoint, $unused)
3349+ {
3350+ $mode = $message->getArg(Auth_OpenID_OPENID_NS, 'mode',
3351+ '<No mode set>');
3352+
3353+ return new Auth_OpenID_FailureResponse($endpoint,
3354+ sprintf("Invalid openid.mode '%s'", $mode));
3355+ }
3356+
3357+ /**
3358+ * @access private
3359+ */
3360+ function _complete_cancel($message, $endpoint, $unused)
3361+ {
3362+ return new Auth_OpenID_CancelResponse($endpoint);
3363+ }
3364+
3365+ /**
3366+ * @access private
3367+ */
3368+ function _complete_error($message, $endpoint, $unused)
3369+ {
3370+ $error = $message->getArg(Auth_OpenID_OPENID_NS, 'error');
3371+ $contact = $message->getArg(Auth_OpenID_OPENID_NS, 'contact');
3372+ $reference = $message->getArg(Auth_OpenID_OPENID_NS, 'reference');
3373+
3374+ return new Auth_OpenID_FailureResponse($endpoint, $error,
3375+ $contact, $reference);
3376+ }
3377+
3378+ /**
3379+ * @access private
3380+ */
3381+ function _complete_setup_needed($message, $endpoint, $unused)
3382+ {
3383+ if (!$message->isOpenID2()) {
3384+ return $this->_completeInvalid($message, $endpoint);
3385+ }
3386+
3387+ $user_setup_url = $message->getArg(Auth_OpenID_OPENID2_NS,
3388+ 'user_setup_url');
3389+ return new Auth_OpenID_SetupNeededResponse($endpoint, $user_setup_url);
3390+ }
3391+
3392+ /**
3393+ * @access private
3394+ */
3395+ function _complete_id_res($message, $endpoint, $return_to)
3396+ {
3397+ $user_setup_url = $message->getArg(Auth_OpenID_OPENID1_NS,
3398+ 'user_setup_url');
3399+
3400+ if ($this->_checkSetupNeeded($message)) {
3401+ return new Auth_OpenID_SetupNeededResponse(
3402+ $endpoint, $user_setup_url);
3403+ } else {
3404+ return $this->_doIdRes($message, $endpoint, $return_to);
3405+ }
3406+ }
3407+
3408+ /**
3409+ * @access private
3410+ */
3411+ function _checkSetupNeeded($message)
3412+ {
3413+ // In OpenID 1, we check to see if this is a cancel from
3414+ // immediate mode by the presence of the user_setup_url
3415+ // parameter.
3416+ if ($message->isOpenID1()) {
3417+ $user_setup_url = $message->getArg(Auth_OpenID_OPENID1_NS,
3418+ 'user_setup_url');
3419+ if ($user_setup_url !== null) {
3420+ return true;
3421+ }
3422+ }
3423+
3424+ return false;
3425+ }
3426+
3427+ /**
3428+ * @access private
3429+ */
3430+ function _doIdRes($message, $endpoint, $return_to)
3431+ {
3432+ // Checks for presence of appropriate fields (and checks
3433+ // signed list fields)
3434+ $result = $this->_idResCheckForFields($message);
3435+
3436+ if (Auth_OpenID::isFailure($result)) {
3437+ return $result;
3438+ }
3439+
3440+ if (!$this->_checkReturnTo($message, $return_to)) {
3441+ return new Auth_OpenID_FailureResponse(null,
3442+ sprintf("return_to does not match return URL. Expected %s, got %s",
3443+ $return_to,
3444+ $message->getArg(Auth_OpenID_OPENID_NS, 'return_to')));
3445+ }
3446+
3447+ // Verify discovery information:
3448+ $result = $this->_verifyDiscoveryResults($message, $endpoint);
3449+
3450+ if (Auth_OpenID::isFailure($result)) {
3451+ return $result;
3452+ }
3453+
3454+ $endpoint = $result;
3455+
3456+ $result = $this->_idResCheckSignature($message,
3457+ $endpoint->server_url);
3458+
3459+ if (Auth_OpenID::isFailure($result)) {
3460+ return $result;
3461+ }
3462+
3463+ $result = $this->_idResCheckNonce($message, $endpoint);
3464+
3465+ if (Auth_OpenID::isFailure($result)) {
3466+ return $result;
3467+ }
3468+
3469+ $signed_list_str = $message->getArg(Auth_OpenID_OPENID_NS, 'signed',
3470+ Auth_OpenID_NO_DEFAULT);
3471+ if (Auth_OpenID::isFailure($signed_list_str)) {
3472+ return $signed_list_str;
3473+ }
3474+ $signed_list = explode(',', $signed_list_str);
3475+
3476+ $signed_fields = Auth_OpenID::addPrefix($signed_list, "openid.");
3477+
3478+ return new Auth_OpenID_SuccessResponse($endpoint, $message,
3479+ $signed_fields);
3480+
3481+ }
3482+
3483+ /**
3484+ * @access private
3485+ */
3486+ function _checkReturnTo($message, $return_to)
3487+ {
3488+ // Check an OpenID message and its openid.return_to value
3489+ // against a return_to URL from an application. Return True
3490+ // on success, False on failure.
3491+
3492+ // Check the openid.return_to args against args in the
3493+ // original message.
3494+ $result = Auth_OpenID_GenericConsumer::_verifyReturnToArgs(
3495+ $message->toPostArgs());
3496+ if (Auth_OpenID::isFailure($result)) {
3497+ return false;
3498+ }
3499+
3500+ // Check the return_to base URL against the one in the
3501+ // message.
3502+ $msg_return_to = $message->getArg(Auth_OpenID_OPENID_NS,
3503+ 'return_to');
3504+ if (Auth_OpenID::isFailure($return_to)) {
3505+ // XXX log me
3506+ return false;
3507+ }
3508+
3509+ $return_to_parts = parse_url(Auth_OpenID_urinorm($return_to));
3510+ $msg_return_to_parts = parse_url(Auth_OpenID_urinorm($msg_return_to));
3511+
3512+ // If port is absent from both, add it so it's equal in the
3513+ // check below.
3514+ if ((!array_key_exists('port', $return_to_parts)) &&
3515+ (!array_key_exists('port', $msg_return_to_parts))) {
3516+ $return_to_parts['port'] = null;
3517+ $msg_return_to_parts['port'] = null;
3518+ }
3519+
3520+ // If path is absent from both, add it so it's equal in the
3521+ // check below.
3522+ if ((!array_key_exists('path', $return_to_parts)) &&
3523+ (!array_key_exists('path', $msg_return_to_parts))) {
3524+ $return_to_parts['path'] = null;
3525+ $msg_return_to_parts['path'] = null;
3526+ }
3527+
3528+ // The URL scheme, authority, and path MUST be the same
3529+ // between the two URLs.
3530+ foreach (array('scheme', 'host', 'port', 'path') as $component) {
3531+ // If the url component is absent in either URL, fail.
3532+ // There should always be a scheme, host, port, and path.
3533+ if (!array_key_exists($component, $return_to_parts)) {
3534+ return false;
3535+ }
3536+
3537+ if (!array_key_exists($component, $msg_return_to_parts)) {
3538+ return false;
3539+ }
3540+
3541+ if (Auth_OpenID::arrayGet($return_to_parts, $component) !==
3542+ Auth_OpenID::arrayGet($msg_return_to_parts, $component)) {
3543+ return false;
3544+ }
3545+ }
3546+
3547+ return true;
3548+ }
3549+
3550+ /**
3551+ * @access private
3552+ */
3553+ function _verifyReturnToArgs($query)
3554+ {
3555+ // Verify that the arguments in the return_to URL are present in this
3556+ // response.
3557+
3558+ $message = Auth_OpenID_Message::fromPostArgs($query);
3559+ $return_to = $message->getArg(Auth_OpenID_OPENID_NS, 'return_to');
3560+
3561+ if (Auth_OpenID::isFailure($return_to)) {
3562+ return $return_to;
3563+ }
3564+ // XXX: this should be checked by _idResCheckForFields
3565+ if (!$return_to) {
3566+ return new Auth_OpenID_FailureResponse(null,
3567+ "Response has no return_to");
3568+ }
3569+
3570+ $parsed_url = parse_url($return_to);
3571+
3572+ $q = array();
3573+ if (array_key_exists('query', $parsed_url)) {
3574+ $rt_query = $parsed_url['query'];
3575+ $q = Auth_OpenID::parse_str($rt_query);
3576+ }
3577+
3578+ foreach ($q as $rt_key => $rt_value) {
3579+ if (!array_key_exists($rt_key, $query)) {
3580+ return new Auth_OpenID_FailureResponse(null,
3581+ sprintf("return_to parameter %s absent from query", $rt_key));
3582+ } else {
3583+ $value = $query[$rt_key];
3584+ if ($rt_value != $value) {
3585+ return new Auth_OpenID_FailureResponse(null,
3586+ sprintf("parameter %s value %s does not match " .
3587+ "return_to value %s", $rt_key,
3588+ $value, $rt_value));
3589+ }
3590+ }
3591+ }
3592+
3593+ // Make sure all non-OpenID arguments in the response are also
3594+ // in the signed return_to.
3595+ $bare_args = $message->getArgs(Auth_OpenID_BARE_NS);
3596+ foreach ($bare_args as $key => $value) {
3597+ if (Auth_OpenID::arrayGet($q, $key) != $value) {
3598+ return new Auth_OpenID_FailureResponse(null,
3599+ sprintf("Parameter %s = %s not in return_to URL",
3600+ $key, $value));
3601+ }
3602+ }
3603+
3604+ return true;
3605+ }
3606+
3607+ /**
3608+ * @access private
3609+ */
3610+ function _idResCheckSignature($message, $server_url)
3611+ {
3612+ $assoc_handle = $message->getArg(Auth_OpenID_OPENID_NS,
3613+ 'assoc_handle');
3614+ if (Auth_OpenID::isFailure($assoc_handle)) {
3615+ return $assoc_handle;
3616+ }
3617+
3618+ $assoc = $this->store->getAssociation($server_url, $assoc_handle);
3619+
3620+ if ($assoc) {
3621+ if ($assoc->getExpiresIn() <= 0) {
3622+ // XXX: It might be a good idea sometimes to re-start
3623+ // the authentication with a new association. Doing it
3624+ // automatically opens the possibility for
3625+ // denial-of-service by a server that just returns
3626+ // expired associations (or really short-lived
3627+ // associations)
3628+ return new Auth_OpenID_FailureResponse(null,
3629+ 'Association with ' . $server_url . ' expired');
3630+ }
3631+
3632+ if (!$assoc->checkMessageSignature($message)) {
3633+ return new Auth_OpenID_FailureResponse(null,
3634+ "Bad signature");
3635+ }
3636+ } else {
3637+ // It's not an association we know about. Stateless mode
3638+ // is our only possible path for recovery. XXX - async
3639+ // framework will not want to block on this call to
3640+ // _checkAuth.
3641+ if (!$this->_checkAuth($message, $server_url)) {
3642+ return new Auth_OpenID_FailureResponse(null,
3643+ "Server denied check_authentication");
3644+ }
3645+ }
3646+
3647+ return null;
3648+ }
3649+
3650+ /**
3651+ * @access private
3652+ */
3653+ function _verifyDiscoveryResults($message, $endpoint=null)
3654+ {
3655+ if ($message->getOpenIDNamespace() == Auth_OpenID_OPENID2_NS) {
3656+ return $this->_verifyDiscoveryResultsOpenID2($message,
3657+ $endpoint);
3658+ } else {
3659+ return $this->_verifyDiscoveryResultsOpenID1($message,
3660+ $endpoint);
3661+ }
3662+ }
3663+
3664+ /**
3665+ * @access private
3666+ */
3667+ function _verifyDiscoveryResultsOpenID1($message, $endpoint)
3668+ {
3669+ $claimed_id = $message->getArg(Auth_OpenID_BARE_NS,
3670+ $this->openid1_return_to_identifier_name);
3671+
3672+ if (($endpoint === null) && ($claimed_id === null)) {
3673+ return new Auth_OpenID_FailureResponse($endpoint,
3674+ 'When using OpenID 1, the claimed ID must be supplied, ' .
3675+ 'either by passing it through as a return_to parameter ' .
3676+ 'or by using a session, and supplied to the GenericConsumer ' .
3677+ 'as the argument to complete()');
3678+ } else if (($endpoint !== null) && ($claimed_id === null)) {
3679+ $claimed_id = $endpoint->claimed_id;
3680+ }
3681+
3682+ $to_match = new Auth_OpenID_ServiceEndpoint();
3683+ $to_match->type_uris = array(Auth_OpenID_TYPE_1_1);
3684+ $to_match->local_id = $message->getArg(Auth_OpenID_OPENID1_NS,
3685+ 'identity');
3686+
3687+ // Restore delegate information from the initiation phase
3688+ $to_match->claimed_id = $claimed_id;
3689+
3690+ if ($to_match->local_id === null) {
3691+ return new Auth_OpenID_FailureResponse($endpoint,
3692+ "Missing required field openid.identity");
3693+ }
3694+
3695+ $to_match_1_0 = $to_match->copy();
3696+ $to_match_1_0->type_uris = array(Auth_OpenID_TYPE_1_0);
3697+
3698+ if ($endpoint !== null) {
3699+ $result = $this->_verifyDiscoverySingle($endpoint, $to_match);
3700+
3701+ if (is_a($result, 'Auth_OpenID_TypeURIMismatch')) {
3702+ $result = $this->_verifyDiscoverySingle($endpoint,
3703+ $to_match_1_0);
3704+ }
3705+
3706+ if (Auth_OpenID::isFailure($result)) {
3707+ // oidutil.log("Error attempting to use stored
3708+ // discovery information: " + str(e))
3709+ // oidutil.log("Attempting discovery to
3710+ // verify endpoint")
3711+ } else {
3712+ return $endpoint;
3713+ }
3714+ }
3715+
3716+ // Endpoint is either bad (failed verification) or None
3717+ return $this->_discoverAndVerify($to_match->claimed_id,
3718+ array($to_match, $to_match_1_0));
3719+ }
3720+
3721+ /**
3722+ * @access private
3723+ */
3724+ function _verifyDiscoverySingle($endpoint, $to_match)
3725+ {
3726+ // Every type URI that's in the to_match endpoint has to be
3727+ // present in the discovered endpoint.
3728+ foreach ($to_match->type_uris as $type_uri) {
3729+ if (!$endpoint->usesExtension($type_uri)) {
3730+ return new Auth_OpenID_TypeURIMismatch($endpoint,
3731+ "Required type ".$type_uri." not present");
3732+ }
3733+ }
3734+
3735+ // Fragments do not influence discovery, so we can't compare a
3736+ // claimed identifier with a fragment to discovered
3737+ // information.
3738+ list($defragged_claimed_id, $_) =
3739+ Auth_OpenID::urldefrag($to_match->claimed_id);
3740+
3741+ if ($defragged_claimed_id != $endpoint->claimed_id) {
3742+ return new Auth_OpenID_FailureResponse($endpoint,
3743+ sprintf('Claimed ID does not match (different subjects!), ' .
3744+ 'Expected %s, got %s', $defragged_claimed_id,
3745+ $endpoint->claimed_id));
3746+ }
3747+
3748+ if ($to_match->getLocalID() != $endpoint->getLocalID()) {
3749+ return new Auth_OpenID_FailureResponse($endpoint,
3750+ sprintf('local_id mismatch. Expected %s, got %s',
3751+ $to_match->getLocalID(), $endpoint->getLocalID()));
3752+ }
3753+
3754+ // If the server URL is None, this must be an OpenID 1
3755+ // response, because op_endpoint is a required parameter in
3756+ // OpenID 2. In that case, we don't actually care what the
3757+ // discovered server_url is, because signature checking or
3758+ // check_auth should take care of that check for us.
3759+ if ($to_match->server_url === null) {
3760+ if ($to_match->preferredNamespace() != Auth_OpenID_OPENID1_NS) {
3761+ return new Auth_OpenID_FailureResponse($endpoint,
3762+ "Preferred namespace mismatch (bug)");
3763+ }
3764+ } else if ($to_match->server_url != $endpoint->server_url) {
3765+ return new Auth_OpenID_FailureResponse($endpoint,
3766+ sprintf('OP Endpoint mismatch. Expected %s, got %s',
3767+ $to_match->server_url, $endpoint->server_url));
3768+ }
3769+
3770+ return null;
3771+ }
3772+
3773+ /**
3774+ * @access private
3775+ */
3776+ function _verifyDiscoveryResultsOpenID2($message, $endpoint)
3777+ {
3778+ $to_match = new Auth_OpenID_ServiceEndpoint();
3779+ $to_match->type_uris = array(Auth_OpenID_TYPE_2_0);
3780+ $to_match->claimed_id = $message->getArg(Auth_OpenID_OPENID2_NS,
3781+ 'claimed_id');
3782+
3783+ $to_match->local_id = $message->getArg(Auth_OpenID_OPENID2_NS,
3784+ 'identity');
3785+
3786+ $to_match->server_url = $message->getArg(Auth_OpenID_OPENID2_NS,
3787+ 'op_endpoint');
3788+
3789+ if ($to_match->server_url === null) {
3790+ return new Auth_OpenID_FailureResponse($endpoint,
3791+ "OP Endpoint URL missing");
3792+ }
3793+
3794+ // claimed_id and identifier must both be present or both be
3795+ // absent
3796+ if (($to_match->claimed_id === null) &&
3797+ ($to_match->local_id !== null)) {
3798+ return new Auth_OpenID_FailureResponse($endpoint,
3799+ 'openid.identity is present without openid.claimed_id');
3800+ }
3801+
3802+ if (($to_match->claimed_id !== null) &&
3803+ ($to_match->local_id === null)) {
3804+ return new Auth_OpenID_FailureResponse($endpoint,
3805+ 'openid.claimed_id is present without openid.identity');
3806+ }
3807+
3808+ if ($to_match->claimed_id === null) {
3809+ // This is a response without identifiers, so there's
3810+ // really no checking that we can do, so return an
3811+ // endpoint that's for the specified `openid.op_endpoint'
3812+ return Auth_OpenID_ServiceEndpoint::fromOPEndpointURL(
3813+ $to_match->server_url);
3814+ }
3815+
3816+ if (!$endpoint) {
3817+ // The claimed ID doesn't match, so we have to do
3818+ // discovery again. This covers not using sessions, OP
3819+ // identifier endpoints and responses that didn't match
3820+ // the original request.
3821+ // oidutil.log('No pre-discovered information supplied.')
3822+ return $this->_discoverAndVerify($to_match->claimed_id,
3823+ array($to_match));
3824+ } else {
3825+
3826+ // The claimed ID matches, so we use the endpoint that we
3827+ // discovered in initiation. This should be the most
3828+ // common case.
3829+ $result = $this->_verifyDiscoverySingle($endpoint, $to_match);
3830+
3831+ if (Auth_OpenID::isFailure($result)) {
3832+ $endpoint = $this->_discoverAndVerify($to_match->claimed_id,
3833+ array($to_match));
3834+ if (Auth_OpenID::isFailure($endpoint)) {
3835+ return $endpoint;
3836+ }
3837+ }
3838+ }
3839+
3840+ // The endpoint we return should have the claimed ID from the
3841+ // message we just verified, fragment and all.
3842+ if ($endpoint->claimed_id != $to_match->claimed_id) {
3843+ $endpoint->claimed_id = $to_match->claimed_id;
3844+ }
3845+
3846+ return $endpoint;
3847+ }
3848+
3849+ /**
3850+ * @access private
3851+ */
3852+ function _discoverAndVerify($claimed_id, $to_match_endpoints)
3853+ {
3854+ // oidutil.log('Performing discovery on %s' % (claimed_id,))
3855+ list($unused, $services) = call_user_func($this->discoverMethod,
3856+ $claimed_id,
3857+ &$this->fetcher);
3858+
3859+ if (!$services) {
3860+ return new Auth_OpenID_FailureResponse(null,
3861+ sprintf("No OpenID information found at %s",
3862+ $claimed_id));
3863+ }
3864+
3865+ return $this->_verifyDiscoveryServices($claimed_id, $services,
3866+ $to_match_endpoints);
3867+ }
3868+
3869+ /**
3870+ * @access private
3871+ */
3872+ function _verifyDiscoveryServices($claimed_id,
3873+ $services, $to_match_endpoints)
3874+ {
3875+ // Search the services resulting from discovery to find one
3876+ // that matches the information from the assertion
3877+
3878+ foreach ($services as $endpoint) {
3879+ foreach ($to_match_endpoints as $to_match_endpoint) {
3880+ $result = $this->_verifyDiscoverySingle($endpoint,
3881+ $to_match_endpoint);
3882+
3883+ if (!Auth_OpenID::isFailure($result)) {
3884+ // It matches, so discover verification has
3885+ // succeeded. Return this endpoint.
3886+ return $endpoint;
3887+ }
3888+ }
3889+ }
3890+
3891+ return new Auth_OpenID_FailureResponse(null,
3892+ sprintf('No matching endpoint found after discovering %s: %s',
3893+ $claimed_id, $result->message));
3894+ }
3895+
3896+ /**
3897+ * Extract the nonce from an OpenID 1 response. Return the nonce
3898+ * from the BARE_NS since we independently check the return_to
3899+ * arguments are the same as those in the response message.
3900+ *
3901+ * See the openid1_nonce_query_arg_name class variable
3902+ *
3903+ * @returns $nonce The nonce as a string or null
3904+ *
3905+ * @access private
3906+ */
3907+ function _idResGetNonceOpenID1($message, $endpoint)
3908+ {
3909+ return $message->getArg(Auth_OpenID_BARE_NS,
3910+ $this->openid1_nonce_query_arg_name);
3911+ }
3912+
3913+ /**
3914+ * @access private
3915+ */
3916+ function _idResCheckNonce($message, $endpoint)
3917+ {
3918+ if ($message->isOpenID1()) {
3919+ // This indicates that the nonce was generated by the consumer
3920+ $nonce = $this->_idResGetNonceOpenID1($message, $endpoint);
3921+ $server_url = '';
3922+ } else {
3923+ $nonce = $message->getArg(Auth_OpenID_OPENID2_NS,
3924+ 'response_nonce');
3925+
3926+ $server_url = $endpoint->server_url;
3927+ }
3928+
3929+ if ($nonce === null) {
3930+ return new Auth_OpenID_FailureResponse($endpoint,
3931+ "Nonce missing from response");
3932+ }
3933+
3934+ $parts = Auth_OpenID_splitNonce($nonce);
3935+
3936+ if ($parts === null) {
3937+ return new Auth_OpenID_FailureResponse($endpoint,
3938+ "Malformed nonce in response");
3939+ }
3940+
3941+ list($timestamp, $salt) = $parts;
3942+
3943+ if (!$this->store->useNonce($server_url, $timestamp, $salt)) {
3944+ return new Auth_OpenID_FailureResponse($endpoint,
3945+ "Nonce already used or out of range");
3946+ }
3947+
3948+ return null;
3949+ }
3950+
3951+ /**
3952+ * @access private
3953+ */
3954+ function _idResCheckForFields($message)
3955+ {
3956+ $basic_fields = array('return_to', 'assoc_handle', 'sig', 'signed');
3957+ $basic_sig_fields = array('return_to', 'identity');
3958+
3959+ $require_fields = array(
3960+ Auth_OpenID_OPENID2_NS => array_merge($basic_fields,
3961+ array('op_endpoint')),
3962+
3963+ Auth_OpenID_OPENID1_NS => array_merge($basic_fields,
3964+ array('identity'))
3965+ );
3966+
3967+ $require_sigs = array(
3968+ Auth_OpenID_OPENID2_NS => array_merge($basic_sig_fields,
3969+ array('response_nonce',
3970+ 'claimed_id',
3971+ 'assoc_handle',
3972+ 'op_endpoint')),
3973+ Auth_OpenID_OPENID1_NS => array_merge($basic_sig_fields,
3974+ array('nonce'))
3975+ );
3976+
3977+ foreach ($require_fields[$message->getOpenIDNamespace()] as $field) {
3978+ if (!$message->hasKey(Auth_OpenID_OPENID_NS, $field)) {
3979+ return new Auth_OpenID_FailureResponse(null,
3980+ "Missing required field '".$field."'");
3981+ }
3982+ }
3983+
3984+ $signed_list_str = $message->getArg(Auth_OpenID_OPENID_NS,
3985+ 'signed',
3986+ Auth_OpenID_NO_DEFAULT);
3987+ if (Auth_OpenID::isFailure($signed_list_str)) {
3988+ return $signed_list_str;
3989+ }
3990+ $signed_list = explode(',', $signed_list_str);
3991+
3992+ foreach ($require_sigs[$message->getOpenIDNamespace()] as $field) {
3993+ // Field is present and not in signed list
3994+ if ($message->hasKey(Auth_OpenID_OPENID_NS, $field) &&
3995+ (!in_array($field, $signed_list))) {
3996+ return new Auth_OpenID_FailureResponse(null,
3997+ "'".$field."' not signed");
3998+ }
3999+ }
4000+
4001+ return null;
4002+ }
4003+
4004+ /**
4005+ * @access private
4006+ */
4007+ function _checkAuth($message, $server_url)
4008+ {
4009+ $request = $this->_createCheckAuthRequest($message);
4010+ if ($request === null) {
4011+ return false;
4012+ }
4013+
4014+ $resp_message = $this->_makeKVPost($request, $server_url);
4015+ if (($resp_message === null) ||
4016+ (is_a($resp_message, 'Auth_OpenID_ServerErrorContainer'))) {
4017+ return false;
4018+ }
4019+
4020+ return $this->_processCheckAuthResponse($resp_message, $server_url);
4021+ }
4022+
4023+ /**
4024+ * @access private
4025+ */
4026+ function _createCheckAuthRequest($message)
4027+ {
4028+ $signed = $message->getArg(Auth_OpenID_OPENID_NS, 'signed');
4029+ if ($signed) {
4030+ foreach (explode(',', $signed) as $k) {
4031+ $value = $message->getAliasedArg($k);
4032+ if ($value === null) {
4033+ return null;
4034+ }
4035+ }
4036+ }
4037+ $ca_message = $message->copy();
4038+ $ca_message->setArg(Auth_OpenID_OPENID_NS, 'mode',
4039+ 'check_authentication');
4040+ return $ca_message;
4041+ }
4042+
4043+ /**
4044+ * @access private
4045+ */
4046+ function _processCheckAuthResponse($response, $server_url)
4047+ {
4048+ $is_valid = $response->getArg(Auth_OpenID_OPENID_NS, 'is_valid',
4049+ 'false');
4050+
4051+ $invalidate_handle = $response->getArg(Auth_OpenID_OPENID_NS,
4052+ 'invalidate_handle');
4053+
4054+ if ($invalidate_handle !== null) {
4055+ $this->store->removeAssociation($server_url,
4056+ $invalidate_handle);
4057+ }
4058+
4059+ if ($is_valid == 'true') {
4060+ return true;
4061+ }
4062+
4063+ return false;
4064+ }
4065+
4066+ /**
4067+ * Adapt a POST response to a Message.
4068+ *
4069+ * @param $response Result of a POST to an OpenID endpoint.
4070+ *
4071+ * @access private
4072+ */
4073+ static function _httpResponseToMessage($response, $server_url)
4074+ {
4075+ // Should this function be named Message.fromHTTPResponse instead?
4076+ $response_message = Auth_OpenID_Message::fromKVForm($response->body);
4077+
4078+ if ($response->status == 400) {
4079+ return Auth_OpenID_ServerErrorContainer::fromMessage(
4080+ $response_message);
4081+ } else if ($response->status != 200 and $response->status != 206) {
4082+ return null;
4083+ }
4084+
4085+ return $response_message;
4086+ }
4087+
4088+ /**
4089+ * @access private
4090+ */
4091+ function _makeKVPost($message, $server_url)
4092+ {
4093+ $body = $message->toURLEncoded();
4094+ $resp = $this->fetcher->post($server_url, $body);
4095+
4096+ if ($resp === null) {
4097+ return null;
4098+ }
4099+
4100+ return $this->_httpResponseToMessage($resp, $server_url);
4101+ }
4102+
4103+ /**
4104+ * @access private
4105+ */
4106+ function _getAssociation($endpoint)
4107+ {
4108+ if (!$this->_use_assocs) {
4109+ return null;
4110+ }
4111+
4112+ $assoc = $this->store->getAssociation($endpoint->server_url);
4113+
4114+ if (($assoc === null) ||
4115+ ($assoc->getExpiresIn() <= 0)) {
4116+
4117+ $assoc = $this->_negotiateAssociation($endpoint);
4118+
4119+ if ($assoc !== null) {
4120+ $this->store->storeAssociation($endpoint->server_url,
4121+ $assoc);
4122+ }
4123+ }
4124+
4125+ return $assoc;
4126+ }
4127+
4128+ /**
4129+ * Handle ServerErrors resulting from association requests.
4130+ *
4131+ * @return $result If server replied with an C{unsupported-type}
4132+ * error, return a tuple of supported C{association_type},
4133+ * C{session_type}. Otherwise logs the error and returns null.
4134+ *
4135+ * @access private
4136+ */
4137+ function _extractSupportedAssociationType($server_error, $endpoint,
4138+ $assoc_type)
4139+ {
4140+ // Any error message whose code is not 'unsupported-type'
4141+ // should be considered a total failure.
4142+ if (($server_error->error_code != 'unsupported-type') ||
4143+ ($server_error->message->isOpenID1())) {
4144+ return null;
4145+ }
4146+
4147+ // The server didn't like the association/session type that we
4148+ // sent, and it sent us back a message that might tell us how
4149+ // to handle it.
4150+
4151+ // Extract the session_type and assoc_type from the error
4152+ // message
4153+ $assoc_type = $server_error->message->getArg(Auth_OpenID_OPENID_NS,
4154+ 'assoc_type');
4155+
4156+ $session_type = $server_error->message->getArg(Auth_OpenID_OPENID_NS,
4157+ 'session_type');
4158+
4159+ if (($assoc_type === null) || ($session_type === null)) {
4160+ return null;
4161+ } else if (!$this->negotiator->isAllowed($assoc_type,
4162+ $session_type)) {
4163+ return null;
4164+ } else {
4165+ return array($assoc_type, $session_type);
4166+ }
4167+ }
4168+
4169+ /**
4170+ * @access private
4171+ */
4172+ function _negotiateAssociation($endpoint)
4173+ {
4174+ // Get our preferred session/association type from the negotiatior.
4175+ list($assoc_type, $session_type) = $this->negotiator->getAllowedType();
4176+
4177+ $assoc = $this->_requestAssociation(
4178+ $endpoint, $assoc_type, $session_type);
4179+
4180+ if (Auth_OpenID::isFailure($assoc)) {
4181+ return null;
4182+ }
4183+
4184+ if (is_a($assoc, 'Auth_OpenID_ServerErrorContainer')) {
4185+ $why = $assoc;
4186+
4187+ $supportedTypes = $this->_extractSupportedAssociationType(
4188+ $why, $endpoint, $assoc_type);
4189+
4190+ if ($supportedTypes !== null) {
4191+ list($assoc_type, $session_type) = $supportedTypes;
4192+
4193+ // Attempt to create an association from the assoc_type
4194+ // and session_type that the server told us it
4195+ // supported.
4196+ $assoc = $this->_requestAssociation(
4197+ $endpoint, $assoc_type, $session_type);
4198+
4199+ if (is_a($assoc, 'Auth_OpenID_ServerErrorContainer')) {
4200+ // Do not keep trying, since it rejected the
4201+ // association type that it told us to use.
4202+ // oidutil.log('Server %s refused its suggested association
4203+ // 'type: session_type=%s, assoc_type=%s'
4204+ // % (endpoint.server_url, session_type,
4205+ // assoc_type))
4206+ return null;
4207+ } else {
4208+ return $assoc;
4209+ }
4210+ } else {
4211+ return null;
4212+ }
4213+ } else {
4214+ return $assoc;
4215+ }
4216+ }
4217+
4218+ /**
4219+ * @access private
4220+ */
4221+ function _requestAssociation($endpoint, $assoc_type, $session_type)
4222+ {
4223+ list($assoc_session, $args) = $this->_createAssociateRequest(
4224+ $endpoint, $assoc_type, $session_type);
4225+
4226+ $response_message = $this->_makeKVPost($args, $endpoint->server_url);
4227+
4228+ if ($response_message === null) {
4229+ // oidutil.log('openid.associate request failed: %s' % (why[0],))
4230+ return null;
4231+ } else if (is_a($response_message,
4232+ 'Auth_OpenID_ServerErrorContainer')) {
4233+ return $response_message;
4234+ }
4235+
4236+ return $this->_extractAssociation($response_message, $assoc_session);
4237+ }
4238+
4239+ /**
4240+ * @access private
4241+ */
4242+ function _extractAssociation($assoc_response, $assoc_session)
4243+ {
4244+ // Extract the common fields from the response, raising an
4245+ // exception if they are not found
4246+ $assoc_type = $assoc_response->getArg(
4247+ Auth_OpenID_OPENID_NS, 'assoc_type',
4248+ Auth_OpenID_NO_DEFAULT);
4249+
4250+ if (Auth_OpenID::isFailure($assoc_type)) {
4251+ return $assoc_type;
4252+ }
4253+
4254+ $assoc_handle = $assoc_response->getArg(
4255+ Auth_OpenID_OPENID_NS, 'assoc_handle',
4256+ Auth_OpenID_NO_DEFAULT);
4257+
4258+ if (Auth_OpenID::isFailure($assoc_handle)) {
4259+ return $assoc_handle;
4260+ }
4261+
4262+ // expires_in is a base-10 string. The Python parsing will
4263+ // accept literals that have whitespace around them and will
4264+ // accept negative values. Neither of these are really in-spec,
4265+ // but we think it's OK to accept them.
4266+ $expires_in_str = $assoc_response->getArg(
4267+ Auth_OpenID_OPENID_NS, 'expires_in',
4268+ Auth_OpenID_NO_DEFAULT);
4269+
4270+ if (Auth_OpenID::isFailure($expires_in_str)) {
4271+ return $expires_in_str;
4272+ }
4273+
4274+ $expires_in = Auth_OpenID::intval($expires_in_str);
4275+ if ($expires_in === false) {
4276+
4277+ $err = sprintf("Could not parse expires_in from association ".
4278+ "response %s", print_r($assoc_response, true));
4279+ return new Auth_OpenID_FailureResponse(null, $err);
4280+ }
4281+
4282+ // OpenID 1 has funny association session behaviour.
4283+ if ($assoc_response->isOpenID1()) {
4284+ $session_type = $this->_getOpenID1SessionType($assoc_response);
4285+ } else {
4286+ $session_type = $assoc_response->getArg(
4287+ Auth_OpenID_OPENID2_NS, 'session_type',
4288+ Auth_OpenID_NO_DEFAULT);
4289+
4290+ if (Auth_OpenID::isFailure($session_type)) {
4291+ return $session_type;
4292+ }
4293+ }
4294+
4295+ // Session type mismatch
4296+ if ($assoc_session->session_type != $session_type) {
4297+ if ($assoc_response->isOpenID1() &&
4298+ ($session_type == 'no-encryption')) {
4299+ // In OpenID 1, any association request can result in
4300+ // a 'no-encryption' association response. Setting
4301+ // assoc_session to a new no-encryption session should
4302+ // make the rest of this function work properly for
4303+ // that case.
4304+ $assoc_session = new Auth_OpenID_PlainTextConsumerSession();
4305+ } else {
4306+ // Any other mismatch, regardless of protocol version
4307+ // results in the failure of the association session
4308+ // altogether.
4309+ return null;
4310+ }
4311+ }
4312+
4313+ // Make sure assoc_type is valid for session_type
4314+ if (!in_array($assoc_type, $assoc_session->allowed_assoc_types)) {
4315+ return null;
4316+ }
4317+
4318+ // Delegate to the association session to extract the secret
4319+ // from the response, however is appropriate for that session
4320+ // type.
4321+ $secret = $assoc_session->extractSecret($assoc_response);
4322+
4323+ if ($secret === null) {
4324+ return null;
4325+ }
4326+
4327+ return Auth_OpenID_Association::fromExpiresIn(
4328+ $expires_in, $assoc_handle, $secret, $assoc_type);
4329+ }
4330+
4331+ /**
4332+ * @access private
4333+ */
4334+ function _createAssociateRequest($endpoint, $assoc_type, $session_type)
4335+ {
4336+ if (array_key_exists($session_type, $this->session_types)) {
4337+ $session_type_class = $this->session_types[$session_type];
4338+
4339+ if (is_callable($session_type_class)) {
4340+ $assoc_session = $session_type_class();
4341+ } else {
4342+ $assoc_session = new $session_type_class();
4343+ }
4344+ } else {
4345+ return null;
4346+ }
4347+
4348+ $args = array(
4349+ 'mode' => 'associate',
4350+ 'assoc_type' => $assoc_type);
4351+
4352+ if (!$endpoint->compatibilityMode()) {
4353+ $args['ns'] = Auth_OpenID_OPENID2_NS;
4354+ }
4355+
4356+ // Leave out the session type if we're in compatibility mode
4357+ // *and* it's no-encryption.
4358+ if ((!$endpoint->compatibilityMode()) ||
4359+ ($assoc_session->session_type != 'no-encryption')) {
4360+ $args['session_type'] = $assoc_session->session_type;
4361+ }
4362+
4363+ $args = array_merge($args, $assoc_session->getRequest());
4364+ $message = Auth_OpenID_Message::fromOpenIDArgs($args);
4365+ return array($assoc_session, $message);
4366+ }
4367+
4368+ /**
4369+ * Given an association response message, extract the OpenID 1.X
4370+ * session type.
4371+ *
4372+ * This function mostly takes care of the 'no-encryption' default
4373+ * behavior in OpenID 1.
4374+ *
4375+ * If the association type is plain-text, this function will
4376+ * return 'no-encryption'
4377+ *
4378+ * @access private
4379+ * @return $typ The association type for this message
4380+ */
4381+ function _getOpenID1SessionType($assoc_response)
4382+ {
4383+ // If it's an OpenID 1 message, allow session_type to default
4384+ // to None (which signifies "no-encryption")
4385+ $session_type = $assoc_response->getArg(Auth_OpenID_OPENID1_NS,
4386+ 'session_type');
4387+
4388+ // Handle the differences between no-encryption association
4389+ // respones in OpenID 1 and 2:
4390+
4391+ // no-encryption is not really a valid session type for OpenID
4392+ // 1, but we'll accept it anyway, while issuing a warning.
4393+ if ($session_type == 'no-encryption') {
4394+ // oidutil.log('WARNING: OpenID server sent "no-encryption"'
4395+ // 'for OpenID 1.X')
4396+ } else if (($session_type == '') || ($session_type === null)) {
4397+ // Missing or empty session type is the way to flag a
4398+ // 'no-encryption' response. Change the session type to
4399+ // 'no-encryption' so that it can be handled in the same
4400+ // way as OpenID 2 'no-encryption' respones.
4401+ $session_type = 'no-encryption';
4402+ }
4403+
4404+ return $session_type;
4405+ }
4406+}
4407+
4408+/**
4409+ * This class represents an authentication request from a consumer to
4410+ * an OpenID server.
4411+ *
4412+ * @package OpenID
4413+ */
4414+class Auth_OpenID_AuthRequest {
4415+
4416+ /**
4417+ * Initialize an authentication request with the specified token,
4418+ * association, and endpoint.
4419+ *
4420+ * Users of this library should not create instances of this
4421+ * class. Instances of this class are created by the library when
4422+ * needed.
4423+ */
4424+ function Auth_OpenID_AuthRequest($endpoint, $assoc)
4425+ {
4426+ $this->assoc = $assoc;
4427+ $this->endpoint = $endpoint;
4428+ $this->return_to_args = array();
4429+ $this->message = new Auth_OpenID_Message(
4430+ $endpoint->preferredNamespace());
4431+ $this->_anonymous = false;
4432+ }
4433+
4434+ /**
4435+ * Add an extension to this checkid request.
4436+ *
4437+ * $extension_request: An object that implements the extension
4438+ * request interface for adding arguments to an OpenID message.
4439+ */
4440+ function addExtension($extension_request)
4441+ {
4442+ $extension_request->toMessage($this->message);
4443+ }
4444+
4445+ /**
4446+ * Add an extension argument to this OpenID authentication
4447+ * request.
4448+ *
4449+ * Use caution when adding arguments, because they will be
4450+ * URL-escaped and appended to the redirect URL, which can easily
4451+ * get quite long.
4452+ *
4453+ * @param string $namespace The namespace for the extension. For
4454+ * example, the simple registration extension uses the namespace
4455+ * 'sreg'.
4456+ *
4457+ * @param string $key The key within the extension namespace. For
4458+ * example, the nickname field in the simple registration
4459+ * extension's key is 'nickname'.
4460+ *
4461+ * @param string $value The value to provide to the server for
4462+ * this argument.
4463+ */
4464+ function addExtensionArg($namespace, $key, $value)
4465+ {
4466+ return $this->message->setArg($namespace, $key, $value);
4467+ }
4468+
4469+ /**
4470+ * Set whether this request should be made anonymously. If a
4471+ * request is anonymous, the identifier will not be sent in the
4472+ * request. This is only useful if you are making another kind of
4473+ * request with an extension in this request.
4474+ *
4475+ * Anonymous requests are not allowed when the request is made
4476+ * with OpenID 1.
4477+ */
4478+ function setAnonymous($is_anonymous)
4479+ {
4480+ if ($is_anonymous && $this->message->isOpenID1()) {
4481+ return false;
4482+ } else {
4483+ $this->_anonymous = $is_anonymous;
4484+ return true;
4485+ }
4486+ }
4487+
4488+ /**
4489+ * Produce a {@link Auth_OpenID_Message} representing this
4490+ * request.
4491+ *
4492+ * @param string $realm The URL (or URL pattern) that identifies
4493+ * your web site to the user when she is authorizing it.
4494+ *
4495+ * @param string $return_to The URL that the OpenID provider will
4496+ * send the user back to after attempting to verify her identity.
4497+ *
4498+ * Not specifying a return_to URL means that the user will not be
4499+ * returned to the site issuing the request upon its completion.
4500+ *
4501+ * @param bool $immediate If true, the OpenID provider is to send
4502+ * back a response immediately, useful for behind-the-scenes
4503+ * authentication attempts. Otherwise the OpenID provider may
4504+ * engage the user before providing a response. This is the
4505+ * default case, as the user may need to provide credentials or
4506+ * approve the request before a positive response can be sent.
4507+ */
4508+ function getMessage($realm, $return_to=null, $immediate=false)
4509+ {
4510+ if ($return_to) {
4511+ $return_to = Auth_OpenID::appendArgs($return_to,
4512+ $this->return_to_args);
4513+ } else if ($immediate) {
4514+ // raise ValueError(
4515+ // '"return_to" is mandatory when
4516+ //using "checkid_immediate"')
4517+ return new Auth_OpenID_FailureResponse(null,
4518+ "'return_to' is mandatory when using checkid_immediate");
4519+ } else if ($this->message->isOpenID1()) {
4520+ // raise ValueError('"return_to" is
4521+ // mandatory for OpenID 1 requests')
4522+ return new Auth_OpenID_FailureResponse(null,
4523+ "'return_to' is mandatory for OpenID 1 requests");
4524+ } else if ($this->return_to_args) {
4525+ // raise ValueError('extra "return_to" arguments
4526+ // were specified, but no return_to was specified')
4527+ return new Auth_OpenID_FailureResponse(null,
4528+ "extra 'return_to' arguments where specified, " .
4529+ "but no return_to was specified");
4530+ }
4531+
4532+ if ($immediate) {
4533+ $mode = 'checkid_immediate';
4534+ } else {
4535+ $mode = 'checkid_setup';
4536+ }
4537+
4538+ $message = $this->message->copy();
4539+ if ($message->isOpenID1()) {
4540+ $realm_key = 'trust_root';
4541+ } else {
4542+ $realm_key = 'realm';
4543+ }
4544+
4545+ $message->updateArgs(Auth_OpenID_OPENID_NS,
4546+ array(
4547+ $realm_key => $realm,
4548+ 'mode' => $mode,
4549+ 'return_to' => $return_to));
4550+
4551+ if (!$this->_anonymous) {
4552+ if ($this->endpoint->isOPIdentifier()) {
4553+ // This will never happen when we're in compatibility
4554+ // mode, as long as isOPIdentifier() returns False
4555+ // whenever preferredNamespace() returns OPENID1_NS.
4556+ $claimed_id = $request_identity =
4557+ Auth_OpenID_IDENTIFIER_SELECT;
4558+ } else {
4559+ $request_identity = $this->endpoint->getLocalID();
4560+ $claimed_id = $this->endpoint->claimed_id;
4561+ }
4562+
4563+ // This is true for both OpenID 1 and 2
4564+ $message->setArg(Auth_OpenID_OPENID_NS, 'identity',
4565+ $request_identity);
4566+
4567+ if ($message->isOpenID2()) {
4568+ $message->setArg(Auth_OpenID_OPENID2_NS, 'claimed_id',
4569+ $claimed_id);
4570+ }
4571+ }
4572+
4573+ if ($this->assoc) {
4574+ $message->setArg(Auth_OpenID_OPENID_NS, 'assoc_handle',
4575+ $this->assoc->handle);
4576+ }
4577+
4578+ return $message;
4579+ }
4580+
4581+ function redirectURL($realm, $return_to = null,
4582+ $immediate = false)
4583+ {
4584+ $message = $this->getMessage($realm, $return_to, $immediate);
4585+
4586+ if (Auth_OpenID::isFailure($message)) {
4587+ return $message;
4588+ }
4589+
4590+ return $message->toURL($this->endpoint->server_url);
4591+ }
4592+
4593+ /**
4594+ * Get html for a form to submit this request to the IDP.
4595+ *
4596+ * form_tag_attrs: An array of attributes to be added to the form
4597+ * tag. 'accept-charset' and 'enctype' have defaults that can be
4598+ * overridden. If a value is supplied for 'action' or 'method', it
4599+ * will be replaced.
4600+ */
4601+ function formMarkup($realm, $return_to=null, $immediate=false,
4602+ $form_tag_attrs=null)
4603+ {
4604+ $message = $this->getMessage($realm, $return_to, $immediate);
4605+
4606+ if (Auth_OpenID::isFailure($message)) {
4607+ return $message;
4608+ }
4609+
4610+ return $message->toFormMarkup($this->endpoint->server_url,
4611+ $form_tag_attrs);
4612+ }
4613+
4614+ /**
4615+ * Get a complete html document that will autosubmit the request
4616+ * to the IDP.
4617+ *
4618+ * Wraps formMarkup. See the documentation for that function.
4619+ */
4620+ function htmlMarkup($realm, $return_to=null, $immediate=false,
4621+ $form_tag_attrs=null)
4622+ {
4623+ $form = $this->formMarkup($realm, $return_to, $immediate,
4624+ $form_tag_attrs);
4625+
4626+ if (Auth_OpenID::isFailure($form)) {
4627+ return $form;
4628+ }
4629+ return Auth_OpenID::autoSubmitHTML($form);
4630+ }
4631+
4632+ function shouldSendRedirect()
4633+ {
4634+ return $this->endpoint->compatibilityMode();
4635+ }
4636+}
4637+
4638+/**
4639+ * The base class for responses from the Auth_OpenID_Consumer.
4640+ *
4641+ * @package OpenID
4642+ */
4643+class Auth_OpenID_ConsumerResponse {
4644+ var $status = null;
4645+
4646+ function setEndpoint($endpoint)
4647+ {
4648+ $this->endpoint = $endpoint;
4649+ if ($endpoint === null) {
4650+ $this->identity_url = null;
4651+ } else {
4652+ $this->identity_url = $endpoint->claimed_id;
4653+ }
4654+ }
4655+
4656+ /**
4657+ * Return the display identifier for this response.
4658+ *
4659+ * The display identifier is related to the Claimed Identifier, but the
4660+ * two are not always identical. The display identifier is something the
4661+ * user should recognize as what they entered, whereas the response's
4662+ * claimed identifier (in the identity_url attribute) may have extra
4663+ * information for better persistence.
4664+ *
4665+ * URLs will be stripped of their fragments for display. XRIs will
4666+ * display the human-readable identifier (i-name) instead of the
4667+ * persistent identifier (i-number).
4668+ *
4669+ * Use the display identifier in your user interface. Use
4670+ * identity_url for querying your database or authorization server.
4671+ *
4672+ */
4673+ function getDisplayIdentifier()
4674+ {
4675+ if ($this->endpoint !== null) {
4676+ return $this->endpoint->getDisplayIdentifier();
4677+ }
4678+ return null;
4679+ }
4680+}
4681+
4682+/**
4683+ * A response with a status of Auth_OpenID_SUCCESS. Indicates that
4684+ * this request is a successful acknowledgement from the OpenID server
4685+ * that the supplied URL is, indeed controlled by the requesting
4686+ * agent. This has three relevant attributes:
4687+ *
4688+ * claimed_id - The identity URL that has been authenticated
4689+ *
4690+ * signed_args - The arguments in the server's response that were
4691+ * signed and verified.
4692+ *
4693+ * status - Auth_OpenID_SUCCESS.
4694+ *
4695+ * @package OpenID
4696+ */
4697+class Auth_OpenID_SuccessResponse extends Auth_OpenID_ConsumerResponse {
4698+ var $status = Auth_OpenID_SUCCESS;
4699+
4700+ /**
4701+ * @access private
4702+ */
4703+ function Auth_OpenID_SuccessResponse($endpoint, $message, $signed_args=null)
4704+ {
4705+ $this->endpoint = $endpoint;
4706+ $this->identity_url = $endpoint->claimed_id;
4707+ $this->signed_args = $signed_args;
4708+ $this->message = $message;
4709+
4710+ if ($this->signed_args === null) {
4711+ $this->signed_args = array();
4712+ }
4713+ }
4714+
4715+ /**
4716+ * Extract signed extension data from the server's response.
4717+ *
4718+ * @param string $prefix The extension namespace from which to
4719+ * extract the extension data.
4720+ */
4721+ function extensionResponse($namespace_uri, $require_signed)
4722+ {
4723+ if ($require_signed) {
4724+ return $this->getSignedNS($namespace_uri);
4725+ } else {
4726+ return $this->message->getArgs($namespace_uri);
4727+ }
4728+ }
4729+
4730+ function isOpenID1()
4731+ {
4732+ return $this->message->isOpenID1();
4733+ }
4734+
4735+ function isSigned($ns_uri, $ns_key)
4736+ {
4737+ // Return whether a particular key is signed, regardless of
4738+ // its namespace alias
4739+ return in_array($this->message->getKey($ns_uri, $ns_key),
4740+ $this->signed_args);
4741+ }
4742+
4743+ function getSigned($ns_uri, $ns_key, $default = null)
4744+ {
4745+ // Return the specified signed field if available, otherwise
4746+ // return default
4747+ if ($this->isSigned($ns_uri, $ns_key)) {
4748+ return $this->message->getArg($ns_uri, $ns_key, $default);
4749+ } else {
4750+ return $default;
4751+ }
4752+ }
4753+
4754+ function getSignedNS($ns_uri)
4755+ {
4756+ $args = array();
4757+
4758+ $msg_args = $this->message->getArgs($ns_uri);
4759+ if (Auth_OpenID::isFailure($msg_args)) {
4760+ return null;
4761+ }
4762+
4763+ foreach ($msg_args as $key => $value) {
4764+ if (!$this->isSigned($ns_uri, $key)) {
4765+ unset($msg_args[$key]);
4766+ }
4767+ }
4768+
4769+ return $msg_args;
4770+ }
4771+
4772+ /**
4773+ * Get the openid.return_to argument from this response.
4774+ *
4775+ * This is useful for verifying that this request was initiated by
4776+ * this consumer.
4777+ *
4778+ * @return string $return_to The return_to URL supplied to the
4779+ * server on the initial request, or null if the response did not
4780+ * contain an 'openid.return_to' argument.
4781+ */
4782+ function getReturnTo()
4783+ {
4784+ return $this->getSigned(Auth_OpenID_OPENID_NS, 'return_to');
4785+ }
4786+}
4787+
4788+/**
4789+ * A response with a status of Auth_OpenID_FAILURE. Indicates that the
4790+ * OpenID protocol has failed. This could be locally or remotely
4791+ * triggered. This has three relevant attributes:
4792+ *
4793+ * claimed_id - The identity URL for which authentication was
4794+ * attempted, if it can be determined. Otherwise, null.
4795+ *
4796+ * message - A message indicating why the request failed, if one is
4797+ * supplied. Otherwise, null.
4798+ *
4799+ * status - Auth_OpenID_FAILURE.
4800+ *
4801+ * @package OpenID
4802+ */
4803+class Auth_OpenID_FailureResponse extends Auth_OpenID_ConsumerResponse {
4804+ var $status = Auth_OpenID_FAILURE;
4805+
4806+ function Auth_OpenID_FailureResponse($endpoint, $message = null,
4807+ $contact = null, $reference = null)
4808+ {
4809+ $this->setEndpoint($endpoint);
4810+ $this->message = $message;
4811+ $this->contact = $contact;
4812+ $this->reference = $reference;
4813+ }
4814+}
4815+
4816+/**
4817+ * A specific, internal failure used to detect type URI mismatch.
4818+ *
4819+ * @package OpenID
4820+ */
4821+class Auth_OpenID_TypeURIMismatch extends Auth_OpenID_FailureResponse {
4822+}
4823+
4824+/**
4825+ * Exception that is raised when the server returns a 400 response
4826+ * code to a direct request.
4827+ *
4828+ * @package OpenID
4829+ */
4830+class Auth_OpenID_ServerErrorContainer {
4831+ function Auth_OpenID_ServerErrorContainer($error_text,
4832+ $error_code,
4833+ $message)
4834+ {
4835+ $this->error_text = $error_text;
4836+ $this->error_code = $error_code;
4837+ $this->message = $message;
4838+ }
4839+
4840+ /**
4841+ * @access private
4842+ */
4843+ static function fromMessage($message)
4844+ {
4845+ $error_text = $message->getArg(
4846+ Auth_OpenID_OPENID_NS, 'error', '<no error message supplied>');
4847+ $error_code = $message->getArg(Auth_OpenID_OPENID_NS, 'error_code');
4848+ return new Auth_OpenID_ServerErrorContainer($error_text,
4849+ $error_code,
4850+ $message);
4851+ }
4852+}
4853+
4854+/**
4855+ * A response with a status of Auth_OpenID_CANCEL. Indicates that the
4856+ * user cancelled the OpenID authentication request. This has two
4857+ * relevant attributes:
4858+ *
4859+ * claimed_id - The identity URL for which authentication was
4860+ * attempted, if it can be determined. Otherwise, null.
4861+ *
4862+ * status - Auth_OpenID_SUCCESS.
4863+ *
4864+ * @package OpenID
4865+ */
4866+class Auth_OpenID_CancelResponse extends Auth_OpenID_ConsumerResponse {
4867+ var $status = Auth_OpenID_CANCEL;
4868+
4869+ function Auth_OpenID_CancelResponse($endpoint)
4870+ {
4871+ $this->setEndpoint($endpoint);
4872+ }
4873+}
4874+
4875+/**
4876+ * A response with a status of Auth_OpenID_SETUP_NEEDED. Indicates
4877+ * that the request was in immediate mode, and the server is unable to
4878+ * authenticate the user without further interaction.
4879+ *
4880+ * claimed_id - The identity URL for which authentication was
4881+ * attempted.
4882+ *
4883+ * setup_url - A URL that can be used to send the user to the server
4884+ * to set up for authentication. The user should be redirected in to
4885+ * the setup_url, either in the current window or in a new browser
4886+ * window. Null in OpenID 2.
4887+ *
4888+ * status - Auth_OpenID_SETUP_NEEDED.
4889+ *
4890+ * @package OpenID
4891+ */
4892+class Auth_OpenID_SetupNeededResponse extends Auth_OpenID_ConsumerResponse {
4893+ var $status = Auth_OpenID_SETUP_NEEDED;
4894+
4895+ function Auth_OpenID_SetupNeededResponse($endpoint,
4896+ $setup_url = null)
4897+ {
4898+ $this->setEndpoint($endpoint);
4899+ $this->setup_url = $setup_url;
4900+ }
4901+}
4902+
4903+
4904
4905=== added file 'Auth/OpenID/CryptUtil.php'
4906--- Auth/OpenID/CryptUtil.php 1970-01-01 00:00:00 +0000
4907+++ Auth/OpenID/CryptUtil.php 2011-06-19 04:48:34 +0000
4908@@ -0,0 +1,108 @@
4909+<?php
4910+
4911+/**
4912+ * CryptUtil: A suite of wrapper utility functions for the OpenID
4913+ * library.
4914+ *
4915+ * PHP versions 4 and 5
4916+ *
4917+ * LICENSE: See the COPYING file included in this distribution.
4918+ *
4919+ * @access private
4920+ * @package OpenID
4921+ * @author JanRain, Inc. <openid@janrain.com>
4922+ * @copyright 2005-2008 Janrain, Inc.
4923+ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
4924+ */
4925+
4926+if (!defined('Auth_OpenID_RAND_SOURCE')) {
4927+ /**
4928+ * The filename for a source of random bytes. Define this yourself
4929+ * if you have a different source of randomness.
4930+ */
4931+ define('Auth_OpenID_RAND_SOURCE', '/dev/urandom');
4932+}
4933+
4934+class Auth_OpenID_CryptUtil {
4935+ /**
4936+ * Get the specified number of random bytes.
4937+ *
4938+ * Attempts to use a cryptographically secure (not predictable)
4939+ * source of randomness if available. If there is no high-entropy
4940+ * randomness source available, it will fail. As a last resort,
4941+ * for non-critical systems, define
4942+ * <code>Auth_OpenID_RAND_SOURCE</code> as <code>null</code>, and
4943+ * the code will fall back on a pseudo-random number generator.
4944+ *
4945+ * @param int $num_bytes The length of the return value
4946+ * @return string $bytes random bytes
4947+ */
4948+ static function getBytes($num_bytes)
4949+ {
4950+ static $f = null;
4951+ $bytes = '';
4952+ if ($f === null) {
4953+ if (Auth_OpenID_RAND_SOURCE === null) {
4954+ $f = false;
4955+ } else {
4956+ $f = @fopen(Auth_OpenID_RAND_SOURCE, "r");
4957+ if ($f === false) {
4958+ $msg = 'Define Auth_OpenID_RAND_SOURCE as null to ' .
4959+ ' continue with an insecure random number generator.';
4960+ trigger_error($msg, E_USER_ERROR);
4961+ }
4962+ }
4963+ }
4964+ if ($f === false) {
4965+ // pseudorandom used
4966+ $bytes = '';
4967+ for ($i = 0; $i < $num_bytes; $i += 4) {
4968+ $bytes .= pack('L', mt_rand());
4969+ }
4970+ $bytes = substr($bytes, 0, $num_bytes);
4971+ } else {
4972+ $bytes = fread($f, $num_bytes);
4973+ }
4974+ return $bytes;
4975+ }
4976+
4977+ /**
4978+ * Produce a string of length random bytes, chosen from chrs. If
4979+ * $chrs is null, the resulting string may contain any characters.
4980+ *
4981+ * @param integer $length The length of the resulting
4982+ * randomly-generated string
4983+ * @param string $chrs A string of characters from which to choose
4984+ * to build the new string
4985+ * @return string $result A string of randomly-chosen characters
4986+ * from $chrs
4987+ */
4988+ static function randomString($length, $population = null)
4989+ {
4990+ if ($population === null) {
4991+ return Auth_OpenID_CryptUtil::getBytes($length);
4992+ }
4993+
4994+ $popsize = strlen($population);
4995+
4996+ if ($popsize > 256) {
4997+ $msg = 'More than 256 characters supplied to ' . __FUNCTION__;
4998+ trigger_error($msg, E_USER_ERROR);
4999+ }
5000+
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches