Fixes the OpenID response when there is no header to display.
[platal.git] / modules / openid / openid.inc.php
1 <?php
2 /***************************************************************************
3 * Copyright (C) 2003-2009 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, $user = null, $sreg_data = null)
110 {
111 // Creates the response.
112 if ($is_authorized && $this->request->idSelect() && $user) {
113 $response = $this->request->answer(
114 $is_authorized, null, $user->login(), $this->GetUserUrl($user));
115 } else {
116 $response = $this->request->answer($is_authorized);
117 }
118
119 // Clobbers response, and get it back to the Relaying Party.
120 if ($sreg_data) {
121 $sreg_data->toMessage($response->fields);
122 }
123 $this->RenderResponse($response);
124 }
125
126 // Automatically handles the request without any user interaction.
127 public function HandleRequest()
128 {
129 $response = $this->server->handleRequest($this->request);
130 $this->RenderResponse($response);
131 }
132
133 // Trust management helpers ------------------------------------------------
134
135 // Returns true iff the current endpoint is currently trusted by |user|.
136 public function IsEndpointTrusted(User $user)
137 {
138 $res = XDB::query(
139 "SELECT COUNT(*)
140 FROM openid_trusted
141 WHERE (user_id = {?} OR user_id IS NULL) AND url = {?}",
142 $user->id(), $this->request->trust_root);
143 return ($res->fetchOneCell() > 0);
144 }
145
146 // Updates the trust level for the given endpoint, based on the value pf
147 // |trusted| and |permanent_trust| (the latter is ignored when the former
148 // value is false). Returns true iff the current endpoint is trusted.
149 public function UpdateEndpointTrust(User &$user, $trusted, $permanent_trust) {
150 $initial_trust = $this->IsEndpointTrusted($user);
151 if (!$initial_trust && $trusted && $permanent_trust) {
152 XDB::execute(
153 "INSERT IGNORE INTO openid_trusted
154 SET user_id = {?}, url = {?}",
155 $user->id(), $this->request->trust_root);
156 }
157
158 return ($initial_trust || $trusted);
159 }
160
161 // Page renderers ----------------------------------------------------------
162
163 // Renders the OpenId discovery page for |user|.
164 public function RenderDiscoveryPage(&$page, User &$user)
165 {
166 $page->changeTpl('openid/openid.tpl');
167 $page->setTitle($user->fullName());
168 $page->addLink('openid.server openid2.provider', $this->base_url);
169 $page->addLink('openid.delegate openid2.local_id', $user->login());
170 $page->assign_by_ref('user', $user);
171
172 // Include the X-XRDS-Location header for Yadis discovery.
173 header('X-XRDS-Location: ' . $this->GetUserXrdsUrl($user));
174 }
175
176 // Renders the main XRDS page.
177 public function RenderMainXrdsPage(&$page)
178 {
179 header('Content-type: application/xrds+xml');
180 $page->changeTpl('openid/idp_xrds.tpl', NO_SKIN);
181 $page->assign('type2', Auth_OpenID_TYPE_2_0_IDP);
182 $page->assign('sreg', Auth_OpenID_SREG_URI);
183 $page->assign('provider', $this->base_url);
184 }
185
186 // Renders the XRDS page of |user|.
187 public function RenderUserXrdsPage(&$page, User &$user)
188 {
189 header('Content-type: application/xrds+xml');
190 $page->changeTpl('openid/user_xrds.tpl', NO_SKIN);
191 $page->assign('type2', Auth_OpenID_TYPE_2_0);
192 $page->assign('type1', Auth_OpenID_TYPE_1_1);
193 $page->assign('sreg', Auth_OpenID_SREG_URI);
194 $page->assign('provider', $this->base_url);
195 $page->assign('local_id', $user->login());
196 }
197
198 // Renders the OpenId response for the HTTP client.
199 public function RenderResponse($response)
200 {
201 if ($response) {
202 $web_response = $this->server->encodeResponse($response);
203 header(sprintf('%s %d', $_SERVER['SERVER_PROTOCOL'], $web_response->code),
204 true, $web_response->code);
205
206 if (count($web_response->headers) > 0) {
207 foreach ($web_response->headers as $key => $value) {
208 header(sprintf('%s: %s', $key, $value));
209 }
210 }
211
212 header('Connection: close');
213 print $web_response->body;
214 }
215 exit;
216 }
217
218 // URL providers -----------------------------------------------------------
219
220 // Returns the OpenId identity URL of the requested user.
221 private function GetUserUrl(User &$user)
222 {
223 return $this->base_url . '/' . $user->login();
224 }
225
226 // Returns the private XRDS page of a user.
227 private function GetUserXrdsUrl(User &$user)
228 {
229 return $this->base_url . '/xrds/' . $user->login();
230 }
231
232 // Returns the endpoint in the current request.
233 public function GetEndpoint()
234 {
235 return $this->request->trust_root;
236 }
237
238 // Extracts the OpenId arguments available in the current request, and
239 // builds a query string with them.
240 public function GetQueryStringForRequest()
241 {
242 foreach (Auth_OpenID::getQuery() as $key => $value) {
243 if (strpos($key, 'openid.') === 0) {
244 $args[$key] = $value;
245 }
246 }
247
248 return http_build_query($args);
249 }
250 }
251
252 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
253 ?>