]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/OpenID/OpenIDPlugin.php
start making OpenID-only mode work
[quix0rs-gnu-social.git] / plugins / OpenID / OpenIDPlugin.php
1 <?php
2 /**
3  * StatusNet, the distributed open-source microblogging tool
4  *
5  * PHP version 5
6  *
7  * LICENCE: This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  * @category  Plugin
21  * @package   StatusNet
22  * @author    Evan Prodromou <evan@status.net>
23  * @copyright 2009 StatusNet, Inc.
24  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
25  * @link      http://status.net/
26  */
27
28 if (!defined('STATUSNET')) {
29     exit(1);
30 }
31
32 /**
33  * Plugin for OpenID authentication and identity
34  *
35  * This class enables consumer support for OpenID, the distributed authentication
36  * and identity system.
37  *
38  * @category Plugin
39  * @package  StatusNet
40  * @author   Evan Prodromou <evan@status.net>
41  * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
42  * @link     http://status.net/
43  * @link     http://openid.net/
44  */
45
46 class OpenIDPlugin extends Plugin
47 {
48     public $openidOnly = false;
49
50     function initialize()
51     {
52         common_debug("OpenID plugin running with openidonly = {$this->openidOnly}");
53     }
54
55     /**
56      * Add OpenID-related paths to the router table
57      *
58      * Hook for RouterInitialized event.
59      *
60      * @param Net_URL_Mapper $m URL mapper
61      *
62      * @return boolean hook return
63      */
64
65     function onStartInitializeRouter($m)
66     {
67         $m->connect('main/openid', array('action' => 'openidlogin'));
68         $m->connect('main/openidtrust', array('action' => 'openidtrust'));
69         $m->connect('settings/openid', array('action' => 'openidsettings'));
70         $m->connect('index.php?action=finishopenidlogin',
71                     array('action' => 'finishopenidlogin'));
72         $m->connect('index.php?action=finishaddopenid',
73                     array('action' => 'finishaddopenid'));
74         $m->connect('main/openidserver', array('action' => 'openidserver'));
75
76         return true;
77     }
78
79     /**
80      * Public XRDS output hook
81      *
82      * Puts the bits of code needed by some OpenID providers to show
83      * we're good citizens.
84      *
85      * @param Action       $action         Action being executed
86      * @param XMLOutputter &$xrdsOutputter Output channel
87      *
88      * @return boolean hook return
89      */
90
91     function onEndPublicXRDS($action, &$xrdsOutputter)
92     {
93         $xrdsOutputter->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
94                                                   'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
95                                                   'version' => '2.0'));
96         $xrdsOutputter->element('Type', null, 'xri://$xrds*simple');
97         //consumer
98         foreach (array('finishopenidlogin', 'finishaddopenid') as $finish) {
99             $xrdsOutputter->showXrdsService(Auth_OpenID_RP_RETURN_TO_URL_TYPE,
100                                             common_local_url($finish));
101         }
102         //provider
103         $xrdsOutputter->showXrdsService('http://specs.openid.net/auth/2.0/server',
104                                         common_local_url('openidserver'),
105                                         null,
106                                         null,
107                                         'http://specs.openid.net/auth/2.0/identifier_select');
108         $xrdsOutputter->elementEnd('XRD');
109     }
110
111     /**
112      * User XRDS output hook
113      *
114      * Puts the bits of code needed to discover OpenID endpoints.
115      *
116      * @param Action       $action         Action being executed
117      * @param XMLOutputter &$xrdsOutputter Output channel
118      *
119      * @return boolean hook return
120      */
121
122     function onEndUserXRDS($action, &$xrdsOutputter)
123     {
124         $xrdsOutputter->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
125                                                   'xml:id' => 'openid',
126                                                   'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
127                                                   'version' => '2.0'));
128         $xrdsOutputter->element('Type', null, 'xri://$xrds*simple');
129
130         //consumer
131         $xrdsOutputter->showXrdsService('http://specs.openid.net/auth/2.0/return_to',
132                                         common_local_url('finishopenidlogin'));
133
134         //provider
135         $xrdsOutputter->showXrdsService('http://specs.openid.net/auth/2.0/signon',
136                                         common_local_url('openidserver'),
137                                         null,
138                                         null,
139                                         common_profile_url($action->user->nickname));
140         $xrdsOutputter->elementEnd('XRD');
141     }
142
143     function onStartPrimaryNav($action)
144     {
145         if ($this->openidOnly && !common_logged_in()) {
146             // TRANS: Tooltip for main menu option "Login"
147             $tooltip = _m('TOOLTIP', 'Login to the site');
148             // TRANS: Main menu option when not logged in to log in
149             $action->menuItem(common_local_url('openidlogin'),
150                               _m('MENU', 'Login'),
151                               $tooltip,
152                               false,
153                               'nav_login');
154             // TRANS: Tooltip for main menu option "Help"
155             $tooltip = _m('TOOLTIP', 'Help me!');
156             // TRANS: Main menu option for help on the StatusNet site
157             $action->menuItem(common_local_url('doc', array('title' => 'help')),
158                               _m('MENU', 'Help'),
159                               $tooltip,
160                               false,
161                               'nav_help');
162             if (!common_config('site', 'private')) {
163                 // TRANS: Tooltip for main menu option "Search"
164                 $tooltip = _m('TOOLTIP', 'Search for people or text');
165                 // TRANS: Main menu option when logged in or when the StatusNet instance is not private
166                 $action->menuItem(common_local_url('peoplesearch'),
167                                   _m('MENU', 'Search'), $tooltip, false, 'nav_search');
168             }
169             Event::handle('EndPrimaryNav', array($action));
170             return false;
171         }
172         return true;
173     }
174
175     /**
176      * Menu for login
177      *
178      * If we're in openidOnly mode, we disable the menu for all other login.
179      *
180      * @param Action &$action Action being executed
181      *
182      * @return boolean hook return
183      */
184
185     function onStartLoginGroupNav(&$action)
186     {
187         if ($this->openidOnly) {
188             $this->showOpenIDLoginTab($action);
189             // Even though we replace this code, we
190             // DON'T run the End* hook, to keep others from
191             // adding tabs. Not nice, but.
192             return false;
193         }
194
195         return true;
196     }
197
198     /**
199      * Menu item for login
200      *
201      * @param Action &$action Action being executed
202      *
203      * @return boolean hook return
204      */
205
206     function onEndLoginGroupNav(&$action)
207     {
208         $this->showOpenIDLoginTab($action);
209
210         return true;
211     }
212
213     /**
214      * Show menu item for login
215      *
216      * @param Action $action Action being executed
217      *
218      * @return void
219      */
220
221     function showOpenIDLoginTab($action)
222     {
223         $action_name = $action->trimmed('action');
224
225         $action->menuItem(common_local_url('openidlogin'),
226                           _m('OpenID'),
227                           _m('Login or register with OpenID'),
228                           $action_name === 'openidlogin');
229     }
230
231     /**
232      * Show menu item for password
233      *
234      * We hide it in openID-only mode
235      *
236      * @param Action $menu    Widget for menu
237      * @param void   &$unused Unused value
238      *
239      * @return void
240      */
241
242     function onStartAccountSettingsPasswordMenuItem($menu, &$unused) {
243         if ($this->openidOnly) {
244             return false;
245         }
246         return true;
247     }
248
249     /**
250      * Menu item for OpenID settings
251      *
252      * @param Action &$action Action being executed
253      *
254      * @return boolean hook return
255      */
256
257     function onEndAccountSettingsNav(&$action)
258     {
259         $action_name = $action->trimmed('action');
260
261         $action->menuItem(common_local_url('openidsettings'),
262                           _m('OpenID'),
263                           _m('Add or remove OpenIDs'),
264                           $action_name === 'openidsettings');
265
266         return true;
267     }
268
269     /**
270      * Autoloader
271      *
272      * Loads our classes if they're requested.
273      *
274      * @param string $cls Class requested
275      *
276      * @return boolean hook return
277      */
278
279     function onAutoload($cls)
280     {
281         switch ($cls)
282         {
283         case 'OpenidloginAction':
284         case 'FinishopenidloginAction':
285         case 'FinishaddopenidAction':
286         case 'XrdsAction':
287         case 'PublicxrdsAction':
288         case 'OpenidsettingsAction':
289         case 'OpenidserverAction':
290         case 'OpenidtrustAction':
291             require_once INSTALLDIR.'/plugins/OpenID/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
292             return false;
293         case 'User_openid':
294             require_once INSTALLDIR.'/plugins/OpenID/User_openid.php';
295             return false;
296         case 'User_openid_trustroot':
297             require_once INSTALLDIR.'/plugins/OpenID/User_openid_trustroot.php';
298             return false;
299         default:
300             return true;
301         }
302     }
303
304     /**
305      * Sensitive actions
306      *
307      * These actions should use https when SSL support is 'sometimes'
308      *
309      * @param Action  $action Action to form an URL for
310      * @param boolean &$ssl   Whether to mark it for SSL
311      *
312      * @return boolean hook return
313      */
314
315     function onSensitiveAction($action, &$ssl)
316     {
317         switch ($action)
318         {
319         case 'finishopenidlogin':
320         case 'finishaddopenid':
321             $ssl = true;
322             return false;
323         default:
324             return true;
325         }
326     }
327
328     /**
329      * Login actions
330      *
331      * These actions should be visible even when the site is marked private
332      *
333      * @param Action  $action Action to show
334      * @param boolean &$login Whether it's a login action
335      *
336      * @return boolean hook return
337      */
338
339     function onLoginAction($action, &$login)
340     {
341         switch ($action)
342         {
343         case 'openidlogin':
344         case 'finishopenidlogin':
345         case 'openidserver':
346             $login = true;
347             return false;
348         default:
349             return true;
350         }
351     }
352
353     /**
354      * We include a <meta> element linking to the userxrds page, for OpenID
355      * client-side authentication.
356      *
357      * @param Action $action Action being shown
358      *
359      * @return void
360      */
361
362     function onEndShowHeadElements($action)
363     {
364         if ($action instanceof ShowstreamAction) {
365             $action->element('link', array('rel' => 'openid2.provider',
366                                            'href' => common_local_url('openidserver')));
367             $action->element('link', array('rel' => 'openid2.local_id',
368                                            'href' => $action->profile->profileurl));
369             $action->element('link', array('rel' => 'openid.server',
370                                            'href' => common_local_url('openidserver')));
371             $action->element('link', array('rel' => 'openid.delegate',
372                                            'href' => $action->profile->profileurl));
373         }
374         return true;
375     }
376
377     /**
378      * Redirect to OpenID login if they have an OpenID
379      *
380      * @param Action $action Action being executed
381      * @param User   $user   User doing the action
382      *
383      * @return boolean whether to continue
384      */
385
386     function onRedirectToLogin($action, $user)
387     {
388         if ($this->openidOnly || (!empty($user) && User_openid::hasOpenID($user->id))) {
389             common_redirect(common_local_url('openidlogin'), 303);
390             return false;
391         }
392         return true;
393     }
394
395     /**
396      * Show some extra instructions for using OpenID
397      *
398      * @param Action $action Action being executed
399      *
400      * @return boolean hook value
401      */
402
403     function onEndShowPageNotice($action)
404     {
405         $name = $action->trimmed('action');
406
407         switch ($name)
408         {
409         case 'register':
410             if (common_logged_in()) {
411                 $instr = '(Have an [OpenID](http://openid.net/)? ' .
412                   '[Add an OpenID to your account](%%action.openidsettings%%)!';
413             } else {
414                 $instr = '(Have an [OpenID](http://openid.net/)? ' .
415                   'Try our [OpenID registration]'.
416                   '(%%action.openidlogin%%)!)';
417             }
418             break;
419         case 'login':
420             $instr = '(Have an [OpenID](http://openid.net/)? ' .
421               'Try our [OpenID login]'.
422               '(%%action.openidlogin%%)!)';
423             break;
424         default:
425             return true;
426         }
427
428         $output = common_markup_to_html($instr);
429         $action->raw($output);
430         return true;
431     }
432
433     /**
434      * Load our document if requested
435      *
436      * @param string &$title  Title to fetch
437      * @param string &$output HTML to output
438      *
439      * @return boolean hook value
440      */
441
442     function onStartLoadDoc(&$title, &$output)
443     {
444         if ($title == 'openid') {
445             $filename = INSTALLDIR.'/plugins/OpenID/doc-src/openid';
446
447             $c      = file_get_contents($filename);
448             $output = common_markup_to_html($c);
449             return false; // success!
450         }
451
452         return true;
453     }
454
455     /**
456      * Add our document to the global menu
457      *
458      * @param string $title   Title being fetched
459      * @param string &$output HTML being output
460      *
461      * @return boolean hook value
462      */
463
464     function onEndLoadDoc($title, &$output)
465     {
466         if ($title == 'help') {
467             $menuitem = '* [OpenID](%%doc.openid%%) - what OpenID is and how to use it with this service';
468
469             $output .= common_markup_to_html($menuitem);
470         }
471
472         return true;
473     }
474
475     /**
476      * Data definitions
477      *
478      * Assure that our data objects are available in the DB
479      *
480      * @return boolean hook value
481      */
482
483     function onCheckSchema()
484     {
485         $schema = Schema::get();
486         $schema->ensureTable('user_openid',
487                              array(new ColumnDef('canonical', 'varchar',
488                                                  '255', false, 'PRI'),
489                                    new ColumnDef('display', 'varchar',
490                                                  '255', false, 'UNI'),
491                                    new ColumnDef('user_id', 'integer',
492                                                  null, false, 'MUL'),
493                                    new ColumnDef('created', 'datetime',
494                                                  null, false),
495                                    new ColumnDef('modified', 'timestamp')));
496         $schema->ensureTable('user_openid_trustroot',
497                              array(new ColumnDef('trustroot', 'varchar',
498                                                  '255', false, 'PRI'),
499                                    new ColumnDef('user_id', 'integer',
500                                                  null, false, 'PRI'),
501                                    new ColumnDef('created', 'datetime',
502                                                  null, false),
503                                    new ColumnDef('modified', 'timestamp')));
504         return true;
505     }
506
507     /**
508      * Add our tables to be deleted when a user is deleted
509      *
510      * @param User  $user    User being deleted
511      * @param array &$tables Array of table names
512      *
513      * @return boolean hook value
514      */
515
516     function onUserDeleteRelated($user, &$tables)
517     {
518         $tables[] = 'User_openid';
519         $tables[] = 'User_openid_trustroot';
520         return true;
521     }
522
523     /**
524      * Add our version information to output
525      *
526      * @param array &$versions Array of version-data arrays
527      *
528      * @return boolean hook value
529      */
530
531     function onPluginVersion(&$versions)
532     {
533         $versions[] = array('name' => 'OpenID',
534                             'version' => STATUSNET_VERSION,
535                             'author' => 'Evan Prodromou, Craig Andrews',
536                             'homepage' => 'http://status.net/wiki/Plugin:OpenID',
537                             'rawdescription' =>
538                             _m('Use <a href="http://openid.net/">OpenID</a> to login to the site.'));
539         return true;
540     }
541 }