Add simpleid-1.0.5
diff --git a/simpleid/www/extensions/ax/ax.extension.php b/simpleid/www/extensions/ax/ax.extension.php
new file mode 100644
index 0000000..1286c52
--- /dev/null
+++ b/simpleid/www/extensions/ax/ax.extension.php
@@ -0,0 +1,327 @@
+<?php
+/*
+ * SimpleID
+ *
+ * Copyright (C) Kelvin Mo 2009
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/**
+ * Implements the Attribute Exchange extension.
+ *
+ *
+ * @package simpleid
+ * @subpackage extensions
+ * @filesource
+ */
+
+/** Namespace for the AX extension */
+define('OPENID_NS_AX', 'http://openid.net/srv/ax/1.0');
+
+/** @ignore */
+global $ax_sreg_map;
+
+/**
+ * A mapping between Type URIs defined for Attribute Exchange and the corresponding
+ * property for the Simple Registration Extension
+ *
+ * @link http://www.axschema.org/types/#sreg
+ * @global array
+ */
+$ax_sreg_map = array(
+ 'http://axschema.org/namePerson/friendly' => 'nickname',
+ 'http://axschema.org/contact/email' => 'email',
+ 'http://axschema.org/namePerson' => 'fullname',
+ 'http://axschema.org/birthDate' => 'dob',
+ 'http://axschema.org/person/gender' => 'gender',
+ 'http://axschema.org/contact/postalCode/home' => 'postcode',
+ 'http://axschema.org/contact/country/home' => 'country',
+ 'http://axschema.org/pref/language' => 'language',
+ 'http://axschema.org/pref/timezone' => 'timezone',
+ 'http://openid.net/schema/namePerson/friendly' => 'nickname',
+ 'http://openid.net/schema/contact/internet/email' => 'email',
+ 'http://openid.net/schema/gender' => 'gender',
+ 'http://openid.net/schema/contact/postalCode/home' => 'postcode',
+ 'http://openid.net/schema/contact/country/home' => 'country',
+ 'http://openid.net/schema/language/pref' => 'language',
+ 'http://openid.net/schema/timezone' => 'timezone'
+);
+
+/**
+ * Returns the support for AX in SimpleID XRDS document
+ *
+ * @return array
+ * @see hook_xrds_types()
+ */
+function ax_xrds_types() {
+ return array(OPENID_NS_AX);
+}
+
+/**
+ * @see hook_response()
+ */
+function ax_response($assertion, $request) {
+ global $user;
+ global $version;
+ global $ax_sreg_map;
+
+ // We only deal with positive assertions
+ if (!$assertion) return array();
+
+ // We only respond if the extension is requested
+ if (!openid_extension_requested(OPENID_NS_AX, $request)) return array();
+
+ $request = openid_extension_filter_request(OPENID_NS_AX, $request);
+ if (!isset($request['mode'])) return array();
+ $mode = $request['mode'];
+
+ $response = array();
+ $alias = openid_extension_alias(OPENID_NS_AX);
+ $response['openid.ns.' . $alias] = OPENID_NS_AX;
+
+ if ($mode == 'fetch_request') {
+ $response['openid.' . $alias . '.mode'] = 'fetch_response';
+
+ $required = (isset($request['required'])) ? explode(',', $request['required']) : array();
+ $optional = (isset($request['if_available'])) ? explode(',', $request['if_available']) : array();
+ $fields = array_merge($required, $optional);
+
+ foreach ($fields as $field) {
+ $type = $request['type.' . $field];
+ $response['openid.' . $alias . '.type.' . $field] = $type;
+ $value = _ax_get_value($type);
+
+ if ($value == NULL) {
+ $response['openid.' . $alias . '.count.' . $field] = 0;
+ } elseif (is_array($value)) {
+ $response['openid.' . $alias . '.count.' . $field] = count($value);
+ for ($i = 0; $i < count($value); $i++) {
+ $response['openid.' . $alias . '.value.' . $field . '.' . ($i + 1)] = $value[$i];
+ }
+ } else {
+ $response['openid.' . $alias . '.value.' . $field] = $value;
+ }
+ }
+ } elseif ($mode == 'store_request') {
+ // Sadly, we don't support storage at this stage
+ $response['openid.' . $alias . '.mode'] = 'store_response_failure';
+ $response['openid.' . $alias . '.error'] = 'OpenID provider does not support storage of attributes';
+ }
+
+ return $response;
+}
+
+/**
+ * Returns an array of fields that need signing.
+ *
+ * @see hook_signed_fields()
+ */
+function ax_signed_fields($response) {
+ // We only respond if the extension is requested
+ if (!openid_extension_requested(OPENID_NS_AX, $response)) return array();
+
+ $fields = array_keys(openid_extension_filter_request(OPENID_NS_AX, $response));
+ $alias = openid_extension_alias(OPENID_NS_AX);
+ $signed_fields = array();
+
+ if (isset($response['openid.ns.' . $alias])) $signed_fields[] = 'ns.' . $alias;
+ foreach ($fields as $field) {
+ if (isset($response['openid.' . $alias . '.' . $field])) $signed_fields[] = $alias . '.' . $field;
+ }
+
+ return $signed_fields;
+}
+
+/**
+ * @see hook_consent_form()
+ */
+function ax_consent_form($request, $response, $rp) {
+ global $user;
+
+ // We only respond if the extension is requested
+ if (!openid_extension_requested(OPENID_NS_AX, $request)) return '';
+
+ $request = openid_extension_filter_request(OPENID_NS_AX, $request);
+ if (!isset($request['mode'])) return '';
+ $mode = $request['mode'];
+
+ $xtpl2 = new XTemplate('extensions/ax/ax.xtpl');
+
+ if ($mode == 'fetch_request') {
+ $xtpl2->assign('alias', openid_extension_alias(OPENID_NS_AX));
+
+ $required = (isset($request['required'])) ? explode(',', $request['required']) : array();
+ $optional = (isset($request['if_available'])) ? explode(',', $request['if_available']) : array();
+ $fields = array_merge($required, $optional);
+ $i = 1;
+
+ foreach ($fields as $field) {
+ $type = $request['type.' . $field];
+ $value = _ax_get_value($type);
+
+ $xtpl2->assign('name', htmlspecialchars($type, ENT_QUOTES, 'UTF-8'));
+ $xtpl2->assign('id', $i);
+
+ if (is_array($value)) {
+ $xtpl2->assign('value', htmlspecialchars(implode(',', $value), ENT_QUOTES, 'UTF-8'));
+ } elseif ($value != NULL) {
+ $xtpl2->assign('value', htmlspecialchars($value, ENT_QUOTES, 'UTF-8'));
+ }
+
+ $xtpl2->assign('checked', (in_array($field, $required) || !isset($rp['ax_consents']) || in_array($field, $rp['ax_consents'])) ? 'checked="checked"' : '');
+ $xtpl2->assign('disabled', (in_array($field, $required)) ? 'disabled="disabled"' : '');
+ if (in_array($field, $required)) $xtpl2->parse('fetch_request.ax.required');
+
+ $xtpl2->parse('fetch_request.ax');
+
+ $i++;
+ }
+
+ $xtpl2->assign('ax_data', t('SimpleID will also be sending the following information to the site.'));
+ $xtpl2->assign('name_label', t('Type URL'));
+ $xtpl2->assign('value_label', t('Value'));
+
+ $xtpl2->parse('fetch_request');
+ return $xtpl2->text('fetch_request');
+ } elseif ($mode == 'store_request') {
+ // Sadly, we don't support storage at this stage
+ $xtpl2->assign('store_request_message', t('This web site requested to store information about you on SimpleID. Sadly, SimpleID does not support this feature.'));
+ $xtpl2->parse('store_request');
+ return $xtpl2->text('store_request');
+ }
+}
+
+/**
+ * @see hook_consent()
+ */
+function ax_consent($form_request, &$response, &$rp) {
+ // We only respond if the extension is requested
+ if (!openid_extension_requested(OPENID_NS_AX, $response)) return array();
+
+ $fields = array_keys(openid_extension_filter_request(OPENID_NS_AX, $response));
+ $alias = openid_extension_alias(OPENID_NS_AX);
+
+ foreach ($fields as $field) {
+ if ((strpos($field, 'value.') !== 0) && (strpos($field, 'count.') !== 0)) continue;
+
+ $type_alias = (strpos($field, '.', 6) === FALSE) ? substr($field, 6) : substr($field, strpos($field, '.', 6) - 6);
+ $type = $response['openid.' . $alias . '.type.' . $type_alias];
+
+ if (isset($response['openid.' . $alias . '.' . $field])) {
+ if (!in_array($type, $form_request['ax_consents'])) {
+ unset($response['openid.' . $alias . '.' . $field]);
+ }
+ }
+ }
+ foreach ($fields as $field) {
+ if (strpos($field, 'type.') !== 0) continue;
+ $type = $response['openid.' . $alias . '.' . $field];
+
+ if (isset($response['openid.' . $alias . '.' . $field])) {
+ if (!in_array($type, $form_request['ax_consents'])) {
+ unset($response['openid.' . $alias . '.' . $field]);
+ }
+ }
+ }
+
+ if (count(array_keys(openid_extension_filter_request(OPENID_NS_AX, $response))) == 0) {
+ // We have removed all the responses, so we remove the namespace as well
+ unset($response['openid.ns.' . $alias]);
+ }
+
+ $rp['ax_consents'] = $form_request['ax_consents'];
+}
+
+/**
+ * @see hook_page_profile()
+ */
+function ax_page_profile() {
+ global $user;
+ $xtpl2 = new XTemplate('extensions/ax/ax.xtpl');
+
+ if (isset($user['ax'])) {
+ foreach ($user['ax'] as $name => $value) {
+ $xtpl2->assign('name', htmlspecialchars($name, ENT_QUOTES, 'UTF-8'));
+ $xtpl2->assign('value', htmlspecialchars($value, ENT_QUOTES, 'UTF-8'));
+ $xtpl2->parse('user_page.ax');
+ }
+ }
+
+ $xtpl2->assign('ax_data', t('SimpleID will send the following information to sites which supports the Attribute Exchange Extension. If you have also supplied OpenID Connect user information in your identity, or have the Simple Registration Extension installed, these may also be sent as part of this Extension.'));
+ $xtpl2->assign('edit_identity_file', t('To change these, <a href="!url">edit your identity file</a>.', array('!url' => 'http://simpleid.org/docs/1/identity-files/')));
+ $xtpl2->assign('name_label', t('Type URL'));
+ $xtpl2->assign('value_label', t('Value'));
+
+ $xtpl2->parse('user_page');
+
+ return array(array(
+ 'id' => 'ax',
+ 'title' => t('Attribute Exchange Extension'),
+ 'content' => $xtpl2->text('user_page')
+ ));
+}
+
+/**
+ * Looks up the value of a specified Attribute Exchange Extension type URI.
+ *
+ * This function looks up the ax section of the user's identity file. If the
+ * specified type cannot be found, it looks up the corresponding field in the
+ * OpenID Connect user information (user_info section) and the Simple Registration
+ * Extension (sreg section).
+ *
+ * @param string $type the type URI to look up
+ * @return string the value or NULL if not found
+ */
+function _ax_get_value($type) {
+ global $user;
+ global $ax_sreg_map;
+
+ if (isset($user['ax'][$type])) {
+ return $user['ax'][$type];
+ } else {
+ // Look up OpenID Connect
+ switch ($type) {
+ case 'http://axschema.org/namePerson/friendly':
+ if (isset($user['user_info']['nickname'])) return $user['user_info']['nickname'];
+ break;
+ case 'http://axschema.org/contact/email':
+ if (isset($user['user_info']['email'])) return $user['user_info']['email'];
+ break;
+ case 'http://axschema.org/namePerson':
+ if (isset($user['user_info']['name'])) return $user['user_info']['name'];
+ break;
+ case 'http://axschema.org/pref/timezone':
+ if (isset($user['user_info']['zoneinfo'])) return $user['user_info']['zoneinfo'];
+ break;
+ case 'http://axschema.org/person/gender':
+ if (isset($user['user_info']['gender'])) return strtoupper(substr($user['user_info']['gender'], 0, 1));
+ break;
+ case 'http://axschema.org/contact/postalCode/home':
+ if (isset($user['user_info']['address']['postal_code'])) return $user['user_info']['address']['postcal_code'];
+ break;
+ }
+
+ // Look up sreg
+ if (isset($ax_sreg_map[$type]) && isset($user['sreg'][$ax_sreg_map[$type]])) {
+ return $user['sreg'][$ax_sreg_map[$type]];
+ } else {
+ return NULL;
+ }
+ }
+}
+?>
diff --git a/simpleid/www/extensions/ax/ax.xtpl b/simpleid/www/extensions/ax/ax.xtpl
new file mode 100644
index 0000000..bf9edbe
--- /dev/null
+++ b/simpleid/www/extensions/ax/ax.xtpl
@@ -0,0 +1,44 @@
+<!-- BEGIN: user_page -->
+<!-- :mode=html: $Id$ -->
+ <p>{ax_data}</p>
+
+ <p>{edit_identity_file}</p>
+
+ <table>
+ <tr>
+ <th>{name_label}</th>
+ <th>{value_label}</th>
+ </tr>
+ <!-- BEGIN: ax -->
+ <tr>
+ <td>{name}</td>
+ <td>{value}</td>
+ </tr>
+ <!-- END: ax -->
+ </table>
+<!-- END: user_page -->
+
+<!-- BEGIN: fetch_request -->
+ <p>{ax_data}</p>
+
+ <table>
+ <tr>
+ <th></th>
+ <th>{name_label}</th>
+ <th>{value_label}</th>
+ </tr>
+ <!-- BEGIN: ax -->
+ <tr>
+ <td><input name="ax_consents[]" type="checkbox" value="{name}" id="ax-consents-{id}" {checked} {disabled} /><!-- BEGIN: required --><input name="ax_consents[]" type="hidden" value="{name}" /><!-- END: required --></td>
+ <td><label for="ax-consents-{id}">{name}</label></td>
+ <td>{value}</td>
+ </tr>
+ <!-- END: ax -->
+ </table>
+<!-- END: fetch_request -->
+
+<!-- BEGIN: store_request -->
+<div class="message">
+ <p>{store_request_message}</p>
+</div>
+<!-- END: store_request -->
diff --git a/simpleid/www/extensions/certauth/certauth.extension.php b/simpleid/www/extensions/certauth/certauth.extension.php
new file mode 100644
index 0000000..b442d93
--- /dev/null
+++ b/simpleid/www/extensions/certauth/certauth.extension.php
@@ -0,0 +1,88 @@
+<?php
+/*
+ * SimpleID
+ *
+ * Copyright (C) Kelvin Mo 2012
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/**
+ * Authentication using a SSL client certificate.
+ *
+ * @package simpleid
+ * @subpackage extensions
+ * @filesource
+ */
+
+
+/**
+ * Attempt to login using a SSL client certificate.
+ *
+ * Note that the web server must be set up to request a SSL client certificate
+ * and pass the certificate's details to PHP.
+ */
+function certauth_user_auto_login() {
+ if (!_certauth_has_client_cert()) return NULL;
+
+ $cert = trim($_SERVER['SSL_CLIENT_M_SERIAL']) . ';' . trim($_SERVER['SSL_CLIENT_I_DN']);
+ log_debug('Client SSL certificate: ' . $cert);
+
+ $uid = store_get_uid_from_cert($cert);
+ if ($uid != NULL) {
+ log_debug('Client SSL certificate accepted for ' . $uid);
+ return user_load($uid);
+ } else {
+ log_warn('Client SSL certificate presented, but no user with that certificate exists.');
+ return NULL;
+ }
+}
+
+/**
+ * Determines whether the user agent supplied valid a certificate identifying the
+ * user.
+ *
+ * A valid certificate is supplied if all of the following occurs:
+ *
+ * - the connection is done using HTTPS (i.e. {@link is_https()} is true)
+ * - the web server has been set up to request a certificate from the user agent
+ * - the web server has been set up to pass the certificate details to PHP
+ * - the certificate has not been revoked
+ * - the certificate contains a serial number and a valid issuer
+ *
+ * @return true if the user agent has supplied a valid SSL certificate
+ */
+function _certauth_has_client_cert() {
+ // False if we are not in HTTP
+ if (!is_https()) return false;
+
+ // False if certificate is not valid
+ if (!isset($_SERVER['SSL_CLIENT_VERIFY']) || ($_SERVER['SSL_CLIENT_VERIFY'] !== 'SUCCESS')) return false;
+
+ // False if certificate is expired or has no expiry date
+ if (!isset($_SERVER['SSL_CLIENT_V_REMAIN']) || ($_SERVER['SSL_CLIENT_V_REMAIN'] < 0)) return false;
+ if (!isset($_SERVER['SSL_CLIENT_V_END'])) return false;
+
+ // False if no serial number
+ if (!isset($_SERVER['SSL_CLIENT_M_SERIAL'])) return false;
+
+ // False if no issuer
+ if (!isset($_SERVER['SSL_CLIENT_I_DN'])) return false;
+
+ return true;
+}
+?>
diff --git a/simpleid/www/extensions/pape/pape.extension.php b/simpleid/www/extensions/pape/pape.extension.php
new file mode 100644
index 0000000..e189f2e
--- /dev/null
+++ b/simpleid/www/extensions/pape/pape.extension.php
@@ -0,0 +1,200 @@
+<?php
+/*
+ * SimpleID
+ *
+ * Copyright (C) Kelvin Mo 2009
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/**
+ * Implements the Provider Authentication Policy Extension extension.
+ *
+ *
+ * @package simpleid
+ * @subpackage extensions
+ * @filesource
+ */
+
+/** Namespace for the PAPE extension */
+define('OPENID_NS_PAPE', 'http://specs.openid.net/extensions/pape/1.0');
+
+/** Namespaces for PAPE policies */
+define('PAPE_POLICY_NONE', 'http://schemas.openid.net/pape/policies/2007/06/none');
+define('PAPE_POLICY_PPID', 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier');
+
+/** Namespaces for PAPE levels */
+define('PAPE_LEVEL_NIST800_63', 'http://csrc.nist.gov/publications/nistpubs/800-63/SP800-63V1_0_2.pdf');
+
+/**
+ * Returns the support for PAPE in SimpleID XRDS document
+ *
+ * @return array
+ * @see hook_xrds_types()
+ */
+function pape_xrds_types() {
+ return array(
+ OPENID_NS_PAPE,
+ PAPE_POLICY_PPID,
+ PAPE_LEVEL_NIST800_63
+ );
+}
+
+/**
+ * @see hook_checkid_identity()
+ */
+function pape_checkid_identity($request, $identity, $immediate) {
+ global $user;
+
+ // We only respond if the extension is requested
+ if (!openid_extension_requested(OPENID_NS_PAPE, $request)) return null;
+
+ // See if we are choosing an identity and save for later
+ // This may be used by pape_response() to produce a private identifier
+ if ($request['openid.identity'] == OPENID_IDENTIFIER_SELECT) _pape_identifier_select(true);
+
+ $pape_request = openid_extension_filter_request(OPENID_NS_PAPE, $request);
+
+ // If the relying party provides a max_auth_age
+ if (isset($pape_request['max_auth_age'])) {
+ // If we are not logged in then we don't need to do anything
+ if ($user == NULL) return NULL;
+
+ // If the last time we logged on actively (i.e. using a password) is greater than
+ // max_auth_age, we then require the user to log in again
+ if ((!isset($user['auth_active']) || !$user['auth_active'])
+ && ((time() - $user['auth_time']) > $pape_request['max_auth_age'])) {
+ set_message(t('This web site\'s policy requires you to log in again to confirm your identity.'));
+
+ _user_logout();
+ return CHECKID_LOGIN_REQUIRED;
+ }
+ }
+}
+
+/**
+ * @see hook_response()
+ */
+function pape_response($assertion, $request) {
+ global $user, $version;
+
+ // We only deal with positive assertions
+ if (!$assertion) return array();
+
+ // We only respond if we are using OpenID 2 or later
+ if ($version < OPENID_VERSION_2) return array();
+
+ // Get what is requested
+ $pape_request = openid_extension_filter_request(OPENID_NS_PAPE, $request);
+
+ // If the extension is requested, we use the same alias, otherwise, we
+ // make one up
+ $alias = openid_extension_alias(OPENID_NS_PAPE, 'pape');
+ $response = array();
+
+ // The PAPE specification recommends us to respond even when the extension
+ // is not present in the request.
+ $response['openid.ns.' . $alias] = OPENID_NS_PAPE;
+
+ // We return the last time the user logged in using the login form
+ $response['openid.' . $alias . '.auth_time'] = gmstrftime('%Y-%m-%dT%H:%M:%SZ', $user['auth_time']);
+
+ // We don't comply with NIST_SP800-63
+ $response['openid.' . $alias . '.auth_level.ns.nist'] = PAPE_LEVEL_NIST800_63;
+ $response['openid.' . $alias . '.auth_level.nist'] = 0;
+
+ // The default is that we don't apply any authentication policies. This can be changed later in the
+ // function
+ $response['openid.' . $alias . '.auth_policies'] = PAPE_POLICY_NONE;
+
+ // Now we go through the authentication policies
+ if (isset($pape_request['preferred_auth_policies'])) {
+ $policies = preg_split('/\s+/', $pape_request['preferred_auth_policies']);
+
+ if (in_array(PAPE_POLICY_PPID, $policies)) {
+ // We want a ppid. Check that the authentication request is correct
+ if (_pape_identifier_select()) {
+ $realm = openid_get_realm($request, $version);
+ $identity = $request['openid.identity'];
+
+ $ppid = _pape_ppid($identity, $realm);
+ $response['openid.claimed_id'] = $ppid;
+ $response['openid.identity'] = $ppid;
+ }
+ }
+ }
+
+ return $response;
+}
+
+/**
+ * Returns an array of fields that need signing.
+ *
+ * @see hook_signed_fields()
+ */
+function pape_signed_fields($response) {
+ $fields = array_keys(openid_extension_filter_request(OPENID_NS_PAPE, $response));
+ $alias = openid_extension_alias(OPENID_NS_PAPE);
+ $signed_fields = array();
+
+ if (isset($response['openid.ns.' . $alias])) $signed_fields[] = 'ns.' . $alias;
+ foreach ($fields as $field) {
+ if (isset($response['openid.' . $alias . '.' . $field])) $signed_fields[] = $alias . '.' . $field;
+ }
+
+ return $signed_fields;
+}
+
+/**
+ * Sets and returns whether the current OpenID request is requesting an identity.
+ *
+ * @param bool $identifier_select
+ * @return bool whether the current OpenID request is requesting an identity
+ */
+function _pape_identifier_select($identifier_select = NULL) {
+ static $static_identifier_select = false;
+
+ if (!is_null($identifier_select)) $static_identifier_select = $identifier_select;
+
+ return $static_identifier_select;
+}
+
+/**
+ * Generates a private personal identifier (PPID). The PPID is an opaque identifier
+ * for a particular user-RP pair
+ *
+ * @param string $identity the identity of the user
+ * @param string $realm the URL of the relying party
+ * @return string the PPID
+ */
+function _pape_ppid($identity, $realm) {
+ // We are reusing the site-token from get_form_token() in common.inc
+ if (store_get('site-token') == NULL) {
+ $site_token = mt_rand();
+ store_set('site-token', $site_token);
+ } else {
+ $site_token = store_get('site-token');
+ }
+
+ $parts = parse_url($realm);
+ $host = $parts['host'];
+ if (strstr($host, 'www.') === 0) $host = substr($host, 4);
+
+ return simpleid_url('ppid/' . md5($site_token . $identity . $host));
+}
+
+?>
diff --git a/simpleid/www/extensions/sreg/sreg.extension.php b/simpleid/www/extensions/sreg/sreg.extension.php
new file mode 100644
index 0000000..955d6f6
--- /dev/null
+++ b/simpleid/www/extensions/sreg/sreg.extension.php
@@ -0,0 +1,240 @@
+<?php
+/*
+ * SimpleID
+ *
+ * Copyright (C) Kelvin Mo 2007-8
+ *
+ * Includes code Drupal OpenID module (http://drupal.org/project/openid)
+ * Rowan Kerr <rowan@standardinteractive.com>
+ * James Walker <james@bryght.com>
+ *
+ * Copyright (C) Rowan Kerr and James Walker
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/**
+ * Implements the Simple Registration extension.
+ *
+ *
+ * @package simpleid
+ * @subpackage extensions
+ * @filesource
+ */
+
+/** Namespace for the Simple Registration extension */
+define('OPENID_NS_SREG', 'http://openid.net/extensions/sreg/1.1');
+
+/**
+ * @see hook_response()
+ */
+function sreg_response($assertion, $request) {
+ global $user;
+ global $version;
+
+ // We only deal with positive assertions
+ if (!$assertion) return array();
+
+ // We only respond if the extension is requested
+ if (!openid_extension_requested(OPENID_NS_SREG, $request)) return array();
+
+ $request = openid_extension_filter_request(OPENID_NS_SREG, $request);
+ $required = (isset($request['required'])) ? explode(',', $request['required']) : array();
+ $optional = (isset($request['optional'])) ? explode(',', $request['optional']) : array();
+ $fields = array_merge($required, $optional);
+ $alias = openid_extension_alias(OPENID_NS_SREG);
+ $response = array();
+
+ if ($version == OPENID_VERSION_2) $response['openid.ns.' . $alias] = OPENID_NS_SREG;
+
+ foreach ($fields as $field) {
+ $value = _sreg_get_value($field);
+
+ if ($value != NULL) $response['openid.' . $alias . '.' . $field] = $value;
+ }
+
+ return $response;
+}
+
+/**
+ * Returns an array of fields that need signing.
+ *
+ * @see hook_signed_fields()
+ */
+function sreg_signed_fields($response) {
+ // We only respond if the extension is requested
+ if (!openid_extension_requested(OPENID_NS_SREG, $response)) return array();
+
+ $fields = array_keys(openid_extension_filter_request(OPENID_NS_SREG, $response));
+ $alias = openid_extension_alias(OPENID_NS_SREG);
+ $signed_fields = array();
+
+ if (isset($response['openid.ns.' . $alias])) $signed_fields[] = 'ns.' . $alias;
+ foreach ($fields as $field) {
+ if (isset($response['openid.' . $alias . '.' . $field])) $signed_fields[] = $alias . '.' . $field;
+ }
+
+ return $signed_fields;
+}
+
+/**
+ * @see hook_consent_form()
+ */
+function sreg_consent_form($request, $response, $rp) {
+ global $user;
+
+ // We only respond if the extension is requested
+ if (!openid_extension_requested(OPENID_NS_SREG, $request)) return '';
+
+ $request = openid_extension_filter_request(OPENID_NS_SREG, $request);
+ $required = (isset($request['required'])) ? explode(',', $request['required']) : array();
+ $optional = (isset($request['optional'])) ? explode(',', $request['optional']) : array();
+ $fields = array_merge($required, $optional);
+
+ if ((count($request)) && isset($user['sreg'])) {
+ $xtpl2 = new XTemplate('extensions/sreg/sreg.xtpl');
+
+ $xtpl2->assign('alias', openid_extension_alias(OPENID_NS_SREG));
+
+ if (isset($request['policy_url'])) {
+ $xtpl2->assign('policy', t('You can view the site\'s policy in relation to the use of this information at this URL: <a href="@url">@url</a>.', array('@url' => $request['policy_url'])));
+ }
+
+ foreach ($fields as $field) {
+ $value = _sreg_get_value($field);
+
+ if ($value != NULL) {
+ $xtpl2->assign('name', htmlspecialchars($field, ENT_QUOTES, 'UTF-8'));
+ $xtpl2->assign('value', htmlspecialchars($value, ENT_QUOTES, 'UTF-8'));
+
+ $xtpl2->assign('checked', (in_array($field, $required) || !isset($rp['sreg_consents']) || in_array($field, $rp['sreg_consents'])) ? 'checked="checked"' : '');
+ $xtpl2->assign('disabled', (in_array($field, $required)) ? 'disabled="disabled"' : '');
+ if (in_array($field, $required)) $xtpl2->parse('form.sreg.required');
+
+ $xtpl2->parse('form.sreg');
+ }
+ }
+
+ $xtpl2->assign('sreg_data', t('SimpleID will also be sending the following registration information to the site.'));
+ $xtpl2->assign('name_label', t('Name'));
+ $xtpl2->assign('value_label', t('Value'));
+
+ $xtpl2->parse('form');
+ return $xtpl2->text('form');
+ }
+}
+
+/**
+ * @see hook_consent()
+ */
+function sreg_consent($form_request, &$response, &$rp) {
+ // We only respond if the extension is requested
+ if (!openid_extension_requested(OPENID_NS_SREG, $response)) return;
+
+ $fields = array_keys(openid_extension_filter_request(OPENID_NS_SREG, $response));
+ $alias = openid_extension_alias(OPENID_NS_SREG);
+
+ foreach ($fields as $field) {
+ if (isset($response['openid.' . $alias . '.' . $field])) {
+ if (!in_array($field, $form_request['sreg_consents'])) {
+ unset($response['openid.' . $alias . '.' . $field]);
+ }
+ }
+ }
+
+ if (count(array_keys(openid_extension_filter_request(OPENID_NS_SREG, $response))) == 0) {
+ // We have removed all the responses, so we remove the namespace as well
+ unset($response['openid.ns.' . $alias]);
+ }
+
+ $rp['sreg_consents'] = $form_request['sreg_consents'];
+}
+
+/**
+ * @see hook_page_profile()
+ */
+function sreg_page_profile() {
+ global $user;
+ $xtpl2 = new XTemplate('extensions/sreg/sreg.xtpl');
+
+ if (isset($user['sreg'])) {
+ foreach ($user['sreg'] as $name => $value) {
+ $xtpl2->assign('name', htmlspecialchars($name, ENT_QUOTES, 'UTF-8'));
+ $xtpl2->assign('value', htmlspecialchars($value, ENT_QUOTES, 'UTF-8'));
+ $xtpl2->parse('user_page.sreg');
+ }
+ }
+
+ $xtpl2->assign('sreg_data', t('SimpleID will send the following information to sites which supports the Simple Registration Extension.'));
+ $xtpl2->assign('connect_data', t('If you have also supplied OpenID Connect user information in your identity file, these may also be sent as part of this Extension.'));
+ $xtpl2->assign('edit_identity_file', t('To change these, <a href="!url">edit your identity file</a>.', array('!url' => 'http://simpleid.org/docs/1/identity-files/')));
+ $xtpl2->assign('name_label', t('Name'));
+ $xtpl2->assign('value_label', t('Value'));
+
+ $xtpl2->parse('user_page');
+
+ return array(array(
+ 'id' => 'sreg',
+ 'title' => t('Simple Registration Extension'),
+ 'content' => $xtpl2->text('user_page')
+ ));
+}
+
+
+/**
+ * Looks up the value of a specified Simple Registration Extension field.
+ *
+ * This function looks up the sreg section of the user's identity file. If the
+ * specified field cannot be found, it looks up the corresponding field in the
+ * OpenID Connect user information (user_info section).
+ *
+ * @param string $field the field to look up
+ * @return string the value or NULL if not found
+ */
+function _sreg_get_value($field) {
+ global $user;
+
+ if (isset($user['sreg'][$field])) {
+ return $user['sreg'][$field];
+ } else {
+ switch ($field) {
+ case 'nickname':
+ case 'email':
+ if (isset($user['user_info'][$field])) return $user['user_info'][$field];
+ break;
+ case 'fullname':
+ if (isset($user['user_info']['name'])) return $user['user_info']['name'];
+ break;
+ case 'timezone':
+ if (isset($user['user_info']['zoneinfo'])) return $user['user_info']['zoneinfo'];
+ break;
+ case 'gender':
+ if (isset($user['user_info']['gender'])) return strtoupper(substr($user['user_info']['gender'], 0, 1));
+ break;
+ case 'postcode':
+ if (isset($user['user_info']['address']['postal_code'])) return $user['user_info']['address']['postcal_code'];
+ break;
+ default:
+ return NULL;
+ }
+ return NULL;
+ }
+}
+
+
+
+?>
diff --git a/simpleid/www/extensions/sreg/sreg.xtpl b/simpleid/www/extensions/sreg/sreg.xtpl
new file mode 100644
index 0000000..07550bb
--- /dev/null
+++ b/simpleid/www/extensions/sreg/sreg.xtpl
@@ -0,0 +1,40 @@
+<!-- BEGIN: user_page -->
+<!-- :mode=html: $Id$ -->
+ <p>{sreg_data}</p>
+
+ <p>{connect_data}</p>
+
+ <p>{edit_identity_file}</p>
+
+ <table>
+ <tr>
+ <th>{name_label}</th>
+ <th>{value_label}</th>
+ </tr>
+ <!-- BEGIN: sreg -->
+ <tr>
+ <td>{name}</td>
+ <td>{value}</td>
+ </tr>
+ <!-- END: sreg -->
+ </table>
+<!-- END: user_page -->
+
+<!-- BEGIN: form -->
+ <p>{sreg_data} {policy}</p>
+
+ <table>
+ <tr>
+ <th></th>
+ <th>{name_label}</th>
+ <th>{value_label}</th>
+ </tr>
+ <!-- BEGIN: sreg -->
+ <tr>
+ <td><input name="sreg_consents[]" type="checkbox" value="{name}" id="sreg-consents-{name}" {checked} {disabled} /><!-- BEGIN: required --><input name="sreg_consents[]" type="hidden" value="{name}" /><!-- END: required --></td>
+ <td><input type="hidden" name="openid.{alias}.{name}" value="{value}" /><label for="sreg-consents-{name}">{name}</label></td>
+ <td>{value}</td>
+ </tr>
+ <!-- END: sreg -->
+ </table>
+<!-- END: form -->
diff --git a/simpleid/www/extensions/ui/ui.css b/simpleid/www/extensions/ui/ui.css
new file mode 100644
index 0000000..a6b9cfd
--- /dev/null
+++ b/simpleid/www/extensions/ui/ui.css
@@ -0,0 +1,31 @@
+/*
+ * SimpleID
+ *
+ * Copyright (C) Kelvin Mo 2009
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+.dialog-page {
+ background: #FFFFFF;
+}
+
+.dialog-page #content {
+ margin: 10px auto;
+ padding: 0;
+ border: 0;
+}
diff --git a/simpleid/www/extensions/ui/ui.extension.php b/simpleid/www/extensions/ui/ui.extension.php
new file mode 100644
index 0000000..3982be0
--- /dev/null
+++ b/simpleid/www/extensions/ui/ui.extension.php
@@ -0,0 +1,260 @@
+<?php
+/*
+ * SimpleID
+ *
+ * Copyright (C) Kelvin Mo 2009
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/**
+ * Implements the popup and icon modes from the User Interface extension
+ *
+ * @package simpleid
+ * @subpackage extensions
+ * @filesource
+ */
+
+/** Namespace for the User Interface extension */
+define('OPENID_NS_UI', 'http://specs.openid.net/extensions/ui/1.0');
+
+/**
+ * Returns the popup mode in SimpleID XRDS document
+ *
+ * @return array
+ * @see hook_xrds_types()
+ */
+function ui_xrds_types() {
+ return array(
+ 'http://specs.openid.net/extensions/ui/1.0/mode/popup',
+ 'http://specs.openid.net/extensions/ui/1.0/icon'
+ );
+}
+
+/**
+ * Detects the openid.ui.x-has-session parameter and processes it accordingly.
+ *
+ * @return array
+ * @see hook_response()
+ */
+function ui_response($assertion, $request) {
+ global $user;
+ global $version;
+
+ // We only deal with negative assertions
+ if ($assertion) return array();
+
+ // We only respond if the extension is requested
+ if (!openid_extension_requested(OPENID_NS_UI, $request)) return array();
+
+ // We only deal with openid.ui.x-has-session requests
+ $filtered_request = openid_extension_filter_request(OPENID_NS_UI, $request);
+ if (!isset($filtered_request['mode']) || ($filtered_request['mode'] != 'x-has-session')) return array();
+
+ // If user is null, there is no active session
+ if ($user == NULL) return array();
+
+ // There is an active session
+ $alias = openid_extension_alias(OPENID_NS_UI);
+ $response = array();
+
+ $response['openid.ns.' . $alias] = OPENID_NS_UI;
+ $response['openid.' . $alias . '.mode'] = 'x-has-session';
+
+ return $response;
+}
+
+/**
+ * Returns an array of fields that need signing.
+ *
+ * @see hook_signed_fields()
+ */
+function ui_signed_fields($response) {
+ // We only respond if the extension is requested
+ if (!openid_extension_requested(OPENID_NS_UI, $response)) return array();
+
+ $fields = array_keys(openid_extension_filter_request(OPENID_NS_UI, $response));
+ $alias = openid_extension_alias(OPENID_NS_UI);
+ $signed_fields = array();
+
+ if (isset($response['openid.ns.' . $alias])) $signed_fields[] = 'ns.' . $alias;
+ foreach ($fields as $field) {
+ if (isset($response['openid.' . $alias . '.' . $field])) $signed_fields[] = $alias . '.' . $field;
+ }
+
+ return $signed_fields;
+}
+
+/**
+ * Detects the presence of the UI extension and modifies the login form
+ * accordingly.
+ *
+ * @param string $destination
+ * @param string $state
+ * @see hook_user_login_form()
+ */
+function ui_user_login_form($destination, $state) {
+ if (($destination != 'continue') || (!$state)) return;
+
+ $request = unpickle($state);
+ openid_parse_request($request);
+
+ // Skip if popup does not exist
+ if (!openid_extension_requested(OPENID_NS_UI, $request)) return;
+
+ $filtered_request = openid_extension_filter_request(OPENID_NS_UI, $request);
+
+ if (isset($filtered_request['mode']) && ($filtered_request['mode'] == 'popup')) _ui_insert_css_js();
+
+ return;
+}
+
+/**
+ * Detects the presence of the UI extension and modifies the relying party
+ * verification form accordingly.
+ *
+ * @param array $request
+ * @param array $response
+ * @param array $rp
+ * @return string
+ * @see hook_consent_form()
+ */
+function ui_consent_form($request, $response, $rp) {
+ // Skip if popup does not exist
+ if (!openid_extension_requested(OPENID_NS_UI, $request)) return '';
+
+ $filtered_request = openid_extension_filter_request(OPENID_NS_UI, $request);
+
+ if (isset($filtered_request['mode']) && ($filtered_request['mode'] == 'popup')) _ui_insert_css_js();
+
+ if (isset($filtered_request['icon']) && ($filtered_request['icon'] == 'true')) {
+ global $xtpl;
+
+ $realm = $request['openid.realm'];
+ $icon_url = simpleid_url('ui/icon', 'realm=' . rawurlencode($realm) . '&tk=' . _ui_icon_token($realm));
+
+ $xtpl->assign('icon_url', htmlspecialchars($icon_url, ENT_QUOTES, 'UTF-8'));
+ $xtpl->parse('main.openid_consent.icon');
+ }
+
+ return '';
+}
+
+/**
+ * Specifies that the OpenID response should be sent via the fragment
+ *
+ */
+function ui_indirect_response($url, $response) {
+ global $openid_ns_to_alias;
+ if (!array_key_exists(OPENID_NS_UI, $openid_ns_to_alias)) return NULL;
+
+ // Cheat - if we run this, then the redirect page will also be themed!
+ _ui_insert_css_js();
+
+ if (strstr($url, '#')) {
+ return OPENID_RESPONSE_FRAGMENT;
+ } else {
+ return NULL;
+ }
+}
+
+/**
+ * Adds an extra route to the SimpleWeb framework.
+ */
+function ui_routes() {
+ return array('ui/icon' => 'ui_icon');
+}
+
+/**
+ * Returns an icon.
+ */
+function ui_icon() {
+ if (!isset($_GET['realm']) || !isset($_GET['tk']) || ($_GET['tk'] != _ui_icon_token($_GET['realm']))) {
+ header_response_code('404 Not Found');
+ indirect_fatal_error(t('Invalid UI icon parameters.'));
+ }
+
+ $realm = $_GET['realm'];
+ $icon_res = _ui_get_icon($realm);
+
+ if ($icon_res === NULL) {
+ header_response_code('404 Not Found');
+ indirect_fatal_error(t('Unable to get icon.'));
+ }
+
+ header('Via: ' . $icon_res['protocol'] . ' simpleid-ui-icon-' . md5($realm));
+ header('Cache-Control: max-age=86400');
+ header('Content-Type: ' . $icon_res['headers']['content-type']);
+ if (isset($icon_res['headers']['content-encoding'])) header('Content-Encoding: ' . $icon_res['headers']['content-encoding']);
+ print $icon_res['data'];
+}
+
+/**
+ * Inserts the necessary CSS and JavaScript code to implement the popup mode
+ * from the User Interface extension.
+ */
+function _ui_insert_css_js() {
+ global $xtpl;
+
+ $css = (isset($xtpl->vars['css'])) ? $xtpl->vars['css'] : '';
+ $js = (isset($xtpl->vars['javascript'])) ? $xtpl->vars['javascript'] : '';
+
+ $xtpl->assign('css', $css . '@import url(' . get_base_path() . 'extensions/ui/ui.css);');
+ $xtpl->assign('javascript', $js . '<script src="' . get_base_path() . 'extensions/ui/ui.js" type="text/javascript"></script>');
+}
+
+/**
+ * Attempts to obtain an icon from a RP
+ *
+ * @param string $realm the openid.realm parameter
+ * @return array the response from {@link http_make_request()} with the discovered URL of the
+ * RP's icon
+ */
+function _ui_get_icon($realm) {
+ $rp_info = simpleid_get_rp_info($realm);
+
+ if (isset($rp_info['ui_icon'])) return $rp_info['ui_icon'];
+
+ $services = discovery_xrds_services_by_type($rp_info['services'], 'http://specs.openid.net/extensions/ui/icon');
+
+ if ($services) {
+ $icon_url = $services[0]['uri'];
+
+ $icon_res = http_make_request($icon_url);
+ if (isset($icon_res['http-error'])) {
+ return NULL;
+ }
+
+ $rp_info['ui_icon'] = $icon_res;
+ simpleid_set_rp_info($realm, $rp_info);
+ } else {
+ return NULL;
+ }
+}
+
+/**
+ * Returns a token to be used when requesting the icon.
+ *
+ * The token is used to prevent flooding SimpleID with external requests.
+ *
+ * @param string $realm the openid.realm parameter
+ * @return string the token
+ */
+function _ui_icon_token($realm) {
+ return get_form_token('q=ui/icon&realm=' . rawurlencode($realm));
+}
+?>
diff --git a/simpleid/www/extensions/ui/ui.js b/simpleid/www/extensions/ui/ui.js
new file mode 100644
index 0000000..1711d13
--- /dev/null
+++ b/simpleid/www/extensions/ui/ui.js
@@ -0,0 +1,22 @@
+/*
+ * SimpleID
+ *
+ * Copyright (C) Kelvin Mo 2009
+ *
+ * This program is licensed under the GPL.
+ *
+ * $Id$
+ */
+
+$(document).ready(function() {
+ $('input#edit-cancel').click(function() {
+ window.close();
+ return false;
+ });
+ $(document).keydown(function(e) {
+ if (e.which == 27) { // Close the window if user presses Esc
+ window.close();
+ return false;
+ }
+ });
+});