source: trunk/lepton/libraries/openid.php @ 85

Revision 85, 7.6 KB checked in by noccy, 15 months ago (diff)

OpenID Bugfixes; now handles delegation properly.

Line 
1<?php
2
3        /**
4         * Lepton OpenID 2.0 Consumer
5         *
6         * @license GPLv3
7         * @author Christopher Vagnetoft <noccy@chillat.net>
8         * @author Eddie Roosenmaalen <eddie@roosenmaallen.com>
9         */
10        class Openid extends Library {
11               
12                private $fields = array();
13                private $config = array();
14                private $server;
15                private $identityurl = '';
16                private $delegateurl = '';
17               
18                function __construct() {
19                        // Read the configuration
20                        $this->fields['required'] =
21                                config::get('lepton.openid.fields.required',array());
22                        $this->fields['optional'] =
23                                config::get('lepton.openid.fields.optional',array());
24                        $this->config['urls'] = array(
25                                'trustroot' => config::get('lepton.openid.trustroot'),
26                                'cancelurl' => config::get('lepton.openid.cancelurl'),
27                                'approvedurl' => config::get('lepton.openid.approvedurl')
28                        );
29                }
30               
31                public function setTrustRoot($url) {
32                        $this->config['urls']['trustroot'] = $url;
33                }
34                public function getTrustRoot() {
35                        return $this->config['urls']['trustroot'];
36                }
37               
38                public function setCancelURL($url) {
39                        $this->config['urls']['cancelurl'];
40                }
41                public function getCancelURL() {
42                        return $this->config['urls']['cancelurl'];
43                }
44               
45                public function setApprovedURL($url) {
46                        $this->config['urls']['approvedurl'] = $url;
47                }
48                public function getApprovedURL() {
49                        return $this->config['urls']['approvedurl'];
50                }
51               
52                /**
53                 * Sets the identity to use for login.
54                 * Set any additional needed parameters manually (or by using the
55                 * lepton.openid.* config space) and call login() to proceed.
56                 * @param string $identity The identity to log in as
57                 * @param string $server The server (if cached)
58                 */
59                public function setIdentity($identity,$server='') {
60                        $this->identityurl = $this->normalizeIdentity($identity);
61                        if ($this->identityurl != '') {
62                                if ($server != '') {
63                                        // Save the server as provided
64                                        $this->server = $server;
65                                } else {
66                                        try {
67                                                // Get the server from the page
68                                                $page = http::get($this->identityurl);
69                                                $dom = DOMDocument::loadHTML($page);
70                                                $domx = new DOMXPath($dom);
71                                                // Look for delegates
72                                                $servers = $domx->query('*/link[@rel=\'openid.delegate\']');
73                                                foreach($servers as $server) {
74                                                        $this->delegateurl = $server->getAttribute('href');
75                                                        break;
76                                                }
77                                                // Look for servers
78                                                $servers = $domx->query('*/link[@rel=\'openid.server\']');
79                                                foreach($servers as $server) {
80                                                        $this->server = $server->getAttribute('href');
81                                                        return;
82                                                }
83                                                throw new OpenIDException('No servers found at identity URL',OpenIDException::ERR_BAD_IDENTITY);
84                                        } catch (HTTPException $e) {
85                                                throw new OpenIDException('Unable to retrieve URL',OpenIDException::ERR_GENERIC);
86                                        }
87                                }
88                        } else {
89                                throw new OpenIDException('Invalid identity URL',OpenIDException::ERR_BAD_IDENTITY);
90                        }
91                }
92               
93                /**
94                 * Returns the assigned identity or delegated identity.
95                 * @return string The identity
96                 */
97                public function getIdentity() {
98                        return $this->identityurl;
99                }
100               
101                /**
102                 * Return the resolved server
103                 * @return string The resolved server
104                 */
105                public function getServer() {
106                        return $this->server;
107                }
108               
109                /**
110                 * Normalize and return the identity
111                 * Makes the identity lowercase and prepends http:// if not there
112                 * already.
113                 * @param string $url The identity URL
114                 * @return string The normalized identity URL
115                 */
116                private function normalizeIdentity($url) {
117                        $url = String::toLowerCase($url);
118                        if ((stripos($url, 'http://') === false) && (stripos($url, 'https://') === false)){
119                                        $url = 'http://'.$url;
120                        }
121                        return $url;
122                }
123               
124                /**
125                 * Send the user off to the provider to sign in
126                 */
127                public function login() {
128                        // Check that everything is in order
129                       
130                        if (($this->config['urls']['trustroot'] != '') &&
131                                ($this->config['urls']['cancelurl'] != '') &&
132                                ($this->config['urls']['approvedurl'] != '')) {
133                               
134                                $url = $this->getRedirectURl();
135                                response::redirect($url);
136                                // echo $url;
137                               
138                        } else {
139                                throw new OpenIDException('Check your configuration!',OpenIDException::ERR_CONFIGURATION);
140                        }
141                       
142                }
143
144                /**
145                 * Get the URL to redirect to for authentication
146                 */
147                private function getRedirectURL() {
148                       
149                        // TODO: Might be a good idea to save the original identity here
150                        // in the case of delegation. If the main identity is saved, it
151                        // can be pulled in place of the returned identity from the provider
152                        if ($this->delegateurl != '') {
153                                Session::set('lepton.openid.delegatedidentity',$this->identityurl);
154                                $identity = $this->delegateurl;
155                        } else {
156                                Session::clear('lepton.openid.delegatedidentity');
157                                $identity = $this->identityurl;
158                        }
159                       
160                        $params = array();
161                        $params['openid.return_to'] = urlencode($this->config['urls']['approvedurl']);
162                        $params['openid.mode'] = 'checkid_setup';
163                        $params['openid.identity'] = urlencode($identity);
164                        $params['openid.trust_root'] = urlencode($this->config['urls']['trustroot']);
165                       
166                        if (isset($this->fields['required'])
167                          && (count($this->fields['required']) > 0)) {
168                                $params['openid.sreg.required'] = implode(',',$this->fields['required']);
169                        }
170                        if (isset($this->fields['optional'])
171                          && (count($this->fields['optional']) > 0)) {
172                                $params['openid.sreg.optional'] = implode(',',$this->fields['optional']);
173                        }
174                        return $this->server . "?". $this->arrayToURL($params);
175                }
176               
177                private function arrayToURL($arr) {
178                        if (!is_array($arr)){
179                                return false;
180                        }
181                        $query = '';
182                        foreach($arr as $key => $value){
183                                $query .= $key . "=" . $value . "&";
184                        }
185                        return $query;
186                }
187               
188                /**
189                 * Validate the response
190                 */
191                public function validate() {
192
193                        $this->setIdentity(urldecode($_GET['openid_identity']));
194                        $params = array(
195                                'openid.assoc_handle' => urlencode($_GET['openid_assoc_handle']),
196                                'openid.signed' => urlencode($_GET['openid_signed']),
197                                'openid.sig' => urlencode($_GET['openid_sig'])
198                        );
199                        // Send only required parameters to confirm validity
200                        $arr_signed = explode(",",str_replace('sreg.','sreg_',$_GET['openid_signed']));
201                        for ($i=0; $i<count($arr_signed); $i++){
202                                $s = str_replace('sreg_','sreg.', $arr_signed[$i]);
203                                $c = $_GET['openid_' . $arr_signed[$i]];
204                                // if ($c != ""){
205                                        $params['openid.' . $s] = urlencode($c);
206                                // }
207                        }
208                        $params['openid.mode'] = "check_authentication";
209       
210                        $openid_server = $this->server;
211                        if ($openid_server == false){
212                                return false;
213                        }
214                        $response = http::post($openid_server,$this->arrayToURL($params));
215                        $data = $this->splitResponse($response);
216       
217                        $this->identityurl = Session::get('lepton.openid.delegatedidentity',$this->identityurl);
218       
219                        if ($data['is_valid'] == "true") {
220                                return true;
221                        }else{
222                                return false;
223                        }
224                       
225                }
226               
227                private function splitResponse($response) {
228                        $r = array();
229                        $response = explode("\n", $response);
230                        foreach($response as $line) {
231                                $line = trim($line);
232                                if ($line != "") {
233                                        list($key, $value) = explode(":", $line, 2);
234                                        $r[trim($key)] = trim($value);
235                                }
236                        }
237                        return $r;
238                }
239
240                public function setRequiredFields($fields) {
241                        if (is_array($fields)) {
242                                $this->fields['required'] = $fields;
243                        } else {
244                                $this->fields['required'] = explode(',',$fields);
245                        }
246                }
247
248                public function setOptionalFields($fields) {
249                        if (is_array($fields)) {
250                                $this->fields['optional'] = $fields;
251                        } else {
252                                $this->fields['optional'] = explode(',',$fields);
253                        }
254                }
255
256                /**
257                 * Return a requested field
258                 */
259                public function getField($key) {
260                        return $_GET['openid_sreg_'.$key];
261                }
262               
263               
264                public function loginUser() {
265                       
266                }
267               
268        }
269       
270        class OpenIDException extends Exception {
271                const ERR_GENERIC = 0;
272                const ERR_BAD_IDENTITY = 1; /// No identity at this URL or bad URL
273                const ERR_CONFIGURATION = 2;
274        }
275
276?>
Note: See TracBrowser for help on using the repository browser.