Subversion Repositories Applications.framework

Rev

Rev 260 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 260 Rev 263
1
<?php 
1
<?php 
-
 
2
/**
-
 
3
 * La classe OpenIdClient est une implémentation d'un client OpenId, depuis une classe Zend.
-
 
4
 * Elle permet d'établir une connexion avec un serveur, en fonction d'un identifiant OpenId.
-
 
5
 * Elle permet de communiquer de manière sécurisée avec ce serveur, et doit aboutir a une 
-
 
6
 * identification centralisée.
-
 
7
 * */
-
 
8
 
2
class OpenIdClient {
9
class OpenIdClient {
3
	
10
	
4
	//OpenID 2.0 namespace. Tous les messages OpenID 2.0 DOIVENT contenir la variable openid.ns et sa valeur
11
	//OpenID 2.0 namespace. Tous les messages OpenID 2.0 DOIVENT contenir la variable openid.ns et sa valeur
5
    const NS_2_0 = 'http://specs.openid.net/auth/2.0';
12
    const NS_2_0 = 'http://specs.openid.net/auth/2.0';
6
    
13
    
-
 
14
    
7
    
15
    // TODO : remplacer _storage par une gestion par cache ?
8
	/**
16
	/**
9
     * Reference to an implementation of storage object
-
 
10
     *
17
     * Variable permettant le stockage d'informations, notammenent à propos des clés DiffieHellmann
11
     * @var Zend_OpenId_Consumer_Storage $_storage
18
     * @var Storage $_storage
12
     */
19
     */
13
    protected $_storage = null;
20
    protected $_storage = null;
14
    
21
    
15
    /**
22
    /**
16
     * Internal cache to prevent unnecessary access to storage
23
     * Tableau "cache" interne permettant d'éviter des accès inutiles au fichier storage
17
     *
-
 
18
     * @var array $_cache
24
     * @var array $_cache
19
     */
25
     */
20
    protected $_cache = array();
26
    protected $_cache = array();
21
    
-
 
22
    
27
 
23
    // TODO : les associations dans ZEND sont gérées avec le fichier Stockage, faire pareil
-
 
24
    //Association
28
    // Client pour les requetes.
25
    private $association = Array('url' => '', 'handle' => '', 'macFunc' => '', 'secret' => '', 'expires' => 0);
-
 
26
    
-
 
27
    private $client;
29
    private $client;
28
    
-
 
29
    
30
    
30
	/**
31
	/**
31
	 * Constructeur de l'application
32
	 * Constructeur de l'application
32
	 * */
33
	 * */
33
	function __construct()	{
34
	function __construct()	{
34
		$this->client = new Client();
35
		$this->client = new Client();
35
		$this->_storage = new StorageFile();
36
		$this->_storage = new StorageFile();
36
	}
37
	}
37
	
38
	
38
	/**
39
	/**
39
	 * Fonction login
40
	 * Fonction login
40
	 * 
41
	 * 
41
	 * Return true ou false
42
	 * Return true ou false
42
	 * > Ne retourne rien si true car redirige vers l'adresse du serveur OID
43
	 * > Ne retourne rien si true car redirige vers l'adresse du serveur OID
43
	 * */
44
	 * */
44
	//FIXME : le paramètre immediate ?
45
	//FIXME : le paramètre immediate ?
45
	// ATTENTION : ca marche en false mais pas en true !!!
46
	// A vérifier mais ça doit permettre de passer directement le mot de passe. Il reste plus qu'à trouver le nom de la variable mot de passe.
46
	
47
	
47
	function login($id, $immediate = false)	{
48
	function login($id, $immediate = false)	{
48
		
49
		
49
		// FIXME : l'original retourne la fonction checkId, avec le parametre immediate = true
50
		// L'original retourne la fonction checkId, avec le parametre immediate = true
-
 
51
		// Je ne comprends pas l'utilité, je fusionne les deux pour l'instant
-
 
52
		// FIXME : si pas de comportement étrange, valider.
50
		// Je ne comprends pas l'utilité, je fusionne les deux pour l'instant
53
		
51
		
54
		
52
		//Tests et arrêt si non validé : 
55
		//Tests et arrêt si non validé : 
53
			//Normaliser (traite si XRI ou URL, normalize URL)
56
			//Normaliser (traite si XRI ou URL, normalize URL)
54
			//FIXME : voir avec JP pour équivalent dans framework
57
			//FIXME : voir avec JP pour équivalent dans framework
55
			if (!$this->normalize($id))	{
58
			if (!$this->normalize($id))	{
56
				return false;
59
				return false;
57
			}
60
			}
58
			
61
			
59
			//Discovery
62
			//Discovery
60
			// Récupérer les informations sur le serveur OPEN ID
63
			// Récupérer les informations sur le serveur OPEN ID
61
			/*
64
			/*
62
			 FIXME : ca change la valeur de l'id !!!
65
			 FIXME : ca change la valeur de l'id !!!
63
			 if (!$this->_discovery($id, $server, $version)) {
66
			 if (!$this->_discovery($id, $server, $version)) {
64
		         trigger_error('Discovery failed');
67
		         trigger_error('Discovery failed');
65
		         return false;
68
		         return false;
66
		    }*/
69
		    }*/
67
			
70
			
68
		    $retour_url = $this->client->consulter($id); 
71
		    $retour_url = $this->client->consulter($id); 
69
		    //Le retour contient les balises suivantes :
72
		    //Le retour contient les balises suivantes :
70
			/*
73
			/*
71
			 * 
74
			 * 
72
			 * <link rel="openid.server" href="http://www.myopenid.com/server" />
75
			 * <link rel="openid.server" href="http://www.myopenid.com/server" />
73
			 * <link rel="openid2.provider" href="http://www.myopenid.com/server" />
76
			 * <link rel="openid2.provider" href="http://www.myopenid.com/server" />
74
			 */
77
			 */
75
			$metaServeur = $this->verifierVersion($retour_url);
78
			$metaServeur = $this->verifierVersion($retour_url);
76
			
79
			
77
			//TODO : Voir avec JP : la classe client ne permet pas de vérifer le statut ?? 
80
			//TODO : Voir avec JP : la classe client ne permet pas de vérifer le statut ?? 
78
			
81
			
79
			if ($retour_url === false) {
82
			if ($retour_url === false) {
80
				trigger_error('L\'adresse $id est inacessible', E_USER_ERROR);
83
				trigger_error('L\'adresse $id est inacessible', E_USER_ERROR);
81
				return false;
84
				return false;
82
			}
85
			}
83
			if ($metaServeur === false)	{
86
			if ($metaServeur === false)	{
84
				return false;
87
				return false;
85
			}
88
			}
86
			if (!$this->_associate($metaServeur['serveur'], $metaServeur['version'])) {
89
			if (!$this->_associate($metaServeur['serveur'], $metaServeur['version'])) {
87
            	trigger_error('Impossible de s\'associer avec le serveur');
90
            	trigger_error('Impossible de s\'associer avec le serveur');
88
        	}
91
        	}
89
        	
92
        	
90
        	
93
        	
91
        	/*TODO : fonctionnement différent
94
        	/*TODO : fonctionnement différent
92
        	 if (!$this->_getAssociation(
95
        	 if (!$this->_getAssociation(
93
                $server,
96
                $server,
94
                $handle,
97
                $handle,
95
                $macFunc,
98
                $macFunc,
96
                $secret,
99
                $secret,
97
                $expires)) {
100
                $expires)) {
98
            /* Use dumb mode *
101
            /* Use dumb mode *
99
            unset($handle);
102
            unset($handle);
100
            unset($macFunc);
103
            unset($macFunc);
101
            unset($secret);
104
            unset($secret);
102
            unset($expires);*
105
            unset($expires);*
103
        }*/
106
        }*/
104
 
107
 
105
			//on a la version, l'adresse du serveur et le realId si c'est une 2.0 dans metaServeur
108
			//on a la version, l'adresse du serveur et le realId si c'est une 2.0 dans metaServeur
106
			if (isset($metaServeur['realId'])) {
109
			if (isset($metaServeur['realId'])) {
107
				$id = $metaServeur['realId']; 
110
				$id = $metaServeur['realId']; 
108
			}
111
			}
109
			
112
			
110
			//Associate
113
			//Associate
111
			//getAssociation
114
			//getAssociation
112
		
115
		
113
		//Organisation des paramètres :
116
		//Organisation des paramètres :
114
		$params = array();
117
		$params = array();
115
		
118
		
116
	
119
	
117
        if ($metaServeur['version'] >= 2.0) {
120
        if ($metaServeur['version'] >= 2.0) {
118
            $params['openid.ns'] = self::NS_2_0;
121
            $params['openid.ns'] = self::NS_2_0;
119
        }
122
        }
120
 
123
 
121
        $params['openid.mode'] = $immediate ?
124
        $params['openid.mode'] = $immediate ?
122
            'checkid_immediate' : 'checkid_setup';
125
            'checkid_immediate' : 'checkid_setup';
123
 
126
 
124
        $params['openid.identity'] = $id;
127
        $params['openid.identity'] = $id;
125
 
128
 
126
        //FIXME : Ex : $params['openid.claimed_id'] = $claimedId; > jvois pas l'intéret
129
        //FIXME : Ex : $params['openid.claimed_id'] = $claimedId; > jvois pas l'intéret
127
        $params['openid.claimed_id'] = $id;
130
        $params['openid.claimed_id'] = $id;
128
        /*
131
        /*
129
         * TODO : gérer les sessions et namespace
132
         * TODO : gérer les sessions et namespace
130
         * if ($metaServeur['version'] <= 2.0) {
133
         * if ($metaServeur['version'] <= 2.0) {
131
            if ($this->_session !== null) {
134
            if ($this->_session !== null) {
132
                $this->_session->identity = $id;
135
                $this->_session->identity = $id;
133
                $this->_session->claimed_id = $claimedId;
136
                $this->_session->claimed_id = $claimedId;
134
            } else if (defined('SID')) {
137
            } else if (defined('SID')) {
135
                $_SESSION["zend_openid"] = array(
138
                $_SESSION["zend_openid"] = array(
136
                    "identity" => $id,
139
                    "identity" => $id,
137
                    "claimed_id" => $claimedId);
140
                    "claimed_id" => $claimedId);
138
            } else {
141
            } else {
139
                require_once "Zend/Session/Namespace.php";
142
                require_once "Zend/Session/Namespace.php";
140
                $this->_session = new Zend_Session_Namespace("zend_openid");
143
                $this->_session = new Zend_Session_Namespace("zend_openid");
141
                $this->_session->identity = $id;
144
                $this->_session->identity = $id;
142
                $this->_session->claimed_id = $claimedId;
145
                $this->_session->claimed_id = $claimedId;
143
            }
146
            }
144
        }*/
147
        }*/
145
 
148
 
146
        if (isset($handle)) {
149
        if (isset($handle)) {
147
            $params['openid.assoc_handle'] = $handle;
150
            $params['openid.assoc_handle'] = $handle;
148
        }
151
        }
149
 
152
 
150
        //FIXME : $params['openid.return_to'] = $this->absoluteUrl($returnTo);
153
        //FIXME : $params['openid.return_to'] = $this->absoluteUrl($returnTo);
151
        $params['openid.return_to'] = $this->absoluteUrl(null);
154
        $params['openid.return_to'] = $this->absoluteUrl(null);
152
 
155
 
153
        if (empty($root)) {
156
        if (empty($root)) {
154
            $root = $this->selfUrl();
157
            $root = $this->selfUrl();
155
            if ($root[strlen($root)-1] != '/') {
158
            if ($root[strlen($root)-1] != '/') {
156
                $root = dirname($root);
159
                $root = dirname($root);
157
            }
160
            }
158
        }
161
        }
159
        if ($metaServeur['version'] >= 2.0) {
162
        if ($metaServeur['version'] >= 2.0) {
160
            $params['openid.realm'] = $root;
163
            $params['openid.realm'] = $root;
161
        } else {
164
        } else {
162
            $params['openid.trust_root'] = $root;
165
            $params['openid.trust_root'] = $root;
163
        }
166
        }
164
 
167
 
165
        /*FIXME :: 
168
        /*FIXME :: 
166
         
169
         
167
         if (!Zend_OpenId_Extension::forAll($extensions, 'prepareRequest', $params)) {
170
         if (!Zend_OpenId_Extension::forAll($extensions, 'prepareRequest', $params)) {
168
            $this->_setError("Extension::prepareRequest failure");
171
            $this->_setError("Extension::prepareRequest failure");
169
            return false;
172
            return false;
170
        }*/
173
        }*/
171
 
174
 
172
        $this->redirect($metaServeur['serveur'], $params);
175
        $this->redirect($metaServeur['serveur'], $params);
173
        return true;
176
        return true;
174
		//Renvoyer vers l'url
177
		//Renvoyer vers l'url
175
	}
178
	}
176
	
179
	
177
	/**
180
	/**
178
     * Verifies authentication response from OpenID server.
181
     * Verifies authentication response from OpenID server.
179
     *
182
     *
180
     * This is the second step of OpenID authentication process.
183
     * This is the second step of OpenID authentication process.
181
     * The function returns true on successful authentication and false on
184
     * The function returns true on successful authentication and false on
182
     * failure.
185
     * failure.
183
     *
186
     *
184
     * @param array $params HTTP query data from OpenID server
187
     * @param array $params HTTP query data from OpenID server
185
     * @param string &$identity this argument is set to end-user's claimed
188
     * @param string &$identity this argument is set to end-user's claimed
186
     *  identifier or OpenID provider local identifier.
189
     *  identifier or OpenID provider local identifier.
187
     * @param mixed $extensions extension object or array of extensions objects
190
     * @param mixed $extensions extension object or array of extensions objects
188
     * @return bool
191
     * @return bool
189
     */
192
     */
190
    public function verify($params, &$identity = "", $extensions = null)
193
    public function verify($params, &$identity = "", $extensions = null)
191
    {
194
    {
192
    	
195
    	
193
    	echo '<pre>'.print_r($params, true).'</pre>';
196
    	echo '<pre>'.print_r($params, true).'</pre>';
194
    	
197
    	
195
        $version = 1.1;
198
        $version = 1.1;
196
        if (isset($params['openid_ns']) &&
199
        if (isset($params['openid_ns']) &&
197
            $params['openid_ns'] == $this->NS_2_0) {
200
            $params['openid_ns'] == $this->NS_2_0) {
198
            $version = 2.0;
201
            $version = 2.0;
199
        }
202
        }
200
 
203
 
201
        if (isset($params["openid_claimed_id"])) {
204
        if (isset($params["openid_claimed_id"])) {
202
            $identity = $params["openid_claimed_id"];
205
            $identity = $params["openid_claimed_id"];
203
        } else if (isset($params["openid_identity"])){
206
        } else if (isset($params["openid_identity"])){
204
            $identity = $params["openid_identity"];
207
            $identity = $params["openid_identity"];
205
        } else {
208
        } else {
206
            $identity = "";
209
            $identity = "";
207
        }
210
        }
208
 
211
 
209
        if ($version < 2.0 && !isset($params["openid_claimed_id"])) {
212
        if ($version < 2.0 && !isset($params["openid_claimed_id"])) {
210
            if ($this->_session !== null) {
213
            if ($this->_session !== null) {
211
                if ($this->_session->identity === $identity) {
214
                if ($this->_session->identity === $identity) {
212
                    $identity = $this->_session->claimed_id;
215
                    $identity = $this->_session->claimed_id;
213
                }
216
                }
214
            } else if (defined('SID')) {
217
            } else if (defined('SID')) {
215
                if (isset($_SESSION["zend_openid"]["identity"]) &&
218
                if (isset($_SESSION["zend_openid"]["identity"]) &&
216
                    isset($_SESSION["zend_openid"]["claimed_id"]) &&
219
                    isset($_SESSION["zend_openid"]["claimed_id"]) &&
217
                    $_SESSION["zend_openid"]["identity"] === $identity) {
220
                    $_SESSION["zend_openid"]["identity"] === $identity) {
218
                    $identity = $_SESSION["zend_openid"]["claimed_id"];
221
                    $identity = $_SESSION["zend_openid"]["claimed_id"];
219
                }
222
                }
220
            } else {
223
            } else {
221
                require_once "Zend/Session/Namespace.php";
224
                require_once "Zend/Session/Namespace.php";
222
                $this->_session = new Zend_Session_Namespace("zend_openid");
225
                $this->_session = new Zend_Session_Namespace("zend_openid");
223
                if ($this->_session->identity === $identity) {
226
                if ($this->_session->identity === $identity) {
224
                    $identity = $this->_session->claimed_id;
227
                    $identity = $this->_session->claimed_id;
225
                }
228
                }
226
            }
229
            }
227
        }
230
        }
228
 
231
 
229
        if (empty($params['openid_mode'])) {
232
        if (empty($params['openid_mode'])) {
230
            $this->_setError("Missing openid.mode");
233
            $this->_setError("Missing openid.mode");
231
            return false;
234
            return false;
232
        }
235
        }
233
        if (empty($params['openid_return_to'])) {
236
        if (empty($params['openid_return_to'])) {
234
            $this->_setError("Missing openid.return_to");
237
            $this->_setError("Missing openid.return_to");
235
            return false;
238
            return false;
236
        }
239
        }
237
        if (empty($params['openid_signed'])) {
240
        if (empty($params['openid_signed'])) {
238
            $this->_setError("Missing openid.signed");
241
            $this->_setError("Missing openid.signed");
239
            return false;
242
            return false;
240
        }
243
        }
241
        if (empty($params['openid_sig'])) {
244
        if (empty($params['openid_sig'])) {
242
            $this->_setError("Missing openid.sig");
245
            $this->_setError("Missing openid.sig");
243
            return false;
246
            return false;
244
        }
247
        }
245
        if ($params['openid_mode'] != 'id_res') {
248
        if ($params['openid_mode'] != 'id_res') {
246
            $this->_setError("Wrong openid.mode '".$params['openid_mode']."' != 'id_res'");
249
            $this->_setError("Wrong openid.mode '".$params['openid_mode']."' != 'id_res'");
247
            return false;
250
            return false;
248
        }
251
        }
249
        if (empty($params['openid_assoc_handle'])) {
252
        if (empty($params['openid_assoc_handle'])) {
250
            $this->_setError("Missing openid.assoc_handle");
253
            $this->_setError("Missing openid.assoc_handle");
251
            return false;
254
            return false;
252
        }
255
        }
253
        
256
        
254
        if ($params['openid_return_to'] != $this->selfUrl()) {
257
        if ($params['openid_return_to'] != $this->selfUrl()) {
255
            /* Ignore query part in openid.return_to */
258
            /* Ignore query part in openid.return_to */
256
            $pos = strpos($params['openid_return_to'], '?');
259
            $pos = strpos($params['openid_return_to'], '?');
257
            if ($pos === false ||
260
            if ($pos === false ||
258
                SUBSTR($params['openid_return_to'], 0 , $pos) != $this->selfUrl()) {
261
                SUBSTR($params['openid_return_to'], 0 , $pos) != $this->selfUrl()) {
259
 
262
 
260
                /*$this->_setError("Wrong openid.return_to '".
263
                /*$this->_setError("Wrong openid.return_to '".
261
                    $params['openid_return_to']."' != '" . $this->selfUrl() ."'");*/
264
                    $params['openid_return_to']."' != '" . $this->selfUrl() ."'");*/
262
                trigger_error('Wrong openid.return_to', E_USER_ERROR);	
265
                trigger_error('Wrong openid.return_to', E_USER_ERROR);	
263
                	
266
                	
264
                return false;
267
                return false;
265
            }
268
            }
266
        }
269
        }
267
 
270
 
268
        if ($version >= 2.0) {
271
        if ($version >= 2.0) {
269
            if (empty($params['openid_response_nonce'])) {
272
            if (empty($params['openid_response_nonce'])) {
270
                trigger_error('Missing openid.response_nonce', E_USER_ERROR);
273
                trigger_error('Missing openid.response_nonce', E_USER_ERROR);
271
                return false;
274
                return false;
272
            }
275
            }
273
            if (empty($params['openid_op_endpoint'])) {
276
            if (empty($params['openid_op_endpoint'])) {
274
                trigger_error('Missing openid.op_endpoint', E_USER_ERROR);
277
                trigger_error('Missing openid.op_endpoint', E_USER_ERROR);
275
                return false;
278
                return false;
276
            /* OpenID 2.0 (11.3) Checking the Nonce */
279
            /* OpenID 2.0 (11.3) Checking the Nonce */
277
            } else if (!$this->_storage->isUniqueNonce($params['openid_op_endpoint'], $params['openid_response_nonce'])) {
280
            } else if (!$this->_storage->isUniqueNonce($params['openid_op_endpoint'], $params['openid_response_nonce'])) {
278
                trigger_error('Duplicate openid.response_nonce', E_USER_ERROR);
281
                trigger_error('Duplicate openid.response_nonce', E_USER_ERROR);
279
                return false;
282
                return false;
280
            }
283
            }
281
        }
284
        }
282
 
285
 
283
        if (!empty($params['openid_invalidate_handle'])) {
286
        if (!empty($params['openid_invalidate_handle'])) {
284
            if ($this->_storage->getAssociationByHandle(
287
            if ($this->_storage->getAssociationByHandle(
285
                $params['openid_invalidate_handle'],
288
                $params['openid_invalidate_handle'],
286
                $url,
289
                $url,
287
                $macFunc,
290
                $macFunc,
288
                $secret,
291
                $secret,
289
                $expires)) {
292
                $expires)) {
290
                $this->_storage->delAssociation($url);
293
                $this->_storage->delAssociation($url);
291
            }
294
            }
292
        }
295
        }
293
 
296
 
294
        if ($this->_storage->getAssociationByHandle(
297
        if ($this->_storage->getAssociationByHandle(
295
                $params['openid_assoc_handle'],
298
                $params['openid_assoc_handle'],
296
                $url,
299
                $url,
297
                $macFunc,
300
                $macFunc,
298
                $secret,
301
                $secret,
299
                $expires)) {
302
                $expires)) {
300
            $signed = explode(',', $params['openid_signed']);
303
            $signed = explode(',', $params['openid_signed']);
301
            $data = '';
304
            $data = '';
302
            foreach ($signed as $key) {
305
            foreach ($signed as $key) {
303
                $data .= $key . ':' . $params['openid_' . strtr($key,'.','_')] . "\n";
306
                $data .= $key . ':' . $params['openid_' . strtr($key,'.','_')] . "\n";
304
            }
307
            }
305
            if (base64_decode($params['openid_sig']) ==
308
            if (base64_decode($params['openid_sig']) ==
306
                Zend_OpenId::hashHmac($macFunc, $data, $secret)) {
309
                Zend_OpenId::hashHmac($macFunc, $data, $secret)) {
307
                /*
310
                /*
308
                 * FIXME dépendance je sais pas pour quoi : a voir :
311
                 * FIXME dépendance je sais pas pour quoi : a voir :
309
                 * if (!Zend_OpenId_Extension::forAll($extensions, 'parseResponse', $params)) {
312
                 * if (!Zend_OpenId_Extension::forAll($extensions, 'parseResponse', $params)) {
310
                    $this->_setError("Extension::parseResponse failure");
313
                    $this->_setError("Extension::parseResponse failure");
311
                    return false;
314
                    return false;
312
                }*/
315
                }*/
313
                /* OpenID 2.0 (11.2) Verifying Discovered Information */
316
                /* OpenID 2.0 (11.2) Verifying Discovered Information */
314
                if (isset($params['openid_claimed_id'])) {
317
                if (isset($params['openid_claimed_id'])) {
315
                    $id = $params['openid_claimed_id'];
318
                    $id = $params['openid_claimed_id'];
316
                    if (!$this->normalize($id)) {
319
                    if (!$this->normalize($id)) {
317
                        $this->_setError("Normalization failed");
320
                        $this->_setError("Normalization failed");
318
                        return false;
321
                        return false;
319
                    } else if (!$this->_discovery($id, $discovered_server, $discovered_version)) {
322
                    } else if (!$this->_discovery($id, $discovered_server, $discovered_version)) {
320
                        $this->_setError("Discovery failed: " . $this->getError());
323
                        $this->_setError("Discovery failed: " . $this->getError());
321
                        return false;
324
                        return false;
322
                    } else if ((!empty($params['openid_identity']) &&
325
                    } else if ((!empty($params['openid_identity']) &&
323
                                $params["openid_identity"] != $id) ||
326
                                $params["openid_identity"] != $id) ||
324
                               (!empty($params['openid_op_endpoint']) &&
327
                               (!empty($params['openid_op_endpoint']) &&
325
                                $params['openid_op_endpoint'] != $discovered_server) ||
328
                                $params['openid_op_endpoint'] != $discovered_server) ||
326
                               $discovered_version != $version) {
329
                               $discovered_version != $version) {
327
                        $this->_setError("Discovery information verification failed");
330
                        $this->_setError("Discovery information verification failed");
328
                        return false;
331
                        return false;
329
                    }
332
                    }
330
                }
333
                }
331
                return true;
334
                return true;
332
            }
335
            }
333
            $this->_storage->delAssociation($url);
336
            $this->_storage->delAssociation($url);
334
            $this->_setError("Signature check failed");
337
            $this->_setError("Signature check failed");
335
            return false;
338
            return false;
336
        }
339
        }
337
        else
340
        else
338
        {
341
        {
339
            /* Use dumb mode */
342
            /* Use dumb mode */
340
            if (isset($params['openid_claimed_id'])) {
343
            if (isset($params['openid_claimed_id'])) {
341
                $id = $params['openid_claimed_id'];
344
                $id = $params['openid_claimed_id'];
342
            } else if (isset($params['openid_identity'])) {
345
            } else if (isset($params['openid_identity'])) {
343
                $id = $params['openid_identity'];
346
                $id = $params['openid_identity'];
344
            } else {
347
            } else {
345
                $this->_setError("Missing openid.claimed_id and openid.identity");
348
                $this->_setError("Missing openid.claimed_id and openid.identity");
346
                return false;
349
                return false;
347
            }
350
            }
348
 
351
 
349
            if (!$this->normalize($id)) {
352
            if (!$this->normalize($id)) {
350
              	trigger_error('Normalization failed', E_USER_ERROR);
353
              	trigger_error('Normalization failed', E_USER_ERROR);
351
                return false;
354
                return false;
352
            } else if (!$this->_discovery($id, $server, $discovered_version)) {
355
            } else if (!$this->_discovery($id, $server, $discovered_version)) {
353
                trigger_error('Discovery failed', E_USER_ERROR);
356
                trigger_error('Discovery failed', E_USER_ERROR);
354
                return false;
357
                return false;
355
            }
358
            }
356
 
359
 
357
            /* OpenID 2.0 (11.2) Verifying Discovered Information */
360
            /* OpenID 2.0 (11.2) Verifying Discovered Information */
358
            if ((isset($params['openid_identity']) &&
361
            if ((isset($params['openid_identity']) &&
359
                 $params["openid_identity"] != $id) ||
362
                 $params["openid_identity"] != $id) ||
360
                (isset($params['openid_op_endpoint']) &&
363
                (isset($params['openid_op_endpoint']) &&
361
                 $params['openid_op_endpoint'] != $server) ||
364
                 $params['openid_op_endpoint'] != $server) ||
362
                $discovered_version != $version) {
365
                $discovered_version != $version) {
363
                trigger_error('Discovery information verification failed', E_USER_ERROR);
366
                trigger_error('Discovery information verification failed', E_USER_ERROR);
364
                return false;
367
                return false;
365
            }
368
            }
366
 
369
 
367
            $params2 = array();
370
            $params2 = array();
368
            foreach ($params as $key => $val) {
371
            foreach ($params as $key => $val) {
369
                if (strpos($key, 'openid_ns_') === 0) {
372
                if (strpos($key, 'openid_ns_') === 0) {
370
                    $key = 'openid.ns.' . substr($key, strlen('openid_ns_'));
373
                    $key = 'openid.ns.' . substr($key, strlen('openid_ns_'));
371
                } else if (strpos($key, 'openid_sreg_') === 0) {
374
                } else if (strpos($key, 'openid_sreg_') === 0) {
372
                    $key = 'openid.sreg.' . substr($key, strlen('openid_sreg_'));
375
                    $key = 'openid.sreg.' . substr($key, strlen('openid_sreg_'));
373
                } else if (strpos($key, 'openid_') === 0) {
376
                } else if (strpos($key, 'openid_') === 0) {
374
                    $key = 'openid.' . substr($key, strlen('openid_'));
377
                    $key = 'openid.' . substr($key, strlen('openid_'));
375
                }
378
                }
376
                $params2[$key] = $val;
379
                $params2[$key] = $val;
377
            }
380
            }
378
            $params2['openid.mode'] = 'check_authentication';
381
            $params2['openid.mode'] = 'check_authentication';
379
            $ret = $this->client->modifier($serveur, $params2);
382
            $ret = $this->client->modifier($serveur, $params2);
380
            
383
            
381
            //_httpRequest($server, 'POST', $params2, $status);
384
            //_httpRequest($server, 'POST', $params2, $status);
382
            if ($ret === false) {
385
            if ($ret === false) {
383
                trigger_error("'Dumb' signature verification HTTP request failed", E_USER_ERROR);
386
                trigger_error("'Dumb' signature verification HTTP request failed", E_USER_ERROR);
384
                return false;
387
                return false;
385
            }
388
            }
386
            $r = array();
389
            $r = array();
387
            if (is_string($ret)) {
390
            if (is_string($ret)) {
388
                foreach(explode("\n", $ret) as $line) {
391
                foreach(explode("\n", $ret) as $line) {
389
                    $line = trim($line);
392
                    $line = trim($line);
390
                    if (!empty($line)) {
393
                    if (!empty($line)) {
391
                        $x = explode(':', $line, 2);
394
                        $x = explode(':', $line, 2);
392
                        if (is_array($x) && count($x) == 2) {
395
                        if (is_array($x) && count($x) == 2) {
393
                            list($key, $value) = $x;
396
                            list($key, $value) = $x;
394
                            $r[trim($key)] = trim($value);
397
                            $r[trim($key)] = trim($value);
395
                        }
398
                        }
396
                    }
399
                    }
397
                }
400
                }
398
            }
401
            }
399
            $ret = $r;
402
            $ret = $r;
400
            if (!empty($ret['invalidate_handle'])) {
403
            if (!empty($ret['invalidate_handle'])) {
401
                if ($this->_storage->getAssociationByHandle(
404
                if ($this->_storage->getAssociationByHandle(
402
                    $ret['invalidate_handle'],
405
                    $ret['invalidate_handle'],
403
                    $url,
406
                    $url,
404
                    $macFunc,
407
                    $macFunc,
405
                    $secret,
408
                    $secret,
406
                    $expires)) {
409
                    $expires)) {
407
                    $this->_storage->delAssociation($url);
410
                    $this->_storage->delAssociation($url);
408
                }
411
                }
409
            }
412
            }
410
            if (isset($ret['is_valid']) && $ret['is_valid'] == 'true') {
413
            if (isset($ret['is_valid']) && $ret['is_valid'] == 'true') {
411
                if (!Zend_OpenId_Extension::forAll($extensions, 'parseResponse', $params)) {
414
                if (!Zend_OpenId_Extension::forAll($extensions, 'parseResponse', $params)) {
412
                    $this->_setError("Extension::parseResponse failure");
415
                    $this->_setError("Extension::parseResponse failure");
413
                    return false;
416
                    return false;
414
                }
417
                }
415
                return true;
418
                return true;
416
            }
419
            }
417
            $this->_setError("'Dumb' signature verification failed");
420
            $this->_setError("'Dumb' signature verification failed");
418
            return false;
421
            return false;
419
        }
422
        }
420
    }
423
    }
421
	
424
	
422
	
425
	
423
	/**
426
	/**
424
     * Performs discovery of identity and finds OpenID URL, OpenID server URL
427
     * Performs discovery of identity and finds OpenID URL, OpenID server URL
425
     * and OpenID protocol version. Returns true on succees and false on
428
     * and OpenID protocol version. Returns true on succees and false on
426
     * failure.
429
     * failure.
427
     *
430
     *
428
     * @param string &$id OpenID identity URL
431
     * @param string &$id OpenID identity URL
429
     * @param string &$server OpenID server URL
432
     * @param string &$server OpenID server URL
430
     * @param float &$version OpenID protocol version
433
     * @param float &$version OpenID protocol version
431
     * @return bool
434
     * @return bool
432
     * @todo OpenID 2.0 (7.3) XRI and Yadis discovery
435
     * @todo OpenID 2.0 (7.3) XRI and Yadis discovery
433
     */
436
     */
434
    protected function _discovery(&$id, &$server, &$version)
437
    protected function _discovery(&$id, &$server, &$version)
435
    { 
438
    { 
436
        $realId = $id;
439
        $realId = $id;
437
        if ($this->_storage->getDiscoveryInfo(
440
        if ($this->_storage->getDiscoveryInfo(
438
                $id,
441
                $id,
439
                $realId,
442
                $realId,
440
                $server,
443
                $server,
441
                $version,
444
                $version,
442
                $expire)) {
445
                $expire)) {
443
            $id = $realId;
446
            $id = $realId;
444
            return true;
447
            return true;
445
        }
448
        }
446
	
449
	
447
        /* TODO: OpenID 2.0 (7.3) XRI and Yadis discovery */
450
        /* TODO: OpenID 2.0 (7.3) XRI and Yadis discovery */
448
 
451
 
449
        /* HTML-based discovery */
452
        /* HTML-based discovery */
450
        $clientDiscovery = new Client();
453
        $clientDiscovery = new Client();
451
               
454
               
452
        //TODO : rajouter un test sur le statut de la réponse
455
        //TODO : rajouter un test sur le statut de la réponse
453
        // Nécessite la prise en compte des entetes dans le framework
456
        // Nécessite la prise en compte des entetes dans le framework
454
        
457
        
455
        /*if ($status != 200 || !is_string($response)) {
458
        /*if ($status != 200 || !is_string($response)) {
456
            return false;
459
            return false;
457
        }*/
460
        }*/
458
        $reponse = $clientDiscovery->consulter($id);
461
        $reponse = $clientDiscovery->consulter($id);
459
        $metaServeur = $this->verifierVersion($reponse);
462
        $metaServeur = $this->verifierVersion($reponse);
460
        if (!isset($metaServeur) || empty($reponse))	{
463
        if (!isset($metaServeur) || empty($reponse))	{
461
        	trigger_error('Aucune donnée OpenId', E_USER_ERROR);
464
        	trigger_error('Aucune donnée OpenId', E_USER_ERROR);
462
        	return false;
465
        	return false;
463
        }
466
        }
464
        
467
        
465
        $expire = time() + 60 * 60;
468
        $expire = time() + 60 * 60;
466
        $this->_storage->addDiscoveryInfo($id, $metaServeur['realId'], $metaServeur['serveur'], $metaServeur['version'], $expire);
469
        $this->_storage->addDiscoveryInfo($id, $metaServeur['realId'], $metaServeur['serveur'], $metaServeur['version'], $expire);
467
        if (!empty($metaServeur['realId'])) {
470
        if (!empty($metaServeur['realId'])) {
468
        	$id = $metaServeur['realId'];
471
        	$id = $metaServeur['realId'];
469
        }
472
        }
470
        return true;
473
        return true;
471
    }
474
    }
472
	
475
	
473
	
476
	
474
	
477
	
475
	
478
	
476
	//Parser l'HTML de réponse pour trouver la version du serveur OPEN ID
479
	//Parser l'HTML de réponse pour trouver la version du serveur OPEN ID
477
	function verifierVersion($reponseHtml)	{
480
	function verifierVersion($reponseHtml)	{
478
		
481
		
479
		// TODO : remplacer l'arlgorythme suivant par cette solution : 
482
		// TODO : remplacer l'arlgorythme suivant par cette solution : 
480
		//1. Chercher l'existence d'une balise openidN.provider 
483
		//1. Chercher l'existence d'une balise openidN.provider 
481
		//2. Déterminer la version en fonction de la chaine : openid2.provider => 2.0; openid.provider => 1.1
484
		//2. Déterminer la version en fonction de la chaine : openid2.provider => 2.0; openid.provider => 1.1
482
		//3. Récupérer l'url du serveur href="serveur"
485
		//3. Récupérer l'url du serveur href="serveur"
483
		//4. SI 2.0, récupérer la valeur réelle de l'ID
486
		//4. SI 2.0, récupérer la valeur réelle de l'ID
484
		
487
		
485
		//TODO : penser à tester les deux versions du serveur
488
		//TODO : penser à tester les deux versions du serveur
486
		
489
		
487
		$metaServeur = Array();
490
		$metaServeur = Array();
488
		
491
		
489
		if (preg_match(
492
		if (preg_match(
490
                '/<link[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid2.provider[ \t]*[^"\']*\\1[^>]*href=(["\'])([^"\']+)\\2[^>]*\/?>/i',
493
                '/<link[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid2.provider[ \t]*[^"\']*\\1[^>]*href=(["\'])([^"\']+)\\2[^>]*\/?>/i',
491
                $reponseHtml,
494
                $reponseHtml,
492
                $r)) {
495
                $r)) {
493
            $metaServeur['version'] = 2.0;
496
            $metaServeur['version'] = 2.0;
494
            $metaServeur['serveur'] = $r[3];
497
            $metaServeur['serveur'] = $r[3];
495
        } else if (preg_match(
498
        } else if (preg_match(
496
                '/<link[^>]*href=(["\'])([^"\']+)\\1[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid2.provider[ \t]*[^"\']*\\3[^>]*\/?>/i',
499
                '/<link[^>]*href=(["\'])([^"\']+)\\1[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid2.provider[ \t]*[^"\']*\\3[^>]*\/?>/i',
497
                $reponseHtml,
500
                $reponseHtml,
498
                $r)) {
501
                $r)) {
499
            $metaServeur['version'] = 2.0;
502
            $metaServeur['version'] = 2.0;
500
            $metaServeur['serveur'] = $r[1];
503
            $metaServeur['serveur'] = $r[1];
501
        } else if (preg_match(
504
        } else if (preg_match(
502
                '/<link[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid.server[ \t]*[^"\']*\\1[^>]*href=(["\'])([^"\']+)\\2[^>]*\/?>/i',
505
                '/<link[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid.server[ \t]*[^"\']*\\1[^>]*href=(["\'])([^"\']+)\\2[^>]*\/?>/i',
503
                $reponseHtml,
506
                $reponseHtml,
504
                $r)) {
507
                $r)) {
505
            $metaServeur['version'] = 1.1;
508
            $metaServeur['version'] = 1.1;
506
            $metaServeur['serveur'] = $r[3];
509
            $metaServeur['serveur'] = $r[3];
507
        } else if (preg_match(
510
        } else if (preg_match(
508
                '/<link[^>]*href=(["\'])([^"\']+)\\1[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid.server[ \t]*[^"\']*\\3[^>]*\/?>/i',
511
                '/<link[^>]*href=(["\'])([^"\']+)\\1[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid.server[ \t]*[^"\']*\\3[^>]*\/?>/i',
509
                $reponseHtml,
512
                $reponseHtml,
510
                $r)) {
513
                $r)) {
511
            $metaServeur['version'] = 1.1;
514
            $metaServeur['version'] = 1.1;
512
            $metaServeur['serveur'] = $r[2];
515
            $metaServeur['serveur'] = $r[2];
513
        } else {
516
        } else {
514
            return false;
517
            return false;
515
        }
518
        }
516
        
519
        
517
        if ($metaServeur['version'] >= 2.0) {
520
        if ($metaServeur['version'] >= 2.0) {
518
            if (preg_match(
521
            if (preg_match(
519
                    '/<link[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid2.local_id[ \t]*[^"\']*\\1[^>]*href=(["\'])([^"\']+)\\2[^>]*\/?>/i',
522
                    '/<link[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid2.local_id[ \t]*[^"\']*\\1[^>]*href=(["\'])([^"\']+)\\2[^>]*\/?>/i',
520
                    $reponseHtml,
523
                    $reponseHtml,
521
                    $r)) {
524
                    $r)) {
522
                $metaServeur['realId'] = $r[3];
525
                $metaServeur['realId'] = $r[3];
523
            } else if (preg_match(
526
            } else if (preg_match(
524
                    '/<link[^>]*href=(["\'])([^"\']+)\\1[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid2.local_id[ \t]*[^"\']*\\3[^>]*\/?>/i',
527
                    '/<link[^>]*href=(["\'])([^"\']+)\\1[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid2.local_id[ \t]*[^"\']*\\3[^>]*\/?>/i',
525
                    $reponseHtml,
528
                    $reponseHtml,
526
                    $r)) {
529
                    $r)) {
527
                $metaServeur['realId'] = $r[2];
530
                $metaServeur['realId'] = $r[2];
528
            }
531
            }
529
        } else {
532
        } else {
530
            if (preg_match(
533
            if (preg_match(
531
                    '/<link[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid.delegate[ \t]*[^"\']*\\1[^>]*href=(["\'])([^"\']+)\\2[^>]*\/?>/i',
534
                    '/<link[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid.delegate[ \t]*[^"\']*\\1[^>]*href=(["\'])([^"\']+)\\2[^>]*\/?>/i',
532
                    $reponseHtml,
535
                    $reponseHtml,
533
                    $r)) {
536
                    $r)) {
534
                $metaServeur['realId'] = $r[3];
537
                $metaServeur['realId'] = $r[3];
535
            } else if (preg_match(
538
            } else if (preg_match(
536
                    '/<link[^>]*href=(["\'])([^"\']+)\\1[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid.delegate[ \t]*[^"\']*\\3[^>]*\/?>/i',
539
                    '/<link[^>]*href=(["\'])([^"\']+)\\1[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid.delegate[ \t]*[^"\']*\\3[^>]*\/?>/i',
537
                    $reponseHtml,
540
                    $reponseHtml,
538
                    $r)) {
541
                    $r)) {
539
                $metaServeur['realId'] = $r[2];
542
                $metaServeur['realId'] = $r[2];
540
            }
543
            }
541
        }
544
        }
542
		
545
		
543
        return $metaServeur;
546
        return $metaServeur;
544
	}
547
	}
545
	
548
	
546
	/**
549
	/**
547
     * Create (or reuse existing) association between OpenID consumer and
550
     * Create (or reuse existing) association between OpenID consumer and
548
     * OpenID server based on Diffie-Hellman key agreement. Returns true
551
     * OpenID server based on Diffie-Hellman key agreement. Returns true
549
     * on success and false on failure.
552
     * on success and false on failure.
550
     *
553
     *
551
     * @param string $url OpenID server url
554
     * @param string $url OpenID server url
552
     * @param float $version OpenID protocol version
555
     * @param float $version OpenID protocol version
553
     * @param string $priv_key for testing only
556
     * @param string $priv_key for testing only
554
     * @return bool
557
     * @return bool
555
     */
558
     */
556
    protected function _associate($url, $version, $priv_key=null)
559
    protected function _associate($url, $version, $priv_key=null)
557
    {
560
    {
558
        /* Check if we already have association in chace or storage */
561
        /* Check if we already have association in chace or storage */
559
       /* 
562
       /* 
560
        * TODO : Utiliser le stockage plutot
563
        * TODO : Utiliser le stockage plutot
561
        * */
564
        * */
562
        if ($this->_getAssociation(
565
        if ($this->_getAssociation(
563
                $url,
566
                $url,
564
                $handle,
567
                $handle,
565
                $macFunc,
568
                $macFunc,
566
                $secret,
569
                $secret,
567
                $expires)) {
570
                $expires)) {
568
            return true;
571
            return true;
569
        }
572
        }
570
 
573
 
571
       /*
574
       /*
572
        * TODO : utiliser le fichier de config
575
        * TODO : utiliser le fichier de config
573
        * if ($this->_dumbMode) {
576
        * if ($this->_dumbMode) {
574
	       return true;
577
	       return true;
575
       }*/
578
       }*/
576
 
579
 
577
        $params = array();
580
        $params = array();
578
 
581
 
579
        if ($version >= 2.0) {
582
        if ($version >= 2.0) {
580
            $params = array(
583
            $params = array(
581
                'openid.ns'           => $this->NS_2_0,
584
                'openid.ns'           => $this->NS_2_0,
582
                'openid.mode'         => 'associate',
585
                'openid.mode'         => 'associate',
583
                'openid.assoc_type'   => 'HMAC-SHA256',
586
                'openid.assoc_type'   => 'HMAC-SHA256',
584
                'openid.session_type' => 'DH-SHA256',
587
                'openid.session_type' => 'DH-SHA256',
585
            );
588
            );
586
        } else {
589
        } else {
587
            $params = array(
590
            $params = array(
588
                'openid.mode'         => 'associate',
591
                'openid.mode'         => 'associate',
589
                'openid.assoc_type'   => 'HMAC-SHA1',
592
                'openid.assoc_type'   => 'HMAC-SHA1',
590
                'openid.session_type' => 'DH-SHA1',
593
                'openid.session_type' => 'DH-SHA1',
591
            );
594
            );
592
        }
595
        }
593
 
596
 
594
        $dh = DiffieHellmanUtil::createDhKey(pack('H*', DiffieHellmanUtil::DH_P),
597
        $dh = DiffieHellmanUtil::createDhKey(pack('H*', DiffieHellmanUtil::DH_P),
595
                                       pack('H*', DiffieHellmanUtil::DH_G),
598
                                       pack('H*', DiffieHellmanUtil::DH_G),
596
                                       $priv_key);
599
                                       $priv_key);
597
        $dh_details = DiffieHellmanUtil::getDhKeyDetails($dh);
600
        $dh_details = DiffieHellmanUtil::getDhKeyDetails($dh);
598
 
601
 
599
        $params['openid.dh_modulus']         = base64_encode(
602
        $params['openid.dh_modulus']         = base64_encode(
600
            DiffieHellmanUtil::btwoc($dh_details['p']));
603
            DiffieHellmanUtil::btwoc($dh_details['p']));
601
        $params['openid.dh_gen']             = base64_encode(
604
        $params['openid.dh_gen']             = base64_encode(
602
            DiffieHellmanUtil::btwoc($dh_details['g']));
605
            DiffieHellmanUtil::btwoc($dh_details['g']));
603
        $params['openid.dh_consumer_public'] = base64_encode(
606
        $params['openid.dh_consumer_public'] = base64_encode(
604
            DiffieHellmanUtil::btwoc($dh_details['pub_key']));
607
            DiffieHellmanUtil::btwoc($dh_details['pub_key']));
605
 
608
 
606
        while(1) {
609
        while(1) {
607
        	//FIXME : c'est pas une modification ...
610
        	//FIXME : c'est pas une modification ...
608
            $ret = $this->client->modifier($url, $params); // FIXME : a quoi sert status ?, $status);
611
            $ret = $this->client->modifier($url, $params); // FIXME : a quoi sert status ?, $status);
609
            if ($ret === false) {
612
            if ($ret === false) {
610
                //$this->_setError("HTTP request failed");
613
                //$this->_setError("HTTP request failed");
611
                trigger_error('La requête a échoué', E_USER_ERROR);
614
                trigger_error('La requête a échoué', E_USER_ERROR);
612
                return false;
615
                return false;
613
            }
616
            }
614
 
617
 
615
            $r = array();
618
            $r = array();
616
            $bad_response = false;
619
            $bad_response = false;
617
            foreach(explode("\n", $ret) as $line) {
620
            foreach(explode("\n", $ret) as $line) {
618
                $line = trim($line);
621
                $line = trim($line);
619
                if (!empty($line)) {
622
                if (!empty($line)) {
620
                    $x = explode(':', $line, 2);
623
                    $x = explode(':', $line, 2);
621
                    if (is_array($x) && count($x) == 2) {
624
                    if (is_array($x) && count($x) == 2) {
622
                        list($key, $value) = $x;
625
                        list($key, $value) = $x;
623
                        $r[trim($key)] = trim($value);
626
                        $r[trim($key)] = trim($value);
624
                    } else {
627
                    } else {
625
                        $bad_response = true;
628
                        $bad_response = true;
626
                    }
629
                    }
627
                }
630
                }
628
            }
631
            }
629
            if ($bad_response && strpos($ret, 'Unknown session type') !== false) {
632
            if ($bad_response && strpos($ret, 'Unknown session type') !== false) {
630
                $r['error_code'] = 'unsupported-type';
633
                $r['error_code'] = 'unsupported-type';
631
            }
634
            }
632
            $ret = $r;
635
            $ret = $r;
633
 
636
 
634
            if (isset($ret['error_code']) &&
637
            if (isset($ret['error_code']) &&
635
                $ret['error_code'] == 'unsupported-type') {
638
                $ret['error_code'] == 'unsupported-type') {
636
                if ($params['openid.session_type'] == 'DH-SHA256') {
639
                if ($params['openid.session_type'] == 'DH-SHA256') {
637
                    $params['openid.session_type'] = 'DH-SHA1';
640
                    $params['openid.session_type'] = 'DH-SHA1';
638
                    $params['openid.assoc_type'] = 'HMAC-SHA1';
641
                    $params['openid.assoc_type'] = 'HMAC-SHA1';
639
                } else if ($params['openid.session_type'] == 'DH-SHA1') {
642
                } else if ($params['openid.session_type'] == 'DH-SHA1') {
640
                    $params['openid.session_type'] = 'no-encryption';
643
                    $params['openid.session_type'] = 'no-encryption';
641
                } else {
644
                } else {
642
                    trigger_error("The OpenID service responded with: " . $ret['error_code'], E_USER_ERROR);
645
                    trigger_error("The OpenID service responded with: " . $ret['error_code'], E_USER_ERROR);
643
                    return false;
646
                    return false;
644
                }
647
                }
645
            } else {
648
            } else {
646
                break;
649
                break;
647
            }
650
            }
648
        }
651
        }
649
 
652
 
650
        /*
653
        /*
651
        FIXME : gestion du statut avec la classe client ??
654
        FIXME : gestion du statut avec la classe client ??
652
        if ($status != 200) {
655
        if ($status != 200) {
653
            $this->_setError("The server responded with status code: " . $status);
656
            $this->_setError("The server responded with status code: " . $status);
654
            return false;
657
            return false;
655
        }*/
658
        }*/
656
 
659
 
657
        if ($version >= 2.0 &&
660
        if ($version >= 2.0 &&
658
            isset($ret['ns']) &&
661
            isset($ret['ns']) &&
659
            $ret['ns'] != $this->NS_2_0) {
662
            $ret['ns'] != $this->NS_2_0) {
660
            $this->_setError("Wrong namespace definition in the server response");
663
            $this->_setError("Wrong namespace definition in the server response");
661
            return false;
664
            return false;
662
        }
665
        }
663
 
666
 
664
        if (!isset($ret['assoc_handle']) ||
667
        if (!isset($ret['assoc_handle']) ||
665
            !isset($ret['expires_in']) ||
668
            !isset($ret['expires_in']) ||
666
            !isset($ret['assoc_type']) ||
669
            !isset($ret['assoc_type']) ||
667
            $params['openid.assoc_type'] != $ret['assoc_type']) {
670
            $params['openid.assoc_type'] != $ret['assoc_type']) {
668
            if ($params['openid.assoc_type'] != $ret['assoc_type']) {
671
            if ($params['openid.assoc_type'] != $ret['assoc_type']) {
669
                $this->_setError("The returned assoc_type differed from the supplied openid.assoc_type");
672
                $this->_setError("The returned assoc_type differed from the supplied openid.assoc_type");
670
            } else {
673
            } else {
671
                $this->_setError("Missing required data from provider (assoc_handle, expires_in, assoc_type are required)");
674
                $this->_setError("Missing required data from provider (assoc_handle, expires_in, assoc_type are required)");
672
            }
675
            }
673
            return false;
676
            return false;
674
        }
677
        }
675
 
678
 
676
        $handle     = $ret['assoc_handle'];
679
        $handle     = $ret['assoc_handle'];
677
        $expiresIn = $ret['expires_in'];
680
        $expiresIn = $ret['expires_in'];
678
 
681
 
679
        if ($ret['assoc_type'] == 'HMAC-SHA1') {
682
        if ($ret['assoc_type'] == 'HMAC-SHA1') {
680
            $macFunc = 'sha1';
683
            $macFunc = 'sha1';
681
        } else if ($ret['assoc_type'] == 'HMAC-SHA256' &&
684
        } else if ($ret['assoc_type'] == 'HMAC-SHA256' &&
682
            $version >= 2.0) {
685
            $version >= 2.0) {
683
            $macFunc = 'sha256';
686
            $macFunc = 'sha256';
684
        } else {
687
        } else {
685
            $this->_setError("Unsupported assoc_type");
688
            $this->_setError("Unsupported assoc_type");
686
            return false;
689
            return false;
687
        }
690
        }
688
 
691
 
689
        if ((empty($ret['session_type']) ||
692
        if ((empty($ret['session_type']) ||
690
             ($version >= 2.0 && $ret['session_type'] == 'no-encryption')) &&
693
             ($version >= 2.0 && $ret['session_type'] == 'no-encryption')) &&
691
             isset($ret['mac_key'])) {
694
             isset($ret['mac_key'])) {
692
            $secret = base64_decode($ret['mac_key']);
695
            $secret = base64_decode($ret['mac_key']);
693
        } else if (isset($ret['session_type']) &&
696
        } else if (isset($ret['session_type']) &&
694
            $ret['session_type'] == 'DH-SHA1' &&
697
            $ret['session_type'] == 'DH-SHA1' &&
695
            !empty($ret['dh_server_public']) &&
698
            !empty($ret['dh_server_public']) &&
696
            !empty($ret['enc_mac_key'])) {
699
            !empty($ret['enc_mac_key'])) {
697
            $dhFunc = 'sha1';
700
            $dhFunc = 'sha1';
698
        } else if (isset($ret['session_type']) &&
701
        } else if (isset($ret['session_type']) &&
699
            $ret['session_type'] == 'DH-SHA256' &&
702
            $ret['session_type'] == 'DH-SHA256' &&
700
            $version >= 2.0 &&
703
            $version >= 2.0 &&
701
            !empty($ret['dh_server_public']) &&
704
            !empty($ret['dh_server_public']) &&
702
            !empty($ret['enc_mac_key'])) {
705
            !empty($ret['enc_mac_key'])) {
703
            $dhFunc = 'sha256';
706
            $dhFunc = 'sha256';
704
        } else {
707
        } else {
705
            $this->_setError("Unsupported session_type");
708
            $this->_setError("Unsupported session_type");
706
            return false;
709
            return false;
707
        }
710
        }
708
        if (isset($dhFunc)) {
711
        if (isset($dhFunc)) {
709
            $serverPub = base64_decode($ret['dh_server_public']);
712
            $serverPub = base64_decode($ret['dh_server_public']);
710
            $dhSec = DiffieHellmanUtil::computeDhSecret($serverPub, $dh);
713
            $dhSec = DiffieHellmanUtil::computeDhSecret($serverPub, $dh);
711
            if ($dhSec === false) {
714
            if ($dhSec === false) {
712
                $this->_setError("DH secret comutation failed");
715
                $this->_setError("DH secret comutation failed");
713
                return false;
716
                return false;
714
            }
717
            }
715
            $sec = $this->digest($dhFunc, $dhSec);
718
            $sec = $this->digest($dhFunc, $dhSec);
716
            if ($sec === false) {
719
            if ($sec === false) {
717
                $this->_setError("Could not create digest");
720
                $this->_setError("Could not create digest");
718
                return false;
721
                return false;
719
            }
722
            }
720
            $secret = $sec ^ base64_decode($ret['enc_mac_key']);
723
            $secret = $sec ^ base64_decode($ret['enc_mac_key']);
721
        }
724
        }
722
        if ($macFunc == 'sha1') {
725
        if ($macFunc == 'sha1') {
723
            if (DiffieHellmanUtil::strlen($secret) != 20) {
726
            if (DiffieHellmanUtil::strlen($secret) != 20) {
724
                $this->_setError("The length of the sha1 secret must be 20");
727
                $this->_setError("The length of the sha1 secret must be 20");
725
                return false;
728
                return false;
726
            }
729
            }
727
        } else if ($macFunc == 'sha256') {
730
        } else if ($macFunc == 'sha256') {
728
            if (DiffieHellmanUtil::strlen($secret) != 32) {
731
            if (DiffieHellmanUtil::strlen($secret) != 32) {
729
                $this->_setError("The length of the sha256 secret must be 32");
732
                $this->_setError("The length of the sha256 secret must be 32");
730
                return false;
733
                return false;
731
            }
734
            }
732
        }
735
        }
733
        
736
        
734
        $this->_addAssociation(
737
        $this->_addAssociation(
735
            $url,
738
            $url,
736
            $handle,
739
            $handle,
737
            $macFunc,
740
            $macFunc,
738
            $secret,
741
            $secret,
739
            time() + $expiresIn);
742
            time() + $expiresIn);
740
       /* $this->association['url'] = $url;
743
       /* $this->association['url'] = $url;
741
        $this->association['handle'] = $handle;
744
        $this->association['handle'] = $handle;
742
        $this->association['macFunc'] = $macFunc;
745
        $this->association['macFunc'] = $macFunc;
743
        $this->association['secret'] = $secret;
746
        $this->association['secret'] = $secret;
744
        $this->association['expiresIn'] = time() + $expiresIn;*/
747
        $this->association['expiresIn'] = time() + $expiresIn;*/
745
        
748
        
746
        return true;
749
        return true;
747
    }
750
    }
748
    
751
    
749
	/**
752
	/**
750
     * Store assiciation in internal chace and external storage
753
     * Store assiciation in internal chace and external storage
751
     *
754
     *
752
     * @param string $url OpenID server url
755
     * @param string $url OpenID server url
753
     * @param string $handle association handle
756
     * @param string $handle association handle
754
     * @param string $macFunc HMAC function (sha1 or sha256)
757
     * @param string $macFunc HMAC function (sha1 or sha256)
755
     * @param string $secret shared secret
758
     * @param string $secret shared secret
756
     * @param integer $expires expiration UNIX time
759
     * @param integer $expires expiration UNIX time
757
     * @return void
760
     * @return void
758
     */
761
     */
759
    protected function _addAssociation($url, $handle, $macFunc, $secret, $expires)
762
    protected function _addAssociation($url, $handle, $macFunc, $secret, $expires)
760
    {
763
    {
761
        $this->_cache[$url] = array($handle, $macFunc, $secret, $expires);
764
        $this->_cache[$url] = array($handle, $macFunc, $secret, $expires);
762
        return $this->_storage->addAssociation(
765
        return $this->_storage->addAssociation(
763
            $url,
766
            $url,
764
            $handle,
767
            $handle,
765
            $macFunc,
768
            $macFunc,
766
            $secret,
769
            $secret,
767
            $expires);
770
            $expires);
768
    }
771
    }
769
    
772
    
770
	/**
773
	/**
771
     * Retrive assiciation information for given $url from internal cahce or
774
     * Retrive assiciation information for given $url from internal cahce or
772
     * external storage
775
     * external storage
773
     *
776
     *
774
     * @param string $url OpenID server url
777
     * @param string $url OpenID server url
775
     * @param string &$handle association handle
778
     * @param string &$handle association handle
776
     * @param string &$macFunc HMAC function (sha1 or sha256)
779
     * @param string &$macFunc HMAC function (sha1 or sha256)
777
     * @param string &$secret shared secret
780
     * @param string &$secret shared secret
778
     * @param integer &$expires expiration UNIX time
781
     * @param integer &$expires expiration UNIX time
779
     * @return void
782
     * @return void
780
     */
783
     */
781
    protected function _getAssociation($url, &$handle, &$macFunc, &$secret, &$expires)
784
    protected function _getAssociation($url, &$handle, &$macFunc, &$secret, &$expires)
782
    {
785
    {
783
        if (isset($this->_cache[$url])) {
786
        if (isset($this->_cache[$url])) {
784
            $handle   = $this->_cache[$url][0];
787
            $handle   = $this->_cache[$url][0];
785
            $macFunc = $this->_cache[$url][1];
788
            $macFunc = $this->_cache[$url][1];
786
            $secret   = $this->_cache[$url][2];
789
            $secret   = $this->_cache[$url][2];
787
            $expires  = $this->_cache[$url][3];
790
            $expires  = $this->_cache[$url][3];
788
            return true;
791
            return true;
789
        }
792
        }
790
        if ($this->_storage->getAssociation(
793
        if ($this->_storage->getAssociation(
791
                $url,
794
                $url,
792
                $handle,
795
                $handle,
793
                $macFunc,
796
                $macFunc,
794
                $secret,
797
                $secret,
795
                $expires)) {
798
                $expires)) {
796
            $this->_cache[$url] = array($handle, $macFunc, $secret, $expires);
799
            $this->_cache[$url] = array($handle, $macFunc, $secret, $expires);
797
            return true;
800
            return true;
798
        }
801
        }
799
        return false;
802
        return false;
800
    }
803
    }
801
    
804
    
802
	/**
805
	/**
803
     * Normalizes URL according to RFC 3986 to use it in comparison operations.
806
     * Normalizes URL according to RFC 3986 to use it in comparison operations.
804
     * The function gets URL argument by reference and modifies it.
807
     * The function gets URL argument by reference and modifies it.
805
     * It returns true on success and false of failure.
808
     * It returns true on success and false of failure.
806
     *
809
     *
807
     * @param string &$id url to be normalized
810
     * @param string &$id url to be normalized
808
     * @return bool
811
     * @return bool
809
     */
812
     */
810
    static public function normalizeUrl(&$id)
813
    static public function normalizeUrl(&$id)
811
    {
814
    {
812
        // RFC 3986, 6.2.2.  Syntax-Based Normalization
815
        // RFC 3986, 6.2.2.  Syntax-Based Normalization
813
 
816
 
814
        // RFC 3986, 6.2.2.2 Percent-Encoding Normalization
817
        // RFC 3986, 6.2.2.2 Percent-Encoding Normalization
815
        $i = 0;
818
        $i = 0;
816
        $n = strlen($id);
819
        $n = strlen($id);
817
        $res = '';
820
        $res = '';
818
        while ($i < $n) {
821
        while ($i < $n) {
819
            if ($id[$i] == '%') {
822
            if ($id[$i] == '%') {
820
                if ($i + 2 >= $n) {
823
                if ($i + 2 >= $n) {
821
                    return false;
824
                    return false;
822
                }
825
                }
823
                ++$i;
826
                ++$i;
824
                if ($id[$i] >= '0' && $id[$i] <= '9') {
827
                if ($id[$i] >= '0' && $id[$i] <= '9') {
825
                    $c = ord($id[$i]) - ord('0');
828
                    $c = ord($id[$i]) - ord('0');
826
                } else if ($id[$i] >= 'A' && $id[$i] <= 'F') {
829
                } else if ($id[$i] >= 'A' && $id[$i] <= 'F') {
827
                    $c = ord($id[$i]) - ord('A') + 10;
830
                    $c = ord($id[$i]) - ord('A') + 10;
828
                } else if ($id[$i] >= 'a' && $id[$i] <= 'f') {
831
                } else if ($id[$i] >= 'a' && $id[$i] <= 'f') {
829
                    $c = ord($id[$i]) - ord('a') + 10;
832
                    $c = ord($id[$i]) - ord('a') + 10;
830
                } else {
833
                } else {
831
                    return false;
834
                    return false;
832
                }
835
                }
833
                ++$i;
836
                ++$i;
834
                if ($id[$i] >= '0' && $id[$i] <= '9') {
837
                if ($id[$i] >= '0' && $id[$i] <= '9') {
835
                    $c = ($c << 4) | (ord($id[$i]) - ord('0'));
838
                    $c = ($c << 4) | (ord($id[$i]) - ord('0'));
836
                } else if ($id[$i] >= 'A' && $id[$i] <= 'F') {
839
                } else if ($id[$i] >= 'A' && $id[$i] <= 'F') {
837
                    $c = ($c << 4) | (ord($id[$i]) - ord('A') + 10);
840
                    $c = ($c << 4) | (ord($id[$i]) - ord('A') + 10);
838
                } else if ($id[$i] >= 'a' && $id[$i] <= 'f') {
841
                } else if ($id[$i] >= 'a' && $id[$i] <= 'f') {
839
                    $c = ($c << 4) | (ord($id[$i]) - ord('a') + 10);
842
                    $c = ($c << 4) | (ord($id[$i]) - ord('a') + 10);
840
                } else {
843
                } else {
841
                    return false;
844
                    return false;
842
                }
845
                }
843
                ++$i;
846
                ++$i;
844
                $ch = chr($c);
847
                $ch = chr($c);
845
                if (($ch >= 'A' && $ch <= 'Z') ||
848
                if (($ch >= 'A' && $ch <= 'Z') ||
846
                    ($ch >= 'a' && $ch <= 'z') ||
849
                    ($ch >= 'a' && $ch <= 'z') ||
847
                    $ch == '-' ||
850
                    $ch == '-' ||
848
                    $ch == '.' ||
851
                    $ch == '.' ||
849
                    $ch == '_' ||
852
                    $ch == '_' ||
850
                    $ch == '~') {
853
                    $ch == '~') {
851
                    $res .= $ch;
854
                    $res .= $ch;
852
                } else {
855
                } else {
853
                    $res .= '%';
856
                    $res .= '%';
854
                    if (($c >> 4) < 10) {
857
                    if (($c >> 4) < 10) {
855
                        $res .= chr(($c >> 4) + ord('0'));
858
                        $res .= chr(($c >> 4) + ord('0'));
856
                    } else {
859
                    } else {
857
                        $res .= chr(($c >> 4) - 10 + ord('A'));
860
                        $res .= chr(($c >> 4) - 10 + ord('A'));
858
                    }
861
                    }
859
                    $c = $c & 0xf;
862
                    $c = $c & 0xf;
860
                    if ($c < 10) {
863
                    if ($c < 10) {
861
                        $res .= chr($c + ord('0'));
864
                        $res .= chr($c + ord('0'));
862
                    } else {
865
                    } else {
863
                        $res .= chr($c - 10 + ord('A'));
866
                        $res .= chr($c - 10 + ord('A'));
864
                    }
867
                    }
865
                }
868
                }
866
            } else {
869
            } else {
867
                $res .= $id[$i++];
870
                $res .= $id[$i++];
868
            }
871
            }
869
        }
872
        }
870
 
873
 
871
        if (!preg_match('|^([^:]+)://([^:@]*(?:[:][^@]*)?@)?([^/:@?#]*)(?:[:]([^/?#]*))?(/[^?#]*)?((?:[?](?:[^#]*))?)((?:#.*)?)$|', $res, $reg)) {
874
        if (!preg_match('|^([^:]+)://([^:@]*(?:[:][^@]*)?@)?([^/:@?#]*)(?:[:]([^/?#]*))?(/[^?#]*)?((?:[?](?:[^#]*))?)((?:#.*)?)$|', $res, $reg)) {
872
            return false;
875
            return false;
873
        }
876
        }
874
        $scheme = $reg[1];
877
        $scheme = $reg[1];
875
        $auth = $reg[2];
878
        $auth = $reg[2];
876
        $host = $reg[3];
879
        $host = $reg[3];
877
        $port = $reg[4];
880
        $port = $reg[4];
878
        $path = $reg[5];
881
        $path = $reg[5];
879
        $query = $reg[6];
882
        $query = $reg[6];
880
        $fragment = $reg[7]; /* strip it */
883
        $fragment = $reg[7]; /* strip it */
881
 
884
 
882
        if (empty($scheme) || empty($host)) {
885
        if (empty($scheme) || empty($host)) {
883
            return false;
886
            return false;
884
        }
887
        }
885
 
888
 
886
        // RFC 3986, 6.2.2.1.  Case Normalization
889
        // RFC 3986, 6.2.2.1.  Case Normalization
887
        $scheme = strtolower($scheme);
890
        $scheme = strtolower($scheme);
888
        $host = strtolower($host);
891
        $host = strtolower($host);
889
 
892
 
890
        // RFC 3986, 6.2.2.3.  Path Segment Normalization
893
        // RFC 3986, 6.2.2.3.  Path Segment Normalization
891
        if (!empty($path)) {
894
        if (!empty($path)) {
892
            $i = 0;
895
            $i = 0;
893
            $n = strlen($path);
896
            $n = strlen($path);
894
            $res = "";
897
            $res = "";
895
            while ($i < $n) {
898
            while ($i < $n) {
896
                if ($path[$i] == '/') {
899
                if ($path[$i] == '/') {
897
                    ++$i;
900
                    ++$i;
898
                    while ($i < $n && $path[$i] == '/') {
901
                    while ($i < $n && $path[$i] == '/') {
899
                        ++$i;
902
                        ++$i;
900
                    }
903
                    }
901
                    if ($i < $n && $path[$i] == '.') {
904
                    if ($i < $n && $path[$i] == '.') {
902
                        ++$i;
905
                        ++$i;
903
                        if ($i < $n && $path[$i] == '.') {
906
                        if ($i < $n && $path[$i] == '.') {
904
                            ++$i;
907
                            ++$i;
905
                            if ($i == $n || $path[$i] == '/') {
908
                            if ($i == $n || $path[$i] == '/') {
906
                                if (($pos = strrpos($res, '/')) !== false) {
909
                                if (($pos = strrpos($res, '/')) !== false) {
907
                                    $res = substr($res, 0, $pos);
910
                                    $res = substr($res, 0, $pos);
908
                                }
911
                                }
909
                            } else {
912
                            } else {
910
                                    $res .= '/..';
913
                                    $res .= '/..';
911
                            }
914
                            }
912
                        } else if ($i != $n && $path[$i] != '/') {
915
                        } else if ($i != $n && $path[$i] != '/') {
913
                            $res .= '/.';
916
                            $res .= '/.';
914
                        }
917
                        }
915
                    } else {
918
                    } else {
916
                        $res .= '/';
919
                        $res .= '/';
917
                    }
920
                    }
918
                } else {
921
                } else {
919
                    $res .= $path[$i++];
922
                    $res .= $path[$i++];
920
                }
923
                }
921
            }
924
            }
922
            $path = $res;
925
            $path = $res;
923
        }
926
        }
924
 
927
 
925
        // RFC 3986,6.2.3.  Scheme-Based Normalization
928
        // RFC 3986,6.2.3.  Scheme-Based Normalization
926
        if ($scheme == 'http') {
929
        if ($scheme == 'http') {
927
            if ($port == 80) {
930
            if ($port == 80) {
928
                $port = '';
931
                $port = '';
929
            }
932
            }
930
        } else if ($scheme == 'https') {
933
        } else if ($scheme == 'https') {
931
            if ($port == 443) {
934
            if ($port == 443) {
932
                $port = '';
935
                $port = '';
933
            }
936
            }
934
        }
937
        }
935
        if (empty($path)) {
938
        if (empty($path)) {
936
            $path = '/';
939
            $path = '/';
937
        }
940
        }
938
 
941
 
939
        $id = $scheme
942
        $id = $scheme
940
            . '://'
943
            . '://'
941
            . $auth
944
            . $auth
942
            . $host
945
            . $host
943
            . (empty($port) ? '' : (':' . $port))
946
            . (empty($port) ? '' : (':' . $port))
944
            . $path
947
            . $path
945
            . $query;
948
            . $query;
946
        return true;
949
        return true;
947
    }
950
    }
948
 
951
 
949
    
952
    
950
    /**
953
    /**
951
     * Normaliser l'identifiant OpenId qui peut être une URL ou nom XRI
954
     * Normaliser l'identifiant OpenId qui peut être une URL ou nom XRI
952
     * Retourne true ou false en cas d'erreur.
955
     * Retourne true ou false en cas d'erreur.
953
     *
956
     *
954
     * Règles de normalisation : 
957
     * Règles de normalisation : 
955
     * 1. If the user's input starts with one of the "xri://", "xri://$ip*",
958
     * 1. If the user's input starts with one of the "xri://", "xri://$ip*",
956
     *    or "xri://$dns*" prefixes, they MUST be stripped off, so that XRIs
959
     *    or "xri://$dns*" prefixes, they MUST be stripped off, so that XRIs
957
     *    are used in the canonical form, and URI-authority XRIs are further
960
     *    are used in the canonical form, and URI-authority XRIs are further
958
     *    considered URL identifiers.
961
     *    considered URL identifiers.
959
     * 2. If the first character of the resulting string is an XRI Global
962
     * 2. If the first character of the resulting string is an XRI Global
960
     *    Context Symbol ("=", "@", "+", "$", "!"), then the input SHOULD be
963
     *    Context Symbol ("=", "@", "+", "$", "!"), then the input SHOULD be
961
     *    treated as an XRI.
964
     *    treated as an XRI.
962
     * 3. Otherwise, the input SHOULD be treated as an http URL; if it does
965
     * 3. Otherwise, the input SHOULD be treated as an http URL; if it does
963
     *    not include a "http" or "https" scheme, the Identifier MUST be
966
     *    not include a "http" or "https" scheme, the Identifier MUST be
964
     *    prefixed with the string "http://".
967
     *    prefixed with the string "http://".
965
     * 4. URL identifiers MUST then be further normalized by both following
968
     * 4. URL identifiers MUST then be further normalized by both following
966
     *    redirects when retrieving their content and finally applying the
969
     *    redirects when retrieving their content and finally applying the
967
     *    rules in Section 6 of [RFC3986] to the final destination URL.
970
     *    rules in Section 6 of [RFC3986] to the final destination URL.
968
     * @param string &$id identifier to be normalized
971
     * @param string &$id identifier to be normalized
969
     * @return bool
972
     * @return bool
970
     */
973
     */
971
    static public function normalize(&$id)
974
    static public function normalize(&$id)
972
    {
975
    {
973
        $id = trim($id);
976
        $id = trim($id);
974
        if (strlen($id) === 0) {
977
        if (strlen($id) === 0) {
975
            return true;
978
            return true;
976
        }
979
        }
977
 
980
 
978
        // 7.2.1
981
        // 7.2.1
979
        if (strpos($id, 'xri://$ip*') === 0) {
982
        if (strpos($id, 'xri://$ip*') === 0) {
980
            $id = substr($id, strlen('xri://$ip*'));
983
            $id = substr($id, strlen('xri://$ip*'));
981
        } else if (strpos($id, 'xri://$dns*') === 0) {
984
        } else if (strpos($id, 'xri://$dns*') === 0) {
982
            $id = substr($id, strlen('xri://$dns*'));
985
            $id = substr($id, strlen('xri://$dns*'));
983
        } else if (strpos($id, 'xri://') === 0) {
986
        } else if (strpos($id, 'xri://') === 0) {
984
            $id = substr($id, strlen('xri://'));
987
            $id = substr($id, strlen('xri://'));
985
        }
988
        }
986
 
989
 
987
        // 7.2.2
990
        // 7.2.2
988
        if ($id[0] == '=' ||
991
        if ($id[0] == '=' ||
989
            $id[0] == '@' ||
992
            $id[0] == '@' ||
990
            $id[0] == '+' ||
993
            $id[0] == '+' ||
991
            $id[0] == '$' ||
994
            $id[0] == '$' ||
992
            $id[0] == '!') {
995
            $id[0] == '!') {
993
            return true;
996
            return true;
994
        }
997
        }
995
 
998
 
996
        // 7.2.3
999
        // 7.2.3
997
        if (strpos($id, "://") === false) {
1000
        if (strpos($id, "://") === false) {
998
            $id = 'http://' . $id;
1001
            $id = 'http://' . $id;
999
        }
1002
        }
1000
 
1003
 
1001
        // 7.2.4
1004
        // 7.2.4
1002
        return self::normalizeURL($id);
1005
        return self::normalizeURL($id);
1003
    }
1006
    }
1004
    
1007
    
1005
	/**
1008
	/**
1006
     * Generates a hash value (message digest) according to given algorithm.
1009
     * Generates a hash value (message digest) according to given algorithm.
1007
     * It returns RAW binary string.
1010
     * It returns RAW binary string.
1008
     *
1011
     *
1009
     * This is a wrapper function that uses one of available internal function
1012
     * This is a wrapper function that uses one of available internal function
1010
     * dependent on given PHP configuration. It may use various functions from
1013
     * dependent on given PHP configuration. It may use various functions from
1011
     *  ext/openssl, ext/hash, ext/mhash or ext/standard.
1014
     *  ext/openssl, ext/hash, ext/mhash or ext/standard.
1012
     *
1015
     *
1013
     * @param string $func digest algorithm
1016
     * @param string $func digest algorithm
1014
     * @param string $data data to sign
1017
     * @param string $data data to sign
1015
     * @return string RAW digital signature
1018
     * @return string RAW digital signature
1016
     * @throws Zend_OpenId_Exception
1019
     * @throws Zend_OpenId_Exception
1017
     */
1020
     */
1018
    public function digest($func, $data)
1021
    public function digest($func, $data)
1019
    {
1022
    {
1020
        if (function_exists('openssl_digest')) {
1023
        if (function_exists('openssl_digest')) {
1021
            return openssl_digest($data, $func, true);
1024
            return openssl_digest($data, $func, true);
1022
        } else if (function_exists('hash')) {
1025
        } else if (function_exists('hash')) {
1023
            return hash($func, $data, true);
1026
            return hash($func, $data, true);
1024
        } else if ($func === 'sha1') {
1027
        } else if ($func === 'sha1') {
1025
            return sha1($data, true);
1028
            return sha1($data, true);
1026
        } else if ($func === 'sha256') {
1029
        } else if ($func === 'sha256') {
1027
            if (function_exists('mhash')) {
1030
            if (function_exists('mhash')) {
1028
                return mhash(MHASH_SHA256 , $data);
1031
                return mhash(MHASH_SHA256 , $data);
1029
            }
1032
            }
1030
        }
1033
        }
1031
        /*require_once "Zend/OpenId/Exception.php";
1034
        /*require_once "Zend/OpenId/Exception.php";
1032
        throw new Zend_OpenId_Exception(
1035
        throw new Zend_OpenId_Exception(
1033
            'Unsupported digest algorithm "' . $func . '".',
1036
            'Unsupported digest algorithm "' . $func . '".',
1034
            Zend_OpenId_Exception::UNSUPPORTED_DIGEST);*/
1037
            Zend_OpenId_Exception::UNSUPPORTED_DIGEST);*/
1035
        trigger_error('Unsupported digest algorithm '.$func , E_USER_ERROR);
1038
        trigger_error('Unsupported digest algorithm '.$func , E_USER_ERROR);
1036
    }
1039
    }
1037
    
1040
    
1038
    
1041
    
1039
    
1042
    
1040
    
1043
    
1041
	
1044
	
1042
    
1045
    
1043
    
1046
    
1044
    
1047
    
1045
 	/**
1048
 	/**
1046
     * Returns a full URL that was requested on current HTTP request.
1049
     * Returns a full URL that was requested on current HTTP request.
1047
     *
1050
     *
1048
     * @return string
1051
     * @return string
1049
     */
1052
     */
1050
    public function selfUrl()
1053
    public function selfUrl()
1051
    {
1054
    {
1052
        /*FIXME : 
1055
        /*FIXME : 
1053
         * if ($this->$selfUrl !== null) {
1056
         * if ($this->$selfUrl !== null) {
1054
            return $this->$selfUrl;
1057
            return $this->$selfUrl;
1055
        } */
1058
        } */
1056
        
1059
        
1057
        if (isset($_SERVER['SCRIPT_URI'])) {
1060
        if (isset($_SERVER['SCRIPT_URI'])) {
1058
            return $_SERVER['SCRIPT_URI'];
1061
            return $_SERVER['SCRIPT_URI'];
1059
        }
1062
        }
1060
        $url = '';
1063
        $url = '';
1061
        $port = '';
1064
        $port = '';
1062
        if (isset($_SERVER['HTTP_HOST'])) {
1065
        if (isset($_SERVER['HTTP_HOST'])) {
1063
            if (($pos = strpos($_SERVER['HTTP_HOST'], ':')) === false) {
1066
            if (($pos = strpos($_SERVER['HTTP_HOST'], ':')) === false) {
1064
                if (isset($_SERVER['SERVER_PORT'])) {
1067
                if (isset($_SERVER['SERVER_PORT'])) {
1065
                    $port = ':' . $_SERVER['SERVER_PORT'];
1068
                    $port = ':' . $_SERVER['SERVER_PORT'];
1066
                }
1069
                }
1067
                $url = $_SERVER['HTTP_HOST'];
1070
                $url = $_SERVER['HTTP_HOST'];
1068
            } else {
1071
            } else {
1069
                $url = substr($_SERVER['HTTP_HOST'], 0, $pos);
1072
                $url = substr($_SERVER['HTTP_HOST'], 0, $pos);
1070
                $port = substr($_SERVER['HTTP_HOST'], $pos);
1073
                $port = substr($_SERVER['HTTP_HOST'], $pos);
1071
            }
1074
            }
1072
        } else if (isset($_SERVER['SERVER_NAME'])) {
1075
        } else if (isset($_SERVER['SERVER_NAME'])) {
1073
            $url = $_SERVER['SERVER_NAME'];
1076
            $url = $_SERVER['SERVER_NAME'];
1074
            if (isset($_SERVER['SERVER_PORT'])) {
1077
            if (isset($_SERVER['SERVER_PORT'])) {
1075
                $port = ':' . $_SERVER['SERVER_PORT'];
1078
                $port = ':' . $_SERVER['SERVER_PORT'];
1076
            }
1079
            }
1077
        }
1080
        }
1078
        if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
1081
        if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
1079
            $url = 'https://' . $url;
1082
            $url = 'https://' . $url;
1080
            if ($port == ':443') {
1083
            if ($port == ':443') {
1081
                $port = '';
1084
                $port = '';
1082
            }
1085
            }
1083
        } else {
1086
        } else {
1084
            $url = 'http://' . $url;
1087
            $url = 'http://' . $url;
1085
            if ($port == ':80') {
1088
            if ($port == ':80') {
1086
                $port = '';
1089
                $port = '';
1087
            }
1090
            }
1088
        }
1091
        }
1089
 
1092
 
1090
        $url .= $port;
1093
        $url .= $port;
1091
        if (isset($_SERVER['HTTP_X_REWRITE_URL'])) {
1094
        if (isset($_SERVER['HTTP_X_REWRITE_URL'])) {
1092
            $url .= $_SERVER['HTTP_X_REWRITE_URL'];
1095
            $url .= $_SERVER['HTTP_X_REWRITE_URL'];
1093
        } elseif (isset($_SERVER['REQUEST_URI'])) {
1096
        } elseif (isset($_SERVER['REQUEST_URI'])) {
1094
            $query = strpos($_SERVER['REQUEST_URI'], '?');
1097
            $query = strpos($_SERVER['REQUEST_URI'], '?');
1095
            if ($query === false) {
1098
            if ($query === false) {
1096
                $url .= $_SERVER['REQUEST_URI'];
1099
                $url .= $_SERVER['REQUEST_URI'];
1097
            } else {
1100
            } else {
1098
                $url .= substr($_SERVER['REQUEST_URI'], 0, $query);
1101
                $url .= substr($_SERVER['REQUEST_URI'], 0, $query);
1099
            }
1102
            }
1100
        } else if (isset($_SERVER['SCRIPT_URL'])) {
1103
        } else if (isset($_SERVER['SCRIPT_URL'])) {
1101
            $url .= $_SERVER['SCRIPT_URL'];
1104
            $url .= $_SERVER['SCRIPT_URL'];
1102
        } else if (isset($_SERVER['REDIRECT_URL'])) {
1105
        } else if (isset($_SERVER['REDIRECT_URL'])) {
1103
            $url .= $_SERVER['REDIRECT_URL'];
1106
            $url .= $_SERVER['REDIRECT_URL'];
1104
        } else if (isset($_SERVER['PHP_SELF'])) {
1107
        } else if (isset($_SERVER['PHP_SELF'])) {
1105
            $url .= $_SERVER['PHP_SELF'];
1108
            $url .= $_SERVER['PHP_SELF'];
1106
        } else if (isset($_SERVER['SCRIPT_NAME'])) {
1109
        } else if (isset($_SERVER['SCRIPT_NAME'])) {
1107
            $url .= $_SERVER['SCRIPT_NAME'];
1110
            $url .= $_SERVER['SCRIPT_NAME'];
1108
            if (isset($_SERVER['PATH_INFO'])) {
1111
            if (isset($_SERVER['PATH_INFO'])) {
1109
                $url .= $_SERVER['PATH_INFO'];
1112
                $url .= $_SERVER['PATH_INFO'];
1110
            }
1113
            }
1111
        }
1114
        }
1112
        return $url;
1115
        return $url;
1113
    }
1116
    }
1114
    
1117
    
1115
    
1118
    
1116
    //TODO : vérifier si les fonctions FWK & ZEND sont bien équivalente
1119
    //TODO : vérifier si les fonctions FWK & ZEND sont bien équivalente
1117
	/**
1120
	/**
1118
     * Retourne l'url absolue d'une url donnée
1121
     * Retourne l'url absolue d'une url donnée
1119
     *
1122
     *
1120
     * @param string $url absilute or relative URL
1123
     * @param string $url absilute or relative URL
1121
     * @return string
1124
     * @return string
1122
     */
1125
     */
1123
    public function absoluteUrl($url)
1126
    public function absoluteUrl($url)
1124
    {
1127
    {
1125
    	if (!empty($ur))	{
1128
    	if (!empty($ur))	{
1126
    		$urlAbsolue = new Url($url);
1129
    		$urlAbsolue = new Url($url);
1127
    		$urlAbsolue->normaliser();
1130
    		$urlAbsolue->normaliser();
1128
    		$url = $urlAbsolue->getUrl();
1131
    		$url = $urlAbsolue->getUrl();
1129
    	} else {
1132
    	} else {
1130
    		$url = $this->selfUrl();
1133
    		$url = $this->selfUrl();
1131
    	}
1134
    	}
1132
    	
1135
    	
1133
    	return $url;
1136
    	return $url;
1134
    	/*
1137
    	/*
1135
        if (empty($url)) {
1138
        if (empty($url)) {
1136
            return $this->selfUrl();
1139
            return $this->selfUrl();
1137
        } else if (!preg_match('|^([^:]+)://|', $url)) {
1140
        } else if (!preg_match('|^([^:]+)://|', $url)) {
1138
            if (preg_match('|^([^:]+)://([^:@]*(?:[:][^@]*)?@)?([^/:@?#]*)(?:[:]([^/?#]*))?(/[^?]*)?((?:[?](?:[^#]*))?(?:#.*)?)$|', $this->selfUrl(), $reg)) {
1141
            if (preg_match('|^([^:]+)://([^:@]*(?:[:][^@]*)?@)?([^/:@?#]*)(?:[:]([^/?#]*))?(/[^?]*)?((?:[?](?:[^#]*))?(?:#.*)?)$|', $this->selfUrl(), $reg)) {
1139
                $scheme = $reg[1];
1142
                $scheme = $reg[1];
1140
                $auth = $reg[2];
1143
                $auth = $reg[2];
1141
                $host = $reg[3];
1144
                $host = $reg[3];
1142
                $port = $reg[4];
1145
                $port = $reg[4];
1143
                $path = $reg[5];
1146
                $path = $reg[5];
1144
                $query = $reg[6];
1147
                $query = $reg[6];
1145
                if ($url[0] == '/') {
1148
                if ($url[0] == '/') {
1146
                    return $scheme
1149
                    return $scheme
1147
                        . '://'
1150
                        . '://'
1148
                        . $auth
1151
                        . $auth
1149
                        . $host
1152
                        . $host
1150
                        . (empty($port) ? '' : (':' . $port))
1153
                        . (empty($port) ? '' : (':' . $port))
1151
                        . $url;
1154
                        . $url;
1152
                } else {
1155
                } else {
1153
                    $dir = dirname($path);
1156
                    $dir = dirname($path);
1154
                    return $scheme
1157
                    return $scheme
1155
                        . '://'
1158
                        . '://'
1156
                        . $auth
1159
                        . $auth
1157
                        . $host
1160
                        . $host
1158
                        . (empty($port) ? '' : (':' . $port))
1161
                        . (empty($port) ? '' : (':' . $port))
1159
                        . (strlen($dir) > 1 ? $dir : '')
1162
                        . (strlen($dir) > 1 ? $dir : '')
1160
                        . '/'
1163
                        . '/'
1161
                        . $url;
1164
                        . $url;
1162
                }
1165
                }
1163
            }
1166
            }
1164
        }
1167
        }
1165
        return $url;*/
1168
        return $url;*/
1166
    }
1169
    }
1167
    
1170
    
1168
    
1171
    
1169
    //TODO : voir si on ne peut pas glisser ça dans client ?
1172
    //TODO : voir si on ne peut pas glisser ça dans client ?
1170
	//FIXME : je met une fonction SIMPLISSIME a améliorer et reécrire
1173
	//FIXME : je met une fonction SIMPLISSIME a améliorer et reécrire
1171
    // La fonction de Zend est plus poussée est prend en compte le cas ou l'header ne peut pas etre envoyé
1174
    // La fonction de Zend est plus poussée est prend en compte le cas ou l'header ne peut pas etre envoyé
1172
    /**
1175
    /**
1173
     * Rediriger vers la page du serveur avec les paramètres de confiration
1176
     * Rediriger vers la page du serveur avec les paramètres de confiration
1174
     *
1177
     *
1175
     * @param string $url URL de retour
1178
     * @param string $url URL de retour
1176
     * @param array $params paramètres additionnels
1179
     * @param array $params paramètres additionnels
1177
     */
1180
     */
1178
    public function redirect($url, $params)	{
1181
    public function redirect($url, $params)	{
1179
    	//1. fabriquer l'url Get
1182
    	//1. fabriquer l'url Get
1180
    	$urlRedirection = new Url($url);
1183
    	$urlRedirection = new Url($url);
1181
    	$urlRedirection->setRequete($params);
1184
    	$urlRedirection->setRequete($params);
1182
    	//echo $urlRedirection->getUrl();
1185
    	//echo $urlRedirection->getUrl();
1183
    	try {
1186
    	try {
1184
    		header('Location:'.$urlRedirection->getUrl());
1187
    		header('Location:'.$urlRedirection->getUrl());
1185
    	} catch (Exception $e) {
1188
    	} catch (Exception $e) {
1186
    		//TODO : voir autres méthodes de redirection
1189
    		//TODO : voir autres méthodes de redirection
1187
    		// > balise META
1190
    		// > balise META
1188
    		// > formulaire HTML
1191
    		// > formulaire HTML
1189
    		// > JS
1192
    		// > JS
1190
    	}
1193
    	}
1191
    }
1194
    }
1192
}
1195
}
1193
?>
1196
?>