Subversion Repositories Applications.papyrus

Rev

Rev 2157 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2154 aurelien 1
<?php
2
 
3
// Remplacement de apache_request_headers pour les vieux serveurs
4
// http://stackoverflow.com/questions/2916232/call-to-undefined-function-apache-request-headers
5
if(!function_exists('apache_request_headers')) {
6
	function apache_request_headers() {
7
		// Based on: http://www.iana.org/assignments/message-headers/message-headers.xml#perm-headers
8
		$arrCasedHeaders = array(
9
				// HTTP
10
				'Dasl'             => 'DASL',
11
				'Dav'              => 'DAV',
12
				'Etag'             => 'ETag',
13
				'Mime-Version'     => 'MIME-Version',
14
				'Slug'             => 'SLUG',
15
				'Te'               => 'TE',
16
				'Www-Authenticate' => 'WWW-Authenticate',
17
				// MIME
18
				'Content-Md5'      => 'Content-MD5',
19
				'Content-Id'       => 'Content-ID',
20
				'Content-Features' => 'Content-features',
21
		);
22
		$arrHttpHeaders = array();
23
 
24
		foreach($_SERVER as $strKey => $mixValue) {
25
			if('HTTP_' !== substr($strKey, 0, 5)) {
26
				continue;
27
			}
28
 
29
			$strHeaderKey = strtolower(substr($strKey, 5));
30
 
31
			if(0 < substr_count($strHeaderKey, '_')) {
32
				$arrHeaderKey = explode('_', $strHeaderKey);
33
				$arrHeaderKey = array_map('ucfirst', $arrHeaderKey);
34
				$strHeaderKey = implode('-', $arrHeaderKey);
35
			}
36
			else {
37
				$strHeaderKey = ucfirst($strHeaderKey);
38
			}
39
 
40
			if(array_key_exists($strHeaderKey, $arrCasedHeaders)) {
41
				$strHeaderKey = $arrCasedHeaders[$strHeaderKey];
42
			}
43
 
44
			$arrHttpHeaders[$strHeaderKey] = $mixValue;
45
		}
46
		return $arrHttpHeaders;
47
	}
48
}
49
 
2156 mathias 50
// Attention bien v�rifier la pr�sence des variables suivantes :
51
// IDEN_UTILISE_SSO, IDEN_URL_SSO, IDEN_COOKIE_SSO, IDEN_SSO_SYNC
52
// dans le fichier iden_config.inc.php
2154 aurelien 53
class identificationSso {
2156 mathias 54
	/**
55
	 * si la valeur est vraiment vide, le cookie n'est pas posé, alors on met
56
	 * une valeur vide pas vide :)
57
	 */
58
	public static $VALEUR_JETON_VIDE = "jeton-vide";
59
 
60
	protected $cookie_mandataire = "";
61
	/** le cookie qui dure jusqu'à Vladivostok, si synchro partielle seulement */
2157 mathias 62
	protected $duree_cookie_mandataire;
2156 mathias 63
 
64
	/**
65
	 * lorsqu'appelé par un client non-navigateur (qui n'envoie et ne reçoit pas
66
	 * de cookies), permet de ne pas rediriger en boucle, en fournissant le
67
	 * paramètre GET "non_interactif"
68
	 */
69
	protected $mode_non_interactif = false;
70
 
71
	/** voir IDEN_SSO_SYNC dans iden_config.inc.php  */
72
	protected $synchro_complete;
73
 
74
	protected $annuaire_url = '';
75
	protected $bdd_annuaire = '';
76
	protected $table_annuaire = '';
77
	protected $champ_login = '';
78
	protected $champ_mdp = '';
2154 aurelien 79
 
2156 mathias 80
	protected $communs_papyrus = null;
2154 aurelien 81
 
82
	public function __construct() {
83
		$this->communs_papyrus = $GLOBALS['_GEN_commun'];
84
 
2156 mathias 85
		$this->cookie_mandataire = IDEN_COOKIE_SSO;
2154 aurelien 86
		$this->auth_header = IDEN_HEADER_SSO;
87
		$this->annuaire_url = IDEN_URL_SSO;
2156 mathias 88
		$this->synchro_complete = IDEN_SSO_SYNC;
89
 
90
		// gestion des clients qui ne gèrent pas les cookies (file_get_contents...)
91
		if (isset($_GET['non_interactif'])) {
92
			$this->mode_non_interactif = true;
93
		}
94
 
95
		// si on est en mode synchro complète, on vérifie périodiquement l'état
96
		// du SSO, en utilisant un cookie qui ne dure pas jusqu'à Vladivostok
2157 mathias 97
		$this->duree_cookie_mandataire = 3600 * 24 * 365;
2156 mathias 98
		if ($this->synchro_complete === true) {
2158 mathias 99
			$this->duree_cookie_mandataire = 180; // une fois toutes les trois minutes, à cause des zozos qui sont pas à l'heure
2156 mathias 100
		}
2154 aurelien 101
 
2155 mathias 102
		// c'est moche mais je n'ai pas trouv� plus simple pour r�cuperer la table annuaire en cours
103
		// d'utilisation pour le site actuel (la bdd annuaire est la derni�re partie du dsn)
2154 aurelien 104
		$dsn_annuaire = $this->communs_papyrus['info_auth_bdd']->gsab_dsn;
105
		$dsn_annuaire = explode('/', $dsn_annuaire);
106
		$this->bdd_annuaire = end($dsn_annuaire);
107
 
108
		$this->table_annuaire = $this->communs_papyrus['info_auth_bdd']->gsab_nom_table;
109
		$this->champ_login = $this->communs_papyrus['info_auth_bdd']->gsab_nom_champ_login;
110
		$this->champ_mdp = $this->communs_papyrus['info_auth_bdd']->gsab_nom_champ_mdp;
111
	}
112
 
2156 mathias 113
	// http://stackoverflow.com/questions/1251582/beautiful-way-to-remove-get-variables-with-php?lq=1
114
	protected function supprimerUrlVar($url, $var) {
115
		 return rtrim(preg_replace('/([?&])'.$var.'=[^&]*(&|$)/','$1',$url), '&?');
2154 aurelien 116
	}
117
 
2156 mathias 118
	/**
119
	 * Se connecte au SSO : redirige vers le service d'authentification, qui pose
120
	 * le cookie tb_auth, puis re-redirige vers Papyrus avec le jeton en GET, puis
121
	 * Papyrus stocke ce jeton dans son cookie mandataire, puis se re-redirige
122
	 * vers lui-même pour éliminer le paramètre GET de l'URL (ouf !)
123
	 */
124
	public function connecterEtRediriger() {
125
		//echo "JE CONNECTE<br/>";
126
		// sauvegarde de l'URL courante
2154 aurelien 127
		$url_redirect = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
128
		$params = 'login='.$_POST['username'].'&password='.$_POST['password'].'&redirect_url='.urlencode($url_redirect);
129
		$connexion_url = $this->annuaire_url."connexion?".$params;
2156 mathias 130
		// redirection vers l'annuaire, qui va nous connecter au SSO et nous
131
		// renvoyer un jeton en GET
2154 aurelien 132
		header('Location: '.$connexion_url);
133
		exit;
134
	}
2156 mathias 135
 
136
	/**
137
	 * Se déconnecte du SSO : redirige vers le service d'authentification, qui
138
	 * supprime le cookie tb_auth, puis re-redirige vers Papyrus avec un jeton
139
	 * vide en GET; Papyrus stocke ce jeton vide dans son cookie mandataire,
140
	 * puis se re-redirige vers lui-même pour éliminer le paramètre GET de l'URL
141
	 */
142
	public function deconnecterEtRediriger() {
143
		//echo "JE DECONNECTE<br/>";
144
		// sauvegarde de l'URL courante
2154 aurelien 145
		$url_redirect = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
146
		$url_redirect = $this->supprimerUrlVar($url_redirect, 'logout');
147
		$deconnexion_url = $this->annuaire_url."deconnexion?".'redirect_url='.urlencode($url_redirect);
2156 mathias 148
		// redirection vers l'annuaire, qui va nous déconnecter du SSO et nous
149
		// renvoyer un jeton vide en GET
2154 aurelien 150
		header('Location: '.$deconnexion_url);
151
		exit;
152
	}
153
 
2156 mathias 154
	protected function synchroniserDepuisEtatSso() {
155
		//echo "JE SYNCHRONISE<br/>";
156
		// sauvegarde de l'URL courante
157
		$url_redirect = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
158
		$params = 'redirect_url='.urlencode($url_redirect);
159
		$identite_url = $this->annuaire_url."identite?".$params;
160
		// redirection vers l'annuaire, qui va nous donner l'état du SSO et nous
161
		// renvoyer un jeton en GET
162
		header('Location: '.$identite_url);
163
		exit;
164
	}
165
 
166
	/**
167
	 * Appelée à chaque chargement de page
168
	 */
169
	public function verifierIdentiteEtRediriger() {
2155 mathias 170
		// si on fait autre chose qu'un GET, on ne vérifie pas l'identité, car
171
		// cela conduirait à une redirection en GET (avec le jeton), qui
172
		// supprimerait les données du corps de la requête
173
		if ($_SERVER['REQUEST_METHOD'] == "GET") {
2154 aurelien 174
 
2156 mathias 175
			// lecture jeton en GET si on vient de l'annuaire
176
			if (isset($_GET['Authorization'])) {
177
				//echo "Re-Redirection pour éliminer le GET<br/>";
2154 aurelien 178
 
2156 mathias 179
				// création / mise à jour du cookie mandataire (le jeton peut être
180
				// vide en cas de déconnexion)
181
				$jetonRecu = $_GET['Authorization'];
182
				if ($jetonRecu == '') {
183
					$jetonRecu = self::$VALEUR_JETON_VIDE;
2154 aurelien 184
				}
2156 mathias 185
				$this->setCookieMandataire($jetonRecu);
186
				//echo "JETON REÇU: " . $_GET['Authorization'];
187
				//echo "JETON POSÉ: "; var_dump($jetonRecu);
188
				//exit;
2155 mathias 189
 
2156 mathias 190
				// redirection pour éliminer le paramètre GET
2155 mathias 191
				$url_redirect = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
2156 mathias 192
				$url_redirect = $this->supprimerUrlVar($url_redirect, 'Authorization');
193
				//echo "URL Redirect: $url_redirect"; exit;
194
				header('Location: ' . $url_redirect);
195
				exit;
196
			}
2155 mathias 197
 
2156 mathias 198
			// une fois qu'on a fait une connexion ou une déconnexion, on se base
199
			// sur le cookie mandataire pour gérer l'identité dans Papyrus
200
			//var_dump($_COOKIE); echo "<br/>";
201
			// lecture cookie mandataire de Papyrus
202
			$jeton = null;
203
			$cookiePresent = false;
204
			if (isset($_COOKIE[$this->cookie_mandataire])) {
205
				$cookiePresent = true;
206
				$jeton = $_COOKIE[$this->cookie_mandataire];
207
			}
208
			//echo "Cookie Présent: "; var_dump($cookiePresent);
209
			//echo "JETON: "; var_dump($jeton); echo "<br/>";
210
			//exit;
2155 mathias 211
 
2156 mathias 212
			// s'il y a un cookie, qu'il contienne un jeton valide ou vide
213
			if ($cookiePresent) {
214
				// s'il contient un jeton non-vide
215
				if ($jeton != self::$VALEUR_JETON_VIDE) {
216
					// reconnexion PEAR (l'utilisateur peut avoir changé)
217
					//echo "RECONNEXION!<br/>"; exit;
218
					$this->deconnexionPear();
219
					$this->connexionPear($jeton);
2155 mathias 220
 
2156 mathias 221
					// prolonge le cookie de 30 secondes si on est connecté, pour
222
					// minimiser les synchros avec le SSO
223
					$this->setCookieMandataire($jeton, 30);
2155 mathias 224
 
2156 mathias 225
					// si mode synchro partielle, le cookie mandataire dure logntemps,
226
					// on rafraîchit donc le jeton pour... euh... on sait jamais :-/
227
					if (! $this->synchro_complete) {
228
						// appel annuaire / identité avec jeton en GET
229
						$infosJson = $this->rafraichirJeton($jeton);
230
						$infos = json_decode($infosJson, true);
231
						//echo "INFOS: "; var_dump($infos); echo "<br/>";
232
						$jetonRafraichi = null;
233
						if (isset($infos['token'])) {
234
							$jetonRafraichi = $infos['token'];
2155 mathias 235
						}
2156 mathias 236
						//echo "JETON Rafraîchi: "; var_dump($jetonRafraichi); echo "<br/>";
237
						//exit;
238
						// si jeton rafraîchi reçu
239
						if ($jetonRafraichi != null) {
240
							// màj cookie avec jeton rafraîchi
241
							$this->setCookieMandataire($jetonRafraichi);
242
							// reconnexion PEAR (l'utilisateur peut avoir changé)
243
							$this->deconnexionPear();
244
							$this->connexionPear($jetonRafraichi);
245
							//exit;
246
						} else {
247
						// sinon (non connecté ou problème annuaire / jeton)
248
							// écriture cookie avec jeton vide
249
							$this->setCookieMandataire(self::$VALEUR_JETON_VIDE);
250
							// déconnexion PEAR
251
							$this->deconnexionPear();
2155 mathias 252
						}
253
					}
2156 mathias 254
				} else {
255
					// déconnexion PEAR ?
256
					$this->deconnexionPear();
2154 aurelien 257
				}
2156 mathias 258
			} else { // sinon (aucun cookie mandataire)
259
				// en mode synchro complète, on vérifie chaque minute (lorsque le
260
				// cookie mandataire n'est plus présent) si on n'est pas connecté
261
				// sur le SSO, sauf si on est en mode non interactif
262
				if ($this->synchro_complete && (! $this->mode_non_interactif)) {
263
					$this->synchroniserDepuisEtatSso();
264
				}
2154 aurelien 265
			}
266
		}
267
	}
2155 mathias 268
 
2156 mathias 269
	protected function setCookieMandataire($valeur, $duree=null) {
270
		if ($duree === null) {
271
			$duree = $this->duree_cookie_mandataire;
272
		}
273
		setcookie($this->cookie_mandataire, $valeur, time() + $duree);
274
	}
275
 
2155 mathias 276
	/**
2156 mathias 277
	 * Connecte l'utilisateur à Papyrus avec le système traditionnel fourni par PEAR
2155 mathias 278
	 */
2156 mathias 279
	protected function connexionPear($jeton) {
280
		$jeton_decode = $this->decoderToken($jeton);
2155 mathias 281
 
2156 mathias 282
		// R�cup�ration du mot de passe pour remplir les infos de l'objet PEAR Auth
283
		$requete =  'SELECT '.$this->champ_mdp.' '.
284
				'FROM '.$this->bdd_annuaire.'.'.$this->table_annuaire.' '.
285
				'WHERE '.$this->champ_login.' = "'.$jeton_decode['sub'].'" ';
2155 mathias 286
 
2156 mathias 287
		// TODO: normalement �a n'est jamais le cas mais que fait t'on si l'utilisateur n'existe pas
288
		// dans notre base de donn�es ? (au pire il ne sera pas connect�)
289
		$this->communs_papyrus['pear_auth']->username = $jeton_decode['sub'];
290
		$this->communs_papyrus['pear_auth']->password = $this->communs_papyrus['pear_db']->getOne($requete);
291
 
292
		// Le mot de passe est d�j� crypt� dans la bdd donc il faut indiquer � pear de ne pas le re crytper
293
		if (isset($this->communs_papyrus['pear_auth']->storage_options)) {
294
			$this->communs_papyrus['pear_auth']->storage_options['cryptType'] = 'none';
295
		}
296
		if (isset($this->communs_papyrus['pear_auth']->storage->options)) {
297
			$this->communs_papyrus['pear_auth']->storage->options['cryptType'] = 'none';
298
		}
299
 
300
		// si on fait pas ça, ça marche pas (régénération de session apparemment)
301
		//$this->communs_papyrus['pear_auth']->setAuth($jeton_decode['sub']);
2155 mathias 302
	}
2156 mathias 303
 
304
	/**
305
	 * Supprime tout ce qui a trait à PEAR afin de déconnecter l'utilisateur du
306
	 * système d'authentification traditionnel de Papyrus
307
	 */
308
	protected function deconnexionPear() {
309
		$this->communs_papyrus['pear_auth']->logout();
310
 
311
		$cookie_persistant_nom = session_name().'-memo';
312
		$cookie_utilisateur_nom = session_name().'-utilisateur';
313
		// Destruction du cookie de session de Papyrus : est ce utile?
314
		setcookie(session_name(), session_id(), time()-3600, '/');
315
		// Destruction du cookie de permanence de l'identitification de Papyrus
316
		setcookie($cookie_persistant_nom, '', time()-3600, '/');
317
		setcookie($cookie_utilisateur_nom, '', time()-3600, '/');
318
	}
319
 
320
	/**
321
	 * Fournit un jeton à l'annuaire (jeton provenant du cookie mandataire
322
	 * de Papyrus), le fait rafraîchir puis met à jour le cookie mandataire avec
323
	 * le jeton rafraîchi
324
	 */
325
	protected function rafraichirJeton($jeton) {
326
		$identiteServiceURL = $this->annuaire_url . "identite";
327
		$identiteServiceURL .= "?token=" . $jeton;
328
		//echo "URL: $identiteServiceURL<br/>";
329
		$ch = curl_init($identiteServiceURL);
330
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
331
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
332
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
333
		$jetonRafraichi = curl_exec($ch);
334
		//var_dump($jetonRafraichi);
335
		//var_dump(curl_error($ch)); exit;
336
 
337
		return $jetonRafraichi;
338
	}
339
 
340
	protected function decoderToken($token) {
341
		$token_parts = explode('.', $token);
342
		return json_decode(base64_decode($token_parts[1]), true);
343
	}
2154 aurelien 344
}
2158 mathias 345
?>