Improves the OpenID support in plat/al:
[platal.git] / modules / openid / openid.inc.php
CommitLineData
a1af4a99
AA
1<?php
2/***************************************************************************
8d84c630 3 * Copyright (C) 2003-2009 Polytechnique.org *
a1af4a99
AA
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
34d91db6 22require_once 'Auth/OpenID/Discover.php';
a1af4a99 23
34d91db6
VZ
24// An helper class for using plat/al as an OpenId Identity Provider.
25class OpenId
a1af4a99 26{
34d91db6
VZ
27 private $base_url; // Base url for all OpenId operations.
28 private $spool_store; // Location of the spool storage for OpenID.
a1af4a99 29
34d91db6
VZ
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;
a1af4a99 36
34d91db6
VZ
37 $this->base_url = $globals->baseurl . '/openid';
38 $this->spool_store = $globals->spoolroot . '/spool/openid/store';
a1af4a99 39 }
a1af4a99 40
34d91db6
VZ
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';
a1af4a99 47
34d91db6
VZ
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();
2d8779e2 51
34d91db6
VZ
52 return !is_a($this->request, 'Auth_OpenID_ServerError');
53 }
2d8779e2 54
34d91db6
VZ
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');
a1af4a99 61 }
a1af4a99 62
34d91db6
VZ
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 }
ab66bf7f 70
34d91db6
VZ
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';
a1af4a99 76 }
a1af4a99 77
34d91db6
VZ
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 }
a1af4a99 86
34d91db6 87 // SimpleRegistration helpers ----------------------------------------------
a1af4a99 88
34d91db6
VZ
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('HTTP/1.1 %d', $web_response->code), true, $web_response->code);
204
205 foreach ($web_response->headers as $key => $value) {
206 header(sprintf('%s: %s', $key, $value));
207 }
208
209 header('Connection: close');
210 print $web_response->body;
211 }
212 exit;
213 }
214
215 // URL providers -----------------------------------------------------------
216
217 // Returns the OpenId identity URL of the requested user.
218 private function GetUserUrl(User &$user)
219 {
220 return $this->base_url . '/' . $user->login();
221 }
222
223 // Returns the private XRDS page of a user.
224 private function GetUserXrdsUrl(User &$user)
225 {
226 return $this->base_url . '/xrds/' . $user->login();
227 }
228
229 // Returns the endpoint in the current request.
230 public function GetEndpoint()
231 {
232 return $this->request->trust_root;
233 }
234
235 // Extracts the OpenId arguments available in the current request, and
236 // builds a query string with them.
237 public function GetQueryStringForRequest()
238 {
239 foreach (Auth_OpenID::getQuery() as $key => $value) {
240 if (strpos($key, 'openid.') === 0) {
241 $args[$key] = $value;
242 }
243 }
244
245 return http_build_query($args);
246 }
2e5fbf5e
AA
247}
248
a1af4a99 249// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
34d91db6 250?>