root/plugins/openid/trunk/openid.plugin.php

Revision 1269, 9.4 kB (checked in by chrismeller, 8 days ago)

Setting the svn:eol-style property on... everything. God help us.

  • Property svn:eol-style set to native
Line 
1<?php
2class OpenID extends Plugin
3{
4    public function info()
5    {
6        return array(
7            'name' => 'OpenID',
8            'version' => '1.1.2',
9            'url' => 'http://phpquebec.org/',
10            'author' =>    'PHP Quebec Community',
11            'authorurl' => 'http://phpquebec.org/',
12            'license' => 'Apache License 2.0',
13            'description' => 'Adds OpenID 2.0 authentification support.',
14            'copyright' => '2007'
15            );
16    }
17
18    public function filter_rewrite_rules( $db_rules )
19    {
20        $db_rules[] = new RewriteRule( array(
21            'name' => 'openid',
22            'parse_regex' => '%^openid/?(?P<user>[^/]*)/?$%i', // For Server, if previous matched, don't look.
23            'build_str' => 'openid/({$user})',
24            'handler' => 'OpenID',
25            'action' => 'dispatch',
26            'priority' => 1,
27            'is_active' => 1,
28            'rule_class' => RewriteRule::RULE_CUSTOM,
29            'description' => 'OpenID Authentification'
30            ) );
31
32        return $db_rules;
33    }
34
35    public function act( $action )
36    {
37        if ( isset( $_GET['openid_mode'] ) ) {
38            switch ( $_GET['openid_mode'] ) {
39                case 'id_res':
40                    self::openid_end();
41                    break;
42                case 'cancel':
43                    EventLog::log( 'Authorization failed: User cancelled authorization.', 'info', 'authentication', 'OpenID' );
44                    throw new Exception( 'Authorization failed: User cancelled authorization.' );
45                    break;
46            }
47        }
48        else if ( isset( $_POST['openid_url'] ) ) {
49            self::openid_start();
50        }
51        else {
52            EventLog::log( 'Authorization failed: unknown error.', 'err', 'authentication', 'OpenID' );
53            throw new Exception( 'Authorization failed: unknown error.' );
54        }
55    }
56
57    public function action_plugin_activation( $file )
58    {
59        if ( realpath( $file ) == __FILE__ ) {
60            if ( !extension_loaded('curl') && !@dl('curl') ) {
61                EventLog::log( 'Could not load CURL, which is needed for OpenID to work.', 'err', 'authentication', 'OpenID' );
62                throw new Exception( 'Could not load CURL, which is needed for OpenID to work.' );
63            }
64            EventLog::register_type( 'authentification', 'OpenID' );
65        }
66    }
67
68    public function action_plugin_deactivation( $file )
69    {
70        if ( realpath( $file ) == __FILE__ ) {
71            EventLog::unregister_type( 'OpenID' );
72        }
73    }
74
75    public function action_init()
76    {
77        if ( session_id() == '' ) {
78            session_start();
79        }
80        ini_set( 'include_path', dirname( __FILE__ ) );
81        Stack::add( 'template_stylesheet', array( $this->get_url() . '/openid.css', 'screen' ), 'openid_style' );
82    }
83
84    public function action_theme_loginform_before()
85    {
86        if ( isset( $_GET['openid_url'] ) ) {
87            echo '<hr><div class="alert"><strong>If you have an existing account</strong>, sign in so we can assign your OpenID identifer to it.</div>';
88        }
89    }
90
91    public function action_theme_loginform_after()
92    {
93     // @todo Remove the !isset( $_GET['openid_url'] ) once registration works in Habari.
94        if ( ( Controller::get_action() != 'register' ) && !isset( $_GET['openid_url'] ) ) {
95            if ( Controller::get_action() == 'login' ) {
96                echo '
97                <form method="post" action="'. URL::get( 'openid' ) .'" id="admin_openidform">
98                <p>
99                <label for="openid_url" class="incontent abovecontent">' . _t('OpenID Identifier') . '</label><input type="text" name="openid_url" id="openid_url"' . ( isset($openid_url) ? 'value="'. $openid_url . '"' : '' ) . ' placeholder="' . _t('openid identifier') . '" class="styledformelement">
100                </p>
101                <p>
102                <input id="openid_submit" class="submit" type="submit" value="Sign in using OpenID">
103                </p>
104                </form>
105                ';
106            }
107            else {
108                echo '
109                <form method="post" action="'. URL::get( 'openid' ) .'" id="openidform">
110                <p>
111                <label for="openid_url">OpenID Identifier:</label>
112                <input type="text" size="25" name="openid_url" id="openid_url">
113                </p>
114                <p>
115                <input type="submit" value="Sign in using OpenID">
116                </p>
117                </form>
118                ';
119            }
120        }
121    }
122
123    public function action_theme_loginform_controls()
124    {
125        if ( isset( $_GET['openid_url'] ) ) {
126            echo '<input type="hidden" value="'.$_GET['openid_url'].'" name="habari_openid_url">';
127        }
128    }
129
130    /* Uncomment once registration is supported by Habari.
131    public function action_theme_registerform_controls()
132    {
133        if ( isset( $_GET['openid_url'] ) ) {
134            echo '<input type="hidden" value="'.$_GET['openid_url'].'" name="habari_openid_url">';
135        }
136    } */
137
138    public function action_theme_admin_user( $user )
139    {
140        $openid_url = isset( $user->info->openid_url ) ? $user->info->openid_url : '';
141        echo '
142        <div class="container settings user openid" id="openid">
143                <h2>' . _t('OpenID') . '</h2>
144                <div class="item clear" id="openid_url">
145                <span class="pct20">
146                        <label for="habari_openid_url">' . _t('OpenID Identifier') . '</label>
147                </span>
148                <span class="pct80">
149                        <input type="text" name="habari_openid_url" id="habari_openid_url" class="border" value="' . $openid_url . '" disabled>
150                    </span>
151                </div>
152        </div>';
153    }
154
155    public function action_user_identify()
156    {
157        if ( ( Controller::get_action() == 'login' ) && !empty( $_POST['openid_url'] ) ) {
158            self::openid_start();
159        }
160    }
161
162    // TODO: Add more security against form hijacking (for instance, check against server sent data)
163    public function action_user_authenticate_successful( $user )
164    {
165        if ( !empty( $_POST['habari_openid_url'] ) ) {
166            $user->info->openid_url = $_POST['habari_openid_url'];
167        }
168    }
169
170    function action_admin_header( $theme )
171    {
172        // Add the css if this is the default login page
173        if ( $theme->admin_page == 'login' ) {
174            Stack::add( 'admin_stylesheet', array( $this->get_url() . '/openid.css', 'screen' ), 'openid_style' );
175        }
176    }
177
178    function getOpenIDURL()
179    {
180        if ( empty( $_POST['openid_url'] ) ) {
181            EventLog::log( 'Expected an OpenID URL.', 'err', 'authentication', 'OpenID' );
182            throw new Exception( 'Expected an OpenID URL.' );
183        }
184
185        return $_POST['openid_url'];
186    }
187
188    function getReturnTo()
189    {
190        return URL::get('openid');
191    }
192
193    function getTrustRoot()
194    {
195        return Site::get_url('habari');
196    }
197
198    function getStore()
199    {
200        $store_path = "/tmp/_php_consumer_test";
201
202        if ( !file_exists( $store_path ) && !mkdir( $store_path ) ) {
203            EventLog::log( 'Could not create the FileStore directory: ' . $store_path, 'err', 'authentication', 'OpenID' );
204            throw new Exception( 'Could not create the FileStore directory: ' . $store_path . '. Please check the effective permissions.' );
205        }
206
207        return new Auth_OpenID_FileStore( $store_path );
208    }
209
210    function getConsumer()
211    {
212        require_once "Auth/OpenID/Consumer.php";
213        require_once "Auth/OpenID/FileStore.php";
214        require_once "Auth/OpenID/SReg.php";
215        $store = self::getStore();
216        return new Auth_OpenID_Consumer( $store );
217    }
218
219    function openid_start()
220    {
221        $openid = self::getOpenIDURL();
222        $consumer = self::getConsumer();
223
224        $auth_request = $consumer->begin( $openid );
225
226        if ( !$auth_request ) {
227            EventLog::log( 'Authentication error: Not a valid OpenID.', 'err', 'authentication', 'OpenID' );
228            throw new Exception( 'Authentication error: Not a valid OpenID.' );
229        }
230
231        $sreg_request = Auth_OpenID_SRegRequest::build( array( 'nickname' ), array( 'fullname', 'email' ) );
232
233        if ( $sreg_request ) {
234            $auth_request->addExtension( $sreg_request );
235        }
236
237        if ( $auth_request->shouldSendRedirect() ) {
238            $redirect_url = $auth_request->redirectURL( self::getTrustRoot(), self::getReturnTo() );
239
240            if ( Auth_OpenID::isFailure( $redirect_url ) ) {
241                EventLog::log( 'Could not redirect to server: ' . $redirect_url->message, 'err', 'authentication', 'OpenID' );
242                throw new Exception( 'Could not redirect to server: ' . $redirect_url->message );
243            }
244            else {
245                header( "Location: ".$redirect_url );
246            }
247        }
248        else {
249            $form_id = 'openid_message';
250            $form_html = $auth_request->formMarkup( self::getTrustRoot(), self::getReturnTo(), false, array( 'id' => $form_id ) );
251
252            if ( Auth_OpenID::isFailure( $form_html ) ) {
253                EventLog::log( 'Could not prepare redirection form: ' . $form_html->message, 'err', 'authentication', 'OpenID' );
254                throw new Exception( 'Could not prepare redirection form: ' . $form_html->message );
255            }
256            else {
257                echo '
258                    <html>
259                    <head>
260                    <title>OpenID transaction in progress</title>
261                    </head>
262                    <body onload="document.getElementById(\''.$form_id.'\').submit()">
263                    '.$form_html.'
264                    </body>
265                    </html>
266                    ';
267            }
268        }
269    }
270
271    function openid_end()
272    {
273        $consumer = self::getConsumer();
274        $return_to = self::getReturnTo();
275        $response = $consumer->complete( $return_to );
276
277        switch( $response->status ) {
278            case Auth_OpenID_CANCEL:
279                EventLog::log( 'Verification cancelled.', 'err', 'authentication', 'OpenID' );
280                throw new Exception( 'Verification cancelled.' );
281                break;
282            case Auth_OpenID_FAILURE:
283                EventLog::log( 'OpenID authentication failed: ' . $response->message, 'err', 'authentication', 'OpenID' );
284                throw new Exception( 'OpenID authentication failed: ' . $response->message );
285                break;
286            case Auth_OpenID_SUCCESS:
287                $openid = $response->getDisplayIdentifier();
288                $esc_identity = htmlspecialchars( $openid, ENT_QUOTES );
289
290                $user = Users::get_by_info( 'openid_url', $openid );
291                if ( count( $user ) != 0 ) {
292                    if ( count( $user ) > 1 ) {
293                        EventLog::log( 'Authentication error: More than one user has this OpenID.', 'err', 'authentication', 'OpenID' );
294                        throw new Exception( 'Authentication error: More than one user has this OpenID.' );
295                    }
296                    $user[0]->remember();
297                    EventLog::log( 'Successful login for ' . $user[0]->username, 'info', 'authentication', 'OpenID' );
298
299                    header( "HTTP/1.1 100 Continue" );
300                    header( "Location: " . Site::get_url( 'admin' ) );
301                    header( "Connection: close" );
302                }
303                else {
304                    Utils::redirect( URL::get( 'user', array( 'page'=>'login', 'openid_url' => $openid ), true ) );
305                }
306            }
307        }
308
309}
310?>
Note: See TracBrowser for help on using the browser.