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