mirror of
https://github.com/Lastorder-DC/rhymix.git
synced 2026-01-09 03:32:00 +09:00
issue 1946 remove open id code in module of member.
git-svn-id: http://xe-core.googlecode.com/svn/branches/1.5.3.1@10965 201d5d3c-b55e-5fd7-737f-ddc643e51545
This commit is contained in:
parent
e63896bbf9
commit
1d4bb452d0
71 changed files with 3 additions and 11775 deletions
|
|
@ -12,7 +12,6 @@
|
||||||
<action name="dispMemberLoginForm" type="view" standalone="true" />
|
<action name="dispMemberLoginForm" type="view" standalone="true" />
|
||||||
<action name="dispMemberLogout" type="view" standalone="true" />
|
<action name="dispMemberLogout" type="view" standalone="true" />
|
||||||
<action name="dispMemberLeave" type="view" standalone="true" />
|
<action name="dispMemberLeave" type="view" standalone="true" />
|
||||||
<action name="dispMemberOpenIDLeave" type="view" standalone="true" />
|
|
||||||
<action name="dispMemberOwnDocument" type="view" standalone="true" />
|
<action name="dispMemberOwnDocument" type="view" standalone="true" />
|
||||||
<action name="dispMemberScrappedDocument" type="view" standalone="true" />
|
<action name="dispMemberScrappedDocument" type="view" standalone="true" />
|
||||||
<action name="dispMemberSavedDocument" type="view" standalone="true" />
|
<action name="dispMemberSavedDocument" type="view" standalone="true" />
|
||||||
|
|
@ -39,11 +38,6 @@
|
||||||
<action name="getMemberAdminIPCheck" type="model" standalone="true" />
|
<action name="getMemberAdminIPCheck" type="model" standalone="true" />
|
||||||
|
|
||||||
<action name="procMemberLogin" type="controller" standalone="true" ruleset="@login" />
|
<action name="procMemberLogin" type="controller" standalone="true" ruleset="@login" />
|
||||||
<action name="procMemberOpenIDLogin" type="controller" standalone="true" ruleset="openidLogin" />
|
|
||||||
<action name="procMemberOpenIDValidate" type="controller" standalone="true" />
|
|
||||||
<action name="procMemberAddOpenIDToMember" type="controller" standalone="true" />
|
|
||||||
<action name="procMemberValidateAddOpenIDToMember" type="controller" standalone="true" />
|
|
||||||
<action name="procMemberDeleteOpenIDFromMember" type="controller" standalone="true" />
|
|
||||||
<action name="procMemberLogout" type="controller" standalone="true" />
|
<action name="procMemberLogout" type="controller" standalone="true" />
|
||||||
<action name="procMemberCheckValue" type="controller" standalone="true" />
|
<action name="procMemberCheckValue" type="controller" standalone="true" />
|
||||||
<action name="procMemberInsert" type="controller" standalone="true" ruleset="@insertMember" />
|
<action name="procMemberInsert" type="controller" standalone="true" ruleset="@insertMember" />
|
||||||
|
|
@ -51,7 +45,6 @@
|
||||||
<action name="procMemberModifyInfo" type="controller" standalone="true" ruleset="@insertMember" />
|
<action name="procMemberModifyInfo" type="controller" standalone="true" ruleset="@insertMember" />
|
||||||
<action name="procMemberModifyPassword" type="controller" standalone="true" ruleset="modifyPassword" />
|
<action name="procMemberModifyPassword" type="controller" standalone="true" ruleset="modifyPassword" />
|
||||||
<action name="procMemberLeave" type="controller" standalone="true" ruleset="leaveMember" />
|
<action name="procMemberLeave" type="controller" standalone="true" ruleset="leaveMember" />
|
||||||
<action name="procMemberOpenIDLeave" type="controller" standalone="true" />
|
|
||||||
<action name="procMemberInsertProfileImage" type="controller" standalone="true" ruleset="insertProfileImage" />
|
<action name="procMemberInsertProfileImage" type="controller" standalone="true" ruleset="insertProfileImage" />
|
||||||
<action name="procMemberInsertImageName" type="controller" standalone="true" ruleset="insertImageName" />
|
<action name="procMemberInsertImageName" type="controller" standalone="true" ruleset="insertImageName" />
|
||||||
<action name="procMemberInsertImageMark" type="controller" standalone="true" ruleset="insertImageMark" />
|
<action name="procMemberInsertImageMark" type="controller" standalone="true" ruleset="insertImageMark" />
|
||||||
|
|
|
||||||
|
|
@ -423,18 +423,6 @@
|
||||||
<value xml:lang="tr"><![CDATA[En Yük. İmza Uzunluğu]]></value>
|
<value xml:lang="tr"><![CDATA[En Yük. İmza Uzunluğu]]></value>
|
||||||
<value xml:lang="vi"><![CDATA[Chiều cao lớn nhất của chữ kí]]></value>
|
<value xml:lang="vi"><![CDATA[Chiều cao lớn nhất của chữ kí]]></value>
|
||||||
</item>
|
</item>
|
||||||
<item name="enable_openid">
|
|
||||||
<value xml:lang="ko"><![CDATA[OpenID 지원]]></value>
|
|
||||||
<value xml:lang="en"><![CDATA[Enable OpenID]]></value>
|
|
||||||
<value xml:lang="jp"><![CDATA[OpenIDサポート]]></value>
|
|
||||||
<value xml:lang="zh-CN"><![CDATA[支持OpenID]]></value>
|
|
||||||
<value xml:lang="zh-TW"><![CDATA[支援 OpenID]]></value>
|
|
||||||
<value xml:lang="fr"><![CDATA[Permettre OpenID]]></value>
|
|
||||||
<value xml:lang="ru"><![CDATA[Включить открытый ID (OpenID)]]></value>
|
|
||||||
<value xml:lang="es"><![CDATA[Activar OpenID]]></value>
|
|
||||||
<value xml:lang="tr"><![CDATA[OpenID Aç]]></value>
|
|
||||||
<value xml:lang="vi"><![CDATA[Kích hoạt OpenID]]></value>
|
|
||||||
</item>
|
|
||||||
<item name="enable_join">
|
<item name="enable_join">
|
||||||
<value xml:lang="ko"><![CDATA[회원 가입 허가]]></value>
|
<value xml:lang="ko"><![CDATA[회원 가입 허가]]></value>
|
||||||
<value xml:lang="en"><![CDATA[Accept New Members]]></value>
|
<value xml:lang="en"><![CDATA[Accept New Members]]></value>
|
||||||
|
|
@ -588,11 +576,6 @@
|
||||||
<value xml:lang="tr"><![CDATA[Geçerli Şifre]]></value>
|
<value xml:lang="tr"><![CDATA[Geçerli Şifre]]></value>
|
||||||
<value xml:lang="vi"><![CDATA[Mật khẩu hiện tại]]></value>
|
<value xml:lang="vi"><![CDATA[Mật khẩu hiện tại]]></value>
|
||||||
</item>
|
</item>
|
||||||
<item name="openid">
|
|
||||||
<value xml:lang="ko"><![CDATA[OpenID]]></value>
|
|
||||||
<value xml:lang="en"><![CDATA[OpenID]]></value>
|
|
||||||
<value xml:lang="zh-TW"><![CDATA[OpenID]]></value>
|
|
||||||
</item>
|
|
||||||
<item name="allow_message">
|
<item name="allow_message">
|
||||||
<value xml:lang="ko"><![CDATA[쪽지 허용]]></value>
|
<value xml:lang="ko"><![CDATA[쪽지 허용]]></value>
|
||||||
<value xml:lang="en"><![CDATA[Allow Messages]]></value>
|
<value xml:lang="en"><![CDATA[Allow Messages]]></value>
|
||||||
|
|
@ -1808,18 +1791,6 @@
|
||||||
<value xml:lang="tr"><![CDATA[Eğer işaretlerseniz, kayıt için gerekli bir öğe olacaktır]]></value>
|
<value xml:lang="tr"><![CDATA[Eğer işaretlerseniz, kayıt için gerekli bir öğe olacaktır]]></value>
|
||||||
<value xml:lang="vi"><![CDATA[Nếu chọn, thông tin này sẽ được hiển thị trong bảng đăng kí.]]></value>
|
<value xml:lang="vi"><![CDATA[Nếu chọn, thông tin này sẽ được hiển thị trong bảng đăng kí.]]></value>
|
||||||
</item>
|
</item>
|
||||||
<item name="about_enable_openid">
|
|
||||||
<value xml:lang="ko"><![CDATA[OpenID 지원을 할 경우 체크하시면 됩니다.]]></value>
|
|
||||||
<value xml:lang="en"><![CDATA[Check this if you want to provide an OpenID service.]]></value>
|
|
||||||
<value xml:lang="jp"><![CDATA[OpenIDをサポートする際にチェックを入れます。]]></value>
|
|
||||||
<value xml:lang="zh-CN"><![CDATA[要想网站支持OpenID时请勾选此项。]]></value>
|
|
||||||
<value xml:lang="zh-TW"><![CDATA[想要網站支援 OpenID 時,請勾選此項。]]></value>
|
|
||||||
<value xml:lang="fr"><![CDATA[Cochez si vous voulez permettre OpenID]]></value>
|
|
||||||
<value xml:lang="ru"><![CDATA[Позволить пользователям регистрироваться как OpenID]]></value>
|
|
||||||
<value xml:lang="es"><![CDATA[Selecciona esta opción si activado OpenID]]></value>
|
|
||||||
<value xml:lang="tr"><![CDATA[Eğer OpenID hizmeti sunmak istiyorsanız, lütfen işaretleyiniz]]></value>
|
|
||||||
<value xml:lang="vi"><![CDATA[Kích hoạt đăng nhập bằng OpenID.]]></value>
|
|
||||||
</item>
|
|
||||||
<item name="about_enable_join">
|
<item name="about_enable_join">
|
||||||
<value xml:lang="ko"><![CDATA[체크하면 회원가입을 할 수 있습니다.]]></value>
|
<value xml:lang="ko"><![CDATA[체크하면 회원가입을 할 수 있습니다.]]></value>
|
||||||
<value xml:lang="en"><![CDATA[Please check this if you want to allow new members to sign up your site.]]></value>
|
<value xml:lang="en"><![CDATA[Please check this if you want to allow new members to sign up your site.]]></value>
|
||||||
|
|
@ -2005,30 +1976,6 @@
|
||||||
<value xml:lang="tr"><![CDATA[Varsayılan grup, kullanıcı kayıt olduktan sonra yönlendirileceği grup olacaktır]]></value>
|
<value xml:lang="tr"><![CDATA[Varsayılan grup, kullanıcı kayıt olduktan sonra yönlendirileceği grup olacaktır]]></value>
|
||||||
<value xml:lang="vi"><![CDATA[Sẽ là nhóm mặc định khi thành viên đăng kí.]]></value>
|
<value xml:lang="vi"><![CDATA[Sẽ là nhóm mặc định khi thành viên đăng kí.]]></value>
|
||||||
</item>
|
</item>
|
||||||
<item name="about_openid">
|
|
||||||
<value xml:lang="ko"><![CDATA[오픈아이디로 가입시 아이디와 메일 등의 기본 정보는 이 사이트에 저장 되지만 비밀번호와 인증을 위한 처리는 해당 오픈아이디 제공서비스에서 이루어집니다.]]></value>
|
|
||||||
<value xml:lang="en"><![CDATA[When you join using an OpenID, basic info like ID or email address will be saved on this site, process for password and verification management will be done on current OpenID offering service]]></value>
|
|
||||||
<value xml:lang="jp"><![CDATA[OpenIDで登録する際、IDとメールなどの基本情報は、このサイトに保存されますが、パスワードと認証のための処理用の情報は該当するOpenID提供サービス側で行われます。]]></value>
|
|
||||||
<value xml:lang="zh-CN"><![CDATA[用OpenID注册时该网站只保存用户名和 邮件等基本信息,密码和认证处理是在提供OpenID服务的站点中得到解决。]]></value>
|
|
||||||
<value xml:lang="zh-TW"><![CDATA[用 OpenID註冊時,該網站只儲存帳號和郵件等基本資料,密碼和認證處理是在提供 OpenID服務的網站中得到解決。]]></value>
|
|
||||||
<value xml:lang="fr"><![CDATA[Si vous vous inscrivez avec OpenID, vos informations primaires comme le Compte(ID) ou l'adresse mél sera gardés sur ce site. Mais le procès pour le Mot de Passe et la certification sera fait sur le service courant qui offre OpenID]]></value>
|
|
||||||
<value xml:lang="ru"><![CDATA[При регистраци как OpenID, основнаая информация (ID или email адрес) будет сохранена на сайте, но операции с паролем и авторизацией будут произведены над текущим OpenID в представленном сервисе]]></value>
|
|
||||||
<value xml:lang="es"><![CDATA[Cuando tu registra como OpenID, la información básica como ID o la dirección del email sera guardado en este sitio, pero la contraseña y la resolución de la certificación se hará en el servicio ofrecido por openID]]></value>
|
|
||||||
<value xml:lang="tr"><![CDATA[OpenID olarak giriş yaptığınızda, e-posta adresi ya da kimliğiniz gibi temel bilgi sitede kaydedilecektir, şifre ve onaylama yönetimi işlemi, hizmet veren geçerli OpenID tarafından yapılacaktır]]></value>
|
|
||||||
<value xml:lang="vi"><![CDATA[Khi bạn đăng nhập bằng OpenID, những thông tin cơ bản và Email của bạn sẽ lưu lại tại Website này. Việc này sẽ giúp bạn lấy lại thông tin nếu như bạn lỡ quên hoặc nhận những thông báo từ Ban Quản trị Website.]]></value>
|
|
||||||
</item>
|
|
||||||
<item name="about_openid_leave">
|
|
||||||
<value xml:lang="ko"><![CDATA[오픈아이디의 탈퇴는 현 사이트에서의 회원 정보를 삭제하는 것입니다.<br />탈퇴 후 로그인하시면 새로 가입하시는 것으로 되어 작성한 글에 대한 권한을 가질 수 없게 됩니다.]]></value>
|
|
||||||
<value xml:lang="en"><![CDATA[The secession of OpenID means deletion of your member info from this site.<br />If you login after secession, it will be recognized as a new member, so you will no longer have the permission for your ex-written articles.]]></value>
|
|
||||||
<value xml:lang="jp"><![CDATA[OpenIDの退会は現在のサイトから会員情報を削除することを意味します。<br />退会後ログインすると新しく登録することになり、書き込んだコンテンツに対する権限を維持することができません。]]></value>
|
|
||||||
<value xml:lang="zh-CN"><![CDATA[删除OpenID就等于永久删除站内用户的信息。<br />被删除后的重新登录就等于新会员注册,因此对以前自己写的主题将失去相应权限。]]></value>
|
|
||||||
<value xml:lang="zh-TW"><![CDATA[刪除 OpenID 就等於永久刪除站內會員的資料。<br />被刪除後,再重新登錄就等於新會員註冊,因此對以前自己寫的主題將失去其權限。]]></value>
|
|
||||||
<value xml:lang="fr"><![CDATA[La sécession de OpenID nous fait supprimer vos informations du membre dans notre site.<br />Si vous ouvrez la connexion après la sécession, nous vous reconnaîtrons comme un nouveau membre, c'est-à-dire, vous n'aurez plus la permission sur les articles que vous avez écrits avant.]]></value>
|
|
||||||
<value xml:lang="ru"><![CDATA[Удаление аккаунта с OpenID производит удаление Вашей информации пользователя на сайте.<br />Если Вы войдете после удаления аккаунта, Вы будете разпознаны как новый пользователь и доступ к написанным Вами ранее записям будет закрыт.]]></value>
|
|
||||||
<value xml:lang="es"><![CDATA[La secesión de OpenID medios eliminación de su información de miembros de este sitio. <br /> Si se registra después de la secesión, se le reconocerá como un nuevo miembro, de modo que ya no tienen el permiso para que su ex-escrito artículos.]]></value>
|
|
||||||
<value xml:lang="tr"><![CDATA[OpenID'nin bu bölünmesi, üyelik bilginizin bu siteden silinmesi demektir.<br />Bölünmeden sonra giriş yaparsanız, yeni bir üye gibi kabul edilecekseniz, bu yüzden eski makalelerinize ulaşma yetkiniz olmayacaktır.]]></value>
|
|
||||||
<value xml:lang="vi"><![CDATA[Thông tin OpenID của bạn sẽ được cập nhật tại Website này.<br />Nếu bạn đăng nhập, Thông tin OpenID của bạn sẽ được lưu lại như một thành viên đã đăng kí, và bạn có thể gửi bài viết hay bình luận.]]></value>
|
|
||||||
</item>
|
|
||||||
<item name="about_find_member_account">
|
<item name="about_find_member_account">
|
||||||
<value xml:lang="ko"><![CDATA[아이디/ 비밀번호는 가입시 등록한 메일 주소로 알려드립니다.<br />가입할 때 등록하신 메일 주소를 입력하시고 "아이디/비밀번호 찾기" 버튼을 클릭해주세요.<br />]]></value>
|
<value xml:lang="ko"><![CDATA[아이디/ 비밀번호는 가입시 등록한 메일 주소로 알려드립니다.<br />가입할 때 등록하신 메일 주소를 입력하시고 "아이디/비밀번호 찾기" 버튼을 클릭해주세요.<br />]]></value>
|
||||||
<value xml:lang="en"><![CDATA[lease input the email address you have entered during the registration and we will send your account info to this email address.]]></value>
|
<value xml:lang="en"><![CDATA[lease input the email address you have entered during the registration and we will send your account info to this email address.]]></value>
|
||||||
|
|
@ -2078,15 +2025,6 @@ Bạn có thể quản lý thành viên bằng cách tạo những nhóm mới,
|
||||||
<value xml:lang="tr"><![CDATA[Eğer varsayılan SSL portundan farklı bir port kullanıyorsanız, lütfen giriniz]]></value>
|
<value xml:lang="tr"><![CDATA[Eğer varsayılan SSL portundan farklı bir port kullanıyorsanız, lütfen giriniz]]></value>
|
||||||
<value xml:lang="vi"><![CDATA[Xin hãy nhập cổng kết nối mặc định cho SSL.]]></value>
|
<value xml:lang="vi"><![CDATA[Xin hãy nhập cổng kết nối mặc định cho SSL.]]></value>
|
||||||
</item>
|
</item>
|
||||||
<item name="add_openid">
|
|
||||||
<value xml:lang="ko"><![CDATA[오픈아이디 추가]]></value>
|
|
||||||
<value xml:lang="en"><![CDATA[Add OpenID]]></value>
|
|
||||||
<value xml:lang="jp"><![CDATA[OpenIDの追加]]></value>
|
|
||||||
<value xml:lang="zh-TW"><![CDATA[新增 OpenID]]></value>
|
|
||||||
<value xml:lang="ru"><![CDATA[Добавить OpenID]]></value>
|
|
||||||
<value xml:lang="tr"><![CDATA[OpenID Ekle]]></value>
|
|
||||||
<value xml:lang="vi"><![CDATA[Thêm OpenID]]></value>
|
|
||||||
</item>
|
|
||||||
<item name="about_resend_auth_mail">
|
<item name="about_resend_auth_mail">
|
||||||
<value xml:lang="ko"><![CDATA[인증 메일을 받지 못하신 경우 다시 받으실 수 있습니다.]]></value>
|
<value xml:lang="ko"><![CDATA[인증 메일을 받지 못하신 경우 다시 받으실 수 있습니다.]]></value>
|
||||||
<value xml:lang="en"><![CDATA[You can request for the activation email if you have not activated yet.]]></value>
|
<value xml:lang="en"><![CDATA[You can request for the activation email if you have not activated yet.]]></value>
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@
|
||||||
$args = $oModuleModel->getModuleConfig('member');
|
$args = $oModuleModel->getModuleConfig('member');
|
||||||
// Set the basic information
|
// Set the basic information
|
||||||
$args->enable_join = 'Y';
|
$args->enable_join = 'Y';
|
||||||
if(!$args->enable_openid) $args->enable_openid = 'N';
|
$args->enable_openid = 'N';
|
||||||
if(!$args->enable_auth_mail) $args->enable_auth_mail = 'N';
|
if(!$args->enable_auth_mail) $args->enable_auth_mail = 'N';
|
||||||
if(!$args->image_name) $args->image_name = 'Y';
|
if(!$args->image_name) $args->image_name = 'Y';
|
||||||
if(!$args->image_mark) $args->image_mark = 'Y';
|
if(!$args->image_mark) $args->image_mark = 'Y';
|
||||||
|
|
@ -373,10 +373,6 @@
|
||||||
* @return void
|
* @return void
|
||||||
**/
|
**/
|
||||||
function recompileCache() {
|
function recompileCache() {
|
||||||
set_include_path(_XE_PATH_."modules/member/php-openid-1.2.3");
|
|
||||||
require_once('Auth/OpenID/XEStore.php');
|
|
||||||
$store = new Auth_OpenID_XEStore();
|
|
||||||
$store->reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -80,305 +80,6 @@
|
||||||
return $this->setRedirectUrl($returnUrl, $output);
|
return $this->setRedirectUrl($returnUrl, $output);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Login by openid
|
|
||||||
*
|
|
||||||
* @deprecated
|
|
||||||
*
|
|
||||||
* @param string $validator
|
|
||||||
*
|
|
||||||
* @return void|Object (void : success, Object : fail)
|
|
||||||
**/
|
|
||||||
function procMemberOpenIDLogin($validator = "procMemberOpenIDValidate") {
|
|
||||||
$oModuleModel = &getModel('module');
|
|
||||||
$config = $oModuleModel->getModuleConfig('member');
|
|
||||||
if($config->enable_openid != 'Y') $this->stop('msg_invalid_request');
|
|
||||||
|
|
||||||
if(!defined('Auth_OpenID_RAND_SOURCE') && !file_exists("/dev/urandom"))
|
|
||||||
{
|
|
||||||
define('Auth_OpenID_RAND_SOURCE', null);
|
|
||||||
}
|
|
||||||
|
|
||||||
set_include_path(_XE_PATH_."modules/member/php-openid-1.2.3");
|
|
||||||
require_once('Auth/OpenID.php');
|
|
||||||
require_once('Auth/OpenID/Consumer.php');
|
|
||||||
require_once('Auth/OpenID/XEStore.php');
|
|
||||||
$store = new Auth_OpenID_XEStore();
|
|
||||||
$consumer = new Auth_OpenID_Consumer($store);
|
|
||||||
|
|
||||||
$user_id = Context::get('user_id');
|
|
||||||
if (!$user_id) $user_id = Context::get('openid');
|
|
||||||
$auth_request = $consumer->begin($user_id);
|
|
||||||
$auth_request->addExtensionArg('sreg', 'required', 'email');
|
|
||||||
$auth_request->addExtensionArg('sreg', 'optional', 'dob');
|
|
||||||
if(!$auth_request)
|
|
||||||
{
|
|
||||||
return new Object(-1, "association failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
$trust_root = 'http://'.$_SERVER["HTTP_HOST"];
|
|
||||||
$referer_url = Context::get('referer_url');
|
|
||||||
if (!$referer_url) $referer_url = $_SERVER['HTTP_REFERER'];
|
|
||||||
if (!$referer_url)
|
|
||||||
$referer_url = htmlspecialchars_decode(getRequestUri(RELEASE_SSL));
|
|
||||||
$goto = urlencode($referer_url);
|
|
||||||
$ApprovedURL = Context::getRequestUri(RELEASE_SSL) . "?module=member&act=" . $validator. "&goto=" . $goto;
|
|
||||||
$redirect_url = $auth_request->redirectURL($trust_root, $ApprovedURL);
|
|
||||||
$this->add("redirect_url", $redirect_url);
|
|
||||||
|
|
||||||
$this->setRedirectUrl($redirect_url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Legacy open id
|
|
||||||
*
|
|
||||||
* @deprecated
|
|
||||||
*
|
|
||||||
* @param string $openid_identity
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
**/
|
|
||||||
function getLegacyUserIDsFromOpenID($openid_identity) {
|
|
||||||
// Issue 17515512: workaround
|
|
||||||
$result = array();
|
|
||||||
$uri_matches = array();
|
|
||||||
preg_match(Auth_OpenID_getURIPattern(), $openid_identity, $uri_matches);
|
|
||||||
|
|
||||||
if (count($uri_matches) < 9) {
|
|
||||||
for ($i = count($uri_matches); $i <= 9; $i++) {
|
|
||||||
$uri_matches[] = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$scheme = $uri_matches[2];
|
|
||||||
$authority = $uri_matches[4];
|
|
||||||
$path = $uri_matches[5];
|
|
||||||
$query = $uri_matches[6];
|
|
||||||
$fragment = $uri_matches[8];
|
|
||||||
|
|
||||||
if ($scheme === null) $scheme = '';
|
|
||||||
if ($authority === null) $authority = '';
|
|
||||||
if ($path === null) $path = '';
|
|
||||||
if ($query === null) $query = '';
|
|
||||||
if ($fragment === null) $fragment = '';
|
|
||||||
|
|
||||||
if ($scheme == 'http' or $scheme == '')
|
|
||||||
$scheme_part = '';
|
|
||||||
else
|
|
||||||
$scheme_part = $scheme."://";
|
|
||||||
|
|
||||||
|
|
||||||
if ($path == '' || $path == '/') {
|
|
||||||
$result[] = $scheme_part.$authority.''.$query.$fragment;
|
|
||||||
$result[] = $scheme_part.$authority.'/'.$query.$fragment;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$result[] = $scheme_part.$authority.$path.$query.$fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* openid authentication check
|
|
||||||
*
|
|
||||||
* @return void|Object (void : success, Object : fail)
|
|
||||||
**/
|
|
||||||
function procMemberOpenIDValidate() {
|
|
||||||
set_include_path(_XE_PATH_."modules/member/php-openid-1.2.3");
|
|
||||||
require_once('Auth/OpenID.php');
|
|
||||||
require_once('Auth/OpenID/Consumer.php');
|
|
||||||
require_once('Auth/OpenID/XEStore.php');
|
|
||||||
require_once('Auth/OpenID/URINorm.php');
|
|
||||||
|
|
||||||
$store = new Auth_OpenID_XEStore();
|
|
||||||
$consumer = new Auth_OpenID_Consumer($store);
|
|
||||||
$response = $consumer->complete($_GET);
|
|
||||||
switch($response->status) {
|
|
||||||
case Auth_OpenID_CANCEL :
|
|
||||||
// Handle if user authentication is canceled
|
|
||||||
return $this->stop('authorization_canceled');
|
|
||||||
case Auth_OpenID_FAILURE :
|
|
||||||
// Handle if user authentication is failed due to a certain problem (for example, openid doesn't exist) (there is no authentication required deunga openid ..)
|
|
||||||
return $this->stop('invalid_authorization');
|
|
||||||
case Auth_OpenID_SUCCESS :
|
|
||||||
// Authentication success!
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return $this->stop('invalid_authorization');
|
|
||||||
}
|
|
||||||
// Authentication success
|
|
||||||
$oMemberModel = &getModel('member');
|
|
||||||
// Get zeroboard ID which is corresponded to the openID ID.
|
|
||||||
$login_success = false;
|
|
||||||
$assoc_member_info = null;
|
|
||||||
$openid_identity = $response->signed_args["openid.identity"];
|
|
||||||
$args->openid = $openid_identity;
|
|
||||||
$output = executeQuery('member.getMemberSrlByOpenID', $args);
|
|
||||||
|
|
||||||
if ($output->toBool() && $output->data && !is_array($output->data)) {
|
|
||||||
$member_srl = $output->data->member_srl;
|
|
||||||
$columnList = array('member_srl', 'user_id');
|
|
||||||
$member_info = $oMemberModel->getMemberInfoByMemberSrl($member_srl, 0, $columnList);
|
|
||||||
if ($member_info) {
|
|
||||||
$assoc_member_info = $member_info;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$user_id_candidates = $this->getLegacyUserIDsFromOpenID($openid_identity);
|
|
||||||
$default_user_id = $user_id_candidates[0];
|
|
||||||
|
|
||||||
if ($assoc_member_info != null) {
|
|
||||||
$user_id_candidates = array_merge(array($assoc_member_info->user_id), $user_id_candidates);
|
|
||||||
}
|
|
||||||
$sreg = $response->extensionResponse('sreg');
|
|
||||||
|
|
||||||
foreach($user_id_candidates as $user_id) {
|
|
||||||
$args->user_id = $args->nick_name = $user_id;
|
|
||||||
// Get basic information
|
|
||||||
$args->email_address = $sreg['email'];
|
|
||||||
$args->user_name = $sreg['fullname'];
|
|
||||||
if(!$args->user_name) list($args->user_name) = explode('@', $args->email_address);
|
|
||||||
$args->birthday = str_replace('-','',$sreg['dob']);
|
|
||||||
// Attempts self-authentication
|
|
||||||
$output = $this->doLogin($args->user_id);
|
|
||||||
|
|
||||||
if ($output->toBool()) {
|
|
||||||
if ($assoc_member_info == null) {
|
|
||||||
$logged_info = Context::get('logged_info');
|
|
||||||
$args->member_srl = $logged_info->member_srl;
|
|
||||||
$args->openid = $openid_identity;
|
|
||||||
executeQuery('member.addOpenIDToMember', $args);
|
|
||||||
}
|
|
||||||
$login_success = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Member join if self-authentication is failed
|
|
||||||
if(!$login_success) {
|
|
||||||
$args->user_id = $args->nick_name = $default_user_id;
|
|
||||||
$args->password = md5(getmicrotime());
|
|
||||||
|
|
||||||
$output = $this->insertMember($args);
|
|
||||||
if(!$output->toBool()) return $this->stop($output->getMessage());
|
|
||||||
$output = $this->doLogin($args->user_id);
|
|
||||||
if(!$output->toBool()) return $this->stop($output->getMessage());
|
|
||||||
|
|
||||||
$logged_info = Context::get('logged_info');
|
|
||||||
$args->member_srl = $logged_info->member_srl;
|
|
||||||
$args->openid = $openid_identity;
|
|
||||||
executeQuery('member.addOpenIDToMember', $args);
|
|
||||||
}
|
|
||||||
|
|
||||||
Context::close();
|
|
||||||
// Move the page
|
|
||||||
if(Context::get('goto')) {
|
|
||||||
$goto = Context::get('goto');
|
|
||||||
header("location:" . $goto);
|
|
||||||
} else {
|
|
||||||
header("location:./");
|
|
||||||
}
|
|
||||||
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request member join by openID
|
|
||||||
*
|
|
||||||
* @return Object
|
|
||||||
**/
|
|
||||||
function procMemberAddOpenIDToMember() {
|
|
||||||
return $this->procMemberOpenIDLogin("procMemberValidateAddOpenIDToMember");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate openID processing
|
|
||||||
*
|
|
||||||
* @return Object
|
|
||||||
**/
|
|
||||||
function procMemberValidateAddOpenIDToMember() {
|
|
||||||
set_include_path(_XE_PATH_."modules/member/php-openid-1.2.3");
|
|
||||||
require_once('Auth/OpenID.php');
|
|
||||||
require_once('Auth/OpenID/Consumer.php');
|
|
||||||
require_once('Auth/OpenID/XEStore.php');
|
|
||||||
require_once('Auth/OpenID/URINorm.php');
|
|
||||||
|
|
||||||
$store = new Auth_OpenID_XEStore();
|
|
||||||
$consumer = new Auth_OpenID_Consumer($store);
|
|
||||||
$response = $consumer->complete($_GET);
|
|
||||||
|
|
||||||
switch($response->status) {
|
|
||||||
case Auth_OpenID_CANCEL :
|
|
||||||
// Handle if user authentication is canceled
|
|
||||||
return $this->stop('authorization_canceled');
|
|
||||||
case Auth_OpenID_FAILURE :
|
|
||||||
// Handle if user authentication is failed due to a certain problem (for example, openid doesn't exist) (there is no authentication required deunga openid ..)
|
|
||||||
return $this->stop('invalid_authorization');
|
|
||||||
case Auth_OpenID_SUCCESS :
|
|
||||||
{
|
|
||||||
$logged_info = Context::get('logged_info');
|
|
||||||
if (!Context::get('is_logged')) return $this->stop('msg_not_logged');
|
|
||||||
|
|
||||||
$member_srl = $logged_info->member_srl;
|
|
||||||
|
|
||||||
$args->member_srl = $member_srl;
|
|
||||||
$openid_identity = $response->signed_args["openid.identity"];
|
|
||||||
$args->openid = $openid_identity;
|
|
||||||
|
|
||||||
$output = executeQuery('member.addOpenIDToMember', $args);
|
|
||||||
if (!$output->toBool()) return $output;
|
|
||||||
|
|
||||||
Context::close();
|
|
||||||
|
|
||||||
if(Context::get('goto')){
|
|
||||||
$goto = Context::get('goto');
|
|
||||||
header("location:" . $goto);
|
|
||||||
}else{
|
|
||||||
header("location:./");
|
|
||||||
}
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
// Authentication success!
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return $this->stop('invalid_authorization');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disconnect OpenID
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
**/
|
|
||||||
function procMemberDeleteOpenIDFromMember() {
|
|
||||||
$logged_info = Context::get('logged_info');
|
|
||||||
$openid_identity = Context::get('openid_to_delete');
|
|
||||||
$arg->openid = $openid_identity;
|
|
||||||
$result = executeQuery('member.getMemberSrlByOpenID', $arg);
|
|
||||||
|
|
||||||
if (!Context::get('is_logged')) {
|
|
||||||
$this->setError(-1);
|
|
||||||
$this->setMessage('msg_not_logged');
|
|
||||||
return;
|
|
||||||
} else if (!$result->data || is_array($result->data)) {
|
|
||||||
$this->setError(-1);
|
|
||||||
$this->setMessage('msg_not_founded');
|
|
||||||
return;
|
|
||||||
} else if ($result->data->member_srl != $logged_info->member_srl) {
|
|
||||||
$this->setError(-1);
|
|
||||||
$this->setMessage('msg_not_permitted');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$arg->openid = $openid_identity;
|
|
||||||
|
|
||||||
$output = executeQuery('member.deleteMemberOpenID', $arg);
|
|
||||||
if(!$output->toBool()) return $output;
|
|
||||||
|
|
||||||
$this->setMessage('success_updated');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log-out
|
* Log-out
|
||||||
*
|
*
|
||||||
|
|
@ -818,28 +519,6 @@
|
||||||
$this->setRedirectUrl($returnUrl);
|
$this->setRedirectUrl($returnUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* OpenID Withdrawal
|
|
||||||
*
|
|
||||||
* @return void|Object (void : success, Object : fail)
|
|
||||||
**/
|
|
||||||
function procMemberOpenIDLeave() {
|
|
||||||
// Return an error if in the non-login state
|
|
||||||
if(!Context::get('is_logged')) return $this->stop('msg_not_logged');
|
|
||||||
// Compare the current IP with session IP
|
|
||||||
if($_SESSION['ipaddress']!=$_SERVER['REMOTE_ADDR']) return $this->stop('msg_not_permitted');
|
|
||||||
// Get information of logged-in user
|
|
||||||
$logged_info = Context::get('logged_info');
|
|
||||||
$member_srl = $logged_info->member_srl;
|
|
||||||
|
|
||||||
$output = $this->deleteMember($member_srl);
|
|
||||||
if(!$output->toBool()) return $output;
|
|
||||||
// Destroy all session information
|
|
||||||
$this->destroySessionInfo();
|
|
||||||
// Return success message
|
|
||||||
$this->setMessage('success_leaved');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a profile image
|
* Add a profile image
|
||||||
*
|
*
|
||||||
|
|
@ -1426,7 +1105,7 @@
|
||||||
if(!$args->editor_skin) $args->editor_skin= "xpresseditor";
|
if(!$args->editor_skin) $args->editor_skin= "xpresseditor";
|
||||||
if(!$args->editor_colorset) $args->editor_colorset = "white";
|
if(!$args->editor_colorset) $args->editor_colorset = "white";
|
||||||
if($args->enable_join!='Y') $args->enable_join = 'N';
|
if($args->enable_join!='Y') $args->enable_join = 'N';
|
||||||
if($args->enable_openid!='Y') $args->enable_openid= 'N';
|
$args->enable_openid= 'N';
|
||||||
if($args->profile_image !='Y') $args->profile_image = 'N';
|
if($args->profile_image !='Y') $args->profile_image = 'N';
|
||||||
if($args->image_name!='Y') $args->image_name = 'N';
|
if($args->image_name!='Y') $args->image_name = 'N';
|
||||||
if($args->image_mark!='Y') $args->image_mark = 'N';
|
if($args->image_mark!='Y') $args->image_mark = 'N';
|
||||||
|
|
@ -1773,9 +1452,6 @@
|
||||||
$this->destroySessionInfo();
|
$this->destroySessionInfo();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// OpenID is a check (only for a determined identity types)
|
|
||||||
if(preg_match("/^([_0-9a-zA-Z]+)$/is", $this->memberInfo->user_id)) $this->memberInfo->is_openid = false;
|
|
||||||
else $this->memberInfo->is_openid = true;
|
|
||||||
// Log in for treatment sessions set
|
// Log in for treatment sessions set
|
||||||
$_SESSION['is_logged'] = true;
|
$_SESSION['is_logged'] = true;
|
||||||
$_SESSION['ipaddress'] = $_SERVER['REMOTE_ADDR'];
|
$_SESSION['ipaddress'] = $_SERVER['REMOTE_ADDR'];
|
||||||
|
|
@ -2179,8 +1855,7 @@
|
||||||
$oDB->rollback();
|
$oDB->rollback();
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
// Delete the entries in member_openid
|
|
||||||
$output = executeQuery('member.deleteMemberOpenIDByMemberSrl', $ags);
|
|
||||||
// TODO: If the table is not an upgrade may fail.
|
// TODO: If the table is not an upgrade may fail.
|
||||||
/*
|
/*
|
||||||
if(!$output->toBool()) {
|
if(!$output->toBool()) {
|
||||||
|
|
|
||||||
|
|
@ -94,8 +94,6 @@ class memberMobile extends member
|
||||||
|
|
||||||
Context::set('member_info', $this->memberInfo);
|
Context::set('member_info', $this->memberInfo);
|
||||||
Context::set('extend_form_list', $oMemberModel->getCombineJoinForm($this->memberInfo));
|
Context::set('extend_form_list', $oMemberModel->getCombineJoinForm($this->memberInfo));
|
||||||
if ($this->memberInfo->member_srl == $logged_info->member_srl)
|
|
||||||
Context::set('openids', $oMemberModel->getMemberOpenIDByMemberSrl($member_srl));
|
|
||||||
$this->setTemplateFile('member_info_mobile');
|
$this->setTemplateFile('member_info_mobile');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,8 +151,6 @@ class memberMobile extends member
|
||||||
// Receive a member join form
|
// Receive a member join form
|
||||||
Context::set('extend_form_list', $oMemberModel->getCombineJoinForm($this->memberInfo));
|
Context::set('extend_form_list', $oMemberModel->getCombineJoinForm($this->memberInfo));
|
||||||
|
|
||||||
Context::set('openids', $oMemberModel->getMemberOpenIDByMemberSrl($member_srl));
|
|
||||||
|
|
||||||
// Call getEditor of the editor module and set it for signiture
|
// Call getEditor of the editor module and set it for signiture
|
||||||
if($this->memberInfo->member_srl) {
|
if($this->memberInfo->member_srl) {
|
||||||
$oEditorModel = &getModel('editor');
|
$oEditorModel = &getModel('editor');
|
||||||
|
|
|
||||||
|
|
@ -767,56 +767,6 @@
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return all the open IDs of the member
|
|
||||||
**/
|
|
||||||
function getMemberOpenIDByMemberSrl($member_srl) {
|
|
||||||
$oModuleModel = &getModel('module');
|
|
||||||
$config = $oModuleModel->getModuleConfig('member');
|
|
||||||
|
|
||||||
$result = array();
|
|
||||||
if ($config->enable_openid != 'Y') return $result;
|
|
||||||
|
|
||||||
$args->member_srl = $member_srl;
|
|
||||||
$output = executeQuery('member.getMemberOpenIDByMemberSrl', $args);
|
|
||||||
|
|
||||||
if (!$output->data) {
|
|
||||||
}
|
|
||||||
else if (is_array($output->data)) {
|
|
||||||
foreach($output->data as $row) {
|
|
||||||
$result[] = $row;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$result[] = $output->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($result as $row) {
|
|
||||||
$openid = $row->openid;
|
|
||||||
$bookmarklet_header = "javascript:var%20U='";
|
|
||||||
$bookmarklet_footer = "';function%20Z(W){var%20X=/(openid|ident)/i;try{var%20F=W.frames;var%20E=W.document.getElementsByTagName('input');for(var%20i=0;i<E.length;i++){var%20A=E[i];if(A.type=='text'&&X.test(A.name)){if(!J)J=E[i]}if(A.name=='submit'){V=A}}for(var%20i=0;i<F.length;i++){Z(F[i]);}}catch(e){}}var%20J,V;Z(window);try{try{V.parentNode.removeChild(V);}catch(z){}J.value=U;J.form.submit();}catch(e){top.document.location.href=((/^https?:\/\//img).test(U)?'':'http://')+U;}";
|
|
||||||
$row->bookmarklet = $bookmarklet_header . $openid . $bookmarklet_footer;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the member of the open ID.
|
|
||||||
**/
|
|
||||||
function getMemberSrlByOpenID($openid) {
|
|
||||||
$oModuleModel = &getModel('module');
|
|
||||||
$config = $oModuleModel->getModuleConfig('member');
|
|
||||||
|
|
||||||
if ($config->enable_openid != 'Y') return $result;
|
|
||||||
|
|
||||||
$args->member_srl = $member_srl;
|
|
||||||
$output = executeQuery('member.getMemberSrlByOpenID', $args);
|
|
||||||
|
|
||||||
if (!$output->data) return null;
|
|
||||||
return $output->data->member_srl;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAdminGroupSrl($site_srl = 0)
|
function getAdminGroupSrl($site_srl = 0)
|
||||||
{
|
{
|
||||||
$groupSrl = 0;
|
$groupSrl = 0;
|
||||||
|
|
|
||||||
|
|
@ -80,8 +80,6 @@
|
||||||
unset($extendForm->find_member_account);
|
unset($extendForm->find_member_account);
|
||||||
unset($extendForm->find_member_answer);
|
unset($extendForm->find_member_answer);
|
||||||
Context::set('extend_form_list', $extendForm);
|
Context::set('extend_form_list', $extendForm);
|
||||||
if ($member_info->member_srl == $logged_info->member_srl)
|
|
||||||
Context::set('openids', $oMemberModel->getMemberOpenIDByMemberSrl($member_srl));
|
|
||||||
|
|
||||||
$this->setTemplateFile('member_info');
|
$this->setTemplateFile('member_info');
|
||||||
}
|
}
|
||||||
|
|
@ -140,7 +138,6 @@
|
||||||
// Get a list of extend join form
|
// Get a list of extend join form
|
||||||
Context::set('extend_form_list', $oMemberModel->getCombineJoinForm($member_info));
|
Context::set('extend_form_list', $oMemberModel->getCombineJoinForm($member_info));
|
||||||
|
|
||||||
Context::set('openids', $oMemberModel->getMemberOpenIDByMemberSrl($member_srl));
|
|
||||||
// Editor of the module set for signing by calling getEditor
|
// Editor of the module set for signing by calling getEditor
|
||||||
if($member_info->member_srl) {
|
if($member_info->member_srl) {
|
||||||
$oEditorModel = &getModel('editor');
|
$oEditorModel = &getModel('editor');
|
||||||
|
|
@ -329,23 +326,6 @@
|
||||||
$this->setTemplateFile('leave_form');
|
$this->setTemplateFile('leave_form');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief OpenID member withdrawl
|
|
||||||
**/
|
|
||||||
function dispMemberOpenIDLeave() {
|
|
||||||
$oMemberModel = &getModel('member');
|
|
||||||
// A message appears if the user is not logged-in
|
|
||||||
if(!$oMemberModel->isLogged()) return $this->stop('msg_not_logged');
|
|
||||||
|
|
||||||
$logged_info = Context::get('logged_info');
|
|
||||||
$member_srl = $logged_info->member_srl;
|
|
||||||
|
|
||||||
$member_info = $oMemberModel->getMemberInfoByMemberSrl($member_srl);
|
|
||||||
Context::set('member_info',$member_info);
|
|
||||||
// Set a template file
|
|
||||||
$this->setTemplateFile('openid_leave_form');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Member log-out
|
* @brief Member log-out
|
||||||
**/
|
**/
|
||||||
|
|
|
||||||
|
|
@ -1,412 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the PHP OpenID library by JanRain, Inc.
|
|
||||||
*
|
|
||||||
* This module contains core utility functionality used by the
|
|
||||||
* library. See Consumer.php and Server.php for the consumer and
|
|
||||||
* server implementations.
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Require the fetcher code.
|
|
||||||
*/
|
|
||||||
require_once "Services/Yadis/PlainHTTPFetcher.php";
|
|
||||||
require_once "Services/Yadis/ParanoidHTTPFetcher.php";
|
|
||||||
require_once "Auth/OpenID/BigMath.php";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Status code returned by the server when the only option is to show
|
|
||||||
* an error page, since we do not have enough information to redirect
|
|
||||||
* back to the consumer. The associated value is an error message that
|
|
||||||
* should be displayed on an HTML error page.
|
|
||||||
*
|
|
||||||
* @see Auth_OpenID_Server
|
|
||||||
*/
|
|
||||||
define('Auth_OpenID_LOCAL_ERROR', 'local_error');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Status code returned when there is an error to return in key-value
|
|
||||||
* form to the consumer. The caller should return a 400 Bad Request
|
|
||||||
* response with content-type text/plain and the value as the body.
|
|
||||||
*
|
|
||||||
* @see Auth_OpenID_Server
|
|
||||||
*/
|
|
||||||
define('Auth_OpenID_REMOTE_ERROR', 'remote_error');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Status code returned when there is a key-value form OK response to
|
|
||||||
* the consumer. The value associated with this code is the
|
|
||||||
* response. The caller should return a 200 OK response with
|
|
||||||
* content-type text/plain and the value as the body.
|
|
||||||
*
|
|
||||||
* @see Auth_OpenID_Server
|
|
||||||
*/
|
|
||||||
define('Auth_OpenID_REMOTE_OK', 'remote_ok');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Status code returned when there is a redirect back to the
|
|
||||||
* consumer. The value is the URL to redirect back to. The caller
|
|
||||||
* should return a 302 Found redirect with a Location: header
|
|
||||||
* containing the URL.
|
|
||||||
*
|
|
||||||
* @see Auth_OpenID_Server
|
|
||||||
*/
|
|
||||||
define('Auth_OpenID_REDIRECT', 'redirect');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Status code returned when the caller needs to authenticate the
|
|
||||||
* user. The associated value is a {@link Auth_OpenID_ServerRequest}
|
|
||||||
* object that can be used to complete the authentication. If the user
|
|
||||||
* has taken some authentication action, use the retry() method of the
|
|
||||||
* {@link Auth_OpenID_ServerRequest} object to complete the request.
|
|
||||||
*
|
|
||||||
* @see Auth_OpenID_Server
|
|
||||||
*/
|
|
||||||
define('Auth_OpenID_DO_AUTH', 'do_auth');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Status code returned when there were no OpenID arguments
|
|
||||||
* passed. This code indicates that the caller should return a 200 OK
|
|
||||||
* response and display an HTML page that says that this is an OpenID
|
|
||||||
* server endpoint.
|
|
||||||
*
|
|
||||||
* @see Auth_OpenID_Server
|
|
||||||
*/
|
|
||||||
define('Auth_OpenID_DO_ABOUT', 'do_about');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines for regexes and format checking.
|
|
||||||
*/
|
|
||||||
define('Auth_OpenID_letters',
|
|
||||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
|
||||||
|
|
||||||
define('Auth_OpenID_digits',
|
|
||||||
"0123456789");
|
|
||||||
|
|
||||||
define('Auth_OpenID_punct',
|
|
||||||
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~");
|
|
||||||
|
|
||||||
if (Auth_OpenID_getMathLib() === null) {
|
|
||||||
define('Auth_OpenID_NO_MATH_SUPPORT', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The OpenID utility function class.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
class Auth_OpenID {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* These namespaces are automatically fixed in query arguments by
|
|
||||||
* Auth_OpenID::fixArgs.
|
|
||||||
*/
|
|
||||||
function getOpenIDNamespaces()
|
|
||||||
{
|
|
||||||
return array('openid',
|
|
||||||
'sreg');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rename query arguments back to 'openid.' from 'openid_'
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @param array $args An associative array of URL query arguments
|
|
||||||
*/
|
|
||||||
function fixArgs($args)
|
|
||||||
{
|
|
||||||
foreach (array_keys($args) as $key) {
|
|
||||||
$fixed = $key;
|
|
||||||
if (preg_match('/^openid/', $key)) {
|
|
||||||
foreach (Auth_OpenID::getOpenIDNamespaces() as $ns) {
|
|
||||||
if (preg_match('/'.$ns.'_/', $key)) {
|
|
||||||
$fixed = preg_replace('/'.$ns.'_/', $ns.'.', $fixed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($fixed != $key) {
|
|
||||||
$val = $args[$key];
|
|
||||||
unset($args[$key]);
|
|
||||||
$args[$fixed] = $val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $args;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create dir_name as a directory if it does not exist. If it
|
|
||||||
* exists, make sure that it is, in fact, a directory. Returns
|
|
||||||
* true if the operation succeeded; false if not.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function ensureDir($dir_name)
|
|
||||||
{
|
|
||||||
if (is_dir($dir_name) || @mkdir($dir_name)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
if (Auth_OpenID::ensureDir(dirname($dir_name))) {
|
|
||||||
return is_dir($dir_name) || @mkdir($dir_name);
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience function for getting array values.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function arrayGet($arr, $key, $fallback = null)
|
|
||||||
{
|
|
||||||
if (is_array($arr)) {
|
|
||||||
if (array_key_exists($key, $arr)) {
|
|
||||||
return $arr[$key];
|
|
||||||
} else {
|
|
||||||
return $fallback;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
trigger_error("Auth_OpenID::arrayGet expected " .
|
|
||||||
"array as first parameter", E_USER_WARNING);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements the PHP 5 'http_build_query' functionality.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @param array $data Either an array key/value pairs or an array
|
|
||||||
* of arrays, each of which holding two values: a key and a value,
|
|
||||||
* sequentially.
|
|
||||||
* @return string $result The result of url-encoding the key/value
|
|
||||||
* pairs from $data into a URL query string
|
|
||||||
* (e.g. "username=bob&id=56").
|
|
||||||
*/
|
|
||||||
function httpBuildQuery($data)
|
|
||||||
{
|
|
||||||
$pairs = array();
|
|
||||||
foreach ($data as $key => $value) {
|
|
||||||
if (is_array($value)) {
|
|
||||||
$pairs[] = urlencode($value[0])."=".urlencode($value[1]);
|
|
||||||
} else {
|
|
||||||
$pairs[] = urlencode($key)."=".urlencode($value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return implode("&", $pairs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* "Appends" query arguments onto a URL. The URL may or may not
|
|
||||||
* already have arguments (following a question mark).
|
|
||||||
*
|
|
||||||
* @param string $url A URL, which may or may not already have
|
|
||||||
* arguments.
|
|
||||||
* @param array $args Either an array key/value pairs or an array of
|
|
||||||
* arrays, each of which holding two values: a key and a value,
|
|
||||||
* sequentially. If $args is an ordinary key/value array, the
|
|
||||||
* parameters will be added to the URL in sorted alphabetical order;
|
|
||||||
* if $args is an array of arrays, their order will be preserved.
|
|
||||||
* @return string $url The original URL with the new parameters added.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function appendArgs($url, $args)
|
|
||||||
{
|
|
||||||
if (count($args) == 0) {
|
|
||||||
return $url;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Non-empty array; if it is an array of arrays, use
|
|
||||||
// multisort; otherwise use sort.
|
|
||||||
if (array_key_exists(0, $args) &&
|
|
||||||
is_array($args[0])) {
|
|
||||||
// Do nothing here.
|
|
||||||
} else {
|
|
||||||
$keys = array_keys($args);
|
|
||||||
sort($keys);
|
|
||||||
$new_args = array();
|
|
||||||
foreach ($keys as $key) {
|
|
||||||
$new_args[] = array($key, $args[$key]);
|
|
||||||
}
|
|
||||||
$args = $new_args;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sep = '?';
|
|
||||||
if (strpos($url, '?') !== false) {
|
|
||||||
$sep = '&';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $url . $sep . Auth_OpenID::httpBuildQuery($args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turn a string into an ASCII string.
|
|
||||||
*
|
|
||||||
* Replace non-ascii characters with a %-encoded, UTF-8
|
|
||||||
* encoding. This function will fail if the input is a string and
|
|
||||||
* there are non-7-bit-safe characters. It is assumed that the
|
|
||||||
* caller will have already translated the input into a Unicode
|
|
||||||
* character sequence, according to the encoding of the HTTP POST
|
|
||||||
* or GET.
|
|
||||||
*
|
|
||||||
* Do not escape anything that is already 7-bit safe, so we do the
|
|
||||||
* minimal transform on the identity URL
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function quoteMinimal($s)
|
|
||||||
{
|
|
||||||
$res = array();
|
|
||||||
for ($i = 0; $i < strlen($s); $i++) {
|
|
||||||
$c = $s[$i];
|
|
||||||
if ($c >= "\x80") {
|
|
||||||
for ($j = 0; $j < count(utf8_encode($c)); $j++) {
|
|
||||||
array_push($res, sprintf("%02X", ord($c[$j])));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
array_push($res, $c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return implode('', $res);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements python's urlunparse, which is not available in PHP.
|
|
||||||
* Given the specified components of a URL, this function rebuilds
|
|
||||||
* and returns the URL.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @param string $scheme The scheme (e.g. 'http'). Defaults to 'http'.
|
|
||||||
* @param string $host The host. Required.
|
|
||||||
* @param string $port The port.
|
|
||||||
* @param string $path The path.
|
|
||||||
* @param string $query The query.
|
|
||||||
* @param string $fragment The fragment.
|
|
||||||
* @return string $url The URL resulting from assembling the
|
|
||||||
* specified components.
|
|
||||||
*/
|
|
||||||
function urlunparse($scheme, $host, $port = null, $path = '/',
|
|
||||||
$query = '', $fragment = '')
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!$scheme) {
|
|
||||||
$scheme = 'http';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$host) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$path) {
|
|
||||||
$path = '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = $scheme . "://" . $host;
|
|
||||||
|
|
||||||
if ($port) {
|
|
||||||
$result .= ":" . $port;
|
|
||||||
}
|
|
||||||
|
|
||||||
$result .= $path;
|
|
||||||
|
|
||||||
if ($query) {
|
|
||||||
$result .= "?" . $query;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($fragment) {
|
|
||||||
$result .= "#" . $fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a URL, this "normalizes" it by adding a trailing slash
|
|
||||||
* and / or a leading http:// scheme where necessary. Returns
|
|
||||||
* null if the original URL is malformed and cannot be normalized.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @param string $url The URL to be normalized.
|
|
||||||
* @return mixed $new_url The URL after normalization, or null if
|
|
||||||
* $url was malformed.
|
|
||||||
*/
|
|
||||||
function normalizeUrl($url)
|
|
||||||
{
|
|
||||||
if ($url === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(is_string($url));
|
|
||||||
|
|
||||||
$old_url = $url;
|
|
||||||
$url = trim($url);
|
|
||||||
|
|
||||||
if (strpos($url, "://") === false) {
|
|
||||||
$url = "http://" . $url;
|
|
||||||
}
|
|
||||||
|
|
||||||
$parsed = @parse_url($url);
|
|
||||||
|
|
||||||
if ($parsed === false) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$defaults = array(
|
|
||||||
'scheme' => '',
|
|
||||||
'host' => '',
|
|
||||||
'path' => '',
|
|
||||||
'query' => '',
|
|
||||||
'fragment' => '',
|
|
||||||
'port' => ''
|
|
||||||
);
|
|
||||||
|
|
||||||
$parsed = array_merge($defaults, $parsed);
|
|
||||||
|
|
||||||
if (($parsed['scheme'] == '') ||
|
|
||||||
($parsed['host'] == '')) {
|
|
||||||
if ($parsed['path'] == '' &&
|
|
||||||
$parsed['query'] == '' &&
|
|
||||||
$parsed['fragment'] == '') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$url = 'http://' + $url;
|
|
||||||
$parsed = parse_url($url);
|
|
||||||
|
|
||||||
$parsed = array_merge($defaults, $parsed);
|
|
||||||
}
|
|
||||||
|
|
||||||
$tail = array_map(array('Auth_OpenID', 'quoteMinimal'),
|
|
||||||
array($parsed['path'],
|
|
||||||
$parsed['query'],
|
|
||||||
$parsed['fragment']));
|
|
||||||
if ($tail[0] == '') {
|
|
||||||
$tail[0] = '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
$url = Auth_OpenID::urlunparse($parsed['scheme'], $parsed['host'],
|
|
||||||
$parsed['port'], $tail[0], $tail[1],
|
|
||||||
$tail[2]);
|
|
||||||
|
|
||||||
assert(is_string($url));
|
|
||||||
|
|
||||||
return $url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,308 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This module contains code for dealing with associations between
|
|
||||||
* consumers and servers.
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
require_once 'Auth/OpenID/CryptUtil.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
require_once 'Auth/OpenID/KVForm.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents an association between a server and a
|
|
||||||
* consumer. In general, users of this library will never see
|
|
||||||
* instances of this object. The only exception is if you implement a
|
|
||||||
* custom {@link Auth_OpenID_OpenIDStore}.
|
|
||||||
*
|
|
||||||
* If you do implement such a store, it will need to store the values
|
|
||||||
* of the handle, secret, issued, lifetime, and assoc_type instance
|
|
||||||
* variables.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
*/
|
|
||||||
class Auth_OpenID_Association {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a HMAC-SHA1 specific value.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
var $SIG_LENGTH = 20;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The ordering and name of keys as stored by serialize.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
var $assoc_keys = array(
|
|
||||||
'version',
|
|
||||||
'handle',
|
|
||||||
'secret',
|
|
||||||
'issued',
|
|
||||||
'lifetime',
|
|
||||||
'assoc_type'
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is an alternate constructor (factory method) used by the
|
|
||||||
* OpenID consumer library to create associations. OpenID store
|
|
||||||
* implementations shouldn't use this constructor.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
*
|
|
||||||
* @param integer $expires_in This is the amount of time this
|
|
||||||
* association is good for, measured in seconds since the
|
|
||||||
* association was issued.
|
|
||||||
*
|
|
||||||
* @param string $handle This is the handle the server gave this
|
|
||||||
* association.
|
|
||||||
*
|
|
||||||
* @param string secret This is the shared secret the server
|
|
||||||
* generated for this association.
|
|
||||||
*
|
|
||||||
* @param assoc_type This is the type of association this
|
|
||||||
* instance represents. The only valid value of this field at
|
|
||||||
* this time is 'HMAC-SHA1', but new types may be defined in the
|
|
||||||
* future.
|
|
||||||
*
|
|
||||||
* @return association An {@link Auth_OpenID_Association}
|
|
||||||
* instance.
|
|
||||||
*/
|
|
||||||
function fromExpiresIn($expires_in, $handle, $secret, $assoc_type)
|
|
||||||
{
|
|
||||||
$issued = time();
|
|
||||||
$lifetime = $expires_in;
|
|
||||||
return new Auth_OpenID_Association($handle, $secret,
|
|
||||||
$issued, $lifetime, $assoc_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the standard constructor for creating an association.
|
|
||||||
* The library should create all of the necessary associations, so
|
|
||||||
* this constructor is not part of the external API.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
*
|
|
||||||
* @param string $handle This is the handle the server gave this
|
|
||||||
* association.
|
|
||||||
*
|
|
||||||
* @param string $secret This is the shared secret the server
|
|
||||||
* generated for this association.
|
|
||||||
*
|
|
||||||
* @param integer $issued This is the time this association was
|
|
||||||
* issued, in seconds since 00:00 GMT, January 1, 1970. (ie, a
|
|
||||||
* unix timestamp)
|
|
||||||
*
|
|
||||||
* @param integer $lifetime This is the amount of time this
|
|
||||||
* association is good for, measured in seconds since the
|
|
||||||
* association was issued.
|
|
||||||
*
|
|
||||||
* @param string $assoc_type This is the type of association this
|
|
||||||
* instance represents. The only valid value of this field at
|
|
||||||
* this time is 'HMAC-SHA1', but new types may be defined in the
|
|
||||||
* future.
|
|
||||||
*/
|
|
||||||
function Auth_OpenID_Association(
|
|
||||||
$handle, $secret, $issued, $lifetime, $assoc_type)
|
|
||||||
{
|
|
||||||
if ($assoc_type != 'HMAC-SHA1') {
|
|
||||||
$fmt = 'HMAC-SHA1 is the only supported association type (got %s)';
|
|
||||||
trigger_error(sprintf($fmt, $assoc_type), E_USER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->handle = $handle;
|
|
||||||
$this->secret = $secret;
|
|
||||||
$this->issued = $issued;
|
|
||||||
$this->lifetime = $lifetime;
|
|
||||||
$this->assoc_type = $assoc_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This returns the number of seconds this association is still
|
|
||||||
* valid for, or 0 if the association is no longer valid.
|
|
||||||
*
|
|
||||||
* @return integer $seconds The number of seconds this association
|
|
||||||
* is still valid for, or 0 if the association is no longer valid.
|
|
||||||
*/
|
|
||||||
function getExpiresIn($now = null)
|
|
||||||
{
|
|
||||||
if ($now == null) {
|
|
||||||
$now = time();
|
|
||||||
}
|
|
||||||
|
|
||||||
return max(0, $this->issued + $this->lifetime - $now);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This checks to see if two {@link Auth_OpenID_Association}
|
|
||||||
* instances represent the same association.
|
|
||||||
*
|
|
||||||
* @return bool $result true if the two instances represent the
|
|
||||||
* same association, false otherwise.
|
|
||||||
*/
|
|
||||||
function equal($other)
|
|
||||||
{
|
|
||||||
return ((gettype($this) == gettype($other))
|
|
||||||
&& ($this->handle == $other->handle)
|
|
||||||
&& ($this->secret == $other->secret)
|
|
||||||
&& ($this->issued == $other->issued)
|
|
||||||
&& ($this->lifetime == $other->lifetime)
|
|
||||||
&& ($this->assoc_type == $other->assoc_type));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert an association to KV form.
|
|
||||||
*
|
|
||||||
* @return string $result String in KV form suitable for
|
|
||||||
* deserialization by deserialize.
|
|
||||||
*/
|
|
||||||
function serialize()
|
|
||||||
{
|
|
||||||
$data = array(
|
|
||||||
'version' => '2',
|
|
||||||
'handle' => $this->handle,
|
|
||||||
'secret' => base64_encode($this->secret),
|
|
||||||
'issued' => strval(intval($this->issued)),
|
|
||||||
'lifetime' => strval(intval($this->lifetime)),
|
|
||||||
'assoc_type' => $this->assoc_type
|
|
||||||
);
|
|
||||||
|
|
||||||
assert(array_keys($data) == $this->assoc_keys);
|
|
||||||
|
|
||||||
return Auth_OpenID_KVForm::fromArray($data, $strict = true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse an association as stored by serialize(). This is the
|
|
||||||
* inverse of serialize.
|
|
||||||
*
|
|
||||||
* @param string $assoc_s Association as serialized by serialize()
|
|
||||||
* @return Auth_OpenID_Association $result instance of this class
|
|
||||||
*/
|
|
||||||
function deserialize($class_name, $assoc_s)
|
|
||||||
{
|
|
||||||
$pairs = Auth_OpenID_KVForm::toArray($assoc_s, $strict = true);
|
|
||||||
$keys = array();
|
|
||||||
$values = array();
|
|
||||||
foreach ($pairs as $key => $value) {
|
|
||||||
if (is_array($value)) {
|
|
||||||
list($key, $value) = $value;
|
|
||||||
}
|
|
||||||
$keys[] = $key;
|
|
||||||
$values[] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
$class_vars = get_class_vars($class_name);
|
|
||||||
$class_assoc_keys = $class_vars['assoc_keys'];
|
|
||||||
|
|
||||||
sort($keys);
|
|
||||||
sort($class_assoc_keys);
|
|
||||||
|
|
||||||
if ($keys != $class_assoc_keys) {
|
|
||||||
trigger_error('Unexpected key values: ' . strval($keys),
|
|
||||||
E_USER_WARNING);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$version = $pairs['version'];
|
|
||||||
$handle = $pairs['handle'];
|
|
||||||
$secret = $pairs['secret'];
|
|
||||||
$issued = $pairs['issued'];
|
|
||||||
$lifetime = $pairs['lifetime'];
|
|
||||||
$assoc_type = $pairs['assoc_type'];
|
|
||||||
|
|
||||||
if ($version != '2') {
|
|
||||||
trigger_error('Unknown version: ' . $version, E_USER_WARNING);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$issued = intval($issued);
|
|
||||||
$lifetime = intval($lifetime);
|
|
||||||
$secret = base64_decode($secret);
|
|
||||||
|
|
||||||
return new $class_name(
|
|
||||||
$handle, $secret, $issued, $lifetime, $assoc_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a signature for a sequence of (key, value) pairs
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @param array $pairs The pairs to sign, in order. This is an
|
|
||||||
* array of two-tuples.
|
|
||||||
* @return string $signature The binary signature of this sequence
|
|
||||||
* of pairs
|
|
||||||
*/
|
|
||||||
function sign($pairs)
|
|
||||||
{
|
|
||||||
$kv = Auth_OpenID_KVForm::fromArray($pairs);
|
|
||||||
return Auth_OpenID_HMACSHA1($this->secret, $kv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a signature for some fields in a dictionary
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @param array $fields The fields to sign, in order; this is an
|
|
||||||
* array of strings.
|
|
||||||
* @param array $data Dictionary of values to sign (an array of
|
|
||||||
* string => string pairs).
|
|
||||||
* @return string $signature The signature, base64 encoded
|
|
||||||
*/
|
|
||||||
function signDict($fields, $data, $prefix = 'openid.')
|
|
||||||
{
|
|
||||||
$pairs = array();
|
|
||||||
foreach ($fields as $field) {
|
|
||||||
$pairs[] = array($field, $data[$prefix . $field]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return base64_encode($this->sign($pairs));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a signature to an array of fields
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function addSignature($fields, &$data, $prefix = 'openid.')
|
|
||||||
{
|
|
||||||
$sig = $this->signDict($fields, $data, $prefix);
|
|
||||||
$signed = implode(",", $fields);
|
|
||||||
$data[$prefix . 'sig'] = $sig;
|
|
||||||
$data[$prefix . 'signed'] = $signed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Confirm that the signature of these fields matches the
|
|
||||||
* signature contained in the data
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function checkSignature($data, $prefix = 'openid.')
|
|
||||||
{
|
|
||||||
$signed = $data[$prefix . 'signed'];
|
|
||||||
$fields = explode(",", $signed);
|
|
||||||
$expected_sig = $this->signDict($fields, $data, $prefix);
|
|
||||||
$request_sig = $data[$prefix . 'sig'];
|
|
||||||
|
|
||||||
return ($request_sig == $expected_sig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,444 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BigMath: A math library wrapper that abstracts out the underlying
|
|
||||||
* long integer library.
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @package OpenID
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Needed for random number generation
|
|
||||||
*/
|
|
||||||
require_once 'Auth/OpenID/CryptUtil.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The superclass of all big-integer math implementations
|
|
||||||
* @access private
|
|
||||||
* @package OpenID
|
|
||||||
*/
|
|
||||||
class Auth_OpenID_MathLibrary {
|
|
||||||
/**
|
|
||||||
* Given a long integer, returns the number converted to a binary
|
|
||||||
* string. This function accepts long integer values of arbitrary
|
|
||||||
* magnitude and uses the local large-number math library when
|
|
||||||
* available.
|
|
||||||
*
|
|
||||||
* @param integer $long The long number (can be a normal PHP
|
|
||||||
* integer or a number created by one of the available long number
|
|
||||||
* libraries)
|
|
||||||
* @return string $binary The binary version of $long
|
|
||||||
*/
|
|
||||||
function longToBinary($long)
|
|
||||||
{
|
|
||||||
$cmp = $this->cmp($long, 0);
|
|
||||||
if ($cmp < 0) {
|
|
||||||
$msg = __FUNCTION__ . " takes only positive integers.";
|
|
||||||
trigger_error($msg, E_USER_ERROR);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($cmp == 0) {
|
|
||||||
return "\x00";
|
|
||||||
}
|
|
||||||
|
|
||||||
$bytes = array();
|
|
||||||
|
|
||||||
while ($this->cmp($long, 0) > 0) {
|
|
||||||
array_unshift($bytes, $this->mod($long, 256));
|
|
||||||
$long = $this->div($long, pow(2, 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($bytes && ($bytes[0] > 127)) {
|
|
||||||
array_unshift($bytes, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
$string = '';
|
|
||||||
foreach ($bytes as $byte) {
|
|
||||||
$string .= pack('C', $byte);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a binary string, returns the binary string converted to a
|
|
||||||
* long number.
|
|
||||||
*
|
|
||||||
* @param string $binary The binary version of a long number,
|
|
||||||
* probably as a result of calling longToBinary
|
|
||||||
* @return integer $long The long number equivalent of the binary
|
|
||||||
* string $str
|
|
||||||
*/
|
|
||||||
function binaryToLong($str)
|
|
||||||
{
|
|
||||||
if ($str === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use array_merge to return a zero-indexed array instead of a
|
|
||||||
// one-indexed array.
|
|
||||||
$bytes = array_merge(unpack('C*', $str));
|
|
||||||
|
|
||||||
$n = $this->init(0);
|
|
||||||
|
|
||||||
if ($bytes && ($bytes[0] > 127)) {
|
|
||||||
trigger_error("bytesToNum works only for positive integers.",
|
|
||||||
E_USER_WARNING);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($bytes as $byte) {
|
|
||||||
$n = $this->mul($n, pow(2, 8));
|
|
||||||
$n = $this->add($n, $byte);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $n;
|
|
||||||
}
|
|
||||||
|
|
||||||
function base64ToLong($str)
|
|
||||||
{
|
|
||||||
$b64 = base64_decode($str);
|
|
||||||
|
|
||||||
if ($b64 === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->binaryToLong($b64);
|
|
||||||
}
|
|
||||||
|
|
||||||
function longToBase64($str)
|
|
||||||
{
|
|
||||||
return base64_encode($this->longToBinary($str));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a random number in the specified range. This function
|
|
||||||
* accepts $start, $stop, and $step values of arbitrary magnitude
|
|
||||||
* and will utilize the local large-number math library when
|
|
||||||
* available.
|
|
||||||
*
|
|
||||||
* @param integer $start The start of the range, or the minimum
|
|
||||||
* random number to return
|
|
||||||
* @param integer $stop The end of the range, or the maximum
|
|
||||||
* random number to return
|
|
||||||
* @param integer $step The step size, such that $result - ($step
|
|
||||||
* * N) = $start for some N
|
|
||||||
* @return integer $result The resulting randomly-generated number
|
|
||||||
*/
|
|
||||||
function rand($stop)
|
|
||||||
{
|
|
||||||
static $duplicate_cache = array();
|
|
||||||
|
|
||||||
// Used as the key for the duplicate cache
|
|
||||||
$rbytes = $this->longToBinary($stop);
|
|
||||||
|
|
||||||
if (array_key_exists($rbytes, $duplicate_cache)) {
|
|
||||||
list($duplicate, $nbytes) = $duplicate_cache[$rbytes];
|
|
||||||
} else {
|
|
||||||
if ($rbytes[0] == "\x00") {
|
|
||||||
$nbytes = strlen($rbytes) - 1;
|
|
||||||
} else {
|
|
||||||
$nbytes = strlen($rbytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
$mxrand = $this->pow(256, $nbytes);
|
|
||||||
|
|
||||||
// If we get a number less than this, then it is in the
|
|
||||||
// duplicated range.
|
|
||||||
$duplicate = $this->mod($mxrand, $stop);
|
|
||||||
|
|
||||||
if (count($duplicate_cache) > 10) {
|
|
||||||
$duplicate_cache = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
$duplicate_cache[$rbytes] = array($duplicate, $nbytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
$bytes = "\x00" . Auth_OpenID_CryptUtil::getBytes($nbytes);
|
|
||||||
$n = $this->binaryToLong($bytes);
|
|
||||||
// Keep looping if this value is in the low duplicated range
|
|
||||||
} while ($this->cmp($n, $duplicate) < 0);
|
|
||||||
|
|
||||||
return $this->mod($n, $stop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exposes BCmath math library functionality.
|
|
||||||
*
|
|
||||||
* {@link Auth_OpenID_BcMathWrapper} wraps the functionality provided
|
|
||||||
* by the BCMath extension.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @package OpenID
|
|
||||||
*/
|
|
||||||
class Auth_OpenID_BcMathWrapper extends Auth_OpenID_MathLibrary{
|
|
||||||
var $type = 'bcmath';
|
|
||||||
|
|
||||||
function add($x, $y)
|
|
||||||
{
|
|
||||||
return bcadd($x, $y);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sub($x, $y)
|
|
||||||
{
|
|
||||||
return bcsub($x, $y);
|
|
||||||
}
|
|
||||||
|
|
||||||
function pow($base, $exponent)
|
|
||||||
{
|
|
||||||
return bcpow($base, $exponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
function cmp($x, $y)
|
|
||||||
{
|
|
||||||
return bccomp($x, $y);
|
|
||||||
}
|
|
||||||
|
|
||||||
function init($number, $base = 10)
|
|
||||||
{
|
|
||||||
return $number;
|
|
||||||
}
|
|
||||||
|
|
||||||
function mod($base, $modulus)
|
|
||||||
{
|
|
||||||
return bcmod($base, $modulus);
|
|
||||||
}
|
|
||||||
|
|
||||||
function mul($x, $y)
|
|
||||||
{
|
|
||||||
return bcmul($x, $y);
|
|
||||||
}
|
|
||||||
|
|
||||||
function div($x, $y)
|
|
||||||
{
|
|
||||||
return bcdiv($x, $y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Same as bcpowmod when bcpowmod is missing
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _powmod($base, $exponent, $modulus)
|
|
||||||
{
|
|
||||||
$square = $this->mod($base, $modulus);
|
|
||||||
$result = 1;
|
|
||||||
while($this->cmp($exponent, 0) > 0) {
|
|
||||||
if ($this->mod($exponent, 2)) {
|
|
||||||
$result = $this->mod($this->mul($result, $square), $modulus);
|
|
||||||
}
|
|
||||||
$square = $this->mod($this->mul($square, $square), $modulus);
|
|
||||||
$exponent = $this->div($exponent, 2);
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function powmod($base, $exponent, $modulus)
|
|
||||||
{
|
|
||||||
if (function_exists('bcpowmod')) {
|
|
||||||
return bcpowmod($base, $exponent, $modulus);
|
|
||||||
} else {
|
|
||||||
return $this->_powmod($base, $exponent, $modulus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toString($num)
|
|
||||||
{
|
|
||||||
return $num;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exposes GMP math library functionality.
|
|
||||||
*
|
|
||||||
* {@link Auth_OpenID_GmpMathWrapper} wraps the functionality provided
|
|
||||||
* by the GMP extension.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @package OpenID
|
|
||||||
*/
|
|
||||||
class Auth_OpenID_GmpMathWrapper extends Auth_OpenID_MathLibrary{
|
|
||||||
var $type = 'gmp';
|
|
||||||
|
|
||||||
function add($x, $y)
|
|
||||||
{
|
|
||||||
return gmp_add($x, $y);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sub($x, $y)
|
|
||||||
{
|
|
||||||
return gmp_sub($x, $y);
|
|
||||||
}
|
|
||||||
|
|
||||||
function pow($base, $exponent)
|
|
||||||
{
|
|
||||||
return gmp_pow($base, $exponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
function cmp($x, $y)
|
|
||||||
{
|
|
||||||
return gmp_cmp($x, $y);
|
|
||||||
}
|
|
||||||
|
|
||||||
function init($number, $base = 10)
|
|
||||||
{
|
|
||||||
return gmp_init($number, $base);
|
|
||||||
}
|
|
||||||
|
|
||||||
function mod($base, $modulus)
|
|
||||||
{
|
|
||||||
return gmp_mod($base, $modulus);
|
|
||||||
}
|
|
||||||
|
|
||||||
function mul($x, $y)
|
|
||||||
{
|
|
||||||
return gmp_mul($x, $y);
|
|
||||||
}
|
|
||||||
|
|
||||||
function div($x, $y)
|
|
||||||
{
|
|
||||||
return gmp_div_q($x, $y);
|
|
||||||
}
|
|
||||||
|
|
||||||
function powmod($base, $exponent, $modulus)
|
|
||||||
{
|
|
||||||
return gmp_powm($base, $exponent, $modulus);
|
|
||||||
}
|
|
||||||
|
|
||||||
function toString($num)
|
|
||||||
{
|
|
||||||
return gmp_strval($num);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define the supported extensions. An extension array has keys
|
|
||||||
* 'modules', 'extension', and 'class'. 'modules' is an array of PHP
|
|
||||||
* module names which the loading code will attempt to load. These
|
|
||||||
* values will be suffixed with a library file extension (e.g. ".so").
|
|
||||||
* 'extension' is the name of a PHP extension which will be tested
|
|
||||||
* before 'modules' are loaded. 'class' is the string name of a
|
|
||||||
* {@link Auth_OpenID_MathWrapper} subclass which should be
|
|
||||||
* instantiated if a given extension is present.
|
|
||||||
*
|
|
||||||
* You can define new math library implementations and add them to
|
|
||||||
* this array.
|
|
||||||
*/
|
|
||||||
global $_Auth_OpenID_math_extensions;
|
|
||||||
$_Auth_OpenID_math_extensions = array(
|
|
||||||
array('modules' => array('gmp', 'php_gmp'),
|
|
||||||
'extension' => 'gmp',
|
|
||||||
'class' => 'Auth_OpenID_GmpMathWrapper'),
|
|
||||||
array('modules' => array('bcmath', 'php_bcmath'),
|
|
||||||
'extension' => 'bcmath',
|
|
||||||
'class' => 'Auth_OpenID_BcMathWrapper')
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Detect which (if any) math library is available
|
|
||||||
*/
|
|
||||||
function Auth_OpenID_detectMathLibrary($exts)
|
|
||||||
{
|
|
||||||
$loaded = false;
|
|
||||||
|
|
||||||
foreach ($exts as $extension) {
|
|
||||||
// See if the extension specified is already loaded.
|
|
||||||
if ($extension['extension'] &&
|
|
||||||
extension_loaded($extension['extension'])) {
|
|
||||||
$loaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to load dynamic modules.
|
|
||||||
if (!$loaded) {
|
|
||||||
foreach ($extension['modules'] as $module) {
|
|
||||||
if (function_exists('dl') && @dl($module . "." . PHP_SHLIB_SUFFIX)) {
|
|
||||||
$loaded = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the load succeeded, supply an instance of
|
|
||||||
// Auth_OpenID_MathWrapper which wraps the specified
|
|
||||||
// module's functionality.
|
|
||||||
if ($loaded) {
|
|
||||||
return $extension;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link Auth_OpenID_getMathLib} checks for the presence of long
|
|
||||||
* number extension modules and returns an instance of
|
|
||||||
* {@link Auth_OpenID_MathWrapper} which exposes the module's
|
|
||||||
* functionality.
|
|
||||||
*
|
|
||||||
* Checks for the existence of an extension module described by the
|
|
||||||
* local {@link Auth_OpenID_math_extensions} array and returns an
|
|
||||||
* instance of a wrapper for that extension module. If no extension
|
|
||||||
* module is found, an instance of {@link Auth_OpenID_MathWrapper} is
|
|
||||||
* returned, which wraps the native PHP integer implementation. The
|
|
||||||
* proper calling convention for this method is $lib =&
|
|
||||||
* Auth_OpenID_getMathLib().
|
|
||||||
*
|
|
||||||
* This function checks for the existence of specific long number
|
|
||||||
* implementations in the following order: GMP followed by BCmath.
|
|
||||||
*
|
|
||||||
* @return Auth_OpenID_MathWrapper $instance An instance of
|
|
||||||
* {@link Auth_OpenID_MathWrapper} or one of its subclasses
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
*/
|
|
||||||
function &Auth_OpenID_getMathLib()
|
|
||||||
{
|
|
||||||
// The instance of Auth_OpenID_MathWrapper that we choose to
|
|
||||||
// supply will be stored here, so that subseqent calls to this
|
|
||||||
// method will return a reference to the same object.
|
|
||||||
static $lib = null;
|
|
||||||
|
|
||||||
if (isset($lib)) {
|
|
||||||
return $lib;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defined('Auth_OpenID_NO_MATH_SUPPORT')) {
|
|
||||||
$null = null;
|
|
||||||
return $null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this method has not been called before, look at
|
|
||||||
// $Auth_OpenID_math_extensions and try to find an extension that
|
|
||||||
// works.
|
|
||||||
global $_Auth_OpenID_math_extensions;
|
|
||||||
$ext = Auth_OpenID_detectMathLibrary($_Auth_OpenID_math_extensions);
|
|
||||||
if ($ext === false) {
|
|
||||||
$tried = array();
|
|
||||||
foreach ($_Auth_OpenID_math_extensions as $extinfo) {
|
|
||||||
$tried[] = $extinfo['extension'];
|
|
||||||
}
|
|
||||||
$triedstr = implode(", ", $tried);
|
|
||||||
|
|
||||||
define('Auth_OpenID_NO_MATH_SUPPORT', true);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Instantiate a new wrapper
|
|
||||||
$class = $ext['class'];
|
|
||||||
$lib = new $class();
|
|
||||||
|
|
||||||
return $lib;
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,109 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CryptUtil: A suite of wrapper utility functions for the OpenID
|
|
||||||
* library.
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @package OpenID
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!defined('Auth_OpenID_RAND_SOURCE')) {
|
|
||||||
/**
|
|
||||||
* The filename for a source of random bytes. Define this yourself
|
|
||||||
* if you have a different source of randomness.
|
|
||||||
*/
|
|
||||||
define('Auth_OpenID_RAND_SOURCE', '/dev/urandom');
|
|
||||||
}
|
|
||||||
|
|
||||||
class Auth_OpenID_CryptUtil {
|
|
||||||
/**
|
|
||||||
* Get the specified number of random bytes.
|
|
||||||
*
|
|
||||||
* Attempts to use a cryptographically secure (not predictable)
|
|
||||||
* source of randomness if available. If there is no high-entropy
|
|
||||||
* randomness source available, it will fail. As a last resort,
|
|
||||||
* for non-critical systems, define
|
|
||||||
* <code>Auth_OpenID_RAND_SOURCE</code> as <code>null</code>, and
|
|
||||||
* the code will fall back on a pseudo-random number generator.
|
|
||||||
*
|
|
||||||
* @param int $num_bytes The length of the return value
|
|
||||||
* @return string $bytes random bytes
|
|
||||||
*/
|
|
||||||
function getBytes($num_bytes)
|
|
||||||
{
|
|
||||||
static $f = null;
|
|
||||||
$bytes = '';
|
|
||||||
if ($f === null) {
|
|
||||||
if (Auth_OpenID_RAND_SOURCE === null) {
|
|
||||||
$f = false;
|
|
||||||
} else {
|
|
||||||
$f = @fopen(Auth_OpenID_RAND_SOURCE, "r");
|
|
||||||
if ($f === false) {
|
|
||||||
$msg = 'Define Auth_OpenID_RAND_SOURCE as null to ' .
|
|
||||||
' continue with an insecure random number generator.';
|
|
||||||
trigger_error($msg, E_USER_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($f === false) {
|
|
||||||
// pseudorandom used
|
|
||||||
$bytes = '';
|
|
||||||
for ($i = 0; $i < $num_bytes; $i += 4) {
|
|
||||||
$bytes .= pack('L', mt_rand());
|
|
||||||
}
|
|
||||||
$bytes = substr($bytes, 0, $num_bytes);
|
|
||||||
} else {
|
|
||||||
$bytes = fread($f, $num_bytes);
|
|
||||||
}
|
|
||||||
return $bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Produce a string of length random bytes, chosen from chrs. If
|
|
||||||
* $chrs is null, the resulting string may contain any characters.
|
|
||||||
*
|
|
||||||
* @param integer $length The length of the resulting
|
|
||||||
* randomly-generated string
|
|
||||||
* @param string $chrs A string of characters from which to choose
|
|
||||||
* to build the new string
|
|
||||||
* @return string $result A string of randomly-chosen characters
|
|
||||||
* from $chrs
|
|
||||||
*/
|
|
||||||
function randomString($length, $population = null)
|
|
||||||
{
|
|
||||||
if ($population === null) {
|
|
||||||
return Auth_OpenID_CryptUtil::getBytes($length);
|
|
||||||
}
|
|
||||||
|
|
||||||
$popsize = strlen($population);
|
|
||||||
|
|
||||||
if ($popsize > 256) {
|
|
||||||
$msg = 'More than 256 characters supplied to ' . __FUNCTION__;
|
|
||||||
trigger_error($msg, E_USER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
$duplicate = 256 % $popsize;
|
|
||||||
|
|
||||||
$str = "";
|
|
||||||
for ($i = 0; $i < $length; $i++) {
|
|
||||||
do {
|
|
||||||
$n = ord(Auth_OpenID_CryptUtil::getBytes(1));
|
|
||||||
} while ($n < $duplicate);
|
|
||||||
|
|
||||||
$n %= $popsize;
|
|
||||||
$str .= $population[$n];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,131 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Auth_OpenID_DatabaseConnection class, which is used to emulate
|
|
||||||
* a PEAR database connection.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An empty base class intended to emulate PEAR connection
|
|
||||||
* functionality in applications that supply their own database
|
|
||||||
* abstraction mechanisms. See {@link Auth_OpenID_SQLStore} for more
|
|
||||||
* information. You should subclass this class if you need to create
|
|
||||||
* an SQL store that needs to access its database using an
|
|
||||||
* application's database abstraction layer instead of a PEAR database
|
|
||||||
* connection. Any subclass of Auth_OpenID_DatabaseConnection MUST
|
|
||||||
* adhere to the interface specified here.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
*/
|
|
||||||
class Auth_OpenID_DatabaseConnection {
|
|
||||||
/**
|
|
||||||
* Sets auto-commit mode on this database connection.
|
|
||||||
*
|
|
||||||
* @param bool $mode True if auto-commit is to be used; false if
|
|
||||||
* not.
|
|
||||||
*/
|
|
||||||
function autoCommit($mode)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run an SQL query with the specified parameters, if any.
|
|
||||||
*
|
|
||||||
* @param string $sql An SQL string with placeholders. The
|
|
||||||
* placeholders are assumed to be specific to the database engine
|
|
||||||
* for this connection.
|
|
||||||
*
|
|
||||||
* @param array $params An array of parameters to insert into the
|
|
||||||
* SQL string using this connection's escaping mechanism.
|
|
||||||
*
|
|
||||||
* @return mixed $result The result of calling this connection's
|
|
||||||
* internal query function. The type of result depends on the
|
|
||||||
* underlying database engine. This method is usually used when
|
|
||||||
* the result of a query is not important, like a DDL query.
|
|
||||||
*/
|
|
||||||
function query($sql, $params = array())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts a transaction on this connection, if supported.
|
|
||||||
*/
|
|
||||||
function begin()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Commits a transaction on this connection, if supported.
|
|
||||||
*/
|
|
||||||
function commit()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs a rollback on this connection, if supported.
|
|
||||||
*/
|
|
||||||
function rollback()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run an SQL query and return the first column of the first row
|
|
||||||
* of the result set, if any.
|
|
||||||
*
|
|
||||||
* @param string $sql An SQL string with placeholders. The
|
|
||||||
* placeholders are assumed to be specific to the database engine
|
|
||||||
* for this connection.
|
|
||||||
*
|
|
||||||
* @param array $params An array of parameters to insert into the
|
|
||||||
* SQL string using this connection's escaping mechanism.
|
|
||||||
*
|
|
||||||
* @return mixed $result The value of the first column of the
|
|
||||||
* first row of the result set. False if no such result was
|
|
||||||
* found.
|
|
||||||
*/
|
|
||||||
function getOne($sql, $params = array())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run an SQL query and return the first row of the result set, if
|
|
||||||
* any.
|
|
||||||
*
|
|
||||||
* @param string $sql An SQL string with placeholders. The
|
|
||||||
* placeholders are assumed to be specific to the database engine
|
|
||||||
* for this connection.
|
|
||||||
*
|
|
||||||
* @param array $params An array of parameters to insert into the
|
|
||||||
* SQL string using this connection's escaping mechanism.
|
|
||||||
*
|
|
||||||
* @return array $result The first row of the result set, if any,
|
|
||||||
* keyed on column name. False if no such result was found.
|
|
||||||
*/
|
|
||||||
function getRow($sql, $params = array())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run an SQL query with the specified parameters, if any.
|
|
||||||
*
|
|
||||||
* @param string $sql An SQL string with placeholders. The
|
|
||||||
* placeholders are assumed to be specific to the database engine
|
|
||||||
* for this connection.
|
|
||||||
*
|
|
||||||
* @param array $params An array of parameters to insert into the
|
|
||||||
* SQL string using this connection's escaping mechanism.
|
|
||||||
*
|
|
||||||
* @return array $result An array of arrays representing the
|
|
||||||
* result of the query; each array is keyed on column name.
|
|
||||||
*/
|
|
||||||
function getAll($sql, $params = array())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,181 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The OpenID library's Diffie-Hellman implementation.
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @package OpenID
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once 'Auth/OpenID/BigMath.php';
|
|
||||||
require_once 'Auth/OpenID/HMACSHA1.php';
|
|
||||||
|
|
||||||
function Auth_OpenID_getDefaultMod()
|
|
||||||
{
|
|
||||||
return '155172898181473697471232257763715539915724801'.
|
|
||||||
'966915404479707795314057629378541917580651227423'.
|
|
||||||
'698188993727816152646631438561595825688188889951'.
|
|
||||||
'272158842675419950341258706556549803580104870537'.
|
|
||||||
'681476726513255747040765857479291291572334510643'.
|
|
||||||
'245094715007229621094194349783925984760375594985'.
|
|
||||||
'848253359305585439638443';
|
|
||||||
}
|
|
||||||
|
|
||||||
function Auth_OpenID_getDefaultGen()
|
|
||||||
{
|
|
||||||
return '2';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Diffie-Hellman key exchange class. This class relies on
|
|
||||||
* {@link Auth_OpenID_MathLibrary} to perform large number operations.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @package OpenID
|
|
||||||
*/
|
|
||||||
class Auth_OpenID_DiffieHellman {
|
|
||||||
|
|
||||||
var $mod;
|
|
||||||
var $gen;
|
|
||||||
var $private;
|
|
||||||
var $lib = null;
|
|
||||||
|
|
||||||
function Auth_OpenID_DiffieHellman($mod = null, $gen = null,
|
|
||||||
$private = null, $lib = null)
|
|
||||||
{
|
|
||||||
if ($lib === null) {
|
|
||||||
$this->lib =& Auth_OpenID_getMathLib();
|
|
||||||
} else {
|
|
||||||
$this->lib =& $lib;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($mod === null) {
|
|
||||||
$this->mod = $this->lib->init(Auth_OpenID_getDefaultMod());
|
|
||||||
} else {
|
|
||||||
$this->mod = $mod;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($gen === null) {
|
|
||||||
$this->gen = $this->lib->init(Auth_OpenID_getDefaultGen());
|
|
||||||
} else {
|
|
||||||
$this->gen = $gen;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($private === null) {
|
|
||||||
$r = $this->lib->rand($this->mod);
|
|
||||||
$this->private = $this->lib->add($r, 1);
|
|
||||||
} else {
|
|
||||||
$this->private = $private;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->public = $this->lib->powmod($this->gen, $this->private,
|
|
||||||
$this->mod);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSharedSecret($composite)
|
|
||||||
{
|
|
||||||
return $this->lib->powmod($composite, $this->private, $this->mod);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPublicKey()
|
|
||||||
{
|
|
||||||
return $this->public;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate the arguments for an OpenID Diffie-Hellman association
|
|
||||||
* request
|
|
||||||
*/
|
|
||||||
function getAssocArgs()
|
|
||||||
{
|
|
||||||
$cpub = $this->lib->longToBase64($this->getPublicKey());
|
|
||||||
$args = array(
|
|
||||||
'openid.dh_consumer_public' => $cpub,
|
|
||||||
'openid.session_type' => 'DH-SHA1'
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($this->lib->cmp($this->mod, Auth_OpenID_getDefaultMod()) ||
|
|
||||||
$this->lib->cmp($this->gen, Auth_OpenID_getDefaultGen())) {
|
|
||||||
$args['openid.dh_modulus'] = $this->lib->longToBase64($this->mod);
|
|
||||||
$args['openid.dh_gen'] = $this->lib->longToBase64($this->gen);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $args;
|
|
||||||
}
|
|
||||||
|
|
||||||
function usingDefaultValues()
|
|
||||||
{
|
|
||||||
return ($this->mod == Auth_OpenID_getDefaultMod() &&
|
|
||||||
$this->gen == Auth_OpenID_getDefaultGen());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform the server side of the OpenID Diffie-Hellman association
|
|
||||||
*/
|
|
||||||
function serverAssociate($consumer_args, $assoc_secret)
|
|
||||||
{
|
|
||||||
$lib =& Auth_OpenID_getMathLib();
|
|
||||||
|
|
||||||
if (isset($consumer_args['openid.dh_modulus'])) {
|
|
||||||
$mod = $lib->base64ToLong($consumer_args['openid.dh_modulus']);
|
|
||||||
} else {
|
|
||||||
$mod = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($consumer_args['openid.dh_gen'])) {
|
|
||||||
$gen = $lib->base64ToLong($consumer_args['openid.dh_gen']);
|
|
||||||
} else {
|
|
||||||
$gen = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$cpub64 = @$consumer_args['openid.dh_consumer_public'];
|
|
||||||
if (!isset($cpub64)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$dh = new Auth_OpenID_DiffieHellman($mod, $gen);
|
|
||||||
$cpub = $lib->base64ToLong($cpub64);
|
|
||||||
$mac_key = $dh->xorSecret($cpub, $assoc_secret);
|
|
||||||
$enc_mac_key = base64_encode($mac_key);
|
|
||||||
$spub64 = $lib->longToBase64($dh->getPublicKey());
|
|
||||||
|
|
||||||
$server_args = array(
|
|
||||||
'session_type' => 'DH-SHA1',
|
|
||||||
'dh_server_public' => $spub64,
|
|
||||||
'enc_mac_key' => $enc_mac_key
|
|
||||||
);
|
|
||||||
|
|
||||||
return $server_args;
|
|
||||||
}
|
|
||||||
|
|
||||||
function consumerFinish($reply)
|
|
||||||
{
|
|
||||||
$spub = $this->lib->base64ToLong($reply['dh_server_public']);
|
|
||||||
if ($this->lib->cmp($spub, 0) <= 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$enc_mac_key = base64_decode($reply['enc_mac_key']);
|
|
||||||
return $this->xorSecret($spub, $enc_mac_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
function xorSecret($composite, $secret)
|
|
||||||
{
|
|
||||||
$dh_shared = $this->getSharedSecret($composite);
|
|
||||||
$dh_shared_str = $this->lib->longToBinary($dh_shared);
|
|
||||||
$sha1_dh_shared = Auth_OpenID_SHA1($dh_shared_str);
|
|
||||||
|
|
||||||
$xsecret = "";
|
|
||||||
for ($i = 0; $i < strlen($secret); $i++) {
|
|
||||||
$xsecret .= chr(ord($secret[$i]) ^ ord($sha1_dh_shared[$i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $xsecret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,258 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The OpenID and Yadis discovery implementation for OpenID 1.2.
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once "Auth/OpenID.php";
|
|
||||||
require_once "Auth/OpenID/Parse.php";
|
|
||||||
require_once "Services/Yadis/XRIRes.php";
|
|
||||||
require_once "Services/Yadis/Yadis.php";
|
|
||||||
|
|
||||||
define('_OPENID_1_0_NS', 'http://openid.net/xmlns/1.0');
|
|
||||||
define('_OPENID_1_2_TYPE', 'http://openid.net/signon/1.2');
|
|
||||||
define('_OPENID_1_1_TYPE', 'http://openid.net/signon/1.1');
|
|
||||||
define('_OPENID_1_0_TYPE', 'http://openid.net/signon/1.0');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Object representing an OpenID service endpoint.
|
|
||||||
*/
|
|
||||||
class Auth_OpenID_ServiceEndpoint {
|
|
||||||
function Auth_OpenID_ServiceEndpoint()
|
|
||||||
{
|
|
||||||
$this->identity_url = null;
|
|
||||||
$this->server_url = null;
|
|
||||||
$this->type_uris = array();
|
|
||||||
$this->delegate = null;
|
|
||||||
$this->canonicalID = null;
|
|
||||||
$this->used_yadis = false; // whether this came from an XRDS
|
|
||||||
}
|
|
||||||
|
|
||||||
function usesExtension($extension_uri)
|
|
||||||
{
|
|
||||||
return in_array($extension_uri, $this->type_uris);
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseService($yadis_url, $uri, $type_uris, $service_element)
|
|
||||||
{
|
|
||||||
// Set the state of this object based on the contents of the
|
|
||||||
// service element.
|
|
||||||
$this->type_uris = $type_uris;
|
|
||||||
$this->identity_url = $yadis_url;
|
|
||||||
$this->server_url = $uri;
|
|
||||||
$this->delegate = Auth_OpenID_ServiceEndpoint::findDelegate(
|
|
||||||
$service_element);
|
|
||||||
$this->used_yadis = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function findDelegate($service)
|
|
||||||
{
|
|
||||||
// Extract a openid:Delegate value from a Yadis Service
|
|
||||||
// element. If no delegate is found, returns null.
|
|
||||||
|
|
||||||
// Try to register new namespace.
|
|
||||||
$service->parser->registerNamespace('openid',
|
|
||||||
'http://openid.net/xmlns/1.0');
|
|
||||||
|
|
||||||
// XXX: should this die if there is more than one delegate
|
|
||||||
// element?
|
|
||||||
$delegates = $service->getElements("openid:Delegate");
|
|
||||||
|
|
||||||
if ($delegates) {
|
|
||||||
return $service->parser->content($delegates[0]);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getServerID()
|
|
||||||
{
|
|
||||||
// Return the identifier that should be sent as the
|
|
||||||
// openid.identity_url parameter to the server.
|
|
||||||
if ($this->delegate === null) {
|
|
||||||
if ($this->canonicalID) {
|
|
||||||
return $this->canonicalID;
|
|
||||||
} else {
|
|
||||||
return $this->identity_url;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return $this->delegate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function fromHTML($uri, $html)
|
|
||||||
{
|
|
||||||
// Parse the given document as HTML looking for an OpenID <link
|
|
||||||
// rel=...>
|
|
||||||
$urls = Auth_OpenID_legacy_discover($html);
|
|
||||||
if ($urls === false) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
list($delegate_url, $server_url) = $urls;
|
|
||||||
|
|
||||||
$service = new Auth_OpenID_ServiceEndpoint();
|
|
||||||
$service->identity_url = $uri;
|
|
||||||
$service->delegate = $delegate_url;
|
|
||||||
$service->server_url = $server_url;
|
|
||||||
$service->type_uris = array(_OPENID_1_0_TYPE);
|
|
||||||
return $service;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function filter_MatchesAnyOpenIDType(&$service)
|
|
||||||
{
|
|
||||||
$uris = $service->getTypes();
|
|
||||||
|
|
||||||
foreach ($uris as $uri) {
|
|
||||||
if (in_array($uri,
|
|
||||||
array(_OPENID_1_0_TYPE,
|
|
||||||
_OPENID_1_1_TYPE,
|
|
||||||
_OPENID_1_2_TYPE))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Auth_OpenID_makeOpenIDEndpoints($uri, $endpoints)
|
|
||||||
{
|
|
||||||
$s = array();
|
|
||||||
|
|
||||||
if (!$endpoints) {
|
|
||||||
return $s;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($endpoints as $service) {
|
|
||||||
$type_uris = $service->getTypes();
|
|
||||||
$uris = $service->getURIs();
|
|
||||||
|
|
||||||
// If any Type URIs match and there is an endpoint URI
|
|
||||||
// specified, then this is an OpenID endpoint
|
|
||||||
if ($type_uris &&
|
|
||||||
$uris) {
|
|
||||||
|
|
||||||
foreach ($uris as $service_uri) {
|
|
||||||
$openid_endpoint = new Auth_OpenID_ServiceEndpoint();
|
|
||||||
$openid_endpoint->parseService($uri,
|
|
||||||
$service_uri,
|
|
||||||
$type_uris,
|
|
||||||
$service);
|
|
||||||
|
|
||||||
$s[] = $openid_endpoint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $s;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Auth_OpenID_discoverWithYadis($uri, &$fetcher)
|
|
||||||
{
|
|
||||||
// Discover OpenID services for a URI. Tries Yadis and falls back
|
|
||||||
// on old-style <link rel='...'> discovery if Yadis fails.
|
|
||||||
|
|
||||||
// Might raise a yadis.discover.DiscoveryFailure if no document
|
|
||||||
// came back for that URI at all. I don't think falling back to
|
|
||||||
// OpenID 1.0 discovery on the same URL will help, so don't bother
|
|
||||||
// to catch it.
|
|
||||||
$openid_services = array();
|
|
||||||
|
|
||||||
$http_response = null;
|
|
||||||
$response = Services_Yadis_Yadis::discover($uri, $http_response,
|
|
||||||
$fetcher);
|
|
||||||
|
|
||||||
if ($response) {
|
|
||||||
$identity_url = $response->uri;
|
|
||||||
$openid_services =
|
|
||||||
$response->xrds->services(array('filter_MatchesAnyOpenIDType'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$openid_services) {
|
|
||||||
return @Auth_OpenID_discoverWithoutYadis($uri,
|
|
||||||
$fetcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$openid_services) {
|
|
||||||
$body = $response->body;
|
|
||||||
|
|
||||||
// Try to parse the response as HTML to get OpenID 1.0/1.1
|
|
||||||
// <link rel="...">
|
|
||||||
$service = Auth_OpenID_ServiceEndpoint::fromHTML($identity_url,
|
|
||||||
$body);
|
|
||||||
|
|
||||||
if ($service !== null) {
|
|
||||||
$openid_services = array($service);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$openid_services = Auth_OpenID_makeOpenIDEndpoints($response->uri,
|
|
||||||
$openid_services);
|
|
||||||
}
|
|
||||||
|
|
||||||
return array($identity_url, $openid_services, $http_response);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _Auth_OpenID_discoverServiceList($uri, &$fetcher)
|
|
||||||
{
|
|
||||||
list($url, $services, $resp) = Auth_OpenID_discoverWithYadis($uri,
|
|
||||||
$fetcher);
|
|
||||||
|
|
||||||
return $services;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _Auth_OpenID_discoverXRIServiceList($uri, &$fetcher)
|
|
||||||
{
|
|
||||||
list($url, $services, $resp) = _Auth_OpenID_discoverXRI($uri,
|
|
||||||
$fetcher);
|
|
||||||
return $services;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Auth_OpenID_discoverWithoutYadis($uri, &$fetcher)
|
|
||||||
{
|
|
||||||
$http_resp = @$fetcher->get($uri);
|
|
||||||
|
|
||||||
if ($http_resp->status != 200) {
|
|
||||||
return array(null, array(), $http_resp);
|
|
||||||
}
|
|
||||||
|
|
||||||
$identity_url = $http_resp->final_url;
|
|
||||||
|
|
||||||
// Try to parse the response as HTML to get OpenID 1.0/1.1 <link
|
|
||||||
// rel="...">
|
|
||||||
$endpoint =& new Auth_OpenID_ServiceEndpoint();
|
|
||||||
$service = $endpoint->fromHTML($identity_url, $http_resp->body);
|
|
||||||
if ($service === null) {
|
|
||||||
$openid_services = array();
|
|
||||||
} else {
|
|
||||||
$openid_services = array($service);
|
|
||||||
}
|
|
||||||
|
|
||||||
return array($identity_url, $openid_services, $http_resp);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _Auth_OpenID_discoverXRI($iname, &$fetcher)
|
|
||||||
{
|
|
||||||
$services = new Services_Yadis_ProxyResolver($fetcher);
|
|
||||||
list($canonicalID, $service_list) = $services->query($iname,
|
|
||||||
array(_OPENID_1_0_TYPE,
|
|
||||||
_OPENID_1_1_TYPE,
|
|
||||||
_OPENID_1_2_TYPE),
|
|
||||||
array('filter_MatchesAnyOpenIDType'));
|
|
||||||
|
|
||||||
$endpoints = Auth_OpenID_makeOpenIDEndpoints($iname, $service_list);
|
|
||||||
|
|
||||||
for ($i = 0; $i < count($endpoints); $i++) {
|
|
||||||
$endpoints[$i]->canonicalID = $canonicalID;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: returned xri should probably be in some normal form
|
|
||||||
return array($iname, $endpoints, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Auth_OpenID_discover($uri, &$fetcher)
|
|
||||||
{
|
|
||||||
return @Auth_OpenID_discoverWithYadis($uri, $fetcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This file supplies a dumb store backend for OpenID servers and
|
|
||||||
* consumers.
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Import the interface for creating a new store class.
|
|
||||||
*/
|
|
||||||
require_once 'Auth/OpenID/Interface.php';
|
|
||||||
require_once 'Auth/OpenID/HMACSHA1.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a store for use in the worst case, when you have no way of
|
|
||||||
* saving state on the consumer site. Using this store makes the
|
|
||||||
* consumer vulnerable to replay attacks, as it's unable to use
|
|
||||||
* nonces. Avoid using this store if it is at all possible.
|
|
||||||
*
|
|
||||||
* Most of the methods of this class are implementation details.
|
|
||||||
* Users of this class need to worry only about the constructor.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
*/
|
|
||||||
class Auth_OpenID_DumbStore extends Auth_OpenID_OpenIDStore {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link Auth_OpenID_DumbStore} instance. For the security
|
|
||||||
* of the tokens generated by the library, this class attempts to
|
|
||||||
* at least have a secure implementation of getAuthKey.
|
|
||||||
*
|
|
||||||
* When you create an instance of this class, pass in a secret
|
|
||||||
* phrase. The phrase is hashed with sha1 to make it the correct
|
|
||||||
* length and form for an auth key. That allows you to use a long
|
|
||||||
* string as the secret phrase, which means you can make it very
|
|
||||||
* difficult to guess.
|
|
||||||
*
|
|
||||||
* Each {@link Auth_OpenID_DumbStore} instance that is created for use by
|
|
||||||
* your consumer site needs to use the same $secret_phrase.
|
|
||||||
*
|
|
||||||
* @param string secret_phrase The phrase used to create the auth
|
|
||||||
* key returned by getAuthKey
|
|
||||||
*/
|
|
||||||
function Auth_OpenID_DumbStore($secret_phrase)
|
|
||||||
{
|
|
||||||
$this->auth_key = Auth_OpenID_SHA1($secret_phrase);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation does nothing.
|
|
||||||
*/
|
|
||||||
function storeAssociation($server_url, $association)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation always returns null.
|
|
||||||
*/
|
|
||||||
function getAssociation($server_url, $handle = null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation always returns false.
|
|
||||||
*/
|
|
||||||
function removeAssociation($server_url, $handle)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation does nothing.
|
|
||||||
*/
|
|
||||||
function storeNonce($nonce)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In a system truly limited to dumb mode, nonces must all be
|
|
||||||
* accepted. This therefore always returns true, which makes
|
|
||||||
* replay attacks feasible.
|
|
||||||
*/
|
|
||||||
function useNonce($nonce)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns the auth key generated by the constructor.
|
|
||||||
*/
|
|
||||||
function getAuthKey()
|
|
||||||
{
|
|
||||||
return $this->auth_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This store is a dumb mode store, so this method is overridden
|
|
||||||
* to return true.
|
|
||||||
*/
|
|
||||||
function isDumb()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,674 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This file supplies a Memcached store backend for OpenID servers and
|
|
||||||
* consumers.
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Require base class for creating a new interface.
|
|
||||||
*/
|
|
||||||
require_once 'Auth/OpenID.php';
|
|
||||||
require_once 'Auth/OpenID/Interface.php';
|
|
||||||
require_once 'Auth/OpenID/HMACSHA1.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a filesystem-based store for OpenID associations and
|
|
||||||
* nonces. This store should be safe for use in concurrent systems on
|
|
||||||
* both windows and unix (excluding NFS filesystems). There are a
|
|
||||||
* couple race conditions in the system, but those failure cases have
|
|
||||||
* been set up in such a way that the worst-case behavior is someone
|
|
||||||
* having to try to log in a second time.
|
|
||||||
*
|
|
||||||
* Most of the methods of this class are implementation details.
|
|
||||||
* People wishing to just use this store need only pay attention to
|
|
||||||
* the constructor.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
*/
|
|
||||||
class Auth_OpenID_FileStore extends Auth_OpenID_OpenIDStore {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes a new {@link Auth_OpenID_FileStore}. This
|
|
||||||
* initializes the nonce and association directories, which are
|
|
||||||
* subdirectories of the directory passed in.
|
|
||||||
*
|
|
||||||
* @param string $directory This is the directory to put the store
|
|
||||||
* directories in.
|
|
||||||
*/
|
|
||||||
function Auth_OpenID_FileStore($directory)
|
|
||||||
{
|
|
||||||
if (!Auth_OpenID::ensureDir($directory)) {
|
|
||||||
trigger_error('Not a directory and failed to create: '
|
|
||||||
. $directory, E_USER_ERROR);
|
|
||||||
}
|
|
||||||
$directory = realpath($directory);
|
|
||||||
|
|
||||||
$this->directory = $directory;
|
|
||||||
$this->active = true;
|
|
||||||
|
|
||||||
$this->nonce_dir = $directory . DIRECTORY_SEPARATOR . 'nonces';
|
|
||||||
|
|
||||||
$this->association_dir = $directory . DIRECTORY_SEPARATOR .
|
|
||||||
'associations';
|
|
||||||
|
|
||||||
// Temp dir must be on the same filesystem as the assciations
|
|
||||||
// $directory and the $directory containing the auth key file.
|
|
||||||
$this->temp_dir = $directory . DIRECTORY_SEPARATOR . 'temp';
|
|
||||||
|
|
||||||
$this->auth_key_name = $directory . DIRECTORY_SEPARATOR . 'auth_key';
|
|
||||||
|
|
||||||
$this->max_nonce_age = 6 * 60 * 60; // Six hours, in seconds
|
|
||||||
|
|
||||||
if (!$this->_setup()) {
|
|
||||||
trigger_error('Failed to initialize OpenID file store in ' .
|
|
||||||
$directory, E_USER_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function destroy()
|
|
||||||
{
|
|
||||||
Auth_OpenID_FileStore::_rmtree($this->directory);
|
|
||||||
$this->active = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make sure that the directories in which we store our data
|
|
||||||
* exist.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _setup()
|
|
||||||
{
|
|
||||||
return (Auth_OpenID::ensureDir(dirname($this->auth_key_name)) &&
|
|
||||||
Auth_OpenID::ensureDir($this->nonce_dir) &&
|
|
||||||
Auth_OpenID::ensureDir($this->association_dir) &&
|
|
||||||
Auth_OpenID::ensureDir($this->temp_dir));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a temporary file on the same filesystem as
|
|
||||||
* $this->auth_key_name and $this->association_dir.
|
|
||||||
*
|
|
||||||
* The temporary directory should not be cleaned if there are any
|
|
||||||
* processes using the store. If there is no active process using
|
|
||||||
* the store, it is safe to remove all of the files in the
|
|
||||||
* temporary directory.
|
|
||||||
*
|
|
||||||
* @return array ($fd, $filename)
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _mktemp()
|
|
||||||
{
|
|
||||||
$name = Auth_OpenID_FileStore::_mkstemp($dir = $this->temp_dir);
|
|
||||||
$file_obj = @fopen($name, 'wb');
|
|
||||||
if ($file_obj !== false) {
|
|
||||||
return array($file_obj, $name);
|
|
||||||
} else {
|
|
||||||
Auth_OpenID_FileStore::_removeIfPresent($name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the auth key from the auth key file. Will return None if
|
|
||||||
* there is currently no key.
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
function readAuthKey()
|
|
||||||
{
|
|
||||||
if (!$this->active) {
|
|
||||||
trigger_error("FileStore no longer active", E_USER_ERROR);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$auth_key_file = @fopen($this->auth_key_name, 'rb');
|
|
||||||
if ($auth_key_file === false) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$key = fread($auth_key_file, filesize($this->auth_key_name));
|
|
||||||
fclose($auth_key_file);
|
|
||||||
|
|
||||||
return $key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a new random auth key and safely store it in the
|
|
||||||
* location specified by $this->auth_key_name.
|
|
||||||
*
|
|
||||||
* @return string $key
|
|
||||||
*/
|
|
||||||
function createAuthKey()
|
|
||||||
{
|
|
||||||
if (!$this->active) {
|
|
||||||
trigger_error("FileStore no longer active", E_USER_ERROR);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$auth_key = Auth_OpenID_CryptUtil::randomString($this->AUTH_KEY_LEN);
|
|
||||||
|
|
||||||
list($file_obj, $tmp) = $this->_mktemp();
|
|
||||||
|
|
||||||
fwrite($file_obj, $auth_key);
|
|
||||||
fflush($file_obj);
|
|
||||||
fclose($file_obj);
|
|
||||||
|
|
||||||
if (function_exists('link')) {
|
|
||||||
// Posix filesystem
|
|
||||||
$saved = link($tmp, $this->auth_key_name);
|
|
||||||
Auth_OpenID_FileStore::_removeIfPresent($tmp);
|
|
||||||
} else {
|
|
||||||
// Windows filesystem
|
|
||||||
$saved = rename($tmp, $this->auth_key_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$saved) {
|
|
||||||
// The link failed, either because we lack the permission,
|
|
||||||
// or because the file already exists; try to read the key
|
|
||||||
// in case the file already existed.
|
|
||||||
$auth_key = $this->readAuthKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $auth_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the auth key from the file specified by
|
|
||||||
* $this->auth_key_name, creating it if it does not exist.
|
|
||||||
*
|
|
||||||
* @return string $key
|
|
||||||
*/
|
|
||||||
function getAuthKey()
|
|
||||||
{
|
|
||||||
if (!$this->active) {
|
|
||||||
trigger_error("FileStore no longer active", E_USER_ERROR);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$auth_key = $this->readAuthKey();
|
|
||||||
if ($auth_key === null) {
|
|
||||||
$auth_key = $this->createAuthKey();
|
|
||||||
|
|
||||||
if (strlen($auth_key) != $this->AUTH_KEY_LEN) {
|
|
||||||
$fmt = 'Got an invalid auth key from %s. Expected '.
|
|
||||||
'%d-byte string. Got: %s';
|
|
||||||
$msg = sprintf($fmt, $this->auth_key_name, $this->AUTH_KEY_LEN,
|
|
||||||
$auth_key);
|
|
||||||
trigger_error($msg, E_USER_WARNING);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $auth_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a unique filename for a given server url and
|
|
||||||
* handle. This implementation does not assume anything about the
|
|
||||||
* format of the handle. The filename that is returned will
|
|
||||||
* contain the domain name from the server URL for ease of human
|
|
||||||
* inspection of the data directory.
|
|
||||||
*
|
|
||||||
* @return string $filename
|
|
||||||
*/
|
|
||||||
function getAssociationFilename($server_url, $handle)
|
|
||||||
{
|
|
||||||
if (!$this->active) {
|
|
||||||
trigger_error("FileStore no longer active", E_USER_ERROR);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strpos($server_url, '://') === false) {
|
|
||||||
trigger_error(sprintf("Bad server URL: %s", $server_url),
|
|
||||||
E_USER_WARNING);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
list($proto, $rest) = explode('://', $server_url, 2);
|
|
||||||
$parts = explode('/', $rest);
|
|
||||||
$domain = Auth_OpenID_FileStore::_filenameEscape($parts[0]);
|
|
||||||
$url_hash = Auth_OpenID_FileStore::_safe64($server_url);
|
|
||||||
if ($handle) {
|
|
||||||
$handle_hash = Auth_OpenID_FileStore::_safe64($handle);
|
|
||||||
} else {
|
|
||||||
$handle_hash = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$filename = sprintf('%s-%s-%s-%s', $proto, $domain, $url_hash,
|
|
||||||
$handle_hash);
|
|
||||||
|
|
||||||
return $this->association_dir. DIRECTORY_SEPARATOR . $filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store an association in the association directory.
|
|
||||||
*/
|
|
||||||
function storeAssociation($server_url, $association)
|
|
||||||
{
|
|
||||||
if (!$this->active) {
|
|
||||||
trigger_error("FileStore no longer active", E_USER_ERROR);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$association_s = $association->serialize();
|
|
||||||
$filename = $this->getAssociationFilename($server_url,
|
|
||||||
$association->handle);
|
|
||||||
list($tmp_file, $tmp) = $this->_mktemp();
|
|
||||||
|
|
||||||
if (!$tmp_file) {
|
|
||||||
trigger_error("_mktemp didn't return a valid file descriptor",
|
|
||||||
E_USER_WARNING);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fwrite($tmp_file, $association_s);
|
|
||||||
|
|
||||||
fflush($tmp_file);
|
|
||||||
|
|
||||||
fclose($tmp_file);
|
|
||||||
|
|
||||||
if (@rename($tmp, $filename)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
// In case we are running on Windows, try unlinking the
|
|
||||||
// file in case it exists.
|
|
||||||
@unlink($filename);
|
|
||||||
|
|
||||||
// Now the target should not exist. Try renaming again,
|
|
||||||
// giving up if it fails.
|
|
||||||
if (@rename($tmp, $filename)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there was an error, don't leave the temporary file
|
|
||||||
// around.
|
|
||||||
Auth_OpenID_FileStore::_removeIfPresent($tmp);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve an association. If no handle is specified, return the
|
|
||||||
* association with the most recent issue time.
|
|
||||||
*
|
|
||||||
* @return mixed $association
|
|
||||||
*/
|
|
||||||
function getAssociation($server_url, $handle = null)
|
|
||||||
{
|
|
||||||
if (!$this->active) {
|
|
||||||
trigger_error("FileStore no longer active", E_USER_ERROR);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($handle === null) {
|
|
||||||
$handle = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// The filename with the empty handle is a prefix of all other
|
|
||||||
// associations for the given server URL.
|
|
||||||
$filename = $this->getAssociationFilename($server_url, $handle);
|
|
||||||
|
|
||||||
if ($handle) {
|
|
||||||
return $this->_getAssociation($filename);
|
|
||||||
} else {
|
|
||||||
$association_files =
|
|
||||||
Auth_OpenID_FileStore::_listdir($this->association_dir);
|
|
||||||
$matching_files = array();
|
|
||||||
|
|
||||||
// strip off the path to do the comparison
|
|
||||||
$name = basename($filename);
|
|
||||||
foreach ($association_files as $association_file) {
|
|
||||||
if (strpos($association_file, $name) === 0) {
|
|
||||||
$matching_files[] = $association_file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$matching_associations = array();
|
|
||||||
// read the matching files and sort by time issued
|
|
||||||
foreach ($matching_files as $name) {
|
|
||||||
$full_name = $this->association_dir . DIRECTORY_SEPARATOR .
|
|
||||||
$name;
|
|
||||||
$association = $this->_getAssociation($full_name);
|
|
||||||
if ($association !== null) {
|
|
||||||
$matching_associations[] = array($association->issued,
|
|
||||||
$association);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$issued = array();
|
|
||||||
$assocs = array();
|
|
||||||
foreach ($matching_associations as $key => $assoc) {
|
|
||||||
$issued[$key] = $assoc[0];
|
|
||||||
$assocs[$key] = $assoc[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
array_multisort($issued, SORT_DESC, $assocs, SORT_DESC,
|
|
||||||
$matching_associations);
|
|
||||||
|
|
||||||
// return the most recently issued one.
|
|
||||||
if ($matching_associations) {
|
|
||||||
list($issued, $assoc) = $matching_associations[0];
|
|
||||||
return $assoc;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _getAssociation($filename)
|
|
||||||
{
|
|
||||||
if (!$this->active) {
|
|
||||||
trigger_error("FileStore no longer active", E_USER_ERROR);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$assoc_file = @fopen($filename, 'rb');
|
|
||||||
|
|
||||||
if ($assoc_file === false) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$assoc_s = fread($assoc_file, filesize($filename));
|
|
||||||
fclose($assoc_file);
|
|
||||||
|
|
||||||
if (!$assoc_s) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$association =
|
|
||||||
Auth_OpenID_Association::deserialize('Auth_OpenID_Association',
|
|
||||||
$assoc_s);
|
|
||||||
|
|
||||||
if (!$association) {
|
|
||||||
Auth_OpenID_FileStore::_removeIfPresent($filename);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($association->getExpiresIn() == 0) {
|
|
||||||
Auth_OpenID_FileStore::_removeIfPresent($filename);
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return $association;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove an association if it exists. Do nothing if it does not.
|
|
||||||
*
|
|
||||||
* @return bool $success
|
|
||||||
*/
|
|
||||||
function removeAssociation($server_url, $handle)
|
|
||||||
{
|
|
||||||
if (!$this->active) {
|
|
||||||
trigger_error("FileStore no longer active", E_USER_ERROR);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$assoc = $this->getAssociation($server_url, $handle);
|
|
||||||
if ($assoc === null) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
$filename = $this->getAssociationFilename($server_url, $handle);
|
|
||||||
return Auth_OpenID_FileStore::_removeIfPresent($filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark this nonce as present.
|
|
||||||
*/
|
|
||||||
function storeNonce($nonce)
|
|
||||||
{
|
|
||||||
if (!$this->active) {
|
|
||||||
trigger_error("FileStore no longer active", E_USER_ERROR);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$filename = $this->nonce_dir . DIRECTORY_SEPARATOR . $nonce;
|
|
||||||
$nonce_file = fopen($filename, 'w');
|
|
||||||
if ($nonce_file === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
fclose($nonce_file);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return whether this nonce is present. As a side effect, mark it
|
|
||||||
* as no longer present.
|
|
||||||
*
|
|
||||||
* @return bool $present
|
|
||||||
*/
|
|
||||||
function useNonce($nonce)
|
|
||||||
{
|
|
||||||
if (!$this->active) {
|
|
||||||
trigger_error("FileStore no longer active", E_USER_ERROR);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$filename = $this->nonce_dir . DIRECTORY_SEPARATOR . $nonce;
|
|
||||||
$st = @stat($filename);
|
|
||||||
|
|
||||||
if ($st === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Either it is too old or we are using it. Either way, we
|
|
||||||
// must remove the file.
|
|
||||||
if (!unlink($filename)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$now = time();
|
|
||||||
$nonce_age = $now - $st[9];
|
|
||||||
|
|
||||||
// We can us it if the age of the file is less than the
|
|
||||||
// expiration time.
|
|
||||||
return $nonce_age <= $this->max_nonce_age;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove expired entries from the database. This is potentially
|
|
||||||
* expensive, so only run when it is acceptable to take time.
|
|
||||||
*/
|
|
||||||
function clean()
|
|
||||||
{
|
|
||||||
if (!$this->active) {
|
|
||||||
trigger_error("FileStore no longer active", E_USER_ERROR);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$nonces = Auth_OpenID_FileStore::_listdir($this->nonce_dir);
|
|
||||||
$now = time();
|
|
||||||
|
|
||||||
// Check all nonces for expiry
|
|
||||||
foreach ($nonces as $nonce) {
|
|
||||||
$filename = $this->nonce_dir . DIRECTORY_SEPARATOR . $nonce;
|
|
||||||
$st = @stat($filename);
|
|
||||||
|
|
||||||
if ($st !== false) {
|
|
||||||
// Remove the nonce if it has expired
|
|
||||||
$nonce_age = $now - $st[9];
|
|
||||||
if ($nonce_age > $this->max_nonce_age) {
|
|
||||||
Auth_OpenID_FileStore::_removeIfPresent($filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$association_filenames =
|
|
||||||
Auth_OpenID_FileStore::_listdir($this->association_dir);
|
|
||||||
|
|
||||||
foreach ($association_filenames as $association_filename) {
|
|
||||||
$association_file = fopen($association_filename, 'rb');
|
|
||||||
|
|
||||||
if ($association_file !== false) {
|
|
||||||
$assoc_s = fread($association_file,
|
|
||||||
filesize($association_filename));
|
|
||||||
fclose($association_file);
|
|
||||||
|
|
||||||
// Remove expired or corrupted associations
|
|
||||||
$association =
|
|
||||||
Auth_OpenID_Association::deserialize(
|
|
||||||
'Auth_OpenID_Association', $assoc_s);
|
|
||||||
|
|
||||||
if ($association === null) {
|
|
||||||
Auth_OpenID_FileStore::_removeIfPresent(
|
|
||||||
$association_filename);
|
|
||||||
} else {
|
|
||||||
if ($association->getExpiresIn() == 0) {
|
|
||||||
Auth_OpenID_FileStore::_removeIfPresent(
|
|
||||||
$association_filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _rmtree($dir)
|
|
||||||
{
|
|
||||||
if ($dir[strlen($dir) - 1] != DIRECTORY_SEPARATOR) {
|
|
||||||
$dir .= DIRECTORY_SEPARATOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($handle = opendir($dir)) {
|
|
||||||
while ($item = readdir($handle)) {
|
|
||||||
if (!in_array($item, array('.', '..'))) {
|
|
||||||
if (is_dir($dir . $item)) {
|
|
||||||
|
|
||||||
if (!Auth_OpenID_FileStore::_rmtree($dir . $item)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (is_file($dir . $item)) {
|
|
||||||
if (!unlink($dir . $item)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir($handle);
|
|
||||||
|
|
||||||
if (!@rmdir($dir)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
// Couldn't open directory.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _mkstemp($dir)
|
|
||||||
{
|
|
||||||
foreach (range(0, 4) as $i) {
|
|
||||||
$name = tempnam($dir, "php_openid_filestore_");
|
|
||||||
|
|
||||||
if ($name !== false) {
|
|
||||||
return $name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _mkdtemp($dir)
|
|
||||||
{
|
|
||||||
foreach (range(0, 4) as $i) {
|
|
||||||
$name = $dir . strval(DIRECTORY_SEPARATOR) . strval(getmypid()) .
|
|
||||||
"-" . strval(rand(1, time()));
|
|
||||||
if (!mkdir($name, 0700)) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return $name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _listdir($dir)
|
|
||||||
{
|
|
||||||
$handle = opendir($dir);
|
|
||||||
$files = array();
|
|
||||||
while (false !== ($filename = readdir($handle))) {
|
|
||||||
$files[] = $filename;
|
|
||||||
}
|
|
||||||
return $files;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _isFilenameSafe($char)
|
|
||||||
{
|
|
||||||
$_Auth_OpenID_filename_allowed = Auth_OpenID_letters .
|
|
||||||
Auth_OpenID_digits . ".";
|
|
||||||
return (strpos($_Auth_OpenID_filename_allowed, $char) !== false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _safe64($str)
|
|
||||||
{
|
|
||||||
$h64 = base64_encode(Auth_OpenID_SHA1($str));
|
|
||||||
$h64 = str_replace('+', '_', $h64);
|
|
||||||
$h64 = str_replace('/', '.', $h64);
|
|
||||||
$h64 = str_replace('=', '', $h64);
|
|
||||||
return $h64;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _filenameEscape($str)
|
|
||||||
{
|
|
||||||
$filename = "";
|
|
||||||
for ($i = 0; $i < strlen($str); $i++) {
|
|
||||||
$c = $str[$i];
|
|
||||||
if (Auth_OpenID_FileStore::_isFilenameSafe($c)) {
|
|
||||||
$filename .= $c;
|
|
||||||
} else {
|
|
||||||
$filename .= sprintf("_%02X", ord($c));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempt to remove a file, returning whether the file existed at
|
|
||||||
* the time of the call.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @return bool $result True if the file was present, false if not.
|
|
||||||
*/
|
|
||||||
function _removeIfPresent($filename)
|
|
||||||
{
|
|
||||||
return @unlink($filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the HMACSHA1 implementation for the OpenID library.
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @package OpenID
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SHA1_BLOCKSIZE is this module's SHA1 blocksize used by the fallback
|
|
||||||
* implementation.
|
|
||||||
*/
|
|
||||||
define('Auth_OpenID_SHA1_BLOCKSIZE', 64);
|
|
||||||
|
|
||||||
if (!function_exists('sha1')) {
|
|
||||||
/**
|
|
||||||
* Return a raw SHA1 hash of the given string
|
|
||||||
*
|
|
||||||
* XXX: include the SHA1 code from Dan Libby's OpenID library
|
|
||||||
*/
|
|
||||||
function Auth_OpenID_SHA1($text)
|
|
||||||
{
|
|
||||||
trigger_error('No SHA1 function found', E_USER_ERROR);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/**
|
|
||||||
* @ignore
|
|
||||||
*/
|
|
||||||
function Auth_OpenID_SHA1($text)
|
|
||||||
{
|
|
||||||
$hex = sha1($text);
|
|
||||||
$raw = '';
|
|
||||||
for ($i = 0; $i < 40; $i += 2) {
|
|
||||||
$hexcode = substr($hex, $i, 2);
|
|
||||||
$charcode = (int)base_convert($hexcode, 16, 10);
|
|
||||||
$raw .= chr($charcode);
|
|
||||||
}
|
|
||||||
return $raw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compute an HMAC/SHA1 hash.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @param string $key The HMAC key
|
|
||||||
* @param string $text The message text to hash
|
|
||||||
* @return string $mac The MAC
|
|
||||||
*/
|
|
||||||
function Auth_OpenID_HMACSHA1($key, $text)
|
|
||||||
{
|
|
||||||
if (strlen($key) > Auth_OpenID_SHA1_BLOCKSIZE) {
|
|
||||||
$key = Auth_OpenID_SHA1($key, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$key = str_pad($key, Auth_OpenID_SHA1_BLOCKSIZE, chr(0x00));
|
|
||||||
$ipad = str_repeat(chr(0x36), Auth_OpenID_SHA1_BLOCKSIZE);
|
|
||||||
$opad = str_repeat(chr(0x5c), Auth_OpenID_SHA1_BLOCKSIZE);
|
|
||||||
$hash1 = Auth_OpenID_SHA1(($key ^ $ipad) . $text, true);
|
|
||||||
$hmac = Auth_OpenID_SHA1(($key ^ $opad) . $hash1, true);
|
|
||||||
return $hmac;
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,188 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This file specifies the interface for PHP OpenID store implementations.
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the interface for the store objects the OpenID library
|
|
||||||
* uses. It is a single class that provides all of the persistence
|
|
||||||
* mechanisms that the OpenID library needs, for both servers and
|
|
||||||
* consumers. If you want to create an SQL-driven store, please see
|
|
||||||
* then {@link Auth_OpenID_SQLStore} class.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
*/
|
|
||||||
class Auth_OpenID_OpenIDStore {
|
|
||||||
/**
|
|
||||||
* @var integer The length of the auth key that should be returned
|
|
||||||
* by the getAuthKey method.
|
|
||||||
*/
|
|
||||||
var $AUTH_KEY_LEN = 20;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method puts an Association object into storage,
|
|
||||||
* retrievable by server URL and handle.
|
|
||||||
*
|
|
||||||
* @param string $server_url The URL of the identity server that
|
|
||||||
* this association is with. Because of the way the server portion
|
|
||||||
* of the library uses this interface, don't assume there are any
|
|
||||||
* limitations on the character set of the input string. In
|
|
||||||
* particular, expect to see unescaped non-url-safe characters in
|
|
||||||
* the server_url field.
|
|
||||||
*
|
|
||||||
* @param Association $association The Association to store.
|
|
||||||
*/
|
|
||||||
function storeAssociation($server_url, $association)
|
|
||||||
{
|
|
||||||
trigger_error("Auth_OpenID_OpenIDStore::storeAssociation ".
|
|
||||||
"not implemented", E_USER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns an Association object from storage that
|
|
||||||
* matches the server URL and, if specified, handle. It returns
|
|
||||||
* null if no such association is found or if the matching
|
|
||||||
* association is expired.
|
|
||||||
*
|
|
||||||
* If no handle is specified, the store may return any association
|
|
||||||
* which matches the server URL. If multiple associations are
|
|
||||||
* valid, the recommended return value for this method is the one
|
|
||||||
* that will remain valid for the longest duration.
|
|
||||||
*
|
|
||||||
* This method is allowed (and encouraged) to garbage collect
|
|
||||||
* expired associations when found. This method must not return
|
|
||||||
* expired associations.
|
|
||||||
*
|
|
||||||
* @param string $server_url The URL of the identity server to get
|
|
||||||
* the association for. Because of the way the server portion of
|
|
||||||
* the library uses this interface, don't assume there are any
|
|
||||||
* limitations on the character set of the input string. In
|
|
||||||
* particular, expect to see unescaped non-url-safe characters in
|
|
||||||
* the server_url field.
|
|
||||||
*
|
|
||||||
* @param mixed $handle This optional parameter is the handle of
|
|
||||||
* the specific association to get. If no specific handle is
|
|
||||||
* provided, any valid association matching the server URL is
|
|
||||||
* returned.
|
|
||||||
*
|
|
||||||
* @return Association The Association for the given identity
|
|
||||||
* server.
|
|
||||||
*/
|
|
||||||
function getAssociation($server_url, $handle = null)
|
|
||||||
{
|
|
||||||
trigger_error("Auth_OpenID_OpenIDStore::getAssociation ".
|
|
||||||
"not implemented", E_USER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method removes the matching association if it's found, and
|
|
||||||
* returns whether the association was removed or not.
|
|
||||||
*
|
|
||||||
* @param string $server_url The URL of the identity server the
|
|
||||||
* association to remove belongs to. Because of the way the server
|
|
||||||
* portion of the library uses this interface, don't assume there
|
|
||||||
* are any limitations on the character set of the input
|
|
||||||
* string. In particular, expect to see unescaped non-url-safe
|
|
||||||
* characters in the server_url field.
|
|
||||||
*
|
|
||||||
* @param string $handle This is the handle of the association to
|
|
||||||
* remove. If there isn't an association found that matches both
|
|
||||||
* the given URL and handle, then there was no matching handle
|
|
||||||
* found.
|
|
||||||
*
|
|
||||||
* @return mixed Returns whether or not the given association existed.
|
|
||||||
*/
|
|
||||||
function removeAssociation($server_url, $handle)
|
|
||||||
{
|
|
||||||
trigger_error("Auth_OpenID_OpenIDStore::removeAssociation ".
|
|
||||||
"not implemented", E_USER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores a nonce. This is used by the consumer to prevent replay
|
|
||||||
* attacks.
|
|
||||||
*
|
|
||||||
* @param string $nonce The nonce to store.
|
|
||||||
*
|
|
||||||
* @return null
|
|
||||||
*/
|
|
||||||
function storeNonce($nonce)
|
|
||||||
{
|
|
||||||
trigger_error("Auth_OpenID_OpenIDStore::storeNonce ".
|
|
||||||
"not implemented", E_USER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is called when the library is attempting to use a
|
|
||||||
* nonce. If the nonce is in the store, this method removes it and
|
|
||||||
* returns a value which evaluates as true. Otherwise it returns a
|
|
||||||
* value which evaluates as false.
|
|
||||||
*
|
|
||||||
* This method is allowed and encouraged to treat nonces older
|
|
||||||
* than some period (a very conservative window would be 6 hours,
|
|
||||||
* for example) as no longer existing, and return False and remove
|
|
||||||
* them.
|
|
||||||
*
|
|
||||||
* @param string $nonce The nonce to use.
|
|
||||||
*
|
|
||||||
* @return bool Whether or not the nonce was valid.
|
|
||||||
*/
|
|
||||||
function useNonce($nonce)
|
|
||||||
{
|
|
||||||
trigger_error("Auth_OpenID_OpenIDStore::useNonce ".
|
|
||||||
"not implemented", E_USER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method returns a key used to sign the tokens, to ensure
|
|
||||||
* that they haven't been tampered with in transit. It should
|
|
||||||
* return the same key every time it is called. The key returned
|
|
||||||
* should be {@link AUTH_KEY_LEN} bytes long.
|
|
||||||
*
|
|
||||||
* @return string The key. It should be {@link AUTH_KEY_LEN} bytes in
|
|
||||||
* length, and use the full range of byte values. That is, it
|
|
||||||
* should be treated as a lump of binary data stored in a string.
|
|
||||||
*/
|
|
||||||
function getAuthKey()
|
|
||||||
{
|
|
||||||
trigger_error("Auth_OpenID_OpenIDStore::getAuthKey ".
|
|
||||||
"not implemented", E_USER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method must return true if the store is a dumb-mode-style
|
|
||||||
* store. Unlike all other methods in this class, this one
|
|
||||||
* provides a default implementation, which returns false.
|
|
||||||
*
|
|
||||||
* In general, any custom subclass of {@link Auth_OpenID_OpenIDStore}
|
|
||||||
* won't override this method, as custom subclasses are only likely to
|
|
||||||
* be created when the store is fully functional.
|
|
||||||
*
|
|
||||||
* @return bool true if the store works fully, false if the
|
|
||||||
* consumer will have to use dumb mode to use this store.
|
|
||||||
*/
|
|
||||||
function isDumb()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes all entries from the store; implementation is optional.
|
|
||||||
*/
|
|
||||||
function reset()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
@ -1,112 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OpenID protocol key-value/comma-newline format parsing and
|
|
||||||
* serialization
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @package OpenID
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Container for key-value/comma-newline OpenID format and parsing
|
|
||||||
*/
|
|
||||||
class Auth_OpenID_KVForm {
|
|
||||||
/**
|
|
||||||
* Convert an OpenID colon/newline separated string into an
|
|
||||||
* associative array
|
|
||||||
*
|
|
||||||
* @static
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function toArray($kvs, $strict=false)
|
|
||||||
{
|
|
||||||
$lines = explode("\n", $kvs);
|
|
||||||
|
|
||||||
$last = array_pop($lines);
|
|
||||||
if ($last !== '') {
|
|
||||||
array_push($lines, $last);
|
|
||||||
if ($strict) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$values = array();
|
|
||||||
|
|
||||||
for ($lineno = 0; $lineno < count($lines); $lineno++) {
|
|
||||||
$line = $lines[$lineno];
|
|
||||||
$kv = explode(':', $line, 2);
|
|
||||||
if (count($kv) != 2) {
|
|
||||||
if ($strict) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$key = $kv[0];
|
|
||||||
$tkey = trim($key);
|
|
||||||
if ($tkey != $key) {
|
|
||||||
if ($strict) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$value = $kv[1];
|
|
||||||
$tval = trim($value);
|
|
||||||
if ($tval != $value) {
|
|
||||||
if ($strict) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$values[$tkey] = $tval;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $values;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert an array into an OpenID colon/newline separated string
|
|
||||||
*
|
|
||||||
* @static
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function fromArray($values)
|
|
||||||
{
|
|
||||||
if ($values === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
ksort($values);
|
|
||||||
|
|
||||||
$serialized = '';
|
|
||||||
foreach ($values as $key => $value) {
|
|
||||||
if (is_array($value)) {
|
|
||||||
list($key, $value) = array($value[0], $value[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strpos($key, ':') !== false) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strpos($key, "\n") !== false) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strpos($value, "\n") !== false) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$serialized .= "$key:$value\n";
|
|
||||||
}
|
|
||||||
return $serialized;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A MySQL store.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Require the base class file.
|
|
||||||
*/
|
|
||||||
require_once "Auth/OpenID/SQLStore.php";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An SQL store that uses MySQL as its backend.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
*/
|
|
||||||
class Auth_OpenID_MySQLStore extends Auth_OpenID_SQLStore {
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function setSQL()
|
|
||||||
{
|
|
||||||
$this->sql['nonce_table'] =
|
|
||||||
"CREATE TABLE %s (nonce CHAR(8) UNIQUE PRIMARY KEY, ".
|
|
||||||
"expires INTEGER) TYPE=InnoDB";
|
|
||||||
|
|
||||||
$this->sql['assoc_table'] =
|
|
||||||
"CREATE TABLE %s (server_url BLOB, handle VARCHAR(255), ".
|
|
||||||
"secret BLOB, issued INTEGER, lifetime INTEGER, ".
|
|
||||||
"assoc_type VARCHAR(64), PRIMARY KEY (server_url(255), handle)) ".
|
|
||||||
"TYPE=InnoDB";
|
|
||||||
|
|
||||||
$this->sql['settings_table'] =
|
|
||||||
"CREATE TABLE %s (setting VARCHAR(128) UNIQUE PRIMARY KEY, ".
|
|
||||||
"value BLOB) TYPE=InnoDB";
|
|
||||||
|
|
||||||
$this->sql['create_auth'] =
|
|
||||||
"INSERT INTO %s VALUES ('auth_key', !)";
|
|
||||||
|
|
||||||
$this->sql['get_auth'] =
|
|
||||||
"SELECT value FROM %s WHERE setting = 'auth_key'";
|
|
||||||
|
|
||||||
$this->sql['set_assoc'] =
|
|
||||||
"REPLACE INTO %s VALUES (?, ?, !, ?, ?, ?)";
|
|
||||||
|
|
||||||
$this->sql['get_assocs'] =
|
|
||||||
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
|
|
||||||
"WHERE server_url = ?";
|
|
||||||
|
|
||||||
$this->sql['get_assoc'] =
|
|
||||||
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
|
|
||||||
"WHERE server_url = ? AND handle = ?";
|
|
||||||
|
|
||||||
$this->sql['remove_assoc'] =
|
|
||||||
"DELETE FROM %s WHERE server_url = ? AND handle = ?";
|
|
||||||
|
|
||||||
$this->sql['add_nonce'] =
|
|
||||||
"REPLACE INTO %s (nonce, expires) VALUES (?, ?)";
|
|
||||||
|
|
||||||
$this->sql['get_nonce'] =
|
|
||||||
"SELECT * FROM %s WHERE nonce = ?";
|
|
||||||
|
|
||||||
$this->sql['remove_nonce'] =
|
|
||||||
"DELETE FROM %s WHERE nonce = ?";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function blobEncode($blob)
|
|
||||||
{
|
|
||||||
return "0x" . bin2hex($blob);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,308 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This module implements a VERY limited parser that finds <link> tags
|
|
||||||
* in the head of HTML or XHTML documents and parses out their
|
|
||||||
* attributes according to the OpenID spec. It is a liberal parser,
|
|
||||||
* but it requires these things from the data in order to work:
|
|
||||||
*
|
|
||||||
* - There must be an open <html> tag
|
|
||||||
*
|
|
||||||
* - There must be an open <head> tag inside of the <html> tag
|
|
||||||
*
|
|
||||||
* - Only <link>s that are found inside of the <head> tag are parsed
|
|
||||||
* (this is by design)
|
|
||||||
*
|
|
||||||
* - The parser follows the OpenID specification in resolving the
|
|
||||||
* attributes of the link tags. This means that the attributes DO
|
|
||||||
* NOT get resolved as they would by an XML or HTML parser. In
|
|
||||||
* particular, only certain entities get replaced, and href
|
|
||||||
* attributes do not get resolved relative to a base URL.
|
|
||||||
*
|
|
||||||
* From http://openid.net/specs.bml:
|
|
||||||
*
|
|
||||||
* - The openid.server URL MUST be an absolute URL. OpenID consumers
|
|
||||||
* MUST NOT attempt to resolve relative URLs.
|
|
||||||
*
|
|
||||||
* - The openid.server URL MUST NOT include entities other than &,
|
|
||||||
* <, >, and ".
|
|
||||||
*
|
|
||||||
* The parser ignores SGML comments and <![CDATA[blocks]]>. Both kinds
|
|
||||||
* of quoting are allowed for attributes.
|
|
||||||
*
|
|
||||||
* The parser deals with invalid markup in these ways:
|
|
||||||
*
|
|
||||||
* - Tag names are not case-sensitive
|
|
||||||
*
|
|
||||||
* - The <html> tag is accepted even when it is not at the top level
|
|
||||||
*
|
|
||||||
* - The <head> tag is accepted even when it is not a direct child of
|
|
||||||
* the <html> tag, but a <html> tag must be an ancestor of the
|
|
||||||
* <head> tag
|
|
||||||
*
|
|
||||||
* - <link> tags are accepted even when they are not direct children
|
|
||||||
* of the <head> tag, but a <head> tag must be an ancestor of the
|
|
||||||
* <link> tag
|
|
||||||
*
|
|
||||||
* - If there is no closing tag for an open <html> or <head> tag, the
|
|
||||||
* remainder of the document is viewed as being inside of the
|
|
||||||
* tag. If there is no closing tag for a <link> tag, the link tag is
|
|
||||||
* treated as a short tag. Exceptions to this rule are that <html>
|
|
||||||
* closes <html> and <body> or <head> closes <head>
|
|
||||||
*
|
|
||||||
* - Attributes of the <link> tag are not required to be quoted.
|
|
||||||
*
|
|
||||||
* - In the case of duplicated attribute names, the attribute coming
|
|
||||||
* last in the tag will be the value returned.
|
|
||||||
*
|
|
||||||
* - Any text that does not parse as an attribute within a link tag
|
|
||||||
* will be ignored. (e.g. <link pumpkin rel='openid.server' /> will
|
|
||||||
* ignore pumpkin)
|
|
||||||
*
|
|
||||||
* - If there are more than one <html> or <head> tag, the parser only
|
|
||||||
* looks inside of the first one.
|
|
||||||
*
|
|
||||||
* - The contents of <script> tags are ignored entirely, except
|
|
||||||
* unclosed <script> tags. Unclosed <script> tags are ignored.
|
|
||||||
*
|
|
||||||
* - Any other invalid markup is ignored, including unclosed SGML
|
|
||||||
* comments and unclosed <![CDATA[blocks.
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @package OpenID
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Require Auth_OpenID::arrayGet().
|
|
||||||
*/
|
|
||||||
require_once "Auth/OpenID.php";
|
|
||||||
|
|
||||||
class Auth_OpenID_Parse {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify some flags for use with regex matching.
|
|
||||||
*/
|
|
||||||
var $_re_flags = "si";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stuff to remove before we start looking for tags
|
|
||||||
*/
|
|
||||||
var $_removed_re =
|
|
||||||
"<!--.*?-->|<!\[CDATA\[.*?\]\]>|<script\b(?!:)[^>]*>.*?<\/script>";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts with the tag name at a word boundary, where the tag name
|
|
||||||
* is not a namespace
|
|
||||||
*/
|
|
||||||
var $_tag_expr = "<%s\b(?!:)([^>]*?)(?:\/>|>(.*?)(?:<\/?%s\s*>|\Z))";
|
|
||||||
|
|
||||||
var $_attr_find = '\b(\w+)=("[^"]*"|\'[^\']*\'|[^\'"\s\/<>]+)';
|
|
||||||
|
|
||||||
function Auth_OpenID_Parse()
|
|
||||||
{
|
|
||||||
$this->_link_find = sprintf("/<link\b(?!:)([^>]*)(?!<)>/%s",
|
|
||||||
$this->_re_flags);
|
|
||||||
|
|
||||||
$this->_entity_replacements = array(
|
|
||||||
'amp' => '&',
|
|
||||||
'lt' => '<',
|
|
||||||
'gt' => '>',
|
|
||||||
'quot' => '"'
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->_attr_find = sprintf("/%s/%s",
|
|
||||||
$this->_attr_find,
|
|
||||||
$this->_re_flags);
|
|
||||||
|
|
||||||
$this->_removed_re = sprintf("/%s/%s",
|
|
||||||
$this->_removed_re,
|
|
||||||
$this->_re_flags);
|
|
||||||
|
|
||||||
$this->_ent_replace =
|
|
||||||
sprintf("&(%s);", implode("|",
|
|
||||||
$this->_entity_replacements));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a regular expression that will match a given tag in an
|
|
||||||
* SGML string.
|
|
||||||
*/
|
|
||||||
function tagMatcher($tag_name, $close_tags = null)
|
|
||||||
{
|
|
||||||
if ($close_tags) {
|
|
||||||
$options = implode("|", array_merge(array($tag_name), $close_tags));
|
|
||||||
$closer = sprintf("(?:%s)", $options);
|
|
||||||
} else {
|
|
||||||
$closer = $tag_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
$expr = sprintf($this->_tag_expr, $tag_name, $closer);
|
|
||||||
return sprintf("/%s/%s", $expr, $this->_re_flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
function htmlFind()
|
|
||||||
{
|
|
||||||
return $this->tagMatcher('html');
|
|
||||||
}
|
|
||||||
|
|
||||||
function headFind()
|
|
||||||
{
|
|
||||||
return $this->tagMatcher('head', array('body'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function replaceEntities($str)
|
|
||||||
{
|
|
||||||
foreach ($this->_entity_replacements as $old => $new) {
|
|
||||||
$str = preg_replace(sprintf("/&%s;/", $old), $new, $str);
|
|
||||||
}
|
|
||||||
return $str;
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeQuotes($str)
|
|
||||||
{
|
|
||||||
$matches = array();
|
|
||||||
$double = '/^"(.*)"$/';
|
|
||||||
$single = "/^\'(.*)\'$/";
|
|
||||||
|
|
||||||
if (preg_match($double, $str, $matches)) {
|
|
||||||
return $matches[1];
|
|
||||||
} else if (preg_match($single, $str, $matches)) {
|
|
||||||
return $matches[1];
|
|
||||||
} else {
|
|
||||||
return $str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find all link tags in a string representing a HTML document and
|
|
||||||
* return a list of their attributes.
|
|
||||||
*
|
|
||||||
* @param string $html The text to parse
|
|
||||||
* @return array $list An array of arrays of attributes, one for each
|
|
||||||
* link tag
|
|
||||||
*/
|
|
||||||
function parseLinkAttrs($html)
|
|
||||||
{
|
|
||||||
$stripped = preg_replace($this->_removed_re,
|
|
||||||
"",
|
|
||||||
$html);
|
|
||||||
|
|
||||||
// Try to find the <HTML> tag.
|
|
||||||
$html_re = $this->htmlFind();
|
|
||||||
$html_matches = array();
|
|
||||||
if (!preg_match($html_re, $stripped, $html_matches)) {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to find the <HEAD> tag.
|
|
||||||
$head_re = $this->headFind();
|
|
||||||
$head_matches = array();
|
|
||||||
if (!preg_match($head_re, $html_matches[0], $head_matches)) {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
$link_data = array();
|
|
||||||
$link_matches = array();
|
|
||||||
|
|
||||||
if (!preg_match_all($this->_link_find, $head_matches[0],
|
|
||||||
$link_matches)) {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($link_matches[0] as $link) {
|
|
||||||
$attr_matches = array();
|
|
||||||
preg_match_all($this->_attr_find, $link, $attr_matches);
|
|
||||||
$link_attrs = array();
|
|
||||||
foreach ($attr_matches[0] as $index => $full_match) {
|
|
||||||
$name = $attr_matches[1][$index];
|
|
||||||
$value = $this->replaceEntities(
|
|
||||||
$this->removeQuotes($attr_matches[2][$index]));
|
|
||||||
|
|
||||||
$link_attrs[strtolower($name)] = $value;
|
|
||||||
}
|
|
||||||
$link_data[] = $link_attrs;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $link_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
function relMatches($rel_attr, $target_rel)
|
|
||||||
{
|
|
||||||
// Does this target_rel appear in the rel_str?
|
|
||||||
// XXX: TESTME
|
|
||||||
$rels = preg_split("/\s+/", trim($rel_attr));
|
|
||||||
foreach ($rels as $rel) {
|
|
||||||
$rel = strtolower($rel);
|
|
||||||
if ($rel == $target_rel) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function linkHasRel($link_attrs, $target_rel)
|
|
||||||
{
|
|
||||||
// Does this link have target_rel as a relationship?
|
|
||||||
// XXX: TESTME
|
|
||||||
$rel_attr = Auth_OpeniD::arrayGet($link_attrs, 'rel', null);
|
|
||||||
return ($rel_attr && $this->relMatches($rel_attr,
|
|
||||||
$target_rel));
|
|
||||||
}
|
|
||||||
|
|
||||||
function findLinksRel($link_attrs_list, $target_rel)
|
|
||||||
{
|
|
||||||
// Filter the list of link attributes on whether it has
|
|
||||||
// target_rel as a relationship.
|
|
||||||
// XXX: TESTME
|
|
||||||
$result = array();
|
|
||||||
foreach ($link_attrs_list as $attr) {
|
|
||||||
if ($this->linkHasRel($attr, $target_rel)) {
|
|
||||||
$result[] = $attr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function findFirstHref($link_attrs_list, $target_rel)
|
|
||||||
{
|
|
||||||
// Return the value of the href attribute for the first link
|
|
||||||
// tag in the list that has target_rel as a relationship.
|
|
||||||
// XXX: TESTME
|
|
||||||
$matches = $this->findLinksRel($link_attrs_list,
|
|
||||||
$target_rel);
|
|
||||||
if (!$matches) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$first = $matches[0];
|
|
||||||
return Auth_OpenID::arrayGet($first, 'href', null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Auth_OpenID_legacy_discover($html_text)
|
|
||||||
{
|
|
||||||
$p = new Auth_OpenID_Parse();
|
|
||||||
|
|
||||||
$link_attrs = $p->parseLinkAttrs($html_text);
|
|
||||||
|
|
||||||
$server_url = $p->findFirstHref($link_attrs,
|
|
||||||
'openid.server');
|
|
||||||
|
|
||||||
if ($server_url === null) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
$delegate_url = $p->findFirstHref($link_attrs,
|
|
||||||
'openid.delegate');
|
|
||||||
return array($delegate_url, $server_url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,136 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A PostgreSQL store.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Require the base class file.
|
|
||||||
*/
|
|
||||||
require_once "Auth/OpenID/SQLStore.php";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An SQL store that uses PostgreSQL as its backend.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
*/
|
|
||||||
class Auth_OpenID_PostgreSQLStore extends Auth_OpenID_SQLStore {
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function setSQL()
|
|
||||||
{
|
|
||||||
$this->sql['nonce_table'] =
|
|
||||||
"CREATE TABLE %s (nonce CHAR(8) UNIQUE PRIMARY KEY, ".
|
|
||||||
"expires INTEGER)";
|
|
||||||
|
|
||||||
$this->sql['assoc_table'] =
|
|
||||||
"CREATE TABLE %s (server_url VARCHAR(2047), handle VARCHAR(255), ".
|
|
||||||
"secret BYTEA, issued INTEGER, lifetime INTEGER, ".
|
|
||||||
"assoc_type VARCHAR(64), PRIMARY KEY (server_url, handle), ".
|
|
||||||
"CONSTRAINT secret_length_constraint CHECK ".
|
|
||||||
"(LENGTH(secret) <= 128))";
|
|
||||||
|
|
||||||
$this->sql['settings_table'] =
|
|
||||||
"CREATE TABLE %s (setting VARCHAR(128) UNIQUE PRIMARY KEY, ".
|
|
||||||
"value BYTEA, ".
|
|
||||||
"CONSTRAINT value_length_constraint CHECK (LENGTH(value) <= 20))";
|
|
||||||
|
|
||||||
$this->sql['create_auth'] =
|
|
||||||
"INSERT INTO %s VALUES ('auth_key', '!')";
|
|
||||||
|
|
||||||
$this->sql['get_auth'] =
|
|
||||||
"SELECT value FROM %s WHERE setting = 'auth_key'";
|
|
||||||
|
|
||||||
$this->sql['set_assoc'] =
|
|
||||||
array(
|
|
||||||
'insert_assoc' => "INSERT INTO %s (server_url, handle, ".
|
|
||||||
"secret, issued, lifetime, assoc_type) VALUES ".
|
|
||||||
"(?, ?, '!', ?, ?, ?)",
|
|
||||||
'update_assoc' => "UPDATE %s SET secret = '!', issued = ?, ".
|
|
||||||
"lifetime = ?, assoc_type = ? WHERE server_url = ? AND ".
|
|
||||||
"handle = ?"
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->sql['get_assocs'] =
|
|
||||||
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
|
|
||||||
"WHERE server_url = ?";
|
|
||||||
|
|
||||||
$this->sql['get_assoc'] =
|
|
||||||
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
|
|
||||||
"WHERE server_url = ? AND handle = ?";
|
|
||||||
|
|
||||||
$this->sql['remove_assoc'] =
|
|
||||||
"DELETE FROM %s WHERE server_url = ? AND handle = ?";
|
|
||||||
|
|
||||||
$this->sql['add_nonce'] =
|
|
||||||
array(
|
|
||||||
'insert_nonce' => "INSERT INTO %s (nonce, expires) VALUES ".
|
|
||||||
"(?, ?)",
|
|
||||||
'update_nonce' => "UPDATE %s SET expires = ? WHERE nonce = ?"
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->sql['get_nonce'] =
|
|
||||||
"SELECT * FROM %s WHERE nonce = ?";
|
|
||||||
|
|
||||||
$this->sql['remove_nonce'] =
|
|
||||||
"DELETE FROM %s WHERE nonce = ?";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _set_assoc($server_url, $handle, $secret, $issued, $lifetime,
|
|
||||||
$assoc_type)
|
|
||||||
{
|
|
||||||
$result = $this->_get_assoc($server_url, $handle);
|
|
||||||
if ($result) {
|
|
||||||
// Update the table since this associations already exists.
|
|
||||||
$this->connection->query($this->sql['set_assoc']['update_assoc'],
|
|
||||||
array($secret, $issued, $lifetime,
|
|
||||||
$assoc_type, $server_url, $handle));
|
|
||||||
} else {
|
|
||||||
// Insert a new record because this association wasn't
|
|
||||||
// found.
|
|
||||||
$this->connection->query($this->sql['set_assoc']['insert_assoc'],
|
|
||||||
array($server_url, $handle, $secret,
|
|
||||||
$issued, $lifetime, $assoc_type));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _add_nonce($nonce, $expires)
|
|
||||||
{
|
|
||||||
if ($this->_get_nonce($nonce)) {
|
|
||||||
return $this->resultToBool($this->connection->query(
|
|
||||||
$this->sql['add_nonce']['update_nonce'],
|
|
||||||
array($expires, $nonce)));
|
|
||||||
} else {
|
|
||||||
return $this->resultToBool($this->connection->query(
|
|
||||||
$this->sql['add_nonce']['insert_nonce'],
|
|
||||||
array($nonce, $expires)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function blobEncode($blob)
|
|
||||||
{
|
|
||||||
return $this->_octify($blob);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function blobDecode($blob)
|
|
||||||
{
|
|
||||||
return $this->_unoctify($blob);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,658 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SQL-backed OpenID stores.
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Require the PEAR DB module because we'll need it for the SQL-based
|
|
||||||
* stores implemented here. We silence any errors from the inclusion
|
|
||||||
* because it might not be present, and a user of the SQL stores may
|
|
||||||
* supply an Auth_OpenID_DatabaseConnection instance that implements
|
|
||||||
* its own storage.
|
|
||||||
*/
|
|
||||||
global $__Auth_OpenID_PEAR_AVAILABLE;
|
|
||||||
$__Auth_OpenID_PEAR_AVAILABLE = @include_once 'DB.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
require_once 'Auth/OpenID/Interface.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the parent class for the SQL stores, which contains the
|
|
||||||
* logic common to all of the SQL stores.
|
|
||||||
*
|
|
||||||
* The table names used are determined by the class variables
|
|
||||||
* settings_table_name, associations_table_name, and
|
|
||||||
* nonces_table_name. To change the name of the tables used, pass new
|
|
||||||
* table names into the constructor.
|
|
||||||
*
|
|
||||||
* To create the tables with the proper schema, see the createTables
|
|
||||||
* method.
|
|
||||||
*
|
|
||||||
* This class shouldn't be used directly. Use one of its subclasses
|
|
||||||
* instead, as those contain the code necessary to use a specific
|
|
||||||
* database. If you're an OpenID integrator and you'd like to create
|
|
||||||
* an SQL-driven store that wraps an application's database
|
|
||||||
* abstraction, be sure to create a subclass of
|
|
||||||
* {@link Auth_OpenID_DatabaseConnection} that calls the application's
|
|
||||||
* database abstraction calls. Then, pass an instance of your new
|
|
||||||
* database connection class to your SQLStore subclass constructor.
|
|
||||||
*
|
|
||||||
* All methods other than the constructor and createTables should be
|
|
||||||
* considered implementation details.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
*/
|
|
||||||
class Auth_OpenID_SQLStore extends Auth_OpenID_OpenIDStore {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This creates a new SQLStore instance. It requires an
|
|
||||||
* established database connection be given to it, and it allows
|
|
||||||
* overriding the default table names.
|
|
||||||
*
|
|
||||||
* @param connection $connection This must be an established
|
|
||||||
* connection to a database of the correct type for the SQLStore
|
|
||||||
* subclass you're using. This must either be an PEAR DB
|
|
||||||
* connection handle or an instance of a subclass of
|
|
||||||
* Auth_OpenID_DatabaseConnection.
|
|
||||||
*
|
|
||||||
* @param string $settings_table This is an optional parameter to
|
|
||||||
* specify the name of the table used for this store's settings.
|
|
||||||
* The default value is 'oid_settings'.
|
|
||||||
*
|
|
||||||
* @param associations_table: This is an optional parameter to
|
|
||||||
* specify the name of the table used for storing associations.
|
|
||||||
* The default value is 'oid_associations'.
|
|
||||||
*
|
|
||||||
* @param nonces_table: This is an optional parameter to specify
|
|
||||||
* the name of the table used for storing nonces. The default
|
|
||||||
* value is 'oid_nonces'.
|
|
||||||
*/
|
|
||||||
function Auth_OpenID_SQLStore($connection, $settings_table = null,
|
|
||||||
$associations_table = null,
|
|
||||||
$nonces_table = null)
|
|
||||||
{
|
|
||||||
global $__Auth_OpenID_PEAR_AVAILABLE;
|
|
||||||
|
|
||||||
$this->settings_table_name = "oid_settings";
|
|
||||||
$this->associations_table_name = "oid_associations";
|
|
||||||
$this->nonces_table_name = "oid_nonces";
|
|
||||||
|
|
||||||
// Check the connection object type to be sure it's a PEAR
|
|
||||||
// database connection.
|
|
||||||
if (!(is_object($connection) &&
|
|
||||||
(is_subclass_of($connection, 'db_common') ||
|
|
||||||
is_subclass_of($connection,
|
|
||||||
'auth_openid_databaseconnection')))) {
|
|
||||||
trigger_error("Auth_OpenID_SQLStore expected PEAR connection " .
|
|
||||||
"object (got ".get_class($connection).")",
|
|
||||||
E_USER_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->connection = $connection;
|
|
||||||
|
|
||||||
// Be sure to set the fetch mode so the results are keyed on
|
|
||||||
// column name instead of column index. This is a PEAR
|
|
||||||
// constant, so only try to use it if PEAR is present. Note
|
|
||||||
// that Auth_Openid_Databaseconnection instances need not
|
|
||||||
// implement ::setFetchMode for this reason.
|
|
||||||
if ($__Auth_OpenID_PEAR_AVAILABLE) {
|
|
||||||
$this->connection->setFetchMode(DB_FETCHMODE_ASSOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($settings_table) {
|
|
||||||
$this->settings_table_name = $settings_table;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($associations_table) {
|
|
||||||
$this->associations_table_name = $associations_table;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($nonces_table) {
|
|
||||||
$this->nonces_table_name = $nonces_table;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->max_nonce_age = 6 * 60 * 60;
|
|
||||||
|
|
||||||
// Be sure to run the database queries with auto-commit mode
|
|
||||||
// turned OFF, because we want every function to run in a
|
|
||||||
// transaction, implicitly. As a rule, methods named with a
|
|
||||||
// leading underscore will NOT control transaction behavior.
|
|
||||||
// Callers of these methods will worry about transactions.
|
|
||||||
$this->connection->autoCommit(false);
|
|
||||||
|
|
||||||
// Create an empty SQL strings array.
|
|
||||||
$this->sql = array();
|
|
||||||
|
|
||||||
// Call this method (which should be overridden by subclasses)
|
|
||||||
// to populate the $this->sql array with SQL strings.
|
|
||||||
$this->setSQL();
|
|
||||||
|
|
||||||
// Verify that all required SQL statements have been set, and
|
|
||||||
// raise an error if any expected SQL strings were either
|
|
||||||
// absent or empty.
|
|
||||||
list($missing, $empty) = $this->_verifySQL();
|
|
||||||
|
|
||||||
if ($missing) {
|
|
||||||
trigger_error("Expected keys in SQL query list: " .
|
|
||||||
implode(", ", $missing),
|
|
||||||
E_USER_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($empty) {
|
|
||||||
trigger_error("SQL list keys have no SQL strings: " .
|
|
||||||
implode(", ", $empty),
|
|
||||||
E_USER_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add table names to queries.
|
|
||||||
$this->_fixSQL();
|
|
||||||
}
|
|
||||||
|
|
||||||
function tableExists($table_name)
|
|
||||||
{
|
|
||||||
return !$this->isError(
|
|
||||||
$this->connection->query("SELECT * FROM %s LIMIT 0",
|
|
||||||
$table_name));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if $value constitutes a database error; returns
|
|
||||||
* false otherwise.
|
|
||||||
*/
|
|
||||||
function isError($value)
|
|
||||||
{
|
|
||||||
return PEAR::isError($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a query result to a boolean. If the result is a
|
|
||||||
* database error according to $this->isError(), this returns
|
|
||||||
* false; otherwise, this returns true.
|
|
||||||
*/
|
|
||||||
function resultToBool($obj)
|
|
||||||
{
|
|
||||||
if ($this->isError($obj)) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method should be overridden by subclasses. This method is
|
|
||||||
* called by the constructor to set values in $this->sql, which is
|
|
||||||
* an array keyed on sql name.
|
|
||||||
*/
|
|
||||||
function setSQL()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the store by removing all records from the store's
|
|
||||||
* tables.
|
|
||||||
*/
|
|
||||||
function reset()
|
|
||||||
{
|
|
||||||
$this->connection->query(sprintf("DELETE FROM %s",
|
|
||||||
$this->associations_table_name));
|
|
||||||
|
|
||||||
$this->connection->query(sprintf("DELETE FROM %s",
|
|
||||||
$this->nonces_table_name));
|
|
||||||
|
|
||||||
$this->connection->query(sprintf("DELETE FROM %s",
|
|
||||||
$this->settings_table_name));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _verifySQL()
|
|
||||||
{
|
|
||||||
$missing = array();
|
|
||||||
$empty = array();
|
|
||||||
|
|
||||||
$required_sql_keys = array(
|
|
||||||
'nonce_table',
|
|
||||||
'assoc_table',
|
|
||||||
'settings_table',
|
|
||||||
'get_auth',
|
|
||||||
'create_auth',
|
|
||||||
'set_assoc',
|
|
||||||
'get_assoc',
|
|
||||||
'get_assocs',
|
|
||||||
'remove_assoc',
|
|
||||||
'add_nonce',
|
|
||||||
'get_nonce',
|
|
||||||
'remove_nonce'
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($required_sql_keys as $key) {
|
|
||||||
if (!array_key_exists($key, $this->sql)) {
|
|
||||||
$missing[] = $key;
|
|
||||||
} else if (!$this->sql[$key]) {
|
|
||||||
$empty[] = $key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return array($missing, $empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _fixSQL()
|
|
||||||
{
|
|
||||||
$replacements = array(
|
|
||||||
array(
|
|
||||||
'value' => $this->nonces_table_name,
|
|
||||||
'keys' => array('nonce_table',
|
|
||||||
'add_nonce',
|
|
||||||
'get_nonce',
|
|
||||||
'remove_nonce')
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'value' => $this->associations_table_name,
|
|
||||||
'keys' => array('assoc_table',
|
|
||||||
'set_assoc',
|
|
||||||
'get_assoc',
|
|
||||||
'get_assocs',
|
|
||||||
'remove_assoc')
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'value' => $this->settings_table_name,
|
|
||||||
'keys' => array('settings_table',
|
|
||||||
'get_auth',
|
|
||||||
'create_auth')
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($replacements as $item) {
|
|
||||||
$value = $item['value'];
|
|
||||||
$keys = $item['keys'];
|
|
||||||
|
|
||||||
foreach ($keys as $k) {
|
|
||||||
if (is_array($this->sql[$k])) {
|
|
||||||
foreach ($this->sql[$k] as $part_key => $part_value) {
|
|
||||||
$this->sql[$k][$part_key] = sprintf($part_value,
|
|
||||||
$value);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$this->sql[$k] = sprintf($this->sql[$k], $value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function blobDecode($blob)
|
|
||||||
{
|
|
||||||
return $blob;
|
|
||||||
}
|
|
||||||
|
|
||||||
function blobEncode($str)
|
|
||||||
{
|
|
||||||
return $str;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createTables()
|
|
||||||
{
|
|
||||||
$this->connection->autoCommit(true);
|
|
||||||
$n = $this->create_nonce_table();
|
|
||||||
$a = $this->create_assoc_table();
|
|
||||||
$s = $this->create_settings_table();
|
|
||||||
$this->connection->autoCommit(false);
|
|
||||||
|
|
||||||
if ($n && $a && $s) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function create_nonce_table()
|
|
||||||
{
|
|
||||||
if (!$this->tableExists($this->nonces_table_name)) {
|
|
||||||
$r = $this->connection->query($this->sql['nonce_table']);
|
|
||||||
return $this->resultToBool($r);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function create_assoc_table()
|
|
||||||
{
|
|
||||||
if (!$this->tableExists($this->associations_table_name)) {
|
|
||||||
$r = $this->connection->query($this->sql['assoc_table']);
|
|
||||||
return $this->resultToBool($r);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function create_settings_table()
|
|
||||||
{
|
|
||||||
if (!$this->tableExists($this->settings_table_name)) {
|
|
||||||
$r = $this->connection->query($this->sql['settings_table']);
|
|
||||||
return $this->resultToBool($r);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _get_auth()
|
|
||||||
{
|
|
||||||
return $this->connection->getOne($this->sql['get_auth']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _create_auth($str)
|
|
||||||
{
|
|
||||||
return $this->connection->query($this->sql['create_auth'],
|
|
||||||
array($str));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAuthKey()
|
|
||||||
{
|
|
||||||
$value = $this->_get_auth();
|
|
||||||
if (!$value) {
|
|
||||||
$auth_key =
|
|
||||||
Auth_OpenID_CryptUtil::randomString($this->AUTH_KEY_LEN);
|
|
||||||
|
|
||||||
$auth_key_s = $this->blobEncode($auth_key);
|
|
||||||
$this->_create_auth($auth_key_s);
|
|
||||||
} else {
|
|
||||||
$auth_key_s = $value;
|
|
||||||
$auth_key = $this->blobDecode($auth_key_s);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->connection->commit();
|
|
||||||
|
|
||||||
if (strlen($auth_key) != $this->AUTH_KEY_LEN) {
|
|
||||||
$fmt = "Expected %d-byte string for auth key. Got key of length %d";
|
|
||||||
trigger_error(sprintf($fmt, $this->AUTH_KEY_LEN, strlen($auth_key)),
|
|
||||||
E_USER_WARNING);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $auth_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _set_assoc($server_url, $handle, $secret, $issued,
|
|
||||||
$lifetime, $assoc_type)
|
|
||||||
{
|
|
||||||
return $this->connection->query($this->sql['set_assoc'],
|
|
||||||
array(
|
|
||||||
$server_url,
|
|
||||||
$handle,
|
|
||||||
$secret,
|
|
||||||
$issued,
|
|
||||||
$lifetime,
|
|
||||||
$assoc_type));
|
|
||||||
}
|
|
||||||
|
|
||||||
function storeAssociation($server_url, $association)
|
|
||||||
{
|
|
||||||
if ($this->resultToBool($this->_set_assoc(
|
|
||||||
$server_url,
|
|
||||||
$association->handle,
|
|
||||||
$this->blobEncode(
|
|
||||||
$association->secret),
|
|
||||||
$association->issued,
|
|
||||||
$association->lifetime,
|
|
||||||
$association->assoc_type
|
|
||||||
))) {
|
|
||||||
$this->connection->commit();
|
|
||||||
} else {
|
|
||||||
$this->connection->rollback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _get_assoc($server_url, $handle)
|
|
||||||
{
|
|
||||||
$result = $this->connection->getRow($this->sql['get_assoc'],
|
|
||||||
array($server_url, $handle));
|
|
||||||
if ($this->isError($result)) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _get_assocs($server_url)
|
|
||||||
{
|
|
||||||
$result = $this->connection->getAll($this->sql['get_assocs'],
|
|
||||||
array($server_url));
|
|
||||||
|
|
||||||
if ($this->isError($result)) {
|
|
||||||
return array();
|
|
||||||
} else {
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeAssociation($server_url, $handle)
|
|
||||||
{
|
|
||||||
if ($this->_get_assoc($server_url, $handle) == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->resultToBool($this->connection->query(
|
|
||||||
$this->sql['remove_assoc'],
|
|
||||||
array($server_url, $handle)))) {
|
|
||||||
$this->connection->commit();
|
|
||||||
} else {
|
|
||||||
$this->connection->rollback();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAssociation($server_url, $handle = null)
|
|
||||||
{
|
|
||||||
if ($handle !== null) {
|
|
||||||
$assoc = $this->_get_assoc($server_url, $handle);
|
|
||||||
|
|
||||||
$assocs = array();
|
|
||||||
if ($assoc) {
|
|
||||||
$assocs[] = $assoc;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$assocs = $this->_get_assocs($server_url);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$assocs || (count($assocs) == 0)) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
$associations = array();
|
|
||||||
|
|
||||||
foreach ($assocs as $assoc_row) {
|
|
||||||
$assoc = new Auth_OpenID_Association($assoc_row['handle'],
|
|
||||||
$assoc_row['secret'],
|
|
||||||
$assoc_row['issued'],
|
|
||||||
$assoc_row['lifetime'],
|
|
||||||
$assoc_row['assoc_type']);
|
|
||||||
|
|
||||||
$assoc->secret = $this->blobDecode($assoc->secret);
|
|
||||||
|
|
||||||
if ($assoc->getExpiresIn() == 0) {
|
|
||||||
$this->removeAssociation($server_url, $assoc->handle);
|
|
||||||
} else {
|
|
||||||
$associations[] = array($assoc->issued, $assoc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($associations) {
|
|
||||||
$issued = array();
|
|
||||||
$assocs = array();
|
|
||||||
foreach ($associations as $key => $assoc) {
|
|
||||||
$issued[$key] = $assoc[0];
|
|
||||||
$assocs[$key] = $assoc[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
array_multisort($issued, SORT_DESC, $assocs, SORT_DESC,
|
|
||||||
$associations);
|
|
||||||
|
|
||||||
// return the most recently issued one.
|
|
||||||
list($issued, $assoc) = $associations[0];
|
|
||||||
return $assoc;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _add_nonce($nonce, $expires)
|
|
||||||
{
|
|
||||||
$sql = $this->sql['add_nonce'];
|
|
||||||
$result = $this->connection->query($sql, array($nonce, $expires));
|
|
||||||
return $this->resultToBool($result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function storeNonce($nonce)
|
|
||||||
{
|
|
||||||
if ($this->_add_nonce($nonce, time())) {
|
|
||||||
$this->connection->commit();
|
|
||||||
} else {
|
|
||||||
$this->connection->rollback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _get_nonce($nonce)
|
|
||||||
{
|
|
||||||
$result = $this->connection->getRow($this->sql['get_nonce'],
|
|
||||||
array($nonce));
|
|
||||||
|
|
||||||
if ($this->isError($result)) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _remove_nonce($nonce)
|
|
||||||
{
|
|
||||||
$this->connection->query($this->sql['remove_nonce'],
|
|
||||||
array($nonce));
|
|
||||||
}
|
|
||||||
|
|
||||||
function useNonce($nonce)
|
|
||||||
{
|
|
||||||
$row = $this->_get_nonce($nonce);
|
|
||||||
|
|
||||||
if ($row !== null) {
|
|
||||||
$nonce = $row['nonce'];
|
|
||||||
$timestamp = $row['expires'];
|
|
||||||
$nonce_age = time() - $timestamp;
|
|
||||||
|
|
||||||
if ($nonce_age > $this->max_nonce_age) {
|
|
||||||
$present = 0;
|
|
||||||
} else {
|
|
||||||
$present = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->_remove_nonce($nonce);
|
|
||||||
} else {
|
|
||||||
$present = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->connection->commit();
|
|
||||||
|
|
||||||
return $present;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* "Octifies" a binary string by returning a string with escaped
|
|
||||||
* octal bytes. This is used for preparing binary data for
|
|
||||||
* PostgreSQL BYTEA fields.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _octify($str)
|
|
||||||
{
|
|
||||||
$result = "";
|
|
||||||
for ($i = 0; $i < strlen($str); $i++) {
|
|
||||||
$ch = substr($str, $i, 1);
|
|
||||||
if ($ch == "\\") {
|
|
||||||
$result .= "\\\\\\\\";
|
|
||||||
} else if (ord($ch) == 0) {
|
|
||||||
$result .= "\\\\000";
|
|
||||||
} else {
|
|
||||||
$result .= "\\" . strval(decoct(ord($ch)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* "Unoctifies" octal-escaped data from PostgreSQL and returns the
|
|
||||||
* resulting ASCII (possibly binary) string.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _unoctify($str)
|
|
||||||
{
|
|
||||||
$result = "";
|
|
||||||
$i = 0;
|
|
||||||
while ($i < strlen($str)) {
|
|
||||||
$char = $str[$i];
|
|
||||||
if ($char == "\\") {
|
|
||||||
// Look to see if the next char is a backslash and
|
|
||||||
// append it.
|
|
||||||
if ($str[$i + 1] != "\\") {
|
|
||||||
$octal_digits = substr($str, $i + 1, 3);
|
|
||||||
$dec = octdec($octal_digits);
|
|
||||||
$char = chr($dec);
|
|
||||||
$i += 4;
|
|
||||||
} else {
|
|
||||||
$char = "\\";
|
|
||||||
$i += 2;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
$result .= $char;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An SQLite store.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Require the base class file.
|
|
||||||
*/
|
|
||||||
require_once "Auth/OpenID/SQLStore.php";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An SQL store that uses SQLite as its backend.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
*/
|
|
||||||
class Auth_OpenID_SQLiteStore extends Auth_OpenID_SQLStore {
|
|
||||||
function setSQL()
|
|
||||||
{
|
|
||||||
$this->sql['nonce_table'] =
|
|
||||||
"CREATE TABLE %s (nonce CHAR(8) UNIQUE PRIMARY KEY, ".
|
|
||||||
"expires INTEGER)";
|
|
||||||
|
|
||||||
$this->sql['assoc_table'] =
|
|
||||||
"CREATE TABLE %s (server_url VARCHAR(2047), handle VARCHAR(255), ".
|
|
||||||
"secret BLOB(128), issued INTEGER, lifetime INTEGER, ".
|
|
||||||
"assoc_type VARCHAR(64), PRIMARY KEY (server_url, handle))";
|
|
||||||
|
|
||||||
$this->sql['settings_table'] =
|
|
||||||
"CREATE TABLE %s (setting VARCHAR(128) UNIQUE PRIMARY KEY, ".
|
|
||||||
"value BLOB(20))";
|
|
||||||
|
|
||||||
$this->sql['create_auth'] =
|
|
||||||
"INSERT INTO %s VALUES ('auth_key', ?)";
|
|
||||||
|
|
||||||
$this->sql['get_auth'] =
|
|
||||||
"SELECT value FROM %s WHERE setting = 'auth_key'";
|
|
||||||
|
|
||||||
$this->sql['set_assoc'] =
|
|
||||||
"INSERT OR REPLACE INTO %s VALUES (?, ?, ?, ?, ?, ?)";
|
|
||||||
|
|
||||||
$this->sql['get_assocs'] =
|
|
||||||
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
|
|
||||||
"WHERE server_url = ?";
|
|
||||||
|
|
||||||
$this->sql['get_assoc'] =
|
|
||||||
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
|
|
||||||
"WHERE server_url = ? AND handle = ?";
|
|
||||||
|
|
||||||
$this->sql['remove_assoc'] =
|
|
||||||
"DELETE FROM %s WHERE server_url = ? AND handle = ?";
|
|
||||||
|
|
||||||
$this->sql['add_nonce'] =
|
|
||||||
"INSERT OR REPLACE INTO %s (nonce, expires) VALUES (?, ?)";
|
|
||||||
|
|
||||||
$this->sql['get_nonce'] =
|
|
||||||
"SELECT * FROM %s WHERE nonce = ?";
|
|
||||||
|
|
||||||
$this->sql['remove_nonce'] =
|
|
||||||
"DELETE FROM %s WHERE nonce = ?";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,37 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* OpenID Server Request
|
|
||||||
*
|
|
||||||
* @see Auth_OpenID_Server
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Imports
|
|
||||||
*/
|
|
||||||
require_once "Auth/OpenID.php";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Object that holds the state of a request to the OpenID server
|
|
||||||
*
|
|
||||||
* With accessor functions to get at the internal request data.
|
|
||||||
*
|
|
||||||
* @see Auth_OpenID_Server
|
|
||||||
* @package OpenID
|
|
||||||
*/
|
|
||||||
class Auth_OpenID_ServerRequest {
|
|
||||||
function Auth_OpenID_ServerRequest()
|
|
||||||
{
|
|
||||||
$this->mode = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,131 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
|
|
||||||
require_once 'Auth/OpenID.php';
|
|
||||||
require_once 'Auth/OpenID/Interface.php';
|
|
||||||
require_once 'Auth/OpenID/HMACSHA1.php';
|
|
||||||
|
|
||||||
class Auth_OpenID_SessionStore extends Auth_OpenID_OpenIDStore {
|
|
||||||
|
|
||||||
|
|
||||||
function Auth_OpenID_SessionStore()
|
|
||||||
{
|
|
||||||
if(!$_SESSION["sessionStore"]) $_SESSION["sessionStore"] = array();
|
|
||||||
|
|
||||||
$this->max_nonce_age = 6 * 60 * 60;
|
|
||||||
}
|
|
||||||
|
|
||||||
function destory()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
function createAuthKey()
|
|
||||||
{
|
|
||||||
$auth_key = Auth_OpenID_CryptUtil::randomString($this->AUTH_KEY_LEN);
|
|
||||||
$_SESSION["sessionStore"]["authkey"] = $auth_key;
|
|
||||||
return $auth_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _readAuthKey()
|
|
||||||
{
|
|
||||||
return $_SESSION["sessionStore"]["authkey"];
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAuthKey()
|
|
||||||
{
|
|
||||||
$auth_key = $this->_readAuthKey();
|
|
||||||
if ($auth_key === null) {
|
|
||||||
$auth_key = $this->createAuthKey();
|
|
||||||
|
|
||||||
if (strlen($auth_key) != $this->AUTH_KEY_LEN) {
|
|
||||||
$fmt = 'Got an invalid auth key from %s. Expected '.
|
|
||||||
'%d-byte string. Got: %s';
|
|
||||||
$msg = sprintf($fmt, $this->auth_key_name, $this->AUTH_KEY_LEN,
|
|
||||||
$auth_key);
|
|
||||||
trigger_error($msg, E_USER_WARNING);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $auth_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
function storeNonce($nonce)
|
|
||||||
{
|
|
||||||
$_SESSION["sessionStore"]["nonce"][$nonce] = time();
|
|
||||||
}
|
|
||||||
|
|
||||||
function useNonce($nonce)
|
|
||||||
{
|
|
||||||
$timestamp = $_SESSION["sessionStore"]["nonce"][$nonce];
|
|
||||||
if($timestamp)
|
|
||||||
{
|
|
||||||
$nonce_age = time() - $timestamp;
|
|
||||||
|
|
||||||
if ($nonce_age > $this->max_nonce_age) {
|
|
||||||
$present = 0;
|
|
||||||
} else {
|
|
||||||
$present = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->_remove_nonce($nonce);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$present = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $present;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _remove_nonce($nonce)
|
|
||||||
{
|
|
||||||
if($_SESSION["sessionStore"]["nonce"][$nonce])
|
|
||||||
{
|
|
||||||
unset($_SESSION["sessionStore"]["nonce"][$nonce]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function storeAssociation($server_url, $association)
|
|
||||||
{
|
|
||||||
$_SESSION["sessionStore"]["association"][$server_url][$association->handle] = $association->serialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAssociation($server_url, $handle = null)
|
|
||||||
{
|
|
||||||
$assoc = null;
|
|
||||||
if ($handle != null) {
|
|
||||||
$assoc = $_SESSION["sessionStore"]["association"][$server_url][$handle];
|
|
||||||
}
|
|
||||||
else if($_SESSION["sessionStore"]["association"][$server_url]){
|
|
||||||
foreach($_SESSION["sessionStore"]["association"][$server_url] as $handle => $asso)
|
|
||||||
{
|
|
||||||
$assoc = $asso;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if($assoc)
|
|
||||||
{
|
|
||||||
$assoc = Auth_OpenID_Association::deserialize('Auth_OpenID_Association', $assoc);
|
|
||||||
}
|
|
||||||
return $assoc;
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeAssociation($server_url, $handle)
|
|
||||||
{
|
|
||||||
if($handle == null) return false;
|
|
||||||
if($_SESSION["sessionStore"]["association"][$server_url][$handle])
|
|
||||||
{
|
|
||||||
unset($_SESSION["sessionStore"]["association"][$server_url][$handle]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function reset()
|
|
||||||
{
|
|
||||||
unset($_SESSION["sessionStore"]);
|
|
||||||
$_SESSION["sessionStore"] = array();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,243 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* Functions for dealing with OpenID trust roots
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A regular expression that matches a domain ending in a top-level domains.
|
|
||||||
* Used in checking trust roots for sanity.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
define('Auth_OpenID___TLDs',
|
|
||||||
'/\.(com|edu|gov|int|mil|net|org|biz|info|name|museum|coop|aero|ac|' .
|
|
||||||
'ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|az|ba|bb|bd|be|bf|bg|' .
|
|
||||||
'bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|' .
|
|
||||||
'cm|cn|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|' .
|
|
||||||
'fi|fj|fk|fm|fo|fr|ga|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|' .
|
|
||||||
'gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|' .
|
|
||||||
'ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|' .
|
|
||||||
'ma|mc|md|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|' .
|
|
||||||
'nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|' .
|
|
||||||
'ps|pt|pw|py|qa|re|ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|' .
|
|
||||||
'so|sr|st|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tm|tn|to|tp|tr|tt|tv|tw|tz|' .
|
|
||||||
'ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)$/');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A wrapper for trust-root related functions
|
|
||||||
*/
|
|
||||||
class Auth_OpenID_TrustRoot {
|
|
||||||
/**
|
|
||||||
* Parse a URL into its trust_root parts.
|
|
||||||
*
|
|
||||||
* @static
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
*
|
|
||||||
* @param string $trust_root The url to parse
|
|
||||||
*
|
|
||||||
* @return mixed $parsed Either an associative array of trust root
|
|
||||||
* parts or false if parsing failed.
|
|
||||||
*/
|
|
||||||
function _parse($trust_root)
|
|
||||||
{
|
|
||||||
$parts = @parse_url($trust_root);
|
|
||||||
if ($parts === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$required_parts = array('scheme', 'host');
|
|
||||||
$forbidden_parts = array('user', 'pass', 'fragment');
|
|
||||||
$keys = array_keys($parts);
|
|
||||||
if (array_intersect($keys, $required_parts) != $required_parts) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (array_intersect($keys, $forbidden_parts) != array()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return false if the original trust root value has more than
|
|
||||||
// one port specification.
|
|
||||||
if (preg_match("/:\/\/[^:]+(:\d+){2,}(\/|$)/", $trust_root)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$scheme = strtolower($parts['scheme']);
|
|
||||||
$allowed_schemes = array('http', 'https');
|
|
||||||
if (!in_array($scheme, $allowed_schemes)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$parts['scheme'] = $scheme;
|
|
||||||
|
|
||||||
$host = strtolower($parts['host']);
|
|
||||||
$hostparts = explode('*', $host);
|
|
||||||
switch (count($hostparts)) {
|
|
||||||
case 1:
|
|
||||||
$parts['wildcard'] = false;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if ($hostparts[0] ||
|
|
||||||
($hostparts[1] && substr($hostparts[1], 0, 1) != '.')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$host = $hostparts[1];
|
|
||||||
$parts['wildcard'] = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (strpos($host, ':') !== false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$parts['host'] = $host;
|
|
||||||
|
|
||||||
if (isset($parts['path'])) {
|
|
||||||
$path = strtolower($parts['path']);
|
|
||||||
if (substr($path, -1) != '/') {
|
|
||||||
$path .= '/';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$path = '/';
|
|
||||||
}
|
|
||||||
$parts['path'] = $path;
|
|
||||||
if (!isset($parts['port'])) {
|
|
||||||
$parts['port'] = false;
|
|
||||||
}
|
|
||||||
return $parts;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is this trust root sane?
|
|
||||||
*
|
|
||||||
* A trust root is sane if it is syntactically valid and it has a
|
|
||||||
* reasonable domain name. Specifically, the domain name must be
|
|
||||||
* more than one level below a standard TLD or more than two
|
|
||||||
* levels below a two-letter tld.
|
|
||||||
*
|
|
||||||
* For example, '*.com' is not a sane trust root, but '*.foo.com'
|
|
||||||
* is. '*.co.uk' is not sane, but '*.bbc.co.uk' is.
|
|
||||||
*
|
|
||||||
* This check is not always correct, but it attempts to err on the
|
|
||||||
* side of marking sane trust roots insane instead of marking
|
|
||||||
* insane trust roots sane. For example, 'kink.fm' is marked as
|
|
||||||
* insane even though it "should" (for some meaning of should) be
|
|
||||||
* marked sane.
|
|
||||||
*
|
|
||||||
* This function should be used when creating OpenID servers to
|
|
||||||
* alert the users of the server when a consumer attempts to get
|
|
||||||
* the user to accept a suspicious trust root.
|
|
||||||
*
|
|
||||||
* @static
|
|
||||||
* @param string $trust_root The trust root to check
|
|
||||||
* @return bool $sanity Whether the trust root looks OK
|
|
||||||
*/
|
|
||||||
function isSane($trust_root)
|
|
||||||
{
|
|
||||||
$parts = Auth_OpenID_TrustRoot::_parse($trust_root);
|
|
||||||
if ($parts === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Localhost is a special case
|
|
||||||
if ($parts['host'] == 'localhost') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the top-level domain of the host. If it is not a valid TLD,
|
|
||||||
// it's not sane.
|
|
||||||
preg_match(Auth_OpenID___TLDs, $parts['host'], $matches);
|
|
||||||
if (!$matches) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$tld = $matches[1];
|
|
||||||
|
|
||||||
// Require at least two levels of specificity for non-country
|
|
||||||
// tlds and three levels for country tlds.
|
|
||||||
$elements = explode('.', $parts['host']);
|
|
||||||
$n = count($elements);
|
|
||||||
if ($parts['wildcard']) {
|
|
||||||
$n -= 1;
|
|
||||||
}
|
|
||||||
if (strlen($tld) == 2) {
|
|
||||||
$n -= 1;
|
|
||||||
}
|
|
||||||
if ($n <= 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does this URL match the given trust root?
|
|
||||||
*
|
|
||||||
* Return whether the URL falls under the given trust root. This
|
|
||||||
* does not check whether the trust root is sane. If the URL or
|
|
||||||
* trust root do not parse, this function will return false.
|
|
||||||
*
|
|
||||||
* @param string $trust_root The trust root to match against
|
|
||||||
*
|
|
||||||
* @param string $url The URL to check
|
|
||||||
*
|
|
||||||
* @return bool $matches Whether the URL matches against the
|
|
||||||
* trust root
|
|
||||||
*/
|
|
||||||
function match($trust_root, $url)
|
|
||||||
{
|
|
||||||
$trust_root_parsed = Auth_OpenID_TrustRoot::_parse($trust_root);
|
|
||||||
$url_parsed = Auth_OpenID_TrustRoot::_parse($url);
|
|
||||||
if (!$trust_root_parsed || !$url_parsed) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check hosts matching
|
|
||||||
if ($url_parsed['wildcard']) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ($trust_root_parsed['wildcard']) {
|
|
||||||
$host_tail = $trust_root_parsed['host'];
|
|
||||||
$host = $url_parsed['host'];
|
|
||||||
if ($host_tail &&
|
|
||||||
substr($host, -(strlen($host_tail))) != $host_tail &&
|
|
||||||
substr($host_tail, 1) != $host) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ($trust_root_parsed['host'] != $url_parsed['host']) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check path and query matching
|
|
||||||
$base_path = $trust_root_parsed['path'];
|
|
||||||
$path = $url_parsed['path'];
|
|
||||||
if (!isset($trust_root_parsed['query'])) {
|
|
||||||
if (substr($path, 0, strlen($base_path)) != $base_path) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$base_query = $trust_root_parsed['query'];
|
|
||||||
$query = @$url_parsed['query'];
|
|
||||||
$qplus = substr($query, 0, strlen($base_query) + 1);
|
|
||||||
$bqplus = $base_query . '&';
|
|
||||||
if ($base_path != $path ||
|
|
||||||
($base_query != $query && $qplus != $bqplus)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The port and scheme need to match exactly
|
|
||||||
return ($trust_root_parsed['scheme'] == $url_parsed['scheme'] &&
|
|
||||||
$url_parsed['port'] === $trust_root_parsed['port']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
@ -1,230 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* URI normalization routines.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
require_once $this->module_path.'php-openid-1.2.3/Services/Yadis/Misc.php';
|
|
||||||
|
|
||||||
// from appendix B of rfc 3986 (http://www.ietf.org/rfc/rfc3986.txt)
|
|
||||||
function Auth_OpenID_getURIPattern()
|
|
||||||
{
|
|
||||||
return '&^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?&';
|
|
||||||
}
|
|
||||||
|
|
||||||
function Auth_OpenID_getAuthorityPattern()
|
|
||||||
{
|
|
||||||
return '/^([^@]*@)?([^:]*)(:.*)?/';
|
|
||||||
}
|
|
||||||
|
|
||||||
function Auth_OpenID_getEncodedPattern()
|
|
||||||
{
|
|
||||||
return '/%([0-9A-Fa-f]{2})/';
|
|
||||||
}
|
|
||||||
|
|
||||||
function Auth_OpenID_getUnreserved()
|
|
||||||
{
|
|
||||||
$_unreserved = array();
|
|
||||||
for ($i = 0; $i < 256; $i++) {
|
|
||||||
$_unreserved[$i] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for ($i = ord('A'); $i <= ord('Z'); $i++) {
|
|
||||||
$_unreserved[$i] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for ($i = ord('0'); $i <= ord('9'); $i++) {
|
|
||||||
$_unreserved[$i] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for ($i = ord('a'); $i <= ord('z'); $i++) {
|
|
||||||
$_unreserved[$i] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$_unreserved[ord('-')] = true;
|
|
||||||
$_unreserved[ord('.')] = true;
|
|
||||||
$_unreserved[ord('_')] = true;
|
|
||||||
$_unreserved[ord('~')] = true;
|
|
||||||
|
|
||||||
return $_unreserved;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Auth_OpenID_getEscapeRE()
|
|
||||||
{
|
|
||||||
$parts = array();
|
|
||||||
foreach (array_merge(Services_Yadis_getUCSChars(),
|
|
||||||
Services_Yadis_getIPrivateChars()) as $pair) {
|
|
||||||
list($m, $n) = $pair;
|
|
||||||
$parts[] = sprintf("%s-%s", chr($m), chr($n));
|
|
||||||
}
|
|
||||||
|
|
||||||
return sprintf('[%s]', implode('', $parts));
|
|
||||||
}
|
|
||||||
|
|
||||||
function Auth_OpenID_pct_encoded_replace_unreserved($mo)
|
|
||||||
{
|
|
||||||
$_unreserved = Auth_OpenID_getUnreserved();
|
|
||||||
|
|
||||||
$i = intval($mo[1], 16);
|
|
||||||
if ($_unreserved[$i]) {
|
|
||||||
return chr($i);
|
|
||||||
} else {
|
|
||||||
return strtoupper($mo[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $mo[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
function Auth_OpenID_pct_encoded_replace($mo)
|
|
||||||
{
|
|
||||||
return chr(intval($mo[1], 16));
|
|
||||||
}
|
|
||||||
|
|
||||||
function Auth_OpenID_remove_dot_segments($path)
|
|
||||||
{
|
|
||||||
$result_segments = array();
|
|
||||||
|
|
||||||
while ($path) {
|
|
||||||
if (Services_Yadis_startswith($path, '../')) {
|
|
||||||
$path = substr($path, 3);
|
|
||||||
} else if (Services_Yadis_startswith($path, './')) {
|
|
||||||
$path = substr($path, 2);
|
|
||||||
} else if (Services_Yadis_startswith($path, '/./')) {
|
|
||||||
$path = substr($path, 2);
|
|
||||||
} else if ($path == '/.') {
|
|
||||||
$path = '/';
|
|
||||||
} else if (Services_Yadis_startswith($path, '/../')) {
|
|
||||||
$path = substr($path, 3);
|
|
||||||
if ($result_segments) {
|
|
||||||
array_pop($result_segments);
|
|
||||||
}
|
|
||||||
} else if ($path == '/..') {
|
|
||||||
$path = '/';
|
|
||||||
if ($result_segments) {
|
|
||||||
array_pop($result_segments);
|
|
||||||
}
|
|
||||||
} else if (($path == '..') ||
|
|
||||||
($path == '.')) {
|
|
||||||
$path = '';
|
|
||||||
} else {
|
|
||||||
$i = 0;
|
|
||||||
if ($path[0] == '/') {
|
|
||||||
$i = 1;
|
|
||||||
}
|
|
||||||
$i = strpos($path, '/', $i);
|
|
||||||
if ($i === false) {
|
|
||||||
$i = strlen($path);
|
|
||||||
}
|
|
||||||
$result_segments[] = substr($path, 0, $i);
|
|
||||||
$path = substr($path, $i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return implode('', $result_segments);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Auth_OpenID_urinorm($uri)
|
|
||||||
{
|
|
||||||
$uri_matches = array();
|
|
||||||
preg_match(Auth_OpenID_getURIPattern(), $uri, $uri_matches);
|
|
||||||
|
|
||||||
if (count($uri_matches) < 9) {
|
|
||||||
for ($i = count($uri_matches); $i <= 9; $i++) {
|
|
||||||
$uri_matches[] = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$scheme = $uri_matches[2];
|
|
||||||
if ($scheme) {
|
|
||||||
$scheme = strtolower($scheme);
|
|
||||||
}
|
|
||||||
|
|
||||||
$scheme = $uri_matches[2];
|
|
||||||
if ($scheme === '') {
|
|
||||||
// No scheme specified
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$scheme = strtolower($scheme);
|
|
||||||
if (!in_array($scheme, array('http', 'https'))) {
|
|
||||||
// Not an absolute HTTP or HTTPS URI
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$authority = $uri_matches[4];
|
|
||||||
if ($authority === '') {
|
|
||||||
// Not an absolute URI
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$authority_matches = array();
|
|
||||||
preg_match(Auth_OpenID_getAuthorityPattern(),
|
|
||||||
$authority, $authority_matches);
|
|
||||||
if (count($authority_matches) === 0) {
|
|
||||||
// URI does not have a valid authority
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count($authority_matches) < 4) {
|
|
||||||
for ($i = count($authority_matches); $i <= 4; $i++) {
|
|
||||||
$authority_matches[] = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
list($_whole, $userinfo, $host, $port) = $authority_matches;
|
|
||||||
|
|
||||||
if ($userinfo === null) {
|
|
||||||
$userinfo = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strpos($host, '%') !== -1) {
|
|
||||||
$host = strtolower($host);
|
|
||||||
$host = preg_replace_callback(
|
|
||||||
Auth_OpenID_getEncodedPattern(),
|
|
||||||
'Auth_OpenID_pct_encoded_replace', $host);
|
|
||||||
// NO IDNA.
|
|
||||||
// $host = unicode($host, 'utf-8').encode('idna');
|
|
||||||
} else {
|
|
||||||
$host = strtolower($host);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($port) {
|
|
||||||
if (($port == ':') ||
|
|
||||||
($scheme == 'http' && $port == ':80') ||
|
|
||||||
($scheme == 'https' && $port == ':443')) {
|
|
||||||
$port = '';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$port = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$authority = $userinfo . $host . $port;
|
|
||||||
|
|
||||||
$path = $uri_matches[5];
|
|
||||||
$path = preg_replace_callback(
|
|
||||||
Auth_OpenID_getEncodedPattern(),
|
|
||||||
'Auth_OpenID_pct_encoded_replace_unreserved', $path);
|
|
||||||
|
|
||||||
$path = Auth_OpenID_remove_dot_segments($path);
|
|
||||||
if (!$path) {
|
|
||||||
$path = '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
$query = $uri_matches[6];
|
|
||||||
if ($query === null) {
|
|
||||||
$query = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$fragment = $uri_matches[8];
|
|
||||||
if ($fragment === null) {
|
|
||||||
$fragment = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $scheme . '://' . $authority . $path . $query . $fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,176 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once 'Auth/OpenID.php';
|
|
||||||
require_once 'Auth/OpenID/Interface.php';
|
|
||||||
require_once 'Auth/OpenID/HMACSHA1.php';
|
|
||||||
|
|
||||||
class Auth_OpenID_XEStore extends Auth_OpenID_OpenIDStore {
|
|
||||||
|
|
||||||
function Auth_OpenID_XEStore()
|
|
||||||
{
|
|
||||||
$this->max_nonce_age = 6 * 60 * 60;
|
|
||||||
}
|
|
||||||
|
|
||||||
function destory()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
function createAuthKey()
|
|
||||||
{
|
|
||||||
$auth_key = Auth_OpenID_CryptUtil::randomString($this->AUTH_KEY_LEN);
|
|
||||||
$oModuleModel = &getModel('module');
|
|
||||||
$memberConfig = $oModuleModel->getModuleConfig('member');
|
|
||||||
$memberConfig->openid_authkey = $auth_key;
|
|
||||||
|
|
||||||
$oModuleController = &getController('module');
|
|
||||||
$oModuleController->inesrtModuleConfig("module", $memberConfig);
|
|
||||||
return $auth_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _readAuthKey()
|
|
||||||
{
|
|
||||||
$oModuleModel = &getModel('module');
|
|
||||||
$memberConfig = $oModuleModel->getModuleConfig('member');
|
|
||||||
return $memberConfig->openid_authkey;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAuthKey()
|
|
||||||
{
|
|
||||||
$auth_key = $this->_readAuthKey();
|
|
||||||
if ($auth_key === null) {
|
|
||||||
$auth_key = $this->createAuthKey();
|
|
||||||
|
|
||||||
if (strlen($auth_key) != $this->AUTH_KEY_LEN) {
|
|
||||||
$fmt = 'Got an invalid auth key from %s. Expected '.
|
|
||||||
'%d-byte string. Got: %s';
|
|
||||||
$msg = sprintf($fmt, $this->auth_key_name, $this->AUTH_KEY_LEN,
|
|
||||||
$auth_key);
|
|
||||||
trigger_error($msg, E_USER_WARNING);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function storeNonce($nonce)
|
|
||||||
{
|
|
||||||
$args->nonce = $nonce;
|
|
||||||
$args->expires = time();
|
|
||||||
$output = executeQuery("member.insertOpenIdNonce", $args);
|
|
||||||
}
|
|
||||||
|
|
||||||
function useNonce($nonce)
|
|
||||||
{
|
|
||||||
$args->nonce = $nonce;
|
|
||||||
$output = executeQuery("member.getOpenIdNonce", $args);
|
|
||||||
if($output->data)
|
|
||||||
{
|
|
||||||
$timestamp = $output->data->expires;
|
|
||||||
$nonce_age = time() - $timestamp;
|
|
||||||
|
|
||||||
if ($nonce_age > $this->max_nonce_age) {
|
|
||||||
$present = 0;
|
|
||||||
} else {
|
|
||||||
$present = 1;
|
|
||||||
}
|
|
||||||
$output = executeQuery("member.deleteOpenIdNonce", $args);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$present = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $present;
|
|
||||||
}
|
|
||||||
|
|
||||||
function storeAssociation($server_url, $association)
|
|
||||||
{
|
|
||||||
$args->server_url = $server_url;
|
|
||||||
$args->handle = $association->handle;
|
|
||||||
$args->secret = bin2hex($association->secret);
|
|
||||||
$args->issued = $association->issued;
|
|
||||||
$args->lifetime = $association->lifetime;
|
|
||||||
$args->assoc_type = $association->assoc_type;
|
|
||||||
executeQuery("member.insertOpenIdAssociation", $args);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _check_expire(&$assoc)
|
|
||||||
{
|
|
||||||
$assoc_o = new Auth_OpenID_Association($assoc->handle, $assoc->secret, $assoc->issued, $assoc->lifetime, $assoc->assoc_type);
|
|
||||||
if ($assoc_o->getExpiresIn() == 0) {
|
|
||||||
$this->removeAssociation($server_url, $assoc_o->handle);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return $assoc_o;
|
|
||||||
}
|
|
||||||
|
|
||||||
function hex2bin($h)
|
|
||||||
{
|
|
||||||
if (!is_string($h)) return null;
|
|
||||||
$r='';
|
|
||||||
for ($a=0; $a<strlen($h); $a+=2) { $r.=chr(hexdec($h{$a}.$h{($a+1)})); }
|
|
||||||
return $r;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _get_assoc($server_url, $handle, $getOrig = false)
|
|
||||||
{
|
|
||||||
$args->server_url = $server_url;
|
|
||||||
$args->handle = $handle;
|
|
||||||
$output = executeQueryArray("member.getOpenIdAssociation", $args);
|
|
||||||
if(!$output->data) return null;
|
|
||||||
|
|
||||||
if(count($output->data) == 1) {
|
|
||||||
$assoc = array_shift($output->data);
|
|
||||||
$assoc->secret = $this->hex2bin($assoc->secret);
|
|
||||||
if($getOrig) return $assoc;
|
|
||||||
return $this->_check_expire($assoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
$res = null;
|
|
||||||
foreach($output->data as $assoc)
|
|
||||||
{
|
|
||||||
if($res == null)
|
|
||||||
{
|
|
||||||
$res = $assoc;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$assoc->secret = $this->hex2bin($assoc->secret);
|
|
||||||
$assoc_o = $this->_check_expire($assoc);
|
|
||||||
if(!$assoc_o) continue;
|
|
||||||
|
|
||||||
if($res->issued < $assoc->issued)
|
|
||||||
{
|
|
||||||
$res = $assoc_o;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $res;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAssociation($server_url, $handle = null)
|
|
||||||
{
|
|
||||||
$assoc = $this->_get_assoc($server_url, $handle);
|
|
||||||
if(!$assoc) return null;
|
|
||||||
$assoc_o = new Auth_OpenID_Association($assoc->handle, $assoc->secret, $assoc->issued, $assoc->lifetime, $assoc->assoc_type);
|
|
||||||
return $assoc_o;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function removeAssociation($server_url, $handle)
|
|
||||||
{
|
|
||||||
if ($this->_get_assoc($server_url, $handle, true) == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$args->server_url = $server_url;
|
|
||||||
$args->handle = $handle;
|
|
||||||
$output = executeQuery("member.deleteOpenIdAssociation", $args);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function reset()
|
|
||||||
{
|
|
||||||
$output = executeQuery("member.deleteOpenIdNonce");
|
|
||||||
$output = executeQuery("member.deleteOpenIdAssociation");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
Thu Apr 26 11:41:52 PDT 2007 cygnus@janrain.com
|
|
||||||
tagged 1.2.3
|
|
||||||
|
|
||||||
Thu Apr 26 11:19:11 PDT 2007 cygnus@janrain.com
|
|
||||||
* Make yadis META tag search ignore comments
|
|
||||||
|
|
||||||
Fri Mar 23 11:15:57 PDT 2007 cygnus@janrain.com
|
|
||||||
tagged 1.2.2
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
PHP OpenID - OpenID consumer and server library
|
|
||||||
|
|
||||||
Copyright (C) 2005 Janrain, Inc.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library 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
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
More info about PHP OpenID:
|
|
||||||
eng+openid@janrain.com
|
|
||||||
http://www.openidenabled.com/openid/libraries/php/
|
|
||||||
|
|
||||||
More info about OpenID:
|
|
||||||
http://www.openid.net
|
|
||||||
|
|
@ -1,504 +0,0 @@
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
Version 2.1, February 1999
|
|
||||||
|
|
||||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
[This is the first released version of the Lesser GPL. It also counts
|
|
||||||
as the successor of the GNU Library Public License, version 2, hence
|
|
||||||
the version number 2.1.]
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
|
||||||
Licenses are intended to guarantee your freedom to share and change
|
|
||||||
free software--to make sure the software is free for all its users.
|
|
||||||
|
|
||||||
This license, the Lesser General Public License, applies to some
|
|
||||||
specially designated software packages--typically libraries--of the
|
|
||||||
Free Software Foundation and other authors who decide to use it. You
|
|
||||||
can use it too, but we suggest you first think carefully about whether
|
|
||||||
this license or the ordinary General Public License is the better
|
|
||||||
strategy to use in any particular case, based on the explanations below.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom of use,
|
|
||||||
not price. Our General Public Licenses are designed to make sure that
|
|
||||||
you have the freedom to distribute copies of free software (and charge
|
|
||||||
for this service if you wish); that you receive source code or can get
|
|
||||||
it if you want it; that you can change the software and use pieces of
|
|
||||||
it in new free programs; and that you are informed that you can do
|
|
||||||
these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to make restrictions that forbid
|
|
||||||
distributors to deny you these rights or to ask you to surrender these
|
|
||||||
rights. These restrictions translate to certain responsibilities for
|
|
||||||
you if you distribute copies of the library or if you modify it.
|
|
||||||
|
|
||||||
For example, if you distribute copies of the library, whether gratis
|
|
||||||
or for a fee, you must give the recipients all the rights that we gave
|
|
||||||
you. You must make sure that they, too, receive or can get the source
|
|
||||||
code. If you link other code with the library, you must provide
|
|
||||||
complete object files to the recipients, so that they can relink them
|
|
||||||
with the library after making changes to the library and recompiling
|
|
||||||
it. And you must show them these terms so they know their rights.
|
|
||||||
|
|
||||||
We protect your rights with a two-step method: (1) we copyright the
|
|
||||||
library, and (2) we offer you this license, which gives you legal
|
|
||||||
permission to copy, distribute and/or modify the library.
|
|
||||||
|
|
||||||
To protect each distributor, we want to make it very clear that
|
|
||||||
there is no warranty for the free library. Also, if the library is
|
|
||||||
modified by someone else and passed on, the recipients should know
|
|
||||||
that what they have is not the original version, so that the original
|
|
||||||
author's reputation will not be affected by problems that might be
|
|
||||||
introduced by others.
|
|
||||||
|
|
||||||
Finally, software patents pose a constant threat to the existence of
|
|
||||||
any free program. We wish to make sure that a company cannot
|
|
||||||
effectively restrict the users of a free program by obtaining a
|
|
||||||
restrictive license from a patent holder. Therefore, we insist that
|
|
||||||
any patent license obtained for a version of the library must be
|
|
||||||
consistent with the full freedom of use specified in this license.
|
|
||||||
|
|
||||||
Most GNU software, including some libraries, is covered by the
|
|
||||||
ordinary GNU General Public License. This license, the GNU Lesser
|
|
||||||
General Public License, applies to certain designated libraries, and
|
|
||||||
is quite different from the ordinary General Public License. We use
|
|
||||||
this license for certain libraries in order to permit linking those
|
|
||||||
libraries into non-free programs.
|
|
||||||
|
|
||||||
When a program is linked with a library, whether statically or using
|
|
||||||
a shared library, the combination of the two is legally speaking a
|
|
||||||
combined work, a derivative of the original library. The ordinary
|
|
||||||
General Public License therefore permits such linking only if the
|
|
||||||
entire combination fits its criteria of freedom. The Lesser General
|
|
||||||
Public License permits more lax criteria for linking other code with
|
|
||||||
the library.
|
|
||||||
|
|
||||||
We call this license the "Lesser" General Public License because it
|
|
||||||
does Less to protect the user's freedom than the ordinary General
|
|
||||||
Public License. It also provides other free software developers Less
|
|
||||||
of an advantage over competing non-free programs. These disadvantages
|
|
||||||
are the reason we use the ordinary General Public License for many
|
|
||||||
libraries. However, the Lesser license provides advantages in certain
|
|
||||||
special circumstances.
|
|
||||||
|
|
||||||
For example, on rare occasions, there may be a special need to
|
|
||||||
encourage the widest possible use of a certain library, so that it becomes
|
|
||||||
a de-facto standard. To achieve this, non-free programs must be
|
|
||||||
allowed to use the library. A more frequent case is that a free
|
|
||||||
library does the same job as widely used non-free libraries. In this
|
|
||||||
case, there is little to gain by limiting the free library to free
|
|
||||||
software only, so we use the Lesser General Public License.
|
|
||||||
|
|
||||||
In other cases, permission to use a particular library in non-free
|
|
||||||
programs enables a greater number of people to use a large body of
|
|
||||||
free software. For example, permission to use the GNU C Library in
|
|
||||||
non-free programs enables many more people to use the whole GNU
|
|
||||||
operating system, as well as its variant, the GNU/Linux operating
|
|
||||||
system.
|
|
||||||
|
|
||||||
Although the Lesser General Public License is Less protective of the
|
|
||||||
users' freedom, it does ensure that the user of a program that is
|
|
||||||
linked with the Library has the freedom and the wherewithal to run
|
|
||||||
that program using a modified version of the Library.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow. Pay close attention to the difference between a
|
|
||||||
"work based on the library" and a "work that uses the library". The
|
|
||||||
former contains code derived from the library, whereas the latter must
|
|
||||||
be combined with the library in order to run.
|
|
||||||
|
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
||||||
|
|
||||||
0. This License Agreement applies to any software library or other
|
|
||||||
program which contains a notice placed by the copyright holder or
|
|
||||||
other authorized party saying it may be distributed under the terms of
|
|
||||||
this Lesser General Public License (also called "this License").
|
|
||||||
Each licensee is addressed as "you".
|
|
||||||
|
|
||||||
A "library" means a collection of software functions and/or data
|
|
||||||
prepared so as to be conveniently linked with application programs
|
|
||||||
(which use some of those functions and data) to form executables.
|
|
||||||
|
|
||||||
The "Library", below, refers to any such software library or work
|
|
||||||
which has been distributed under these terms. A "work based on the
|
|
||||||
Library" means either the Library or any derivative work under
|
|
||||||
copyright law: that is to say, a work containing the Library or a
|
|
||||||
portion of it, either verbatim or with modifications and/or translated
|
|
||||||
straightforwardly into another language. (Hereinafter, translation is
|
|
||||||
included without limitation in the term "modification".)
|
|
||||||
|
|
||||||
"Source code" for a work means the preferred form of the work for
|
|
||||||
making modifications to it. For a library, complete source code means
|
|
||||||
all the source code for all modules it contains, plus any associated
|
|
||||||
interface definition files, plus the scripts used to control compilation
|
|
||||||
and installation of the library.
|
|
||||||
|
|
||||||
Activities other than copying, distribution and modification are not
|
|
||||||
covered by this License; they are outside its scope. The act of
|
|
||||||
running a program using the Library is not restricted, and output from
|
|
||||||
such a program is covered only if its contents constitute a work based
|
|
||||||
on the Library (independent of the use of the Library in a tool for
|
|
||||||
writing it). Whether that is true depends on what the Library does
|
|
||||||
and what the program that uses the Library does.
|
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Library's
|
|
||||||
complete source code as you receive it, in any medium, provided that
|
|
||||||
you conspicuously and appropriately publish on each copy an
|
|
||||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
|
||||||
all the notices that refer to this License and to the absence of any
|
|
||||||
warranty; and distribute a copy of this License along with the
|
|
||||||
Library.
|
|
||||||
|
|
||||||
You may charge a fee for the physical act of transferring a copy,
|
|
||||||
and you may at your option offer warranty protection in exchange for a
|
|
||||||
fee.
|
|
||||||
|
|
||||||
2. You may modify your copy or copies of the Library or any portion
|
|
||||||
of it, thus forming a work based on the Library, and copy and
|
|
||||||
distribute such modifications or work under the terms of Section 1
|
|
||||||
above, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) The modified work must itself be a software library.
|
|
||||||
|
|
||||||
b) You must cause the files modified to carry prominent notices
|
|
||||||
stating that you changed the files and the date of any change.
|
|
||||||
|
|
||||||
c) You must cause the whole of the work to be licensed at no
|
|
||||||
charge to all third parties under the terms of this License.
|
|
||||||
|
|
||||||
d) If a facility in the modified Library refers to a function or a
|
|
||||||
table of data to be supplied by an application program that uses
|
|
||||||
the facility, other than as an argument passed when the facility
|
|
||||||
is invoked, then you must make a good faith effort to ensure that,
|
|
||||||
in the event an application does not supply such function or
|
|
||||||
table, the facility still operates, and performs whatever part of
|
|
||||||
its purpose remains meaningful.
|
|
||||||
|
|
||||||
(For example, a function in a library to compute square roots has
|
|
||||||
a purpose that is entirely well-defined independent of the
|
|
||||||
application. Therefore, Subsection 2d requires that any
|
|
||||||
application-supplied function or table used by this function must
|
|
||||||
be optional: if the application does not supply it, the square
|
|
||||||
root function must still compute square roots.)
|
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
|
||||||
identifiable sections of that work are not derived from the Library,
|
|
||||||
and can be reasonably considered independent and separate works in
|
|
||||||
themselves, then this License, and its terms, do not apply to those
|
|
||||||
sections when you distribute them as separate works. But when you
|
|
||||||
distribute the same sections as part of a whole which is a work based
|
|
||||||
on the Library, the distribution of the whole must be on the terms of
|
|
||||||
this License, whose permissions for other licensees extend to the
|
|
||||||
entire whole, and thus to each and every part regardless of who wrote
|
|
||||||
it.
|
|
||||||
|
|
||||||
Thus, it is not the intent of this section to claim rights or contest
|
|
||||||
your rights to work written entirely by you; rather, the intent is to
|
|
||||||
exercise the right to control the distribution of derivative or
|
|
||||||
collective works based on the Library.
|
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Library
|
|
||||||
with the Library (or with a work based on the Library) on a volume of
|
|
||||||
a storage or distribution medium does not bring the other work under
|
|
||||||
the scope of this License.
|
|
||||||
|
|
||||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
|
||||||
License instead of this License to a given copy of the Library. To do
|
|
||||||
this, you must alter all the notices that refer to this License, so
|
|
||||||
that they refer to the ordinary GNU General Public License, version 2,
|
|
||||||
instead of to this License. (If a newer version than version 2 of the
|
|
||||||
ordinary GNU General Public License has appeared, then you can specify
|
|
||||||
that version instead if you wish.) Do not make any other change in
|
|
||||||
these notices.
|
|
||||||
|
|
||||||
Once this change is made in a given copy, it is irreversible for
|
|
||||||
that copy, so the ordinary GNU General Public License applies to all
|
|
||||||
subsequent copies and derivative works made from that copy.
|
|
||||||
|
|
||||||
This option is useful when you wish to copy part of the code of
|
|
||||||
the Library into a program that is not a library.
|
|
||||||
|
|
||||||
4. You may copy and distribute the Library (or a portion or
|
|
||||||
derivative of it, under Section 2) in object code or executable form
|
|
||||||
under the terms of Sections 1 and 2 above provided that you accompany
|
|
||||||
it with the complete corresponding machine-readable source code, which
|
|
||||||
must be distributed under the terms of Sections 1 and 2 above on a
|
|
||||||
medium customarily used for software interchange.
|
|
||||||
|
|
||||||
If distribution of object code is made by offering access to copy
|
|
||||||
from a designated place, then offering equivalent access to copy the
|
|
||||||
source code from the same place satisfies the requirement to
|
|
||||||
distribute the source code, even though third parties are not
|
|
||||||
compelled to copy the source along with the object code.
|
|
||||||
|
|
||||||
5. A program that contains no derivative of any portion of the
|
|
||||||
Library, but is designed to work with the Library by being compiled or
|
|
||||||
linked with it, is called a "work that uses the Library". Such a
|
|
||||||
work, in isolation, is not a derivative work of the Library, and
|
|
||||||
therefore falls outside the scope of this License.
|
|
||||||
|
|
||||||
However, linking a "work that uses the Library" with the Library
|
|
||||||
creates an executable that is a derivative of the Library (because it
|
|
||||||
contains portions of the Library), rather than a "work that uses the
|
|
||||||
library". The executable is therefore covered by this License.
|
|
||||||
Section 6 states terms for distribution of such executables.
|
|
||||||
|
|
||||||
When a "work that uses the Library" uses material from a header file
|
|
||||||
that is part of the Library, the object code for the work may be a
|
|
||||||
derivative work of the Library even though the source code is not.
|
|
||||||
Whether this is true is especially significant if the work can be
|
|
||||||
linked without the Library, or if the work is itself a library. The
|
|
||||||
threshold for this to be true is not precisely defined by law.
|
|
||||||
|
|
||||||
If such an object file uses only numerical parameters, data
|
|
||||||
structure layouts and accessors, and small macros and small inline
|
|
||||||
functions (ten lines or less in length), then the use of the object
|
|
||||||
file is unrestricted, regardless of whether it is legally a derivative
|
|
||||||
work. (Executables containing this object code plus portions of the
|
|
||||||
Library will still fall under Section 6.)
|
|
||||||
|
|
||||||
Otherwise, if the work is a derivative of the Library, you may
|
|
||||||
distribute the object code for the work under the terms of Section 6.
|
|
||||||
Any executables containing that work also fall under Section 6,
|
|
||||||
whether or not they are linked directly with the Library itself.
|
|
||||||
|
|
||||||
6. As an exception to the Sections above, you may also combine or
|
|
||||||
link a "work that uses the Library" with the Library to produce a
|
|
||||||
work containing portions of the Library, and distribute that work
|
|
||||||
under terms of your choice, provided that the terms permit
|
|
||||||
modification of the work for the customer's own use and reverse
|
|
||||||
engineering for debugging such modifications.
|
|
||||||
|
|
||||||
You must give prominent notice with each copy of the work that the
|
|
||||||
Library is used in it and that the Library and its use are covered by
|
|
||||||
this License. You must supply a copy of this License. If the work
|
|
||||||
during execution displays copyright notices, you must include the
|
|
||||||
copyright notice for the Library among them, as well as a reference
|
|
||||||
directing the user to the copy of this License. Also, you must do one
|
|
||||||
of these things:
|
|
||||||
|
|
||||||
a) Accompany the work with the complete corresponding
|
|
||||||
machine-readable source code for the Library including whatever
|
|
||||||
changes were used in the work (which must be distributed under
|
|
||||||
Sections 1 and 2 above); and, if the work is an executable linked
|
|
||||||
with the Library, with the complete machine-readable "work that
|
|
||||||
uses the Library", as object code and/or source code, so that the
|
|
||||||
user can modify the Library and then relink to produce a modified
|
|
||||||
executable containing the modified Library. (It is understood
|
|
||||||
that the user who changes the contents of definitions files in the
|
|
||||||
Library will not necessarily be able to recompile the application
|
|
||||||
to use the modified definitions.)
|
|
||||||
|
|
||||||
b) Use a suitable shared library mechanism for linking with the
|
|
||||||
Library. A suitable mechanism is one that (1) uses at run time a
|
|
||||||
copy of the library already present on the user's computer system,
|
|
||||||
rather than copying library functions into the executable, and (2)
|
|
||||||
will operate properly with a modified version of the library, if
|
|
||||||
the user installs one, as long as the modified version is
|
|
||||||
interface-compatible with the version that the work was made with.
|
|
||||||
|
|
||||||
c) Accompany the work with a written offer, valid for at
|
|
||||||
least three years, to give the same user the materials
|
|
||||||
specified in Subsection 6a, above, for a charge no more
|
|
||||||
than the cost of performing this distribution.
|
|
||||||
|
|
||||||
d) If distribution of the work is made by offering access to copy
|
|
||||||
from a designated place, offer equivalent access to copy the above
|
|
||||||
specified materials from the same place.
|
|
||||||
|
|
||||||
e) Verify that the user has already received a copy of these
|
|
||||||
materials or that you have already sent this user a copy.
|
|
||||||
|
|
||||||
For an executable, the required form of the "work that uses the
|
|
||||||
Library" must include any data and utility programs needed for
|
|
||||||
reproducing the executable from it. However, as a special exception,
|
|
||||||
the materials to be distributed need not include anything that is
|
|
||||||
normally distributed (in either source or binary form) with the major
|
|
||||||
components (compiler, kernel, and so on) of the operating system on
|
|
||||||
which the executable runs, unless that component itself accompanies
|
|
||||||
the executable.
|
|
||||||
|
|
||||||
It may happen that this requirement contradicts the license
|
|
||||||
restrictions of other proprietary libraries that do not normally
|
|
||||||
accompany the operating system. Such a contradiction means you cannot
|
|
||||||
use both them and the Library together in an executable that you
|
|
||||||
distribute.
|
|
||||||
|
|
||||||
7. You may place library facilities that are a work based on the
|
|
||||||
Library side-by-side in a single library together with other library
|
|
||||||
facilities not covered by this License, and distribute such a combined
|
|
||||||
library, provided that the separate distribution of the work based on
|
|
||||||
the Library and of the other library facilities is otherwise
|
|
||||||
permitted, and provided that you do these two things:
|
|
||||||
|
|
||||||
a) Accompany the combined library with a copy of the same work
|
|
||||||
based on the Library, uncombined with any other library
|
|
||||||
facilities. This must be distributed under the terms of the
|
|
||||||
Sections above.
|
|
||||||
|
|
||||||
b) Give prominent notice with the combined library of the fact
|
|
||||||
that part of it is a work based on the Library, and explaining
|
|
||||||
where to find the accompanying uncombined form of the same work.
|
|
||||||
|
|
||||||
8. You may not copy, modify, sublicense, link with, or distribute
|
|
||||||
the Library except as expressly provided under this License. Any
|
|
||||||
attempt otherwise to copy, modify, sublicense, link with, or
|
|
||||||
distribute the Library is void, and will automatically terminate your
|
|
||||||
rights under this License. However, parties who have received copies,
|
|
||||||
or rights, from you under this License will not have their licenses
|
|
||||||
terminated so long as such parties remain in full compliance.
|
|
||||||
|
|
||||||
9. You are not required to accept this License, since you have not
|
|
||||||
signed it. However, nothing else grants you permission to modify or
|
|
||||||
distribute the Library or its derivative works. These actions are
|
|
||||||
prohibited by law if you do not accept this License. Therefore, by
|
|
||||||
modifying or distributing the Library (or any work based on the
|
|
||||||
Library), you indicate your acceptance of this License to do so, and
|
|
||||||
all its terms and conditions for copying, distributing or modifying
|
|
||||||
the Library or works based on it.
|
|
||||||
|
|
||||||
10. Each time you redistribute the Library (or any work based on the
|
|
||||||
Library), the recipient automatically receives a license from the
|
|
||||||
original licensor to copy, distribute, link with or modify the Library
|
|
||||||
subject to these terms and conditions. You may not impose any further
|
|
||||||
restrictions on the recipients' exercise of the rights granted herein.
|
|
||||||
You are not responsible for enforcing compliance by third parties with
|
|
||||||
this License.
|
|
||||||
|
|
||||||
11. If, as a consequence of a court judgment or allegation of patent
|
|
||||||
infringement or for any other reason (not limited to patent issues),
|
|
||||||
conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot
|
|
||||||
distribute so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you
|
|
||||||
may not distribute the Library at all. For example, if a patent
|
|
||||||
license would not permit royalty-free redistribution of the Library by
|
|
||||||
all those who receive copies directly or indirectly through you, then
|
|
||||||
the only way you could satisfy both it and this License would be to
|
|
||||||
refrain entirely from distribution of the Library.
|
|
||||||
|
|
||||||
If any portion of this section is held invalid or unenforceable under any
|
|
||||||
particular circumstance, the balance of the section is intended to apply,
|
|
||||||
and the section as a whole is intended to apply in other circumstances.
|
|
||||||
|
|
||||||
It is not the purpose of this section to induce you to infringe any
|
|
||||||
patents or other property right claims or to contest validity of any
|
|
||||||
such claims; this section has the sole purpose of protecting the
|
|
||||||
integrity of the free software distribution system which is
|
|
||||||
implemented by public license practices. Many people have made
|
|
||||||
generous contributions to the wide range of software distributed
|
|
||||||
through that system in reliance on consistent application of that
|
|
||||||
system; it is up to the author/donor to decide if he or she is willing
|
|
||||||
to distribute software through any other system and a licensee cannot
|
|
||||||
impose that choice.
|
|
||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
|
||||||
be a consequence of the rest of this License.
|
|
||||||
|
|
||||||
12. If the distribution and/or use of the Library is restricted in
|
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
|
||||||
original copyright holder who places the Library under this License may add
|
|
||||||
an explicit geographical distribution limitation excluding those countries,
|
|
||||||
so that distribution is permitted only in or among countries not thus
|
|
||||||
excluded. In such case, this License incorporates the limitation as if
|
|
||||||
written in the body of this License.
|
|
||||||
|
|
||||||
13. The Free Software Foundation may publish revised and/or new
|
|
||||||
versions of the Lesser General Public License from time to time.
|
|
||||||
Such new versions will be similar in spirit to the present version,
|
|
||||||
but may differ in detail to address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Library
|
|
||||||
specifies a version number of this License which applies to it and
|
|
||||||
"any later version", you have the option of following the terms and
|
|
||||||
conditions either of that version or of any later version published by
|
|
||||||
the Free Software Foundation. If the Library does not specify a
|
|
||||||
license version number, you may choose any version ever published by
|
|
||||||
the Free Software Foundation.
|
|
||||||
|
|
||||||
14. If you wish to incorporate parts of the Library into other free
|
|
||||||
programs whose distribution conditions are incompatible with these,
|
|
||||||
write to the author to ask for permission. For software which is
|
|
||||||
copyrighted by the Free Software Foundation, write to the Free
|
|
||||||
Software Foundation; we sometimes make exceptions for this. Our
|
|
||||||
decision will be guided by the two goals of preserving the free status
|
|
||||||
of all derivatives of our free software and of promoting the sharing
|
|
||||||
and reuse of software generally.
|
|
||||||
|
|
||||||
NO WARRANTY
|
|
||||||
|
|
||||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
|
||||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
|
||||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
|
||||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
|
||||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
|
||||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
|
||||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
|
||||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
|
||||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
|
||||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
|
||||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
|
||||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
|
||||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
|
||||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
|
||||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
|
||||||
DAMAGES.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Libraries
|
|
||||||
|
|
||||||
If you develop a new library, and you want it to be of the greatest
|
|
||||||
possible use to the public, we recommend making it free software that
|
|
||||||
everyone can redistribute and change. You can do so by permitting
|
|
||||||
redistribution under these terms (or, alternatively, under the terms of the
|
|
||||||
ordinary General Public License).
|
|
||||||
|
|
||||||
To apply these terms, attach the following notices to the library. It is
|
|
||||||
safest to attach them to the start of each source file to most effectively
|
|
||||||
convey the exclusion of warranty; and each file should have at least the
|
|
||||||
"copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the library's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library 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
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or your
|
|
||||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
|
||||||
necessary. Here is a sample; alter the names:
|
|
||||||
|
|
||||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
|
||||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
|
||||||
|
|
||||||
<signature of Ty Coon>, 1 April 1990
|
|
||||||
Ty Coon, President of Vice
|
|
||||||
|
|
||||||
That's all there is to it!
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
What's New in PHP OpenID 1.1.0
|
|
||||||
==============================
|
|
||||||
|
|
||||||
Version 1.1 of the PHP OpenID library implements recent changes to the
|
|
||||||
OpenID specification as well as making API changes that should make
|
|
||||||
integration with applications easier. The consumer and server
|
|
||||||
examples have been updated to use the new APIs. As usual, if you have
|
|
||||||
any questions or would like to provide any kind of feedback at all,
|
|
||||||
please subscribe to our development discussion list (see README) and
|
|
||||||
let us know!
|
|
||||||
|
|
||||||
Yadis Support
|
|
||||||
-------------
|
|
||||||
|
|
||||||
One of the major changes to OpenID since the last release has been the
|
|
||||||
approval of Yadis discovery as the preferred way to specify the OpenID
|
|
||||||
metadata for an identity URL instead of using <link> tags in
|
|
||||||
HTML. This library does Yadis discovery, and if that fails, it falls
|
|
||||||
back to old-style discovery.
|
|
||||||
|
|
||||||
Some advantages of Yadis support are:
|
|
||||||
|
|
||||||
* Support for fallback if your primary OpenID provider is not
|
|
||||||
available
|
|
||||||
|
|
||||||
* Support for load-balancing between OpenID servers
|
|
||||||
|
|
||||||
* Easy interoperability for different identity services
|
|
||||||
|
|
||||||
For more information about Yadis, see http://yadis.org/ or
|
|
||||||
http://www.openidenabled.com/yadis/.
|
|
||||||
|
|
||||||
Extension Support
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
OpenID also has formalized support for extensions. Extensions are a
|
|
||||||
mechanism for transferring information from the consumer to the server
|
|
||||||
and from the server to the consumer in the process of performing
|
|
||||||
OpenID authentication. Extensions are implemented as additional
|
|
||||||
namespaced query arguments that go along with standard OpenID requests
|
|
||||||
and responses. This library provides a simple API for adding extension
|
|
||||||
arguments to requests and extracting extension responses from replies.
|
|
||||||
|
|
||||||
Consumer API
|
|
||||||
------------
|
|
||||||
|
|
||||||
The consumer API has been changed for more natural use as well as to
|
|
||||||
support extension arguments.
|
|
||||||
|
|
||||||
* Auth_OpenID_Consumer($store, [$fetcher], [$immediate]) is now
|
|
||||||
Auth_OpenID_Consumer($store, [$session]). The session object is an
|
|
||||||
instance of Services_Yadis_PHPSession or a subclass thereof. The
|
|
||||||
default implementation wraps PHP's session machinery.
|
|
||||||
|
|
||||||
* Auth_OpenID_Consumer::beginAuth($user_url) is now
|
|
||||||
Auth_OpenID_Consumer::begin($user_url) and either returns an
|
|
||||||
Auth_OpenID_AuthRequest object or returns null. There is no more
|
|
||||||
tuple unpacking or status codes.
|
|
||||||
|
|
||||||
* Auth_OpenID_Consumer::constructRedirect($auth_req, $return_to,
|
|
||||||
$trust_root) is now
|
|
||||||
Auth_OpenID_AuthRequest::redirectURL($trust_root, $return_to,
|
|
||||||
[$immediate]).
|
|
||||||
|
|
||||||
* Auth_OpenID_Consumer::completeAuth($token, $query) is now
|
|
||||||
Auth_OpenID_Consumer::complete($query). It no longer returns a
|
|
||||||
tuple. Instead it returns an object that has a status code and
|
|
||||||
additional information about the response. See the API
|
|
||||||
documentation and examples for more information.
|
|
||||||
|
|
||||||
Server API
|
|
||||||
----------
|
|
||||||
|
|
||||||
The server API has been changed for greater extensibility. Instead of
|
|
||||||
taking an "is_authorized" callback, processing happens in several
|
|
||||||
stages, allowing you to insert extension data into the response before
|
|
||||||
it is signed and returned. See the documentation for the Server.php
|
|
||||||
file. Particularly, see the server example code in the examples/
|
|
||||||
directory.
|
|
||||||
|
|
||||||
Upgrading
|
|
||||||
---------
|
|
||||||
|
|
||||||
The server changed the way it indexes associations in the store, so if
|
|
||||||
you're upgrading a server installation, we recommend you clear the old
|
|
||||||
records from your store when you do so. As a consequence, consumers
|
|
||||||
will re-establish associations with your server a little sooner than
|
|
||||||
they would have otherwise.
|
|
||||||
|
|
@ -1,122 +0,0 @@
|
||||||
|
|
||||||
PHP OpenID
|
|
||||||
----------
|
|
||||||
|
|
||||||
This is the PHP OpenID library by JanRain, Inc. You can visit our
|
|
||||||
website for more information about this package and other OpenID
|
|
||||||
implementations and tools:
|
|
||||||
|
|
||||||
http://www.openidenabled.com/
|
|
||||||
|
|
||||||
GETTING STARTED
|
|
||||||
===============
|
|
||||||
|
|
||||||
First, run the 'examples/detect.php' script either from the command
|
|
||||||
line or via the web. It will generate a report of any system
|
|
||||||
configuration changes necessary to run the library.
|
|
||||||
|
|
||||||
INSTALLATION
|
|
||||||
============
|
|
||||||
|
|
||||||
You will need PHP 4.3.0 or greater to use this library. We have
|
|
||||||
tested the library Linux on PHP 4.3.0, 4.4.1, 5.0.5, and 5.1.1. We
|
|
||||||
have tested the library on Windows XP on PHP 4.4.4.
|
|
||||||
|
|
||||||
Follow these steps:
|
|
||||||
|
|
||||||
1. Install dependencies.
|
|
||||||
|
|
||||||
- Enable either the GMP extension or Bcmath extension. (GMP is
|
|
||||||
STRONGLY recommended because it's MUCH faster!) This is
|
|
||||||
required.
|
|
||||||
|
|
||||||
- Enable the CURL extension.
|
|
||||||
|
|
||||||
- If you plan to use SQLite, PostgreSQL, or MySQL to store OpenID
|
|
||||||
data, you'll need PEAR DB. You can install this by running this
|
|
||||||
as root:
|
|
||||||
|
|
||||||
# pear install DB
|
|
||||||
|
|
||||||
You'll also need to install and enable the appropriate PHP
|
|
||||||
database extension. Alternatively, you can store OpenID data on
|
|
||||||
the filesystem instead of using a relational database. Nothing
|
|
||||||
special is required for using the filesystem method.
|
|
||||||
|
|
||||||
- Install either the DOM or domxml PHP XML processing extension,
|
|
||||||
but not both (they are incompatible).
|
|
||||||
|
|
||||||
2. Use the PEAR installer to install the package. To use the PEAR
|
|
||||||
installer, run this command from the package directory:
|
|
||||||
|
|
||||||
# pear install package.xml
|
|
||||||
|
|
||||||
If your PEAR version is sufficiently new, you can run this instead:
|
|
||||||
|
|
||||||
# pear install package2.xml
|
|
||||||
|
|
||||||
If the PEAR installer isn't available, you can copy the Auth/ and
|
|
||||||
Services/ directories into your PHP include path.
|
|
||||||
|
|
||||||
TESTING YOUR SETUP
|
|
||||||
==================
|
|
||||||
|
|
||||||
You can use the example code to test your setup. To run the example
|
|
||||||
consumer or server, follow the instructions in the examples/README
|
|
||||||
file.
|
|
||||||
|
|
||||||
USING THE API
|
|
||||||
=============
|
|
||||||
|
|
||||||
The best way to get started using the API is to take a look at the
|
|
||||||
example consumer and server in the examples/ directory. See the
|
|
||||||
examples/README file for more details.
|
|
||||||
|
|
||||||
TROUBLESHOOTING
|
|
||||||
===============
|
|
||||||
|
|
||||||
On some systems, PHP basedir restrictions prevent web servers from
|
|
||||||
opening a source of randomness, such as /dev/urandom. If your PHP
|
|
||||||
OpenID library has trouble getting a satisfactory source of
|
|
||||||
randomness, check your Apache and PHP configurations to be sure that
|
|
||||||
the randomness source is in the list of allowed paths for the
|
|
||||||
"open_basedir" option.
|
|
||||||
|
|
||||||
GETTING HELP
|
|
||||||
============
|
|
||||||
|
|
||||||
If you have any questions, recommendations, or patches, please tell
|
|
||||||
us! Subscribe to our OpenID development discussion list at
|
|
||||||
|
|
||||||
http://lists.openidenabled.com/mailman/listinfo/dev
|
|
||||||
|
|
||||||
DOCUMENTATION
|
|
||||||
=============
|
|
||||||
|
|
||||||
You can view the HTML library documentation in the doc/ directory.
|
|
||||||
You can also find it on the web at
|
|
||||||
|
|
||||||
http://www.openidenabled.com/resources/docs/openid/php/
|
|
||||||
|
|
||||||
This package's documentation is in PhpDoc format. To generate the
|
|
||||||
documentation, install phpdoc and run the admin/makedoc.sh script.
|
|
||||||
Phpdoc lives at:
|
|
||||||
|
|
||||||
http://www.phpdoc.org/
|
|
||||||
|
|
||||||
CONTRIBUTING
|
|
||||||
============
|
|
||||||
|
|
||||||
If you have a bugfix or feature you'd like to contribute, don't
|
|
||||||
hesitate to send it to us. Post your patch to the development list at
|
|
||||||
|
|
||||||
http://lists.openidenabled.com/mailman/listinfo/dev
|
|
||||||
|
|
||||||
To run the test suite included with this package, install PHPUnit 1.x
|
|
||||||
and run
|
|
||||||
|
|
||||||
php admin/texttest.php
|
|
||||||
|
|
||||||
PHPUnit 1.x can be found at
|
|
||||||
|
|
||||||
http://pear.phpunit.de/get/
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
Development Environment Setup
|
|
||||||
=============================
|
|
||||||
|
|
||||||
Janrain note: You'll need to run these commands to generate
|
|
||||||
documentation for this project:
|
|
||||||
|
|
||||||
apt-get install php4-pear
|
|
||||||
pear install PhpDocumentor
|
|
||||||
|
|
@ -1,92 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This module contains the HTTP fetcher interface
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Services_Yadis_HTTPResponse {
|
|
||||||
function Services_Yadis_HTTPResponse($final_url = null, $status = null,
|
|
||||||
$headers = null, $body = null)
|
|
||||||
{
|
|
||||||
$this->final_url = $final_url;
|
|
||||||
$this->status = $status;
|
|
||||||
$this->headers = $headers;
|
|
||||||
$this->body = $body;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is the interface for HTTP fetchers the Yadis library
|
|
||||||
* uses. This interface is only important if you need to write a new
|
|
||||||
* fetcher for some reason.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @package Yadis
|
|
||||||
*/
|
|
||||||
class Services_Yadis_HTTPFetcher {
|
|
||||||
|
|
||||||
var $timeout = 20; // timeout in seconds.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return whether a URL should be allowed. Override this method to
|
|
||||||
* conform to your local policy.
|
|
||||||
*
|
|
||||||
* By default, will attempt to fetch any http or https URL.
|
|
||||||
*/
|
|
||||||
function allowedURL($url)
|
|
||||||
{
|
|
||||||
return $this->URLHasAllowedScheme($url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is this an http or https URL?
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function URLHasAllowedScheme($url)
|
|
||||||
{
|
|
||||||
return (bool)preg_match('/^https?:\/\//i', $url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _findRedirect($headers)
|
|
||||||
{
|
|
||||||
foreach ($headers as $line) {
|
|
||||||
if (strpos($line, "Location: ") === 0) {
|
|
||||||
$parts = explode(" ", $line, 2);
|
|
||||||
return $parts[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches the specified URL using optional extra headers and
|
|
||||||
* returns the server's response.
|
|
||||||
*
|
|
||||||
* @param string $url The URL to be fetched.
|
|
||||||
* @param array $extra_headers An array of header strings
|
|
||||||
* (e.g. "Accept: text/html").
|
|
||||||
* @return mixed $result An array of ($code, $url, $headers,
|
|
||||||
* $body) if the URL could be fetched; null if the URL does not
|
|
||||||
* pass the URLHasAllowedScheme check or if the server's response
|
|
||||||
* is malformed.
|
|
||||||
*/
|
|
||||||
function get($url, $headers)
|
|
||||||
{
|
|
||||||
trigger_error("not implemented", E_USER_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,496 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Yadis service manager to be used during yadis-driven authentication
|
|
||||||
* attempts.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The base session class used by the Services_Yadis_Manager. This
|
|
||||||
* class wraps the default PHP session machinery and should be
|
|
||||||
* subclassed if your application doesn't use PHP sessioning.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
*/
|
|
||||||
class Services_Yadis_PHPSession {
|
|
||||||
/**
|
|
||||||
* Set a session key/value pair.
|
|
||||||
*
|
|
||||||
* @param string $name The name of the session key to add.
|
|
||||||
* @param string $value The value to add to the session.
|
|
||||||
*/
|
|
||||||
function set($name, $value)
|
|
||||||
{
|
|
||||||
$_SESSION[$name] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a key's value from the session.
|
|
||||||
*
|
|
||||||
* @param string $name The name of the key to retrieve.
|
|
||||||
* @param string $default The optional value to return if the key
|
|
||||||
* is not found in the session.
|
|
||||||
* @return string $result The key's value in the session or
|
|
||||||
* $default if it isn't found.
|
|
||||||
*/
|
|
||||||
function get($name, $default=null)
|
|
||||||
{
|
|
||||||
if (array_key_exists($name, $_SESSION)) {
|
|
||||||
return $_SESSION[$name];
|
|
||||||
} else {
|
|
||||||
return $default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a key/value pair from the session.
|
|
||||||
*
|
|
||||||
* @param string $name The name of the key to remove.
|
|
||||||
*/
|
|
||||||
function del($name)
|
|
||||||
{
|
|
||||||
unset($_SESSION[$name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the contents of the session in array form.
|
|
||||||
*/
|
|
||||||
function contents()
|
|
||||||
{
|
|
||||||
return $_SESSION;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A session helper class designed to translate between arrays and
|
|
||||||
* objects. Note that the class used must have a constructor that
|
|
||||||
* takes no parameters. This is not a general solution, but it works
|
|
||||||
* for dumb objects that just need to have attributes set. The idea
|
|
||||||
* is that you'll subclass this and override $this->check($data) ->
|
|
||||||
* bool to implement your own session data validation.
|
|
||||||
*/
|
|
||||||
class Services_Yadis_SessionLoader {
|
|
||||||
/**
|
|
||||||
* Override this.
|
|
||||||
*/
|
|
||||||
function check($data)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a session data value (an array), this creates an object
|
|
||||||
* (returned by $this->newObject()) whose attributes and values
|
|
||||||
* are those in $data. Returns null if $data lacks keys found in
|
|
||||||
* $this->requiredKeys(). Returns null if $this->check($data)
|
|
||||||
* evaluates to false. Returns null if $this->newObject()
|
|
||||||
* evaluates to false.
|
|
||||||
*/
|
|
||||||
function fromSession($data)
|
|
||||||
{
|
|
||||||
if (!$data) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$required = $this->requiredKeys();
|
|
||||||
|
|
||||||
foreach ($required as $k) {
|
|
||||||
if (!array_key_exists($k, $data)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->check($data)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = array_merge($data, $this->prepareForLoad($data));
|
|
||||||
$obj = $this->newObject($data);
|
|
||||||
|
|
||||||
if (!$obj) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($required as $k) {
|
|
||||||
$obj->$k = $data[$k];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepares the data array by making any necessary changes.
|
|
||||||
* Returns an array whose keys and values will be used to update
|
|
||||||
* the original data array before calling $this->newObject($data).
|
|
||||||
*/
|
|
||||||
function prepareForLoad($data)
|
|
||||||
{
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new instance of this loader's class, using the
|
|
||||||
* session data to construct it if necessary. The object need
|
|
||||||
* only be created; $this->fromSession() will take care of setting
|
|
||||||
* the object's attributes.
|
|
||||||
*/
|
|
||||||
function newObject($data)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an array of keys and values built from the attributes
|
|
||||||
* of $obj. If $this->prepareForSave($obj) returns an array, its keys
|
|
||||||
* and values are used to update the $data array of attributes
|
|
||||||
* from $obj.
|
|
||||||
*/
|
|
||||||
function toSession($obj)
|
|
||||||
{
|
|
||||||
$data = array();
|
|
||||||
foreach ($obj as $k => $v) {
|
|
||||||
$data[$k] = $v;
|
|
||||||
}
|
|
||||||
|
|
||||||
$extra = $this->prepareForSave($obj);
|
|
||||||
|
|
||||||
if ($extra && is_array($extra)) {
|
|
||||||
foreach ($extra as $k => $v) {
|
|
||||||
$data[$k] = $v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override this.
|
|
||||||
*/
|
|
||||||
function prepareForSave($obj)
|
|
||||||
{
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Auth_OpenID_ServiceEndpointLoader extends Services_Yadis_SessionLoader {
|
|
||||||
function newObject($data)
|
|
||||||
{
|
|
||||||
return new Auth_OpenID_ServiceEndpoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
function requiredKeys()
|
|
||||||
{
|
|
||||||
$obj = new Auth_OpenID_ServiceEndpoint();
|
|
||||||
$data = array();
|
|
||||||
foreach ($obj as $k => $v) {
|
|
||||||
$data[] = $k;
|
|
||||||
}
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
function check($data)
|
|
||||||
{
|
|
||||||
return is_array($data['type_uris']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Services_Yadis_ManagerLoader extends Services_Yadis_SessionLoader {
|
|
||||||
function requiredKeys()
|
|
||||||
{
|
|
||||||
return array('starting_url',
|
|
||||||
'yadis_url',
|
|
||||||
'services',
|
|
||||||
'session_key',
|
|
||||||
'_current',
|
|
||||||
'stale');
|
|
||||||
}
|
|
||||||
|
|
||||||
function newObject($data)
|
|
||||||
{
|
|
||||||
return new Services_Yadis_Manager($data['starting_url'],
|
|
||||||
$data['yadis_url'],
|
|
||||||
$data['services'],
|
|
||||||
$data['session_key']);
|
|
||||||
}
|
|
||||||
|
|
||||||
function check($data)
|
|
||||||
{
|
|
||||||
return is_array($data['services']);
|
|
||||||
}
|
|
||||||
|
|
||||||
function prepareForLoad($data)
|
|
||||||
{
|
|
||||||
$loader = new Auth_OpenID_ServiceEndpointLoader();
|
|
||||||
$services = array();
|
|
||||||
foreach ($data['services'] as $s) {
|
|
||||||
$services[] = $loader->fromSession($s);
|
|
||||||
}
|
|
||||||
return array('services' => $services);
|
|
||||||
}
|
|
||||||
|
|
||||||
function prepareForSave($obj)
|
|
||||||
{
|
|
||||||
$loader = new Auth_OpenID_ServiceEndpointLoader();
|
|
||||||
$services = array();
|
|
||||||
foreach ($obj->services as $s) {
|
|
||||||
$services[] = $loader->toSession($s);
|
|
||||||
}
|
|
||||||
return array('services' => $services);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Yadis service manager which stores state in a session and
|
|
||||||
* iterates over <Service> elements in a Yadis XRDS document and lets
|
|
||||||
* a caller attempt to use each one. This is used by the Yadis
|
|
||||||
* library internally.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
*/
|
|
||||||
class Services_Yadis_Manager {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Intialize a new yadis service manager.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function Services_Yadis_Manager($starting_url, $yadis_url,
|
|
||||||
$services, $session_key)
|
|
||||||
{
|
|
||||||
// The URL that was used to initiate the Yadis protocol
|
|
||||||
$this->starting_url = $starting_url;
|
|
||||||
|
|
||||||
// The URL after following redirects (the identifier)
|
|
||||||
$this->yadis_url = $yadis_url;
|
|
||||||
|
|
||||||
// List of service elements
|
|
||||||
$this->services = $services;
|
|
||||||
|
|
||||||
$this->session_key = $session_key;
|
|
||||||
|
|
||||||
// Reference to the current service object
|
|
||||||
$this->_current = null;
|
|
||||||
|
|
||||||
// Stale flag for cleanup if PHP lib has trouble.
|
|
||||||
$this->stale = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function length()
|
|
||||||
{
|
|
||||||
// How many untried services remain?
|
|
||||||
return count($this->services);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the next service
|
|
||||||
*
|
|
||||||
* $this->current() will continue to return that service until the
|
|
||||||
* next call to this method.
|
|
||||||
*/
|
|
||||||
function nextService()
|
|
||||||
{
|
|
||||||
|
|
||||||
if ($this->services) {
|
|
||||||
$this->_current = array_shift($this->services);
|
|
||||||
} else {
|
|
||||||
$this->_current = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->_current;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function current()
|
|
||||||
{
|
|
||||||
// Return the current service.
|
|
||||||
// Returns None if there are no services left.
|
|
||||||
return $this->_current;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function forURL($url)
|
|
||||||
{
|
|
||||||
return in_array($url, array($this->starting_url, $this->yadis_url));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function started()
|
|
||||||
{
|
|
||||||
// Has the first service been returned?
|
|
||||||
return $this->_current !== null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* State management for discovery.
|
|
||||||
*
|
|
||||||
* High-level usage pattern is to call .getNextService(discover) in
|
|
||||||
* order to find the next available service for this user for this
|
|
||||||
* session. Once a request completes, call .finish() to clean up the
|
|
||||||
* session state.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
*/
|
|
||||||
class Services_Yadis_Discovery {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
var $DEFAULT_SUFFIX = 'auth';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
var $PREFIX = '_yadis_services_';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize a discovery object.
|
|
||||||
*
|
|
||||||
* @param Services_Yadis_PHPSession $session An object which
|
|
||||||
* implements the Services_Yadis_PHPSession API.
|
|
||||||
* @param string $url The URL on which to attempt discovery.
|
|
||||||
* @param string $session_key_suffix The optional session key
|
|
||||||
* suffix override.
|
|
||||||
*/
|
|
||||||
function Services_Yadis_Discovery(&$session, $url,
|
|
||||||
$session_key_suffix = null)
|
|
||||||
{
|
|
||||||
/// Initialize a discovery object
|
|
||||||
$this->session =& $session;
|
|
||||||
$this->url = $url;
|
|
||||||
if ($session_key_suffix === null) {
|
|
||||||
$session_key_suffix = $this->DEFAULT_SUFFIX;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->session_key_suffix = $session_key_suffix;
|
|
||||||
$this->session_key = $this->PREFIX . $this->session_key_suffix;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the next authentication service for the pair of
|
|
||||||
* user_input and session. This function handles fallback.
|
|
||||||
*/
|
|
||||||
function getNextService($discover_cb, &$fetcher)
|
|
||||||
{
|
|
||||||
$manager = $this->getManager();
|
|
||||||
if (!$manager || (!$manager->services)) {
|
|
||||||
$this->destroyManager();
|
|
||||||
$http_response = array();
|
|
||||||
|
|
||||||
$services = call_user_func($discover_cb, $this->url,
|
|
||||||
$fetcher);
|
|
||||||
|
|
||||||
$manager = $this->createManager($services, $this->url);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($manager) {
|
|
||||||
$loader = new Services_Yadis_ManagerLoader();
|
|
||||||
$service = $manager->nextService();
|
|
||||||
$this->session->set($this->session_key,
|
|
||||||
serialize($loader->toSession($manager)));
|
|
||||||
} else {
|
|
||||||
$service = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $service;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clean up Yadis-related services in the session and return the
|
|
||||||
* most-recently-attempted service from the manager, if one
|
|
||||||
* exists.
|
|
||||||
*/
|
|
||||||
function cleanup()
|
|
||||||
{
|
|
||||||
$manager = $this->getManager();
|
|
||||||
if ($manager) {
|
|
||||||
$service = $manager->current();
|
|
||||||
$this->destroyManager();
|
|
||||||
} else {
|
|
||||||
$service = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $service;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function getSessionKey()
|
|
||||||
{
|
|
||||||
// Get the session key for this starting URL and suffix
|
|
||||||
return $this->PREFIX . $this->session_key_suffix;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function &getManager()
|
|
||||||
{
|
|
||||||
// Extract the YadisServiceManager for this object's URL and
|
|
||||||
// suffix from the session.
|
|
||||||
|
|
||||||
$manager_str = $this->session->get($this->getSessionKey());
|
|
||||||
$manager = null;
|
|
||||||
|
|
||||||
if ($manager_str !== null) {
|
|
||||||
$loader = new Services_Yadis_ManagerLoader();
|
|
||||||
$manager = $loader->fromSession(unserialize($manager_str));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($manager && $manager->forURL($this->url)) {
|
|
||||||
return $manager;
|
|
||||||
} else {
|
|
||||||
$unused = null;
|
|
||||||
return $unused;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function &createManager($services, $yadis_url = null)
|
|
||||||
{
|
|
||||||
$key = $this->getSessionKey();
|
|
||||||
if ($this->getManager()) {
|
|
||||||
return $this->getManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($services) {
|
|
||||||
$loader = new Services_Yadis_ManagerLoader();
|
|
||||||
$manager = new Services_Yadis_Manager($this->url, $yadis_url,
|
|
||||||
$services, $key);
|
|
||||||
$this->session->set($this->session_key,
|
|
||||||
serialize($loader->toSession($manager)));
|
|
||||||
return $manager;
|
|
||||||
} else {
|
|
||||||
// Oh, PHP.
|
|
||||||
$unused = null;
|
|
||||||
return $unused;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function destroyManager()
|
|
||||||
{
|
|
||||||
if ($this->getManager() !== null) {
|
|
||||||
$key = $this->getSessionKey();
|
|
||||||
$this->session->del($key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Miscellaneous utility values and functions for OpenID and Yadis.
|
|
||||||
*
|
|
||||||
* @package OpenID
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
function Services_Yadis_getUCSChars()
|
|
||||||
{
|
|
||||||
return array(
|
|
||||||
array(0xA0, 0xD7FF),
|
|
||||||
array(0xF900, 0xFDCF),
|
|
||||||
array(0xFDF0, 0xFFEF),
|
|
||||||
array(0x10000, 0x1FFFD),
|
|
||||||
array(0x20000, 0x2FFFD),
|
|
||||||
array(0x30000, 0x3FFFD),
|
|
||||||
array(0x40000, 0x4FFFD),
|
|
||||||
array(0x50000, 0x5FFFD),
|
|
||||||
array(0x60000, 0x6FFFD),
|
|
||||||
array(0x70000, 0x7FFFD),
|
|
||||||
array(0x80000, 0x8FFFD),
|
|
||||||
array(0x90000, 0x9FFFD),
|
|
||||||
array(0xA0000, 0xAFFFD),
|
|
||||||
array(0xB0000, 0xBFFFD),
|
|
||||||
array(0xC0000, 0xCFFFD),
|
|
||||||
array(0xD0000, 0xDFFFD),
|
|
||||||
array(0xE1000, 0xEFFFD)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Services_Yadis_getIPrivateChars()
|
|
||||||
{
|
|
||||||
return array(
|
|
||||||
array(0xE000, 0xF8FF),
|
|
||||||
array(0xF0000, 0xFFFFD),
|
|
||||||
array(0x100000, 0x10FFFD)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Services_Yadis_pct_escape_unicode($char_match)
|
|
||||||
{
|
|
||||||
$c = $char_match[0];
|
|
||||||
$result = "";
|
|
||||||
for ($i = 0; $i < strlen($c); $i++) {
|
|
||||||
$result .= "%".sprintf("%X", ord($c[$i]));
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Services_Yadis_startswith($s, $stuff)
|
|
||||||
{
|
|
||||||
return strpos($s, $stuff) === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,177 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This module contains the CURL-based HTTP fetcher implementation.
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface import
|
|
||||||
*/
|
|
||||||
require_once "Services/Yadis/HTTPFetcher.php";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A paranoid {@link Services_Yadis_HTTPFetcher} class which uses CURL
|
|
||||||
* for fetching.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
*/
|
|
||||||
class Services_Yadis_ParanoidHTTPFetcher extends Services_Yadis_HTTPFetcher {
|
|
||||||
function Services_Yadis_ParanoidHTTPFetcher()
|
|
||||||
{
|
|
||||||
$this->reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
function reset()
|
|
||||||
{
|
|
||||||
$this->headers = array();
|
|
||||||
$this->data = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _writeHeader($ch, $header)
|
|
||||||
{
|
|
||||||
array_push($this->headers, rtrim($header));
|
|
||||||
return strlen($header);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _writeData($ch, $data)
|
|
||||||
{
|
|
||||||
$this->data .= $data;
|
|
||||||
return strlen($data);
|
|
||||||
}
|
|
||||||
|
|
||||||
function get($url, $extra_headers = null)
|
|
||||||
{
|
|
||||||
$stop = time() + $this->timeout;
|
|
||||||
$off = $this->timeout;
|
|
||||||
|
|
||||||
$redir = true;
|
|
||||||
|
|
||||||
while ($redir && ($off > 0)) {
|
|
||||||
$this->reset();
|
|
||||||
|
|
||||||
$c = curl_init();
|
|
||||||
if (defined('CURLOPT_NOSIGNAL')) {
|
|
||||||
curl_setopt($c, CURLOPT_NOSIGNAL, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->allowedURL($url)) {
|
|
||||||
trigger_error(sprintf("Fetching URL not allowed: %s", $url),
|
|
||||||
E_USER_WARNING);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
curl_setopt($c, CURLOPT_WRITEFUNCTION,
|
|
||||||
array(&$this, "_writeData"));
|
|
||||||
curl_setopt($c, CURLOPT_HEADERFUNCTION,
|
|
||||||
array(&$this, "_writeHeader"));
|
|
||||||
|
|
||||||
if ($extra_headers) {
|
|
||||||
curl_setopt($c, CURLOPT_HTTPHEADER, $extra_headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
curl_setopt($c, CURLOPT_TIMEOUT, $off);
|
|
||||||
curl_setopt($c, CURLOPT_URL, $url);
|
|
||||||
|
|
||||||
curl_exec($c);
|
|
||||||
|
|
||||||
$code = curl_getinfo($c, CURLINFO_HTTP_CODE);
|
|
||||||
$body = $this->data;
|
|
||||||
$headers = $this->headers;
|
|
||||||
|
|
||||||
if (!$code) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_array($code, array(301, 302, 303, 307))) {
|
|
||||||
$url = $this->_findRedirect($headers);
|
|
||||||
$redir = true;
|
|
||||||
} else {
|
|
||||||
$redir = false;
|
|
||||||
curl_close($c);
|
|
||||||
|
|
||||||
$new_headers = array();
|
|
||||||
|
|
||||||
foreach ($headers as $header) {
|
|
||||||
if (preg_match("/:/", $header)) {
|
|
||||||
list($name, $value) = explode(": ", $header, 2);
|
|
||||||
$new_headers[$name] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Services_Yadis_HTTPResponse($url, $code,
|
|
||||||
$new_headers, $body);
|
|
||||||
}
|
|
||||||
|
|
||||||
$off = $stop - time();
|
|
||||||
}
|
|
||||||
|
|
||||||
trigger_error(sprintf("Timed out fetching: %s", $url),
|
|
||||||
E_USER_WARNING);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function post($url, $body)
|
|
||||||
{
|
|
||||||
$this->reset();
|
|
||||||
|
|
||||||
if (!$this->allowedURL($url)) {
|
|
||||||
trigger_error(sprintf("Fetching URL not allowed: %s", $url),
|
|
||||||
E_USER_WARNING);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$c = curl_init();
|
|
||||||
|
|
||||||
curl_setopt($c, CURLOPT_NOSIGNAL, true);
|
|
||||||
curl_setopt($c, CURLOPT_POST, true);
|
|
||||||
curl_setopt($c, CURLOPT_POSTFIELDS, $body);
|
|
||||||
curl_setopt($c, CURLOPT_TIMEOUT, $this->timeout);
|
|
||||||
curl_setopt($c, CURLOPT_URL, $url);
|
|
||||||
curl_setopt($c, CURLOPT_WRITEFUNCTION,
|
|
||||||
array(&$this, "_writeData"));
|
|
||||||
|
|
||||||
curl_exec($c);
|
|
||||||
|
|
||||||
$code = curl_getinfo($c, CURLINFO_HTTP_CODE);
|
|
||||||
|
|
||||||
if (!$code) {
|
|
||||||
trigger_error("No HTTP code returned", E_USER_WARNING);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$body = $this->data;
|
|
||||||
|
|
||||||
curl_close($c);
|
|
||||||
|
|
||||||
$new_headers = array();
|
|
||||||
|
|
||||||
foreach ($this->headers as $header) {
|
|
||||||
if (preg_match("/:/", $header)) {
|
|
||||||
list($name, $value) = explode(": ", $header, 2);
|
|
||||||
$new_headers[$name] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Services_Yadis_HTTPResponse($url, $code,
|
|
||||||
$new_headers, $body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,258 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the HTML pseudo-parser for the Yadis library.
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is responsible for scanning an HTML string to find META
|
|
||||||
* tags and their attributes. This is used by the Yadis discovery
|
|
||||||
* process. This class must be instantiated to be used.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
*/
|
|
||||||
class Services_Yadis_ParseHTML {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
var $_re_flags = "si";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
var $_removed_re =
|
|
||||||
"<!--.*?-->|<!\[CDATA\[.*?\]\]>|<script\b(?!:)[^>]*>.*?<\/script>";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
var $_tag_expr = "<%s%s(?:\s.*?)?%s>";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
var $_attr_find = '\b([-\w]+)=(".*?"|\'.*?\'|.+?)[\s>]';
|
|
||||||
|
|
||||||
function Services_Yadis_ParseHTML()
|
|
||||||
{
|
|
||||||
$this->_attr_find = sprintf("/%s/%s",
|
|
||||||
$this->_attr_find,
|
|
||||||
$this->_re_flags);
|
|
||||||
|
|
||||||
$this->_removed_re = sprintf("/%s/%s",
|
|
||||||
$this->_removed_re,
|
|
||||||
$this->_re_flags);
|
|
||||||
|
|
||||||
$this->_entity_replacements = array(
|
|
||||||
'amp' => '&',
|
|
||||||
'lt' => '<',
|
|
||||||
'gt' => '>',
|
|
||||||
'quot' => '"'
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->_ent_replace =
|
|
||||||
sprintf("&(%s);", implode("|",
|
|
||||||
$this->_entity_replacements));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace HTML entities (amp, lt, gt, and quot) as well as
|
|
||||||
* numeric entities (e.g. #x9f;) with their actual values and
|
|
||||||
* return the new string.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @param string $str The string in which to look for entities
|
|
||||||
* @return string $new_str The new string entities decoded
|
|
||||||
*/
|
|
||||||
function replaceEntities($str)
|
|
||||||
{
|
|
||||||
foreach ($this->_entity_replacements as $old => $new) {
|
|
||||||
$str = preg_replace(sprintf("/&%s;/", $old), $new, $str);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace numeric entities because html_entity_decode doesn't
|
|
||||||
// do it for us.
|
|
||||||
$str = preg_replace('~&#x([0-9a-f]+);~ei', 'chr(hexdec("\\1"))', $str);
|
|
||||||
$str = preg_replace('~&#([0-9]+);~e', 'chr(\\1)', $str);
|
|
||||||
|
|
||||||
return $str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Strip single and double quotes off of a string, if they are
|
|
||||||
* present.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @param string $str The original string
|
|
||||||
* @return string $new_str The new string with leading and
|
|
||||||
* trailing quotes removed
|
|
||||||
*/
|
|
||||||
function removeQuotes($str)
|
|
||||||
{
|
|
||||||
$matches = array();
|
|
||||||
$double = '/^"(.*)"$/';
|
|
||||||
$single = "/^\'(.*)\'$/";
|
|
||||||
|
|
||||||
if (preg_match($double, $str, $matches)) {
|
|
||||||
return $matches[1];
|
|
||||||
} else if (preg_match($single, $str, $matches)) {
|
|
||||||
return $matches[1];
|
|
||||||
} else {
|
|
||||||
return $str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a regular expression that will match an opening
|
|
||||||
* or closing tag from a set of names.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @param mixed $tag_names Tag names to match
|
|
||||||
* @param mixed $close false/0 = no, true/1 = yes, other = maybe
|
|
||||||
* @param mixed $self_close false/0 = no, true/1 = yes, other = maybe
|
|
||||||
* @return string $regex A regular expression string to be used
|
|
||||||
* in, say, preg_match.
|
|
||||||
*/
|
|
||||||
function tagPattern($tag_names, $close, $self_close)
|
|
||||||
{
|
|
||||||
if (is_array($tag_names)) {
|
|
||||||
$tag_names = '(?:'.implode('|',$tag_names).')';
|
|
||||||
}
|
|
||||||
if ($close) {
|
|
||||||
$close = '\/' . (($close == 1)? '' : '?');
|
|
||||||
} else {
|
|
||||||
$close = '';
|
|
||||||
}
|
|
||||||
if ($self_close) {
|
|
||||||
$self_close = '(?:\/\s*)' . (($self_close == 1)? '' : '?');
|
|
||||||
} else {
|
|
||||||
$self_close = '';
|
|
||||||
}
|
|
||||||
$expr = sprintf($this->_tag_expr, $close, $tag_names, $self_close);
|
|
||||||
|
|
||||||
return sprintf("/%s/%s", $expr, $this->_re_flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given an HTML document string, this finds all the META tags in
|
|
||||||
* the document, provided they are found in the
|
|
||||||
* <HTML><HEAD>...</HEAD> section of the document. The <HTML> tag
|
|
||||||
* may be missing.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @param string $html_string An HTMl document string
|
|
||||||
* @return array $tag_list Array of tags; each tag is an array of
|
|
||||||
* attribute -> value.
|
|
||||||
*/
|
|
||||||
function getMetaTags($html_string)
|
|
||||||
{
|
|
||||||
$html_string = preg_replace($this->_removed_re,
|
|
||||||
"",
|
|
||||||
$html_string);
|
|
||||||
|
|
||||||
$key_tags = array($this->tagPattern('html', false, false),
|
|
||||||
$this->tagPattern('head', false, false),
|
|
||||||
$this->tagPattern('head', true, false),
|
|
||||||
$this->tagPattern('html', true, false),
|
|
||||||
$this->tagPattern(array(
|
|
||||||
'body', 'frameset', 'frame', 'p', 'div',
|
|
||||||
'table','span','a'), 'maybe', 'maybe'));
|
|
||||||
$key_tags_pos = array();
|
|
||||||
foreach ($key_tags as $pat) {
|
|
||||||
$matches = array();
|
|
||||||
preg_match($pat, $html_string, $matches, PREG_OFFSET_CAPTURE);
|
|
||||||
if($matches) {
|
|
||||||
$key_tags_pos[] = $matches[0][1];
|
|
||||||
} else {
|
|
||||||
$key_tags_pos[] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// no opening head tag
|
|
||||||
if (is_null($key_tags_pos[1])) {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
// the effective </head> is the min of the following
|
|
||||||
if (is_null($key_tags_pos[2])) {
|
|
||||||
$key_tags_pos[2] = strlen($html_string);
|
|
||||||
}
|
|
||||||
foreach (array($key_tags_pos[3], $key_tags_pos[4]) as $pos) {
|
|
||||||
if (!is_null($pos) && $pos < $key_tags_pos[2]) {
|
|
||||||
$key_tags_pos[2] = $pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// closing head tag comes before opening head tag
|
|
||||||
if ($key_tags_pos[1] > $key_tags_pos[2]) {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
// if there is an opening html tag, make sure the opening head tag
|
|
||||||
// comes after it
|
|
||||||
if (!is_null($key_tags_pos[0]) && $key_tags_pos[1] < $key_tags_pos[0]) {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
$html_string = substr($html_string, $key_tags_pos[1], ($key_tags_pos[2]-$key_tags_pos[1]));
|
|
||||||
|
|
||||||
$link_data = array();
|
|
||||||
$link_matches = array();
|
|
||||||
|
|
||||||
if (!preg_match_all($this->tagPattern('meta', false, 'maybe'),
|
|
||||||
$html_string, $link_matches)) {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($link_matches[0] as $link) {
|
|
||||||
$attr_matches = array();
|
|
||||||
preg_match_all($this->_attr_find, $link, $attr_matches);
|
|
||||||
$link_attrs = array();
|
|
||||||
foreach ($attr_matches[0] as $index => $full_match) {
|
|
||||||
$name = $attr_matches[1][$index];
|
|
||||||
$value = $this->replaceEntities(
|
|
||||||
$this->removeQuotes($attr_matches[2][$index]));
|
|
||||||
|
|
||||||
$link_attrs[strtolower($name)] = $value;
|
|
||||||
}
|
|
||||||
$link_data[] = $link_attrs;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $link_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Looks for a META tag with an "http-equiv" attribute whose value
|
|
||||||
* is one of ("x-xrds-location", "x-yadis-location"), ignoring
|
|
||||||
* case. If such a META tag is found, its "content" attribute
|
|
||||||
* value is returned.
|
|
||||||
*
|
|
||||||
* @param string $html_string An HTML document in string format
|
|
||||||
* @return mixed $content The "content" attribute value of the
|
|
||||||
* META tag, if found, or null if no such tag was found.
|
|
||||||
*/
|
|
||||||
function getHTTPEquiv($html_string)
|
|
||||||
{
|
|
||||||
$meta_tags = $this->getMetaTags($html_string);
|
|
||||||
|
|
||||||
if ($meta_tags) {
|
|
||||||
foreach ($meta_tags as $tag) {
|
|
||||||
if (array_key_exists('http-equiv', $tag) &&
|
|
||||||
(in_array(strtolower($tag['http-equiv']),
|
|
||||||
array('x-xrds-location', 'x-yadis-location'))) &&
|
|
||||||
array_key_exists('content', $tag)) {
|
|
||||||
return $tag['content'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,245 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This module contains the plain non-curl HTTP fetcher
|
|
||||||
* implementation.
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface import
|
|
||||||
*/
|
|
||||||
require_once "Services/Yadis/HTTPFetcher.php";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class implements a plain, hand-built socket-based fetcher
|
|
||||||
* which will be used in the event that CURL is unavailable.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
*/
|
|
||||||
class Services_Yadis_PlainHTTPFetcher extends Services_Yadis_HTTPFetcher {
|
|
||||||
function get($url, $extra_headers = null)
|
|
||||||
{
|
|
||||||
if (!$this->allowedURL($url)) {
|
|
||||||
trigger_error("Bad URL scheme in url: " . $url,
|
|
||||||
E_USER_WARNING);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$redir = true;
|
|
||||||
|
|
||||||
$stop = time() + $this->timeout;
|
|
||||||
$off = $this->timeout;
|
|
||||||
|
|
||||||
while ($redir && ($off > 0)) {
|
|
||||||
|
|
||||||
$parts = parse_url($url);
|
|
||||||
|
|
||||||
$specify_port = true;
|
|
||||||
|
|
||||||
// Set a default port.
|
|
||||||
if (!array_key_exists('port', $parts)) {
|
|
||||||
$specify_port = false;
|
|
||||||
if ($parts['scheme'] == 'http') {
|
|
||||||
$parts['port'] = 80;
|
|
||||||
} elseif ($parts['scheme'] == 'https') {
|
|
||||||
$parts['port'] = 443;
|
|
||||||
} else {
|
|
||||||
trigger_error("fetcher post method doesn't support " .
|
|
||||||
" scheme '" . $parts['scheme'] .
|
|
||||||
"', no default port available",
|
|
||||||
E_USER_WARNING);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$host = $parts['host'];
|
|
||||||
|
|
||||||
if ($parts['scheme'] == 'https') {
|
|
||||||
$host = 'ssl://' . $host;
|
|
||||||
}
|
|
||||||
|
|
||||||
$user_agent = "PHP Yadis Library Fetcher";
|
|
||||||
|
|
||||||
$headers = array(
|
|
||||||
"GET ".$parts['path'].
|
|
||||||
(array_key_exists('query', $parts) ?
|
|
||||||
"?".$parts['query'] : "").
|
|
||||||
" HTTP/1.0",
|
|
||||||
"User-Agent: $user_agent",
|
|
||||||
"Host: ".$parts['host'].
|
|
||||||
($specify_port ? ":".$parts['port'] : ""),
|
|
||||||
"Port: ".$parts['port']);
|
|
||||||
|
|
||||||
$errno = 0;
|
|
||||||
$errstr = '';
|
|
||||||
|
|
||||||
if ($extra_headers) {
|
|
||||||
foreach ($extra_headers as $h) {
|
|
||||||
$headers[] = $h;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@$sock = fsockopen($host, $parts['port'], $errno, $errstr,
|
|
||||||
$this->timeout);
|
|
||||||
if ($sock === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream_set_timeout($sock, $this->timeout);
|
|
||||||
|
|
||||||
fputs($sock, implode("\r\n", $headers) . "\r\n\r\n");
|
|
||||||
|
|
||||||
$data = "";
|
|
||||||
while (!feof($sock)) {
|
|
||||||
$data .= fgets($sock, 1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose($sock);
|
|
||||||
|
|
||||||
// Split response into header and body sections
|
|
||||||
list($headers, $body) = explode("\r\n\r\n", $data, 2);
|
|
||||||
$headers = explode("\r\n", $headers);
|
|
||||||
|
|
||||||
$http_code = explode(" ", $headers[0]);
|
|
||||||
$code = $http_code[1];
|
|
||||||
|
|
||||||
if (in_array($code, array('301', '302'))) {
|
|
||||||
$url = $this->_findRedirect($headers);
|
|
||||||
$redir = true;
|
|
||||||
} else {
|
|
||||||
$redir = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$off = $stop - time();
|
|
||||||
}
|
|
||||||
|
|
||||||
$new_headers = array();
|
|
||||||
|
|
||||||
foreach ($headers as $header) {
|
|
||||||
if (preg_match("/:/", $header)) {
|
|
||||||
list($name, $value) = explode(": ", $header, 2);
|
|
||||||
$new_headers[$name] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Services_Yadis_HTTPResponse($url, $code, $new_headers, $body);
|
|
||||||
}
|
|
||||||
|
|
||||||
function post($url, $body, $extra_headers = null)
|
|
||||||
{
|
|
||||||
if (!$this->allowedURL($url)) {
|
|
||||||
trigger_error("Bad URL scheme in url: " . $url,
|
|
||||||
E_USER_WARNING);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$parts = parse_url($url);
|
|
||||||
|
|
||||||
$headers = array();
|
|
||||||
|
|
||||||
$post_path = $parts['path'];
|
|
||||||
if (isset($parts['query'])) {
|
|
||||||
$post_path .= '?' . $parts['query'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$headers[] = "POST ".$post_path." HTTP/1.0";
|
|
||||||
$headers[] = "Host: " . $parts['host'];
|
|
||||||
$headers[] = "Content-type: application/x-www-form-urlencoded";
|
|
||||||
$headers[] = "Content-length: " . strval(strlen($body));
|
|
||||||
|
|
||||||
if ($extra_headers &&
|
|
||||||
is_array($extra_headers)) {
|
|
||||||
$headers = array_merge($headers, $extra_headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Join all headers together.
|
|
||||||
$all_headers = implode("\r\n", $headers);
|
|
||||||
|
|
||||||
// Add headers, two newlines, and request body.
|
|
||||||
$request = $all_headers . "\r\n\r\n" . $body;
|
|
||||||
|
|
||||||
// Set a default port.
|
|
||||||
if (!array_key_exists('port', $parts)) {
|
|
||||||
if ($parts['scheme'] == 'http') {
|
|
||||||
$parts['port'] = 80;
|
|
||||||
} elseif ($parts['scheme'] == 'https') {
|
|
||||||
$parts['port'] = 443;
|
|
||||||
} else {
|
|
||||||
trigger_error("fetcher post method doesn't support scheme '" .
|
|
||||||
$parts['scheme'] .
|
|
||||||
"', no default port available",
|
|
||||||
E_USER_WARNING);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($parts['scheme'] == 'https') {
|
|
||||||
$parts['host'] = sprintf("ssl://%s", $parts['host']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect to the remote server.
|
|
||||||
$errno = 0;
|
|
||||||
$errstr = '';
|
|
||||||
|
|
||||||
$sock = fsockopen($parts['host'], $parts['port'], $errno, $errstr,
|
|
||||||
$this->timeout);
|
|
||||||
|
|
||||||
if ($sock === false) {
|
|
||||||
trigger_error("Could not connect to " . $parts['host'] .
|
|
||||||
" port " . $parts['port'],
|
|
||||||
E_USER_WARNING);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream_set_timeout($sock, $this->timeout);
|
|
||||||
|
|
||||||
// Write the POST request.
|
|
||||||
fputs($sock, $request);
|
|
||||||
|
|
||||||
// Get the response from the server.
|
|
||||||
$response = "";
|
|
||||||
while (!feof($sock)) {
|
|
||||||
if ($data = fgets($sock, 128)) {
|
|
||||||
$response .= $data;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Split the request into headers and body.
|
|
||||||
list($headers, $response_body) = explode("\r\n\r\n", $response, 2);
|
|
||||||
|
|
||||||
$headers = explode("\r\n", $headers);
|
|
||||||
|
|
||||||
// Expect the first line of the headers data to be something
|
|
||||||
// like HTTP/1.1 200 OK. Split the line on spaces and take
|
|
||||||
// the second token, which should be the return code.
|
|
||||||
$http_code = explode(" ", $headers[0]);
|
|
||||||
$code = $http_code[1];
|
|
||||||
|
|
||||||
$new_headers = array();
|
|
||||||
|
|
||||||
foreach ($headers as $header) {
|
|
||||||
if (preg_match("/:/", $header)) {
|
|
||||||
list($name, $value) = explode(": ", $header, 2);
|
|
||||||
$new_headers[$name] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Services_Yadis_HTTPResponse($url, $code,
|
|
||||||
$headers, $response_body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,365 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* XML-parsing classes to wrap the domxml and DOM extensions for PHP 4
|
|
||||||
* and 5, respectively.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The base class for wrappers for available PHP XML-parsing
|
|
||||||
* extensions. To work with this Yadis library, subclasses of this
|
|
||||||
* class MUST implement the API as defined in the remarks for this
|
|
||||||
* class. Subclasses of Services_Yadis_XMLParser are used to wrap
|
|
||||||
* particular PHP XML extensions such as 'domxml'. These are used
|
|
||||||
* internally by the library depending on the availability of
|
|
||||||
* supported PHP XML extensions.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
*/
|
|
||||||
class Services_Yadis_XMLParser {
|
|
||||||
/**
|
|
||||||
* Initialize an instance of Services_Yadis_XMLParser with some
|
|
||||||
* XML and namespaces. This SHOULD NOT be overridden by
|
|
||||||
* subclasses.
|
|
||||||
*
|
|
||||||
* @param string $xml_string A string of XML to be parsed.
|
|
||||||
* @param array $namespace_map An array of ($ns_name => $ns_uri)
|
|
||||||
* to be registered with the XML parser. May be empty.
|
|
||||||
* @return boolean $result True if the initialization and
|
|
||||||
* namespace registration(s) succeeded; false otherwise.
|
|
||||||
*/
|
|
||||||
function init($xml_string, $namespace_map)
|
|
||||||
{
|
|
||||||
if (!$this->setXML($xml_string)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($namespace_map as $prefix => $uri) {
|
|
||||||
if (!$this->registerNamespace($prefix, $uri)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a namespace with the XML parser. This should be
|
|
||||||
* overridden by subclasses.
|
|
||||||
*
|
|
||||||
* @param string $prefix The namespace prefix to appear in XML tag
|
|
||||||
* names.
|
|
||||||
*
|
|
||||||
* @param string $uri The namespace URI to be used to identify the
|
|
||||||
* namespace in the XML.
|
|
||||||
*
|
|
||||||
* @return boolean $result True if the registration succeeded;
|
|
||||||
* false otherwise.
|
|
||||||
*/
|
|
||||||
function registerNamespace($prefix, $uri)
|
|
||||||
{
|
|
||||||
// Not implemented.
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set this parser object's XML payload. This should be
|
|
||||||
* overridden by subclasses.
|
|
||||||
*
|
|
||||||
* @param string $xml_string The XML string to pass to this
|
|
||||||
* object's XML parser.
|
|
||||||
*
|
|
||||||
* @return boolean $result True if the initialization succeeded;
|
|
||||||
* false otherwise.
|
|
||||||
*/
|
|
||||||
function setXML($xml_string)
|
|
||||||
{
|
|
||||||
// Not implemented.
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Evaluate an XPath expression and return the resulting node
|
|
||||||
* list. This should be overridden by subclasses.
|
|
||||||
*
|
|
||||||
* @param string $xpath The XPath expression to be evaluated.
|
|
||||||
*
|
|
||||||
* @param mixed $node A node object resulting from a previous
|
|
||||||
* evalXPath call. This node, if specified, provides the context
|
|
||||||
* for the evaluation of this xpath expression.
|
|
||||||
*
|
|
||||||
* @return array $node_list An array of matching opaque node
|
|
||||||
* objects to be used with other methods of this parser class.
|
|
||||||
*/
|
|
||||||
function evalXPath($xpath, $node = null)
|
|
||||||
{
|
|
||||||
// Not implemented.
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the textual content of a specified node.
|
|
||||||
*
|
|
||||||
* @param mixed $node A node object from a previous call to
|
|
||||||
* $this->evalXPath().
|
|
||||||
*
|
|
||||||
* @return string $content The content of this node.
|
|
||||||
*/
|
|
||||||
function content($node)
|
|
||||||
{
|
|
||||||
// Not implemented.
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the attributes of a specified node.
|
|
||||||
*
|
|
||||||
* @param mixed $node A node object from a previous call to
|
|
||||||
* $this->evalXPath().
|
|
||||||
*
|
|
||||||
* @return array $attrs An array mapping attribute names to
|
|
||||||
* values.
|
|
||||||
*/
|
|
||||||
function attributes($node)
|
|
||||||
{
|
|
||||||
// Not implemented.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This concrete implementation of Services_Yadis_XMLParser implements
|
|
||||||
* the appropriate API for the 'domxml' extension which is typically
|
|
||||||
* packaged with PHP 4. This class will be used whenever the 'domxml'
|
|
||||||
* extension is detected. See the Services_Yadis_XMLParser class for
|
|
||||||
* details on this class's methods.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
*/
|
|
||||||
class Services_Yadis_domxml extends Services_Yadis_XMLParser {
|
|
||||||
function Services_Yadis_domxml()
|
|
||||||
{
|
|
||||||
$this->xml = null;
|
|
||||||
$this->doc = null;
|
|
||||||
$this->xpath = null;
|
|
||||||
$this->errors = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setXML($xml_string)
|
|
||||||
{
|
|
||||||
$this->xml = $xml_string;
|
|
||||||
$this->doc = @domxml_open_mem($xml_string, DOMXML_LOAD_PARSING,
|
|
||||||
$this->errors);
|
|
||||||
|
|
||||||
if (!$this->doc) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->xpath = $this->doc->xpath_new_context();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerNamespace($prefix, $uri)
|
|
||||||
{
|
|
||||||
return xpath_register_ns($this->xpath, $prefix, $uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
function &evalXPath($xpath, $node = null)
|
|
||||||
{
|
|
||||||
if ($node) {
|
|
||||||
$result = @$this->xpath->xpath_eval($xpath, $node);
|
|
||||||
} else {
|
|
||||||
$result = @$this->xpath->xpath_eval($xpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$result->nodeset) {
|
|
||||||
$n = array();
|
|
||||||
return $n;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result->nodeset;
|
|
||||||
}
|
|
||||||
|
|
||||||
function content($node)
|
|
||||||
{
|
|
||||||
if ($node) {
|
|
||||||
return $node->get_content();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function attributes($node)
|
|
||||||
{
|
|
||||||
if ($node) {
|
|
||||||
$arr = $node->attributes();
|
|
||||||
$result = array();
|
|
||||||
|
|
||||||
if ($arr) {
|
|
||||||
foreach ($arr as $attrnode) {
|
|
||||||
$result[$attrnode->name] = $attrnode->value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This concrete implementation of Services_Yadis_XMLParser implements
|
|
||||||
* the appropriate API for the 'dom' extension which is typically
|
|
||||||
* packaged with PHP 5. This class will be used whenever the 'dom'
|
|
||||||
* extension is detected. See the Services_Yadis_XMLParser class for
|
|
||||||
* details on this class's methods.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
*/
|
|
||||||
class Services_Yadis_dom extends Services_Yadis_XMLParser {
|
|
||||||
function Services_Yadis_dom()
|
|
||||||
{
|
|
||||||
$this->xml = null;
|
|
||||||
$this->doc = null;
|
|
||||||
$this->xpath = null;
|
|
||||||
$this->errors = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setXML($xml_string)
|
|
||||||
{
|
|
||||||
$this->xml = $xml_string;
|
|
||||||
$this->doc = new DOMDocument;
|
|
||||||
|
|
||||||
if (!$this->doc) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!@$this->doc->loadXML($xml_string)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->xpath = new DOMXPath($this->doc);
|
|
||||||
|
|
||||||
if ($this->xpath) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerNamespace($prefix, $uri)
|
|
||||||
{
|
|
||||||
return $this->xpath->registerNamespace($prefix, $uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
function &evalXPath($xpath, $node = null)
|
|
||||||
{
|
|
||||||
if ($node) {
|
|
||||||
$result = @$this->xpath->query($xpath, $node);
|
|
||||||
} else {
|
|
||||||
$result = @$this->xpath->query($xpath);
|
|
||||||
}
|
|
||||||
|
|
||||||
$n = array();
|
|
||||||
|
|
||||||
for ($i = 0; $i < $result->length; $i++) {
|
|
||||||
$n[] = $result->item($i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $n;
|
|
||||||
}
|
|
||||||
|
|
||||||
function content($node)
|
|
||||||
{
|
|
||||||
if ($node) {
|
|
||||||
return $node->textContent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function attributes($node)
|
|
||||||
{
|
|
||||||
if ($node) {
|
|
||||||
$arr = $node->attributes;
|
|
||||||
$result = array();
|
|
||||||
|
|
||||||
if ($arr) {
|
|
||||||
for ($i = 0; $i < $arr->length; $i++) {
|
|
||||||
$node = $arr->item($i);
|
|
||||||
$result[$node->nodeName] = $node->nodeValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
global $__Services_Yadis_defaultParser;
|
|
||||||
$__Services_Yadis_defaultParser = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a default parser to override the extension-driven selection of
|
|
||||||
* available parser classes. This is helpful in a test environment or
|
|
||||||
* one in which multiple parsers can be used but one is more
|
|
||||||
* desirable.
|
|
||||||
*
|
|
||||||
* @param Services_Yadis_XMLParser $parser An instance of a
|
|
||||||
* Services_Yadis_XMLParser subclass.
|
|
||||||
*/
|
|
||||||
function Services_Yadis_setDefaultParser(&$parser)
|
|
||||||
{
|
|
||||||
global $__Services_Yadis_defaultParser;
|
|
||||||
$__Services_Yadis_defaultParser =& $parser;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Services_Yadis_getSupportedExtensions()
|
|
||||||
{
|
|
||||||
return array(
|
|
||||||
'dom' => array('classname' => 'Services_Yadis_dom',
|
|
||||||
'libname' => array('dom.so', 'dom.dll')),
|
|
||||||
'domxml' => array('classname' => 'Services_Yadis_domxml',
|
|
||||||
'libname' => array('domxml.so', 'php_domxml.dll')),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an instance of a Services_Yadis_XMLParser subclass based on
|
|
||||||
* the availability of PHP extensions for XML parsing. If
|
|
||||||
* Services_Yadis_setDefaultParser has been called, the parser used in
|
|
||||||
* that call will be returned instead.
|
|
||||||
*/
|
|
||||||
function &Services_Yadis_getXMLParser()
|
|
||||||
{
|
|
||||||
global $__Services_Yadis_defaultParser;
|
|
||||||
|
|
||||||
if (isset($__Services_Yadis_defaultParser)) {
|
|
||||||
return $__Services_Yadis_defaultParser;
|
|
||||||
}
|
|
||||||
|
|
||||||
$p = null;
|
|
||||||
$classname = null;
|
|
||||||
|
|
||||||
$extensions = Services_Yadis_getSupportedExtensions();
|
|
||||||
|
|
||||||
// Return a wrapper for the resident implementation, if any.
|
|
||||||
foreach ($extensions as $name => $params) {
|
|
||||||
if (!extension_loaded($name)) {
|
|
||||||
foreach ($params['libname'] as $libname) {
|
|
||||||
if (@dl($libname)) {
|
|
||||||
$classname = $params['classname'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$classname = $params['classname'];
|
|
||||||
}
|
|
||||||
if (isset($classname)) {
|
|
||||||
$p = new $classname();
|
|
||||||
return $p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($p)) {
|
|
||||||
trigger_error('No XML parser was found', E_USER_ERROR);
|
|
||||||
} else {
|
|
||||||
Services_Yadis_setDefaultParser($p);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $p;
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,425 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This module contains the XRDS parsing code.
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Require the XPath implementation.
|
|
||||||
*/
|
|
||||||
require_once 'Services/Yadis/XML.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This match mode means a given service must match ALL filters passed
|
|
||||||
* to the Services_Yadis_XRDS::services() call.
|
|
||||||
*/
|
|
||||||
define('SERVICES_YADIS_MATCH_ALL', 101);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This match mode means a given service must match ANY filters (at
|
|
||||||
* least one) passed to the Services_Yadis_XRDS::services() call.
|
|
||||||
*/
|
|
||||||
define('SERVICES_YADIS_MATCH_ANY', 102);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The priority value used for service elements with no priority
|
|
||||||
* specified.
|
|
||||||
*/
|
|
||||||
define('SERVICES_YADIS_MAX_PRIORITY', pow(2, 30));
|
|
||||||
|
|
||||||
function Services_Yadis_getNSMap()
|
|
||||||
{
|
|
||||||
return array('xrds' => 'xri://$xrds',
|
|
||||||
'xrd' => 'xri://$xrd*($v*2.0)');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function Services_Yadis_array_scramble($arr)
|
|
||||||
{
|
|
||||||
$result = array();
|
|
||||||
|
|
||||||
while (count($arr)) {
|
|
||||||
$index = array_rand($arr, 1);
|
|
||||||
$result[] = $arr[$index];
|
|
||||||
unset($arr[$index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents a <Service> element in an XRDS document.
|
|
||||||
* Objects of this type are returned by
|
|
||||||
* Services_Yadis_XRDS::services() and
|
|
||||||
* Services_Yadis_Yadis::services(). Each object corresponds directly
|
|
||||||
* to a <Service> element in the XRDS and supplies a
|
|
||||||
* getElements($name) method which you should use to inspect the
|
|
||||||
* element's contents. See {@link Services_Yadis_Yadis} for more
|
|
||||||
* information on the role this class plays in Yadis discovery.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
*/
|
|
||||||
class Services_Yadis_Service {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an empty service object.
|
|
||||||
*/
|
|
||||||
function Services_Yadis_Service()
|
|
||||||
{
|
|
||||||
$this->element = null;
|
|
||||||
$this->parser = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the URIs in the "Type" elements, if any, of this Service
|
|
||||||
* element.
|
|
||||||
*
|
|
||||||
* @return array $type_uris An array of Type URI strings.
|
|
||||||
*/
|
|
||||||
function getTypes()
|
|
||||||
{
|
|
||||||
$t = array();
|
|
||||||
foreach ($this->getElements('xrd:Type') as $elem) {
|
|
||||||
$c = $this->parser->content($elem);
|
|
||||||
if ($c) {
|
|
||||||
$t[] = $c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $t;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the URIs in the "URI" elements, if any, of this Service
|
|
||||||
* element. The URIs are returned sorted in priority order.
|
|
||||||
*
|
|
||||||
* @return array $uris An array of URI strings.
|
|
||||||
*/
|
|
||||||
function getURIs()
|
|
||||||
{
|
|
||||||
$uris = array();
|
|
||||||
$last = array();
|
|
||||||
|
|
||||||
foreach ($this->getElements('xrd:URI') as $elem) {
|
|
||||||
$uri_string = $this->parser->content($elem);
|
|
||||||
$attrs = $this->parser->attributes($elem);
|
|
||||||
if ($attrs &&
|
|
||||||
array_key_exists('priority', $attrs)) {
|
|
||||||
$priority = intval($attrs['priority']);
|
|
||||||
if (!array_key_exists($priority, $uris)) {
|
|
||||||
$uris[$priority] = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
$uris[$priority][] = $uri_string;
|
|
||||||
} else {
|
|
||||||
$last[] = $uri_string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$keys = array_keys($uris);
|
|
||||||
sort($keys);
|
|
||||||
|
|
||||||
// Rebuild array of URIs.
|
|
||||||
$result = array();
|
|
||||||
foreach ($keys as $k) {
|
|
||||||
$new_uris = Services_Yadis_array_scramble($uris[$k]);
|
|
||||||
$result = array_merge($result, $new_uris);
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = array_merge($result,
|
|
||||||
Services_Yadis_array_scramble($last));
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the "priority" attribute value of this <Service>
|
|
||||||
* element, if the attribute is present. Returns null if not.
|
|
||||||
*
|
|
||||||
* @return mixed $result Null or integer, depending on whether
|
|
||||||
* this Service element has a 'priority' attribute.
|
|
||||||
*/
|
|
||||||
function getPriority()
|
|
||||||
{
|
|
||||||
$attributes = $this->parser->attributes($this->element);
|
|
||||||
|
|
||||||
if (array_key_exists('priority', $attributes)) {
|
|
||||||
return intval($attributes['priority']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to get XML elements from this object's <Service> element.
|
|
||||||
*
|
|
||||||
* This is what you should use to get all custom information out
|
|
||||||
* of this element. This is used by service filter functions to
|
|
||||||
* determine whether a service element contains specific tags,
|
|
||||||
* etc. NOTE: this only considers elements which are direct
|
|
||||||
* children of the <Service> element for this object.
|
|
||||||
*
|
|
||||||
* @param string $name The name of the element to look for
|
|
||||||
* @return array $list An array of elements with the specified
|
|
||||||
* name which are direct children of the <Service> element. The
|
|
||||||
* nodes returned by this function can be passed to $this->parser
|
|
||||||
* methods (see {@link Services_Yadis_XMLParser}).
|
|
||||||
*/
|
|
||||||
function getElements($name)
|
|
||||||
{
|
|
||||||
return $this->parser->evalXPath($name, $this->element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class performs parsing of XRDS documents.
|
|
||||||
*
|
|
||||||
* You should not instantiate this class directly; rather, call
|
|
||||||
* parseXRDS statically:
|
|
||||||
*
|
|
||||||
* <pre> $xrds = Services_Yadis_XRDS::parseXRDS($xml_string);</pre>
|
|
||||||
*
|
|
||||||
* If the XRDS can be parsed and is valid, an instance of
|
|
||||||
* Services_Yadis_XRDS will be returned. Otherwise, null will be
|
|
||||||
* returned. This class is used by the Services_Yadis_Yadis::discover
|
|
||||||
* method.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
*/
|
|
||||||
class Services_Yadis_XRDS {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate a Services_Yadis_XRDS object. Requires an XPath
|
|
||||||
* instance which has been used to parse a valid XRDS document.
|
|
||||||
*/
|
|
||||||
function Services_Yadis_XRDS(&$xmlParser, &$xrdNodes)
|
|
||||||
{
|
|
||||||
$this->parser =& $xmlParser;
|
|
||||||
$this->xrdNode = $xrdNodes[count($xrdNodes) - 1];
|
|
||||||
$this->allXrdNodes =& $xrdNodes;
|
|
||||||
$this->serviceList = array();
|
|
||||||
$this->_parse();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse an XML string (XRDS document) and return either a
|
|
||||||
* Services_Yadis_XRDS object or null, depending on whether the
|
|
||||||
* XRDS XML is valid.
|
|
||||||
*
|
|
||||||
* @param string $xml_string An XRDS XML string.
|
|
||||||
* @return mixed $xrds An instance of Services_Yadis_XRDS or null,
|
|
||||||
* depending on the validity of $xml_string
|
|
||||||
*/
|
|
||||||
function &parseXRDS($xml_string, $extra_ns_map = null)
|
|
||||||
{
|
|
||||||
$_null = null;
|
|
||||||
|
|
||||||
if (!$xml_string) {
|
|
||||||
return $_null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$parser = Services_Yadis_getXMLParser();
|
|
||||||
|
|
||||||
$ns_map = Services_Yadis_getNSMap();
|
|
||||||
|
|
||||||
if ($extra_ns_map && is_array($extra_ns_map)) {
|
|
||||||
$ns_map = array_merge($ns_map, $extra_ns_map);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!($parser && $parser->init($xml_string, $ns_map))) {
|
|
||||||
return $_null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to get root element.
|
|
||||||
$root = $parser->evalXPath('/xrds:XRDS[1]');
|
|
||||||
if (!$root) {
|
|
||||||
return $_null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_array($root)) {
|
|
||||||
$root = $root[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
$attrs = $parser->attributes($root);
|
|
||||||
|
|
||||||
if (array_key_exists('xmlns:xrd', $attrs) &&
|
|
||||||
$attrs['xmlns:xrd'] != 'xri://$xrd*($v*2.0)') {
|
|
||||||
return $_null;
|
|
||||||
} else if (array_key_exists('xmlns', $attrs) &&
|
|
||||||
preg_match('/xri/', $attrs['xmlns']) &&
|
|
||||||
$attrs['xmlns'] != 'xri://$xrd*($v*2.0)') {
|
|
||||||
return $_null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the last XRD node.
|
|
||||||
$xrd_nodes = $parser->evalXPath('/xrds:XRDS[1]/xrd:XRD');
|
|
||||||
|
|
||||||
if (!$xrd_nodes) {
|
|
||||||
return $_null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$xrds = new Services_Yadis_XRDS($parser, $xrd_nodes);
|
|
||||||
return $xrds;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _addService($priority, $service)
|
|
||||||
{
|
|
||||||
$priority = intval($priority);
|
|
||||||
|
|
||||||
if (!array_key_exists($priority, $this->serviceList)) {
|
|
||||||
$this->serviceList[$priority] = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->serviceList[$priority][] = $service;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the service list using nodes from the XRDS XML
|
|
||||||
* document.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _parse()
|
|
||||||
{
|
|
||||||
$this->serviceList = array();
|
|
||||||
|
|
||||||
$services = $this->parser->evalXPath('xrd:Service', $this->xrdNode);
|
|
||||||
|
|
||||||
foreach ($services as $node) {
|
|
||||||
$s =& new Services_Yadis_Service();
|
|
||||||
$s->element = $node;
|
|
||||||
$s->parser =& $this->parser;
|
|
||||||
|
|
||||||
$priority = $s->getPriority();
|
|
||||||
|
|
||||||
if ($priority === null) {
|
|
||||||
$priority = SERVICES_YADIS_MAX_PRIORITY;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->_addService($priority, $s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of service objects which correspond to <Service>
|
|
||||||
* elements in the XRDS XML document for this object.
|
|
||||||
*
|
|
||||||
* Optionally, an array of filter callbacks may be given to limit
|
|
||||||
* the list of returned service objects. Furthermore, the default
|
|
||||||
* mode is to return all service objects which match ANY of the
|
|
||||||
* specified filters, but $filter_mode may be
|
|
||||||
* SERVICES_YADIS_MATCH_ALL if you want to be sure that the
|
|
||||||
* returned services match all the given filters. See {@link
|
|
||||||
* Services_Yadis_Yadis} for detailed usage information on filter
|
|
||||||
* functions.
|
|
||||||
*
|
|
||||||
* @param mixed $filters An array of callbacks to filter the
|
|
||||||
* returned services, or null if all services are to be returned.
|
|
||||||
* @param integer $filter_mode SERVICES_YADIS_MATCH_ALL or
|
|
||||||
* SERVICES_YADIS_MATCH_ANY, depending on whether the returned
|
|
||||||
* services should match ALL or ANY of the specified filters,
|
|
||||||
* respectively.
|
|
||||||
* @return mixed $services An array of {@link
|
|
||||||
* Services_Yadis_Service} objects if $filter_mode is a valid
|
|
||||||
* mode; null if $filter_mode is an invalid mode (i.e., not
|
|
||||||
* SERVICES_YADIS_MATCH_ANY or SERVICES_YADIS_MATCH_ALL).
|
|
||||||
*/
|
|
||||||
function services($filters = null,
|
|
||||||
$filter_mode = SERVICES_YADIS_MATCH_ANY)
|
|
||||||
{
|
|
||||||
|
|
||||||
$pri_keys = array_keys($this->serviceList);
|
|
||||||
sort($pri_keys, SORT_NUMERIC);
|
|
||||||
|
|
||||||
// If no filters are specified, return the entire service
|
|
||||||
// list, ordered by priority.
|
|
||||||
if (!$filters ||
|
|
||||||
(!is_array($filters))) {
|
|
||||||
|
|
||||||
$result = array();
|
|
||||||
foreach ($pri_keys as $pri) {
|
|
||||||
$result = array_merge($result, $this->serviceList[$pri]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a bad filter mode is specified, return null.
|
|
||||||
if (!in_array($filter_mode, array(SERVICES_YADIS_MATCH_ANY,
|
|
||||||
SERVICES_YADIS_MATCH_ALL))) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, use the callbacks in the filter list to
|
|
||||||
// determine which services are returned.
|
|
||||||
$filtered = array();
|
|
||||||
|
|
||||||
foreach ($pri_keys as $priority_value) {
|
|
||||||
$service_obj_list = $this->serviceList[$priority_value];
|
|
||||||
|
|
||||||
foreach ($service_obj_list as $service) {
|
|
||||||
|
|
||||||
$matches = 0;
|
|
||||||
|
|
||||||
foreach ($filters as $filter) {
|
|
||||||
if (call_user_func_array($filter, array($service))) {
|
|
||||||
$matches++;
|
|
||||||
|
|
||||||
if ($filter_mode == SERVICES_YADIS_MATCH_ANY) {
|
|
||||||
$pri = $service->getPriority();
|
|
||||||
if ($pri === null) {
|
|
||||||
$pri = SERVICES_YADIS_MAX_PRIORITY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!array_key_exists($pri, $filtered)) {
|
|
||||||
$filtered[$pri] = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
$filtered[$pri][] = $service;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($filter_mode == SERVICES_YADIS_MATCH_ALL) &&
|
|
||||||
($matches == count($filters))) {
|
|
||||||
|
|
||||||
$pri = $service->getPriority();
|
|
||||||
if ($pri === null) {
|
|
||||||
$pri = SERVICES_YADIS_MAX_PRIORITY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!array_key_exists($pri, $filtered)) {
|
|
||||||
$filtered[$pri] = array();
|
|
||||||
}
|
|
||||||
$filtered[$pri][] = $service;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$pri_keys = array_keys($filtered);
|
|
||||||
sort($pri_keys, SORT_NUMERIC);
|
|
||||||
|
|
||||||
$result = array();
|
|
||||||
foreach ($pri_keys as $pri) {
|
|
||||||
$result = array_merge($result, $filtered[$pri]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,233 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Routines for XRI resolution.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once 'Services/Yadis/Misc.php';
|
|
||||||
require_once 'Services/Yadis/Yadis.php';
|
|
||||||
require_once 'Auth/OpenID.php';
|
|
||||||
|
|
||||||
function Services_Yadis_getDefaultProxy()
|
|
||||||
{
|
|
||||||
return 'http://proxy.xri.net/';
|
|
||||||
}
|
|
||||||
|
|
||||||
function Services_Yadis_getXRIAuthorities()
|
|
||||||
{
|
|
||||||
return array('!', '=', '@', '+', '$', '(');
|
|
||||||
}
|
|
||||||
|
|
||||||
function Services_Yadis_getEscapeRE()
|
|
||||||
{
|
|
||||||
$parts = array();
|
|
||||||
foreach (array_merge(Services_Yadis_getUCSChars(),
|
|
||||||
Services_Yadis_getIPrivateChars()) as $pair) {
|
|
||||||
list($m, $n) = $pair;
|
|
||||||
$parts[] = sprintf("%s-%s", chr($m), chr($n));
|
|
||||||
}
|
|
||||||
|
|
||||||
return sprintf('/[%s]/', implode('', $parts));
|
|
||||||
}
|
|
||||||
|
|
||||||
function Services_Yadis_getXrefRE()
|
|
||||||
{
|
|
||||||
return '/\((.*?)\)/';
|
|
||||||
}
|
|
||||||
|
|
||||||
function Services_Yadis_identifierScheme($identifier)
|
|
||||||
{
|
|
||||||
if (Services_Yadis_startswith($identifier, 'xri://') ||
|
|
||||||
(in_array($identifier[0], Services_Yadis_getXRIAuthorities()))) {
|
|
||||||
return "XRI";
|
|
||||||
} else {
|
|
||||||
return "URI";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Services_Yadis_toIRINormal($xri)
|
|
||||||
{
|
|
||||||
if (!Services_Yadis_startswith($xri, 'xri://')) {
|
|
||||||
$xri = 'xri://' . $xri;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Services_Yadis_escapeForIRI($xri);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _escape_xref($xref_match)
|
|
||||||
{
|
|
||||||
$xref = $xref_match[0];
|
|
||||||
$xref = str_replace('/', '%2F', $xref);
|
|
||||||
$xref = str_replace('?', '%3F', $xref);
|
|
||||||
$xref = str_replace('#', '%23', $xref);
|
|
||||||
return $xref;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Services_Yadis_escapeForIRI($xri)
|
|
||||||
{
|
|
||||||
$xri = str_replace('%', '%25', $xri);
|
|
||||||
$xri = preg_replace_callback(Services_Yadis_getXrefRE(),
|
|
||||||
'_escape_xref', $xri);
|
|
||||||
return $xri;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Services_Yadis_toURINormal($xri)
|
|
||||||
{
|
|
||||||
return Services_Yadis_iriToURI(Services_Yadis_toIRINormal($xri));
|
|
||||||
}
|
|
||||||
|
|
||||||
function Services_Yadis_iriToURI($iri)
|
|
||||||
{
|
|
||||||
if (1) {
|
|
||||||
return $iri;
|
|
||||||
} else {
|
|
||||||
// According to RFC 3987, section 3.1, "Mapping of IRIs to URIs"
|
|
||||||
return preg_replace_callback(Services_Yadis_getEscapeRE(),
|
|
||||||
'Services_Yadis_pct_escape_unicode', $iri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function Services_Yadis_XRIAppendArgs($url, $args)
|
|
||||||
{
|
|
||||||
// Append some arguments to an HTTP query. Yes, this is just like
|
|
||||||
// OpenID's appendArgs, but with special seasoning for XRI
|
|
||||||
// queries.
|
|
||||||
|
|
||||||
if (count($args) == 0) {
|
|
||||||
return $url;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Non-empty array; if it is an array of arrays, use multisort;
|
|
||||||
// otherwise use sort.
|
|
||||||
if (array_key_exists(0, $args) &&
|
|
||||||
is_array($args[0])) {
|
|
||||||
// Do nothing here.
|
|
||||||
} else {
|
|
||||||
$keys = array_keys($args);
|
|
||||||
sort($keys);
|
|
||||||
$new_args = array();
|
|
||||||
foreach ($keys as $key) {
|
|
||||||
$new_args[] = array($key, $args[$key]);
|
|
||||||
}
|
|
||||||
$args = $new_args;
|
|
||||||
}
|
|
||||||
|
|
||||||
// According to XRI Resolution section "QXRI query parameters":
|
|
||||||
//
|
|
||||||
// "If the original QXRI had a null query component (only a
|
|
||||||
// leading question mark), or a query component consisting of
|
|
||||||
// only question marks, one additional leading question mark MUST
|
|
||||||
// be added when adding any XRI resolution parameters."
|
|
||||||
if (strpos(rtrim($url, '?'), '?') !== false) {
|
|
||||||
$sep = '&';
|
|
||||||
} else {
|
|
||||||
$sep = '?';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $url . $sep . Auth_OpenID::httpBuildQuery($args);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Services_Yadis_providerIsAuthoritative($providerID, $canonicalID)
|
|
||||||
{
|
|
||||||
$lastbang = strrpos($canonicalID, '!');
|
|
||||||
$p = substr($canonicalID, 0, $lastbang);
|
|
||||||
return $p == $providerID;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Services_Yadis_rootAuthority($xri)
|
|
||||||
{
|
|
||||||
// Return the root authority for an XRI.
|
|
||||||
|
|
||||||
$root = null;
|
|
||||||
|
|
||||||
if (Services_Yadis_startswith($xri, 'xri://')) {
|
|
||||||
$xri = substr($xri, 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
$authority = explode('/', $xri, 2);
|
|
||||||
$authority = $authority[0];
|
|
||||||
if ($authority[0] == '(') {
|
|
||||||
// Cross-reference.
|
|
||||||
// XXX: This is incorrect if someone nests cross-references so
|
|
||||||
// there is another close-paren in there. Hopefully nobody
|
|
||||||
// does that before we have a real xriparse function.
|
|
||||||
// Hopefully nobody does that *ever*.
|
|
||||||
$root = substr($authority, 0, strpos($authority, ')') + 1);
|
|
||||||
} else if (in_array($authority[0], Services_Yadis_getXRIAuthorities())) {
|
|
||||||
// Other XRI reference.
|
|
||||||
$root = $authority[0];
|
|
||||||
} else {
|
|
||||||
// IRI reference.
|
|
||||||
$_segments = explode("!", $authority);
|
|
||||||
$segments = array();
|
|
||||||
foreach ($_segments as $s) {
|
|
||||||
$segments = array_merge($segments, explode("*", $s));
|
|
||||||
}
|
|
||||||
$root = $segments[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return Services_Yadis_XRI($root);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Services_Yadis_XRI($xri)
|
|
||||||
{
|
|
||||||
if (!Services_Yadis_startswith($xri, 'xri://')) {
|
|
||||||
$xri = 'xri://' . $xri;
|
|
||||||
}
|
|
||||||
return $xri;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Services_Yadis_getCanonicalID($iname, $xrds)
|
|
||||||
{
|
|
||||||
// Returns FALSE or a canonical ID value.
|
|
||||||
|
|
||||||
// Now nodes are in reverse order.
|
|
||||||
$xrd_list = array_reverse($xrds->allXrdNodes);
|
|
||||||
$parser =& $xrds->parser;
|
|
||||||
$node = $xrd_list[0];
|
|
||||||
|
|
||||||
$canonicalID_nodes = $parser->evalXPath('xrd:CanonicalID', $node);
|
|
||||||
|
|
||||||
if (!$canonicalID_nodes) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$canonicalID = $canonicalID_nodes[count($canonicalID_nodes) - 1];
|
|
||||||
$canonicalID = Services_Yadis_XRI($parser->content($canonicalID));
|
|
||||||
|
|
||||||
$childID = $canonicalID;
|
|
||||||
|
|
||||||
for ($i = 1; $i < count($xrd_list); $i++) {
|
|
||||||
$xrd = $xrd_list[$i];
|
|
||||||
|
|
||||||
$parent_sought = substr($childID, 0, strrpos($childID, '!'));
|
|
||||||
$parent_list = array();
|
|
||||||
|
|
||||||
foreach ($parser->evalXPath('xrd:CanonicalID', $xrd) as $c) {
|
|
||||||
$parent_list[] = Services_Yadis_XRI($parser->content($c));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!in_array($parent_sought, $parent_list)) {
|
|
||||||
// raise XRDSFraud.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$childID = $parent_sought;
|
|
||||||
}
|
|
||||||
|
|
||||||
$root = Services_Yadis_rootAuthority($iname);
|
|
||||||
if (!Services_Yadis_providerIsAuthoritative($root, $childID)) {
|
|
||||||
// raise XRDSFraud.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $canonicalID;
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once 'Services/Yadis/XRDS.php';
|
|
||||||
require_once 'Services/Yadis/XRI.php';
|
|
||||||
|
|
||||||
class Services_Yadis_ProxyResolver {
|
|
||||||
function Services_Yadis_ProxyResolver(&$fetcher, $proxy_url = null)
|
|
||||||
{
|
|
||||||
$this->fetcher =& $fetcher;
|
|
||||||
$this->proxy_url = $proxy_url;
|
|
||||||
if (!$this->proxy_url) {
|
|
||||||
$this->proxy_url = Services_Yadis_getDefaultProxy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function queryURL($xri, $service_type = null)
|
|
||||||
{
|
|
||||||
// trim off the xri:// prefix
|
|
||||||
$qxri = substr(Services_Yadis_toURINormal($xri), 6);
|
|
||||||
$hxri = $this->proxy_url . $qxri;
|
|
||||||
$args = array(
|
|
||||||
'_xrd_r' => 'application/xrds+xml'
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($service_type) {
|
|
||||||
$args['_xrd_t'] = $service_type;
|
|
||||||
} else {
|
|
||||||
// Don't perform service endpoint selection.
|
|
||||||
$args['_xrd_r'] .= ';sep=false';
|
|
||||||
}
|
|
||||||
|
|
||||||
$query = Services_Yadis_XRIAppendArgs($hxri, $args);
|
|
||||||
return $query;
|
|
||||||
}
|
|
||||||
|
|
||||||
function query($xri, $service_types, $filters = array())
|
|
||||||
{
|
|
||||||
$services = array();
|
|
||||||
$canonicalID = null;
|
|
||||||
foreach ($service_types as $service_type) {
|
|
||||||
$url = $this->queryURL($xri, $service_type);
|
|
||||||
$response = $this->fetcher->get($url);
|
|
||||||
if ($response->status != 200) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$xrds = Services_Yadis_XRDS::parseXRDS($response->body);
|
|
||||||
if (!$xrds) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$canonicalID = Services_Yadis_getCanonicalID($xri,
|
|
||||||
$xrds);
|
|
||||||
|
|
||||||
if ($canonicalID === false) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$some_services = $xrds->services($filters);
|
|
||||||
$services = array_merge($services, $some_services);
|
|
||||||
// TODO:
|
|
||||||
// * If we do get hits for multiple service_types, we're
|
|
||||||
// almost certainly going to have duplicated service
|
|
||||||
// entries and broken priority ordering.
|
|
||||||
}
|
|
||||||
return array($canonicalID, $services);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,313 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The core PHP Yadis implementation.
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* LICENSE: See the COPYING file included in this distribution.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
* @author JanRain, Inc. <openid@janrain.com>
|
|
||||||
* @copyright 2005 Janrain, Inc.
|
|
||||||
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Need both fetcher types so we can use the right one based on the
|
|
||||||
* presence or absence of CURL.
|
|
||||||
*/
|
|
||||||
require_once "Services/Yadis/PlainHTTPFetcher.php";
|
|
||||||
require_once "Services/Yadis/ParanoidHTTPFetcher.php";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Need this for parsing HTML (looking for META tags).
|
|
||||||
*/
|
|
||||||
require_once "Services/Yadis/ParseHTML.php";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Need this to parse the XRDS document during Yadis discovery.
|
|
||||||
*/
|
|
||||||
require_once "Services/Yadis/XRDS.php";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the core of the PHP Yadis library. This is the only class
|
|
||||||
* a user needs to use to perform Yadis discovery. This class
|
|
||||||
* performs the discovery AND stores the result of the discovery.
|
|
||||||
*
|
|
||||||
* First, require this library into your program source:
|
|
||||||
*
|
|
||||||
* <pre> require_once "Services/Yadis/Yadis.php";</pre>
|
|
||||||
*
|
|
||||||
* To perform Yadis discovery, first call the "discover" method
|
|
||||||
* statically with a URI parameter:
|
|
||||||
*
|
|
||||||
* <pre> $http_response = array();
|
|
||||||
* $fetcher = Services_Yadis_Yadis::getHTTPFetcher();
|
|
||||||
* $yadis_object = Services_Yadis_Yadis::discover($uri,
|
|
||||||
* $http_response, $fetcher);</pre>
|
|
||||||
*
|
|
||||||
* If the discovery succeeds, $yadis_object will be an instance of
|
|
||||||
* {@link Services_Yadis_Yadis}. If not, it will be null. The XRDS
|
|
||||||
* document found during discovery should have service descriptions,
|
|
||||||
* which can be accessed by calling
|
|
||||||
*
|
|
||||||
* <pre> $service_list = $yadis_object->services();</pre>
|
|
||||||
*
|
|
||||||
* which returns an array of objects which describe each service.
|
|
||||||
* These objects are instances of Services_Yadis_Service. Each object
|
|
||||||
* describes exactly one whole Service element, complete with all of
|
|
||||||
* its Types and URIs (no expansion is performed). The common use
|
|
||||||
* case for using the service objects returned by services() is to
|
|
||||||
* write one or more filter functions and pass those to services():
|
|
||||||
*
|
|
||||||
* <pre> $service_list = $yadis_object->services(
|
|
||||||
* array("filterByURI",
|
|
||||||
* "filterByExtension"));</pre>
|
|
||||||
*
|
|
||||||
* The filter functions (whose names appear in the array passed to
|
|
||||||
* services()) take the following form:
|
|
||||||
*
|
|
||||||
* <pre> function myFilter(&$service) {
|
|
||||||
* // Query $service object here. Return true if the service
|
|
||||||
* // matches your query; false if not.
|
|
||||||
* }</pre>
|
|
||||||
*
|
|
||||||
* This is an example of a filter which uses a regular expression to
|
|
||||||
* match the content of URI tags (note that the Services_Yadis_Service
|
|
||||||
* class provides a getURIs() method which you should use instead of
|
|
||||||
* this contrived example):
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* function URIMatcher(&$service) {
|
|
||||||
* foreach ($service->getElements('xrd:URI') as $uri) {
|
|
||||||
* if (preg_match("/some_pattern/",
|
|
||||||
* $service->parser->content($uri))) {
|
|
||||||
* return true;
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* return false;
|
|
||||||
* }</pre>
|
|
||||||
*
|
|
||||||
* The filter functions you pass will be called for each service
|
|
||||||
* object to determine which ones match the criteria your filters
|
|
||||||
* specify. The default behavior is that if a given service object
|
|
||||||
* matches ANY of the filters specified in the services() call, it
|
|
||||||
* will be returned. You can specify that a given service object will
|
|
||||||
* be returned ONLY if it matches ALL specified filters by changing
|
|
||||||
* the match mode of services():
|
|
||||||
*
|
|
||||||
* <pre> $yadis_object->services(array("filter1", "filter2"),
|
|
||||||
* SERVICES_YADIS_MATCH_ALL);</pre>
|
|
||||||
*
|
|
||||||
* See {@link SERVICES_YADIS_MATCH_ALL} and {@link
|
|
||||||
* SERVICES_YADIS_MATCH_ANY}.
|
|
||||||
*
|
|
||||||
* Services described in an XRDS should have a library which you'll
|
|
||||||
* probably be using. Those libraries are responsible for defining
|
|
||||||
* filters that can be used with the "services()" call. If you need
|
|
||||||
* to write your own filter, see the documentation for {@link
|
|
||||||
* Services_Yadis_Service}.
|
|
||||||
*
|
|
||||||
* @package Yadis
|
|
||||||
*/
|
|
||||||
class Services_Yadis_Yadis {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an HTTP fetcher object. If the CURL extension is
|
|
||||||
* present, an instance of {@link Services_Yadis_ParanoidHTTPFetcher}
|
|
||||||
* is returned. If not, an instance of
|
|
||||||
* {@link Services_Yadis_PlainHTTPFetcher} is returned.
|
|
||||||
*/
|
|
||||||
function getHTTPFetcher($timeout = 20)
|
|
||||||
{
|
|
||||||
if (Services_Yadis_Yadis::curlPresent()) {
|
|
||||||
$fetcher = new Services_Yadis_ParanoidHTTPFetcher($timeout);
|
|
||||||
} else {
|
|
||||||
$fetcher = new Services_Yadis_PlainHTTPFetcher($timeout);
|
|
||||||
}
|
|
||||||
return $fetcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
function curlPresent()
|
|
||||||
{
|
|
||||||
return function_exists('curl_init');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _getHeader($header_list, $names)
|
|
||||||
{
|
|
||||||
foreach ($header_list as $name => $value) {
|
|
||||||
foreach ($names as $n) {
|
|
||||||
if (strtolower($name) == strtolower($n)) {
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _getContentType($content_type_header)
|
|
||||||
{
|
|
||||||
if ($content_type_header) {
|
|
||||||
$parts = explode(";", $content_type_header);
|
|
||||||
return strtolower($parts[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This should be called statically and will build a Yadis
|
|
||||||
* instance if the discovery process succeeds. This implements
|
|
||||||
* Yadis discovery as specified in the Yadis specification.
|
|
||||||
*
|
|
||||||
* @param string $uri The URI on which to perform Yadis discovery.
|
|
||||||
*
|
|
||||||
* @param array $http_response An array reference where the HTTP
|
|
||||||
* response object will be stored (see {@link
|
|
||||||
* Services_Yadis_HTTPResponse}.
|
|
||||||
*
|
|
||||||
* @param Services_Yadis_HTTPFetcher $fetcher An instance of a
|
|
||||||
* Services_Yadis_HTTPFetcher subclass.
|
|
||||||
*
|
|
||||||
* @param array $extra_ns_map An array which maps namespace names
|
|
||||||
* to namespace URIs to be used when parsing the Yadis XRDS
|
|
||||||
* document.
|
|
||||||
*
|
|
||||||
* @param integer $timeout An optional fetcher timeout, in seconds.
|
|
||||||
*
|
|
||||||
* @return mixed $obj Either null or an instance of
|
|
||||||
* Services_Yadis_Yadis, depending on whether the discovery
|
|
||||||
* succeeded.
|
|
||||||
*/
|
|
||||||
function discover($uri, &$http_response, &$fetcher,
|
|
||||||
$extra_ns_map = null, $timeout = 20)
|
|
||||||
{
|
|
||||||
if (!$uri) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$request_uri = $uri;
|
|
||||||
$headers = array("Accept: application/xrds+xml");
|
|
||||||
|
|
||||||
if (!$fetcher) {
|
|
||||||
$fetcher = Services_Yadis_Yadis::getHTTPFetcher($timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = $fetcher->get($uri, $headers);
|
|
||||||
$http_response = $response;
|
|
||||||
|
|
||||||
if (!$response) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($response->status != 200) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$xrds_uri = $response->final_url;
|
|
||||||
$uri = $response->final_url;
|
|
||||||
$body = $response->body;
|
|
||||||
|
|
||||||
$xrds_header_uri = Services_Yadis_Yadis::_getHeader(
|
|
||||||
$response->headers,
|
|
||||||
array('x-xrds-location',
|
|
||||||
'x-yadis-location'));
|
|
||||||
|
|
||||||
$content_type = Services_Yadis_Yadis::_getHeader($response->headers,
|
|
||||||
array('content-type'));
|
|
||||||
|
|
||||||
if ($xrds_header_uri) {
|
|
||||||
$xrds_uri = $xrds_header_uri;
|
|
||||||
$response = $fetcher->get($xrds_uri);
|
|
||||||
$http_response = $response;
|
|
||||||
if (!$response) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
$body = $response->body;
|
|
||||||
$headers = $response->headers;
|
|
||||||
$content_type = Services_Yadis_Yadis::_getHeader($headers,
|
|
||||||
array('content-type'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Services_Yadis_Yadis::_getContentType($content_type) !=
|
|
||||||
'application/xrds+xml') {
|
|
||||||
// Treat the body as HTML and look for a META tag.
|
|
||||||
$parser = new Services_Yadis_ParseHTML();
|
|
||||||
$new_uri = $parser->getHTTPEquiv($body);
|
|
||||||
$xrds_uri = null;
|
|
||||||
if ($new_uri) {
|
|
||||||
$response = $fetcher->get($new_uri);
|
|
||||||
if ($response->status != 200) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$http_response = $response;
|
|
||||||
$body = $response->body;
|
|
||||||
$xrds_uri = $new_uri;
|
|
||||||
$content_type = Services_Yadis_Yadis::_getHeader(
|
|
||||||
$response->headers,
|
|
||||||
array('content-type'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$xrds = Services_Yadis_XRDS::parseXRDS($body, $extra_ns_map);
|
|
||||||
|
|
||||||
if ($xrds !== null) {
|
|
||||||
$y = new Services_Yadis_Yadis();
|
|
||||||
|
|
||||||
$y->request_uri = $request_uri;
|
|
||||||
$y->xrds = $xrds;
|
|
||||||
$y->uri = $uri;
|
|
||||||
$y->xrds_uri = $xrds_uri;
|
|
||||||
$y->body = $body;
|
|
||||||
$y->content_type = $content_type;
|
|
||||||
|
|
||||||
return $y;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiates an empty Services_Yadis_Yadis object. This
|
|
||||||
* constructor should not be used by any user of the library.
|
|
||||||
* This constructor results in a completely useless object which
|
|
||||||
* must be populated with valid discovery information. Instead of
|
|
||||||
* using this constructor, call
|
|
||||||
* Services_Yadis_Yadis::discover($uri).
|
|
||||||
*/
|
|
||||||
function Services_Yadis_Yadis()
|
|
||||||
{
|
|
||||||
$this->request_uri = null;
|
|
||||||
$this->uri = null;
|
|
||||||
$this->xrds = null;
|
|
||||||
$this->xrds_uri = null;
|
|
||||||
$this->body = null;
|
|
||||||
$this->content_type = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the list of service objects as described by the XRDS
|
|
||||||
* document, if this yadis object represents a successful Yadis
|
|
||||||
* discovery.
|
|
||||||
*
|
|
||||||
* @return array $services An array of {@link Services_Yadis_Service}
|
|
||||||
* objects
|
|
||||||
*/
|
|
||||||
function services()
|
|
||||||
{
|
|
||||||
if ($this->xrds) {
|
|
||||||
return $this->xrds->services();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
<query id="addOpenIDToMember" action="insert">
|
|
||||||
<tables>
|
|
||||||
<table name="member_openid" />
|
|
||||||
</tables>
|
|
||||||
<columns>
|
|
||||||
<column name="openid" var="openid" notnull="notnull" />
|
|
||||||
<column name="member_srl" var="member_srl" notnull="notnull" />
|
|
||||||
<column name="regdate" default="curdate()" />
|
|
||||||
</columns>
|
|
||||||
</query>
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
<query id="deleteMemberOpenID" action="delete">
|
|
||||||
<tables>
|
|
||||||
<table name="member_openid" />
|
|
||||||
</tables>
|
|
||||||
<conditions>
|
|
||||||
<condition operation="equal" column="openid" var="openid" notnull="notnull" />
|
|
||||||
</conditions>
|
|
||||||
</query>
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
<query id="deleteMemberOpenIDByMemberSrl" action="delete">
|
|
||||||
<tables>
|
|
||||||
<table name="member_openid" />
|
|
||||||
</tables>
|
|
||||||
<conditions>
|
|
||||||
<condition operation="equal" column="member_srl" var="member_srl" notnull="notnull" />
|
|
||||||
</conditions>
|
|
||||||
</query>
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<query id="deleteOpenIdAssociation" action="delete">
|
|
||||||
<tables>
|
|
||||||
<table name="member_openid_association" />
|
|
||||||
</tables>
|
|
||||||
<conditions>
|
|
||||||
<condition operation="equal" column="server_url" var="server_url" />
|
|
||||||
<condition operation="equal" column="handle" var="handle" pipe="and" />
|
|
||||||
</conditions>
|
|
||||||
</query>
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
<query id="deleteOpenIdNonce" action="delete">
|
|
||||||
<tables>
|
|
||||||
<table name="member_openid_nonce" />
|
|
||||||
</tables>
|
|
||||||
<conditions>
|
|
||||||
<condition operation="equal" column="nonce" var="nonce" />
|
|
||||||
</conditions>
|
|
||||||
</query>
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
<query id="getMemberOpenIDByMemberSrl" action="select">
|
|
||||||
<tables>
|
|
||||||
<table name="member_openid" />
|
|
||||||
</tables>
|
|
||||||
<columns>
|
|
||||||
<column name="openid" />
|
|
||||||
</columns>
|
|
||||||
<navigation>
|
|
||||||
<index var="sort_index" default="regdate" order="asc" />
|
|
||||||
</navigation>
|
|
||||||
<conditions>
|
|
||||||
<condition operation="equal" column="member_srl" var="member_srl" notnull="notnull" />
|
|
||||||
</conditions>
|
|
||||||
</query>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<query id="getMemberSrlByOpenID" action="select">
|
|
||||||
<tables>
|
|
||||||
<table name="member_openid" />
|
|
||||||
</tables>
|
|
||||||
<columns>
|
|
||||||
<column name="member_srl" />
|
|
||||||
</columns>
|
|
||||||
<conditions>
|
|
||||||
<condition operation="equal" column="openid" var="openid" notnull="notnull" />
|
|
||||||
</conditions>
|
|
||||||
</query>
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
<query id="getOpenIdAssociation" action="select">
|
|
||||||
<tables>
|
|
||||||
<table name="member_openid_association" />
|
|
||||||
</tables>
|
|
||||||
<columns>
|
|
||||||
<column name="*" />
|
|
||||||
</columns>
|
|
||||||
<conditions>
|
|
||||||
<condition operation="equal" column="server_url" var="server_url" notnull="notnull" />
|
|
||||||
<condition operation="equal" column="handle" var="handle" pipe="and" />
|
|
||||||
</conditions>
|
|
||||||
</query>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<query id="getOpenIdNonce" action="select">
|
|
||||||
<tables>
|
|
||||||
<table name="member_openid_nonce" />
|
|
||||||
</tables>
|
|
||||||
<columns>
|
|
||||||
<column name="*" />
|
|
||||||
</columns>
|
|
||||||
<conditions>
|
|
||||||
<condition operation="equal" column="nonce" var="nonce" notnull="notnull" />
|
|
||||||
</conditions>
|
|
||||||
</query>
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
<query id="insertOpenIdAssociation" action="insert">
|
|
||||||
<tables>
|
|
||||||
<table name="member_openid_association" />
|
|
||||||
</tables>
|
|
||||||
<columns>
|
|
||||||
<column name="server_url" var="server_url" notnull="notnull" />
|
|
||||||
<column name="handle" var="handle" notnull="notnull" />
|
|
||||||
<column name="secret" var="secret" notnull="notnull" />
|
|
||||||
<column name="issued" var="issued" notnull="notnull" />
|
|
||||||
<column name="lifetime" var="lifetime" notnull="notnull" />
|
|
||||||
<column name="assoc_type" var="assoc_type" notnull="notnull" />
|
|
||||||
</columns>
|
|
||||||
</query>
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<query id="insertOpenIdNonce" action="insert">
|
|
||||||
<tables>
|
|
||||||
<table name="member_openid_nonce" />
|
|
||||||
</tables>
|
|
||||||
<columns>
|
|
||||||
<column name="nonce" var="nonce" notnull="notnull" />
|
|
||||||
<column name="expires" var="expires" notnull="notnull" />
|
|
||||||
</columns>
|
|
||||||
</query>
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<ruleset version="1.5.0">
|
|
||||||
<customrules>
|
|
||||||
</customrules>
|
|
||||||
<fields>
|
|
||||||
<field name="openid" required="true" />
|
|
||||||
<field name="referer_url" required="true" />
|
|
||||||
</fields>
|
|
||||||
</ruleset>
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
<table name="member_openid">
|
|
||||||
<column name="member_srl" type="number" size="11" notnull="notnull" index="idx_member_srl" />
|
|
||||||
<column name="openid" type="varchar" size="80" notnull="notnull" unique="unique_openid" />
|
|
||||||
<column name="regdate" type="date" index="idx_regdate" />
|
|
||||||
</table>
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
<table name="member_openid_association">
|
|
||||||
<column name="server_url" type="text" notnull="notnull" />
|
|
||||||
<column name="handle" type="varchar" size="255" notnull="notnull" />
|
|
||||||
<column name="secret" type="text" notnull="notnull" />
|
|
||||||
<column name="issued" type="number" size="11" />
|
|
||||||
<column name="lifetime" type="number" size="11" />
|
|
||||||
<column name="assoc_type" type="varchar" size="64" />
|
|
||||||
</table>
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
<table name="member_openid_nonce">
|
|
||||||
<column name="nonce" type="char" size="8" notnull="notnull" primary_key="primary_key" />
|
|
||||||
<column name="expires" type="number" size="11" />
|
|
||||||
</table>
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
<filter name="add_openid_to_member" module="member" act="procMemberAddOpenIDToMember">
|
|
||||||
<form>
|
|
||||||
<node target="openid" required="true" minlength="2" maxlength="80" />
|
|
||||||
</form>
|
|
||||||
<parameter>
|
|
||||||
<param name="openid" target="openid" />
|
|
||||||
</parameter>
|
|
||||||
<response callback_func="completeModify">
|
|
||||||
<tag name="error" />
|
|
||||||
<tag name="message" />
|
|
||||||
</response>
|
|
||||||
</filter>
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
<filter name="delete_openid_from_member" module="member" act="procMemberDeleteOpenIDFromMember">
|
|
||||||
<form>
|
|
||||||
<node target="openid_to_delete" required="true" minlength="2" maxlength="80" />
|
|
||||||
</form>
|
|
||||||
<parameter>
|
|
||||||
<param name="openid_to_delete" target="openid_to_delete" />
|
|
||||||
</parameter>
|
|
||||||
<response callback_func="completeModify">
|
|
||||||
<tag name="error" />
|
|
||||||
<tag name="message" />
|
|
||||||
</response>
|
|
||||||
</filter>
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
<filter name="openid_leave_member" module="member" act="procMemberOpenIDLeave" confirm_msg_code="confirm_leave">
|
|
||||||
<form />
|
|
||||||
<parameter />
|
|
||||||
<response callback_func="completeLeave">
|
|
||||||
<tag name="error" />
|
|
||||||
<tag name="message" />
|
|
||||||
</response>
|
|
||||||
</filter>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<filter name="openid_login" module="member" act="procMemberOpenIDLogin">
|
|
||||||
<form>
|
|
||||||
<node target="openid" required="true" />
|
|
||||||
<node target="referer_url" required="true" />
|
|
||||||
</form>
|
|
||||||
<parameter />
|
|
||||||
<response callback_func="completeOpenIDLogin">
|
|
||||||
<tag name="error" />
|
|
||||||
<tag name="message" />
|
|
||||||
</response>
|
|
||||||
</filter>
|
|
||||||
|
|
@ -77,12 +77,6 @@ function completeLogout(ret_obj) {
|
||||||
location.href = current_url.setQuery('act','');
|
location.href = current_url.setQuery('act','');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 오픈아이디 로그인 후 */
|
|
||||||
function completeOpenIDLogin(ret_obj, response_tags) {
|
|
||||||
var redirect_url = ret_obj['redirect_url'];
|
|
||||||
location.href = redirect_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 인증 메일 재발송 후 */
|
/* 인증 메일 재발송 후 */
|
||||||
function completeResendAuthMail(ret_obj, response_tags) {
|
function completeResendAuthMail(ret_obj, response_tags) {
|
||||||
var error = ret_obj['error'];
|
var error = ret_obj['error'];
|
||||||
|
|
@ -166,16 +160,3 @@ function doDeleteSavedDocument(document_srl, confirm_message) {
|
||||||
function insertSelectedModule(id, module_srl, mid, browser_title) {
|
function insertSelectedModule(id, module_srl, mid, browser_title) {
|
||||||
location.href = current_url.setQuery('selected_module_srl',module_srl);
|
location.href = current_url.setQuery('selected_module_srl',module_srl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 오픈아이디 연결 */
|
|
||||||
function doAddOpenIDToMember() {
|
|
||||||
var fo_obj = get_by_id("fo_insert_member");
|
|
||||||
procFilter(fo_obj, add_openid_to_member);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 오픈아이디 연결 해제 */
|
|
||||||
function doDeleteOpenIDFromMember(openid) {
|
|
||||||
var fo_obj = get_by_id("fo_insert_member");
|
|
||||||
fo_obj.openid_to_delete.value = openid;
|
|
||||||
procFilter(fo_obj, delete_openid_from_member);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
<include target="./common_header.html" />
|
|
||||||
<load target="filter/openid_leave_member.xml" />
|
|
||||||
<h1 class="h1">{$member_title = $lang->msg_leave_member}</h1>
|
|
||||||
<form id="fo_insert_member" class="form" action="./" method="get" onsubmit="return procFilter(this, openid_leave_member)">
|
|
||||||
<input type="hidden" name="mid" value="{$mid}" />
|
|
||||||
<input type="hidden" name="document_srl" value="{$document_srl}" />
|
|
||||||
<input type="hidden" name="page" value="{$page}" />
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<p class="q"><label for="oid">{$lang->user_id}</label></p>
|
|
||||||
<p class="a">
|
|
||||||
<input type="text" disabled="disabled" value="{$member_info->user_id}" id="oid" />
|
|
||||||
<span class="desc">{$lang->about_openid_leave}</span>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div class="btnArea">
|
|
||||||
<span class="btn"><input type="submit" value="{$lang->cmd_leave}" /></span>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<include target="./common_footer.html" />
|
|
||||||
|
|
@ -34,14 +34,6 @@
|
||||||
<!--@if($member_info->member_srl == $logged_info->member_srl || $logged_info->is_admin == 'Y' )-->
|
<!--@if($member_info->member_srl == $logged_info->member_srl || $logged_info->is_admin == 'Y' )-->
|
||||||
<li><label for="llogin" class="db fb al">{$lang->last_login}</label><div>{zdate($member_info->last_login,"Y-m-d H:i")}</div></li>
|
<li><label for="llogin" class="db fb al">{$lang->last_login}</label><div>{zdate($member_info->last_login,"Y-m-d H:i")}</div></li>
|
||||||
<!--@end-->
|
<!--@end-->
|
||||||
<!--@if($member_config->enable_openid=="Y")-->
|
|
||||||
<!--@if(sizeof($openids) > 0)-->
|
|
||||||
<li><label for="openid" class="db fb al">{$lang->openid} </label>
|
|
||||||
<!--@foreach($openids as $openid)-->
|
|
||||||
<div id="openid">{$openid->openid}</div></li>
|
|
||||||
<!--@end-->
|
|
||||||
<!--@end-->
|
|
||||||
<!--@end-->
|
|
||||||
</ul>
|
</ul>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<!--@if($extend_form_list)-->
|
<!--@if($extend_form_list)-->
|
||||||
|
|
@ -78,13 +70,9 @@
|
||||||
<li>
|
<li>
|
||||||
<!--@if($member_info->member_srl == $logged_info->member_srl)-->
|
<!--@if($member_info->member_srl == $logged_info->member_srl)-->
|
||||||
<a href="{getUrl('act','dispMemberModifyInfo','member_srl','')}" class="bn"><span>{$lang->cmd_modify_member_info}</span></a>
|
<a href="{getUrl('act','dispMemberModifyInfo','member_srl','')}" class="bn"><span>{$lang->cmd_modify_member_info}</span></a>
|
||||||
<!--@if($logged_info->is_openid)-->
|
|
||||||
<a href="{getUrl('act','dispMemberOpenIDLeave','member_srl','')}" class="bn"><span>{$lang->cmd_leave}</span></a>
|
|
||||||
<!--@else-->
|
|
||||||
<a href="{getUrl('act','dispMemberModifyPassword','member_srl','')}" class="bn"><span>{$lang->cmd_modify_member_password}</span></a>
|
<a href="{getUrl('act','dispMemberModifyPassword','member_srl','')}" class="bn"><span>{$lang->cmd_modify_member_password}</span></a>
|
||||||
<a href="{getUrl('act','dispMemberLeave','member_srl','')}" class="bn"><span>{$lang->cmd_leave}</span></a>
|
<a href="{getUrl('act','dispMemberLeave','member_srl','')}" class="bn"><span>{$lang->cmd_leave}</span></a>
|
||||||
<!--@end-->
|
<!--@end-->
|
||||||
<!--@end-->
|
|
||||||
<a href="{getUrl('act','','member_srl','')}" class="bn"><span>{$lang->cmd_back}</span></a>
|
<a href="{getUrl('act','','member_srl','')}" class="bn"><span>{$lang->cmd_back}</span></a>
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,6 @@
|
||||||
<!--%import("../skins/default/filter/delete_image_mark.xml")-->
|
<!--%import("../skins/default/filter/delete_image_mark.xml")-->
|
||||||
<!--@end-->
|
<!--@end-->
|
||||||
|
|
||||||
<!--@if($member_config->enable_openid=="Y")-->
|
|
||||||
<!--%import("../skins/default/filter/add_openid_to_member.xml")-->
|
|
||||||
<!--%import("../skins/default/filter/delete_openid_from_member.xml")-->
|
|
||||||
<!--@end-->
|
|
||||||
<div class="bd">
|
<div class="bd">
|
||||||
<h2 class="h2">{$lang->msg_update_member}</h2>
|
<h2 class="h2">{$lang->msg_update_member}</h2>
|
||||||
<h3 class="h3">{$lang->member_default_info}</h3>
|
<h3 class="h3">{$lang->member_default_info}</h3>
|
||||||
|
|
@ -181,22 +177,6 @@
|
||||||
</ul>
|
</ul>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<!--@end-->
|
<!--@end-->
|
||||||
<!--@if($member_config->enable_openid=="Y")-->
|
|
||||||
<h3 class="h3">{$lang->openid}</h3>
|
|
||||||
<fieldset class="sn">
|
|
||||||
<ul>
|
|
||||||
<!--@foreach($openids as $openid)-->
|
|
||||||
<li><a href="{$openid->bookmarklet}">{$openid->openid}</a> <a onclick="doDeleteOpenIDFromMember('{$openid->openid}')" class="bn"><span>{$lang->cmd_delete}</span></a></li>
|
|
||||||
<!--@end-->
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<input name="openid" type="text" class="itx" />
|
|
||||||
<input name="openid_to_delete" type="hidden" />
|
|
||||||
<a onclick="doAddOpenIDToMember()" class="bn"><span>{$lang->cmd_insert}</span></a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</fieldset>
|
|
||||||
<!--@end-->
|
|
||||||
<div class="cm">
|
<div class="cm">
|
||||||
<input type="submit" value="{$lang->cmd_registration}" class="bn"/>
|
<input type="submit" value="{$lang->cmd_registration}" class="bn"/>
|
||||||
<a href="{getUrl('act','dispMemberInfo','member_srl','')}" class="bn"><span>{$lang->cmd_cancel}</span></a>
|
<a href="{getUrl('act','dispMemberInfo','member_srl','')}" class="bn"><span>{$lang->cmd_cancel}</span></a>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue