Subversion Repositories Applications.framework

Rev

Rev 263 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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