<?php
/***************************************************************************
- * Copyright (C) 2003-2008 Polytechnique.org *
+ * Copyright (C) 2003-2011 Polytechnique.org *
* http://opensource.polytechnique.org/ *
* *
* This program is free software; you can redistribute it and/or modify *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
***************************************************************************/
+
+/* Definitions for the OpenId Specification
+ * http://openid.net/specs/openid-authentication-2_0.html
+ *
+ * OP Endpoint URL: https://www.polytechnique.org/openid
+ * OP Identifier: https://www.polytechnique.org/openid
+ * User Identifier: https://www.polytechnique.org/openid/{hruid}
+ * OP-Local Identifier: {hruid}
+ */
+
+/* This implementation supports two modes:
+ * - entering the OP Identifier, which can simply be 'polytechnique.org'
+ * - entering the User Identifier, or some URL that resolves there
+ * In both cases, Yadis discovery is made possible through the X-XRDS-Location
+ * header.
+ *
+ * In the former case, Yadis discovery is performed on /, or where it redirects;
+ * see platal.php. It resolves to the XRDS for this OP, and User Identifier
+ * selection is performed after forcing the user to log in. This only works for
+ * version 2.0 of the OpenId protocol.
+ *
+ * In the latter cas, Yadis discovery is performed on /openid/{hruid}. It
+ * resolves ta a user-specific XRDS. This page also features HTML-based
+ * discovery. This works with any version of the protocol.
+ */
+
+/* Testing suite is here:
+ * http://openidenabled.com/resources/openid-test/
+ * It only supports User Indentifiers.
+ *
+ * To test OP Identifiers, download the JanRain PHP library and use the
+ * consumer provided as an example (although it appears that a failure is
+ * mistakenly reported: 'Server denied check_authentication').
+ * Reading the source of the server can also help understanding the code below.
+ */
+
+
class OpenidModule extends PLModule
{
function handlers()
{
return array(
- 'openid' => $this->make_hook('openid', AUTH_PUBLIC),
- 'openid/idp_xrds' => $this->make_hook('idp_xrds', AUTH_PUBLIC),
- 'openid/user_xrds' => $this->make_hook('user_xrds', AUTH_PUBLIC),
- 'openid/trust' => $this->make_hook('trust', AUTH_PUBLIC),
+ 'openid' => $this->make_hook('openid', AUTH_PUBLIC),
+ 'openid/melix' => $this->make_hook('melix', AUTH_PUBLIC),
+ 'openid/xrds' => $this->make_hook('xrds', AUTH_PUBLIC),
+ 'openid/trust' => $this->make_hook('trust', AUTH_MDP),
+ 'openid/trusted' => $this->make_hook('trusted', AUTH_MDP),
+ 'admin/openid/trusted' => $this->make_hook('admin_trusted', AUTH_MDP, 'admin'),
);
}
- function init_openid()
+ function handler_openid($page, $login = null)
{
- require_once 'Auth/OpenID.php';
$this->load('openid.inc.php');
+ $requested_user = User::getSilent($login);
+ $server = new OpenId();
+
+ // Spec §4.1.2: if "openid.mode" is absent, we SHOULD assume that
+ // the request is not an OpenId message.
+ if (!$server->IsOpenIdRequest()) {
+ if ($requested_user) {
+ $server->RenderDiscoveryPage($page, $requested_user);
+ return;
+ } else {
+ pl_redirect('Xorg/OpenId');
+ }
+ exit;
+ }
+
+ // Initializes the OpenId environment from the request.
+ $server->Initialize();
+
+ // In modes 'checkid_immediate' and 'checkid_setup', we need to check
+ // by ourselves that we want to allow the user to be authenticated.
+ // Otherwise it can simply be forwarded to the Server object.
+ if ($server->IsAuthorizationRequest()) {
+ $authorized = S::logged() &&
+ $server->IsUserAuthorized(S::user()) &&
+ $server->IsEndpointTrusted(S::user());
+
+ if ($authorized) {
+ // TODO(vzanotti): SReg requests are currently not honored if
+ // the website is already trusted. We may want to redirect SReg
+ // requests to /openid/trust, to allow the user to choose.
+ $server->AnswerRequest(true);
+ } else if ($server->IsImmediateRequest()) {
+ $server->AnswerRequest(false);
+ } else {
+ // The user is currently not authorized to get her authorization
+ // request approved. Two possibilities:
+ // * the endpoint is not yet trusted => redirect to openid/trust
+ // * the user is not logged in => log in the user.
+ //
+ // The second case requires a special handling when the request
+ // was POSTed, as our current log in mechanism does not preserve
+ // POST arguments.
+ $openid_args = $server->GetQueryStringForRequest();
+ if (S::logged()) {
+ pl_redirect('openid/trust', $openid_args);
+ } else if (Post::has('openid_mode')) {
+ pl_redirect('openid', $openid_args);
+ } else {
+ return PL_DO_AUTH;
+ }
+ }
+ } else {
+ $server->HandleRequest();
+ }
+
+ // All requests should have been answered at this point. The best here
+ // is to get the user back to a safe page.
+ pl_redirect('');
}
- function handler_openid(&$page, $x = null)
+ function handler_melix($page, $login = null)
{
+ $this->load('openid.inc.php');
+
global $globals;
+ $melix = ($login ? $login . '@' . $globals->mail->alias_dom : null);
- // Determines the user whose openid we are going to display
- if (is_null($x)) {
- return PL_NOT_FOUND;
+ if ($melix && ($requested_user = User::getSilent($melix))) {
+ $server = new OpenId();
+ $server->RenderDiscoveryPage($page, $requested_user);
+ } else {
+ pl_redirect('Xorg/OpenId');
}
+ }
+
+ function handler_xrds($page, $login = null)
+ {
+ $this->load('openid.inc.php');
+ $requested_user = User::getSilent($login);
+ $server = new OpenId();
- $login = S::logged() ? User::get($x) : User::getSilent($x);
if (!$login) {
+ $server->RenderMainXrdsPage($page);
+ } else if ($requested_user) {
+ $server->RenderUserXrdsPage($page, $requested_user);
+ } else {
return PL_NOT_FOUND;
}
+ }
- // Include X-XRDS-Location response-header for Yadis discovery
- $user_xrds = $globals->baseurl . 'openid/user_xrds/' . $login->hruid;
- header('X-XRDS-Location: ' . $user_xrds);
+ function handler_trust($page)
+ {
+ $this->load('openid.inc.php');
+ $server = new OpenId();
+ $user = S::user();
+
+ // Initializes the OpenId environment from the request.
+ if (!$server->Initialize() || !$server->IsAuthorizationRequest()) {
+ $page->kill("Ta requête OpenID a échoué, merci de réessayer.");
+ }
- // Select template
- $page->changeTpl('openid/openid.tpl');
+ // Prepares the SREG data, if any is required.
+ $sreg_response = $server->GetSRegDataForRequest($user);
- // Sets the title of the html page.
- $page->setTitle($login->fullName());
+ // Asks the user about her trust level of the current request, if not
+ // done yet.
+ if (!Post::has('trust_accept') && !Post::has('trust_cancel')) {
+ $page->changeTpl('openid/trust.tpl');
+ $page->assign('openid_query', $server->GetQueryStringForRequest());
+ $page->assign('relying_party', $server->GetEndpoint());
+ $page->assign('sreg_data', $sreg_response->contents());
- // Sets the <link> tags for HTML-Based Discovery
- $page->addLink('openid.server openid2.provider',
- $globals->baseurl . '/openid');
- $page->addLink('openid.delegate openid2.local_id',
- $login->hruid);
+ return;
+ }
- // Adds the global user property array to the display.
- $page->assign_by_ref('user', $login);
+ // Interprets the form results, and updates the user whitelist.
+ S::assert_xsrf_token();
+ $trusted = $server->UpdateEndpointTrust(
+ $user,
+ Post::b('trust_accept') && !Post::b('trust_cancel'),
+ Post::b('trust_always'));
+
+ // Finally answers the request.
+ if ($server->IsUserAuthorized($user) && $trusted) {
+ $server->AnswerRequest(true, Post::b('trust_sreg') ? $sreg_response : null);
+ } else {
+ $server->AnswerRequest(false);
+ }
}
- function handler_idp_xrds(&$page)
+ function handler_trusted($page, $action = 'list', $id = null)
{
- global $globals;
-
- // Load constants
- require_once "Auth/OpenID/Discover.php";
-
- // Set XRDS content-type and template
- header('Content-type: application/xrds+xml');
- $page->changeTpl('openid/idp_xrds.tpl', NO_SKIN);
-
- // Set variables
- $page->changeTpl('openid/idp_xrds.tpl', NO_SKIN);
- $page->assign('type', Auth_OpenID_TYPE_2_0_IDP);
- $page->assign('uri', $globals->baseurl . '/openid');
+ $page->setTitle('Sites tiers de confiance');
+ $page->assign('title', 'Mes sites tiers de confiance pour OpenId');
+ $table_editor = new PLTableEditor('openid/trusted', 'account_auth_openid', 'id');
+ $table_editor->set_where_clause(XDB::format('uid = {?}', S::user()->id()));
+ $table_editor->vars['uid']['display'] = false;
+ $table_editor->describe('url', 'site tiers', true);
+ $page->assign('deleteonly', true);
+ $table_editor->apply($page, $action, $id);
}
- function handler_user_xrds(&$page, $x = null)
+ function handler_admin_trusted($page, $action = 'list', $id = null)
{
- global $globals;
-
- // Load constants
- require_once "Auth/OpenID/Discover.php";
-
- // Set XRDS content-type and template
- header('Content-type: application/xrds+xml');
- $page->changeTpl('openid/user_xrds.tpl', NO_SKIN);
-
- // Set variables
- $page->assign('type1', Auth_OpenID_TYPE_2_0);
- $page->assign('type2', Auth_OpenID_TYPE_1_1);
- $page->assign('uri', $globals->baseurl . '/openid');
+ $page->setTitle('Sites tiers de confiance');
+ $page->assign('title', 'Sites tiers de confiance globaux pour OpenId');
+ $table_editor = new PLTableEditor('admin/openid/trusted', 'account_auth_openid', 'id');
+ $table_editor->set_where_clause('uid IS NULL');
+ $table_editor->vars['uid']['display'] = false;
+ $table_editor->describe('url', 'site tiers', true);
+ $page->assign('readonly', true);
+ $table_editor->apply($page, $action, $id);
}
-
}
// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8: