Happy New Year!
[platal.git] / modules / openid / openid.inc.php
1 <?php
2 /***************************************************************************
3 * Copyright (C) 2003-2014 Polytechnique.org *
4 * http://opensource.polytechnique.org/ *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., *
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
20 ***************************************************************************/
21
22 require_once 'Auth/OpenID/Discover.php';
23
24 // An helper class for using plat/al as an OpenId Identity Provider.
25 class OpenId
26 {
27 private $base_url; // Base url for all OpenId operations.
28 private $spool_store; // Location of the spool storage for OpenID.
29
30 private $server = null; // Auth::OpenId::Server object.
31 private $request = null; // Request extracted by the Server object.
32
33 public function __construct()
34 {
35 global $globals;
36
37 $this->base_url = $globals->baseurl . '/openid';
38 $this->spool_store = $globals->spoolroot . '/spool/openid/store';
39 }
40
41 // Initializes an OpenId Server object; it will use a defined spool-based
42 // directory to store OpenID secrets. Returns true on success.
43 public function Initialize()
44 {
45 require_once 'Auth/OpenID/FileStore.php';
46 require_once 'Auth/OpenID/Server.php';
47
48 $store = new Auth_OpenID_FileStore($this->spool_store);
49 $this->server = new Auth_OpenID_Server($store, $this->base_url);
50 $this->request = $this->server->decodeRequest();
51
52 return !is_a($this->request, 'Auth_OpenID_ServerError');
53 }
54
55 // Authorization logic helpers ---------------------------------------------
56
57 // Returns true iff the current request is a valid openid request.
58 public function IsOpenIdRequest()
59 {
60 return Env::has('openid_mode');
61 }
62
63 // Returns true iff the request needs to be handled directly by the calling
64 // code (ie. the current user needs to be authorized).
65 public function IsAuthorizationRequest()
66 {
67 return $this->request->mode == 'checkid_immediate' ||
68 $this->request->mode == 'checkid_setup';
69 }
70
71 // Returns true iff the request requires an immediate answer (no user
72 // interaction is allowed).
73 public function IsImmediateRequest()
74 {
75 return $this->request->mode == 'checkid_immediate';
76 }
77
78 // Returns true iff the logged-in user is authorized for the current request.
79 // It checks that the user is logged in, and has the authorization to use
80 // that identity.
81 public function IsUserAuthorized(User $user)
82 {
83 return $user && ($user->login() == $this->request->identity ||
84 $this->request->idSelect());
85 }
86
87 // SimpleRegistration helpers ----------------------------------------------
88
89 // Determines which SREG data are requested by the endpoint, and returns them.
90 public function GetSRegDataForRequest(User $user)
91 {
92 require_once 'Auth/OpenID/SReg.php';
93
94 // Other common SReg fields we could fill are:
95 // dob, country, language, timezone.
96 $sreg_request = Auth_OpenID_SRegRequest::fromOpenIDRequest($this->request);
97 return Auth_OpenID_SRegResponse::extractResponse($sreg_request, array(
98 'fullname' => $user->fullName(),
99 'nickname' => $user->displayName(),
100 'email' => $user->bestEmail(),
101 'gender' => $user->isFemale() ? 'F' : 'M',
102 ));
103 }
104
105 // Handling and answering helpers ------------------------------------------
106
107 // Answers the current request, and renders the response. Appends the |sreg|
108 // data when not null.
109 public function AnswerRequest($is_authorized, $sreg_data = null)
110 {
111 // Creates the response.
112 if ($is_authorized && $this->request->idSelect()) {
113 $user = S::user();
114 $response = $this->request->answer(
115 $is_authorized, null, $user->login(), $this->GetUserUrl($user));
116 } else {
117 $response = $this->request->answer($is_authorized);
118 }
119
120 // Clobbers response, and get it back to the Relaying Party.
121 if ($sreg_data) {
122 $sreg_data->toMessage($response->fields);
123 }
124 $this->RenderResponse($response);
125 }
126
127 // Automatically handles the request without any user interaction.
128 public function HandleRequest()
129 {
130 $response = $this->server->handleRequest($this->request);
131 $this->RenderResponse($response);
132 }
133
134 // Trust management helpers ------------------------------------------------
135
136 // Returns true iff the current endpoint is currently trusted by |user|.
137 public function IsEndpointTrusted(User $user)
138 {
139 $res = XDB::query(
140 "SELECT COUNT(*)
141 FROM account_auth_openid
142 WHERE (uid = {?} OR uid IS NULL) AND url = {?}",
143 $user->id(), $this->request->trust_root);
144 return ($res->fetchOneCell() > 0);
145 }
146
147 // Updates the trust level for the given endpoint, based on the value pf
148 // |trusted| and |permanent_trust| (the latter is ignored when the former
149 // value is false). Returns true iff the current endpoint is trusted.
150 public function UpdateEndpointTrust(User $user, $trusted, $permanent_trust) {
151 $initial_trust = $this->IsEndpointTrusted($user);
152 if (!$initial_trust && $trusted && $permanent_trust) {
153 XDB::execute(
154 "INSERT IGNORE INTO account_auth_openid
155 SET uid = {?}, url = {?}",
156 $user->id(), $this->request->trust_root);
157 }
158
159 return ($initial_trust || $trusted);
160 }
161
162 // Page renderers ----------------------------------------------------------
163
164 // Renders the OpenId discovery page for |user|.
165 public function RenderDiscoveryPage($page, User $user)
166 {
167 $page->changeTpl('openid/openid.tpl');
168 $page->setTitle($user->fullName());
169 $page->addLink('openid.server openid2.provider', $this->base_url);
170 $page->addLink('openid.delegate openid2.local_id', $user->login());
171 $page->assign_by_ref('user', $user);
172
173 // Include the X-XRDS-Location header for Yadis discovery.
174 header('X-XRDS-Location: ' . $this->GetUserXrdsUrl($user));
175 }
176
177 // Renders the main XRDS page.
178 public function RenderMainXrdsPage($page)
179 {
180 pl_content_headers("application/xrds+xml");
181 $page->changeTpl('openid/idp_xrds.tpl', NO_SKIN);
182 $page->assign('type2', Auth_OpenID_TYPE_2_0_IDP);
183 $page->assign('sreg', Auth_OpenID_SREG_URI);
184 $page->assign('provider', $this->base_url);
185 }
186
187 // Renders the XRDS page of |user|.
188 public function RenderUserXrdsPage($page, User $user)
189 {
190 pl_content_headers("application/xrds+xml");
191 $page->changeTpl('openid/user_xrds.tpl', NO_SKIN);
192 $page->assign('type2', Auth_OpenID_TYPE_2_0);
193 $page->assign('type1', Auth_OpenID_TYPE_1_1);
194 $page->assign('sreg', Auth_OpenID_SREG_URI);
195 $page->assign('provider', $this->base_url);
196 $page->assign('local_id', $user->login());
197 }
198
199 // Renders the OpenId response for the HTTP client.
200 public function RenderResponse($response)
201 {
202 if ($response) {
203 $web_response = $this->server->encodeResponse($response);
204 header(sprintf('%s %d', $_SERVER['SERVER_PROTOCOL'], $web_response->code),
205 true, $web_response->code);
206
207 if (is_a($response, 'Auth_OpenID_ServerError')) {
208 print "Erreur lors de l'authentification OpenId: " . $response->toString();
209 } else {
210 foreach ($web_response->headers as $key => $value) {
211 header(sprintf('%s: %s', $key, $value));
212 }
213
214 header('Connection: close');
215 print $web_response->body;
216 }
217 }
218 exit;
219 }
220
221 // URL providers -----------------------------------------------------------
222
223 // Returns the OpenId identity URL of the requested user.
224 private function GetUserUrl(User $user)
225 {
226 return $this->base_url . '/' . $user->login();
227 }
228
229 // Returns the private XRDS page of a user.
230 private function GetUserXrdsUrl(User $user)
231 {
232 return $this->base_url . '/xrds/' . $user->login();
233 }
234
235 // Returns the endpoint in the current request.
236 public function GetEndpoint()
237 {
238 return $this->request->trust_root;
239 }
240
241 // Extracts the OpenId arguments available in the current request, and
242 // builds a query string with them.
243 public function GetQueryStringForRequest()
244 {
245 foreach (Auth_OpenID::getQuery() as $key => $value) {
246 if (strpos($key, 'openid.') === 0) {
247 $args[$key] = $value;
248 }
249 }
250
251 return http_build_query($args);
252 }
253 }
254
255 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
256 ?>