<?php function id_init(&$a) { logger('id: ' . print_r($_REQUEST,true)); /** * This example shows several things: * - How a setup interface should look like. * - How to use a mysql table for authentication * - How to store associations in mysql table, instead of php sessions. * - How to store realm authorizations. * - How to send AX/SREG parameters. * For the example to work, you need to create the necessary tables: CREATE TABLE Users ( id INT NOT NULL auto_increment PRIMARY KEY, login VARCHAR(32) NOT NULL, password CHAR(40) NOT NULL, firstName VARCHAR(32) NOT NULL, lastName VARCHAR(32) NOT NULL ); CREATE TABLE AllowedSites ( user INT NOT NULL, realm TEXT NOT NULL, attributes TEXT NOT NULL, INDEX(user) ); CREATE TABLE Associations ( id INT NOT NULL PRIMARY KEY, data TEXT NOT NULL ); * * This is only an example. Don't use it in your code as-is. * It has several security flaws, which you shouldn't copy (like storing plaintext login and password in forms). * * This setup could be very easily flooded with many associations, * since non-private ones aren't automatically deleted. * You could prevent this by storing a date of association and removing old ones, * or by setting $this->dh = false; * However, the latter one would disable stateful mode, unless connecting via HTTPS. */ require 'library/openid/provider/provider.php'; function getUserData($handle=null) { if(! local_channel()) { notice( t('Permission denied.') . EOL); get_app()->page['content'] = login(); return false; } // logger('handle: ' . $handle); if($handle) { $r = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_address = '%s' limit 1", dbesc($handle) ); } else { $r = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d", intval(local_channel()) ); } if(! r) return false; $x = q("select * from account where account_id = %d limit 1", intval($r[0]['channel_account_id']) ); if($x) $r[0]['email'] = $x[0]['account_email']; $p = q("select * from profile where is_default = 1 and uid = %d limit 1", intval($r[0]['channel_account_id']) ); $gender = ''; if($p[0]['gender'] == t('Male')) $gender = 'M'; if($p[0]['gender'] == t('Female')) $gender = 'F'; $r[0]['firstName'] = ((strpos($r[0]['channel_name'],' ')) ? substr($r[0]['channel_name'],0,strpos($r[0]['channel_name'],' ')) : $r[0]['channel_name']); $r[0]['lastName'] = ((strpos($r[0]['channel_name'],' ')) ? substr($r[0]['channel_name'],strpos($r[0]['channel_name'],' ')+1) : ''); $r[0]['namePerson'] = $r[0]['channel_name']; $r[0]['pphoto'] = $r[0]['xchan_photo_l']; $r[0]['pphoto16'] = z_root() . '/photo/profile/16/' . $r[0]['channel_id'] . '.jpg'; $r[0]['pphoto32'] = z_root() . '/photo/profile/32/' . $r[0]['channel_id'] . '.jpg'; $r[0]['pphoto48'] = z_root() . '/photo/profile/48/' . $r[0]['channel_id'] . '.jpg'; $r[0]['pphoto64'] = z_root() . '/photo/profile/64/' . $r[0]['channel_id'] . '.jpg'; $r[0]['pphoto80'] = z_root() . '/photo/profile/80/' . $r[0]['channel_id'] . '.jpg'; $r[0]['pphoto128'] = z_root() . '/photo/profile/128/' . $r[0]['channel_id'] . '.jpg'; $r[0]['timezone'] = $r[0]['channel_timezone']; $r[0]['url'] = $r[0]['xchan_url']; $r[0]['language'] = (($x[0]['account_language']) ? $x[0]['account_language'] : 'en'); $r[0]['birthyear'] = ((intval(substr($p[0]['dob'],0,4))) ? intval(substr($p[0]['dob'],0,4)) : ''); $r[0]['birthmonth'] = ((intval(substr($p[0]['dob'],5,2))) ? intval(substr($p[0]['dob'],5,2)) : ''); $r[0]['birthday'] = ((intval(substr($p[0]['dob'],8,2))) ? intval(substr($p[0]['dob'],8,2)) : ''); $r[0]['birthdate'] = (($r[0]['birthyear'] && $r[0]['birthmonth'] && $r[0]['birthday']) ? $p[0]['dob'] : ''); $r[0]['gender'] = $gender; return $r[0]; /* if(isset($_POST['login'],$_POST['password'])) { $login = mysql_real_escape_string($_POST['login']); $password = sha1($_POST['password']); $q = mysql_query("SELECT * FROM Users WHERE login = '$login' AND password = '$password'"); if($data = mysql_fetch_assoc($q)) { return $data; } if($handle) { echo 'Wrong login/password.'; } } if($handle) { ?> <form action="" method="post"> <input type="hidden" name="openid.assoc_handle" value="<?php echo $handle?>"> Login: <input type="text" name="login"><br> Password: <input type="password" name="password"><br> <button>Submit</button> </form> <?php die(); } */ } function translate_regs() { // This exists to get around scoping rules $attrMap = array( 'namePerson/first' => t('First Name'), 'namePerson/last' => t('Last Name'), 'namePerson/friendly' => t('Nickname'), 'namePerson' => t('Full Name'), 'contact/internet/email' => t('Email'), 'contact/email' => t('Email'), 'media/image/aspect11' => t('Profile Photo'), 'media/image' => t('Profile Photo'), 'media/image/default' => t('Profile Photo'), 'media/image/16x16' => t('Profile Photo 16px'), 'media/image/32x32' => t('Profile Photo 32px'), 'media/image/48x48' => t('Profile Photo 48px'), 'media/image/64x64' => t('Profile Photo 64px'), 'media/image/80x80' => t('Profile Photo 80px'), 'media/image/128x128' => t('Profile Photo 128px'), 'timezone' => t('Timezone'), 'contact/web/default' => t('Homepage URL'), 'language/pref' => t('Language'), 'birthDate/birthYear' => t('Birth Year'), 'birthDate/birthMonth' => t('Birth Month'), 'birthDate/birthday' => t('Birth Day'), 'birthDate' => t('Birthdate'), 'gender' => t('Gender'), ); return $attrMap; } class MysqlProvider extends LightOpenIDProvider { // See http://openid.net/specs/openid-attribute-properties-list-1_0-01.html // This list contains a few variations of these attributes to maintain // compatibility with legacy clients private $attrMap = array( 'namePerson/first' => 'First Name', 'namePerson/last' => 'Last Name', 'namePerson/friendly' => 'Nickname', 'namePerson' => 'Full Name', 'contact/internet/email' => 'Email', 'contact/email' => 'Email', 'media/image/aspect11' => 'Profile Photo', 'media/image' => 'Profile Photo', 'media/image/default' => 'Profile Photo', 'media/image/16x16' => 'Profile Photo 16px', 'media/image/32x32' => 'Profile Photo 32px', 'media/image/48x48' => 'Profile Photo 48px', 'media/image/64x64' => 'Profile Photo 64px', 'media/image/80x80' => 'Profile Photo 80px', 'media/image/128x128' => 'Profile Photo 128px', 'timezone' => 'Timezone', 'contact/web/default' => 'Homepage URL', 'language/pref' => 'Language', 'birthDate/birthYear' => 'Birth Year', 'birthDate/birthMonth' => 'Birth Month', 'birthDate/birthday' => 'Birth Day', 'birthDate' => 'Birthdate', 'gender' => 'Gender', ); private $attrFieldMap = array( 'namePerson/first' => 'firstName', 'namePerson/last' => 'lastName', 'namePerson/friendly' => 'channel_address', 'namePerson' => 'namePerson', 'contact/internet/email' => 'email', 'contact/email' => 'email', 'media/image/aspect11' => 'pphoto', 'media/image' => 'pphoto', 'media/image/default' => 'pphoto', 'media/image/16x16' => 'pphoto16', 'media/image/32x32' => 'pphoto32', 'media/image/48x48' => 'pphoto48', 'media/image/64x64' => 'pphoto64', 'media/image/80x80' => 'pphoto80', 'media/image/128x128' => 'pphoto128', 'timezone' => 'timezone', 'contact/web/default' => 'url', 'language/pref' => 'language', 'birthDate/birthYear' => 'birthyear', 'birthDate/birthMonth' => 'birthmonth', 'birthDate/birthday' => 'birthday', 'birthDate' => 'birthdate', 'gender' => 'gender', ); function setup($identity, $realm, $assoc_handle, $attributes) { // logger('identity: ' . $identity); // logger('realm: ' . $realm); // logger('assoc_handle: ' . $assoc_handle); // logger('attributes: ' . print_r($attributes,true)); $data = getUserData($assoc_handle); $o .= '<form action="" method="post">' . '<input type="hidden" name="openid.assoc_handle" value="' . $assoc_handle . '">' . '<input type="hidden" name="login" value="' . $_POST['login'] .'">' . '<input type="hidden" name="password" value="' . $_POST['password'] .'">' . "<b>$realm</b> wishes to authenticate you."; if($attributes['required'] || $attributes['optional']) { $o .= " It also requests following information (required fields marked with *):" . '<ul>'; foreach($attributes['required'] as $attr) { if(isset($this->attrMap[$attr])) { $o .= '<li>' . '<input type="checkbox" name="attributes[' . $attr . ']"> ' . $this->attrMap[$attr] . ' <span class="required">*</span></li>'; } } foreach($attributes['optional'] as $attr) { if(isset($this->attrMap[$attr])) { $o .= '<li>' . '<input type="checkbox" name="attributes[' . $attr . ']"> ' . $this->attrMap[$attr] . '</li>'; } } $o .= '</ul>'; } $o .= '<br>' . '<button name="once">Allow once</button> ' . '<button name="always">Always allow</button> ' . '<button name="cancel">cancel</button> ' . '</form>'; get_app()->page['content'] .= $o; } function checkid($realm, &$attributes) { logger('checkid: ' . $realm); logger('checkid attrs: ' . print_r($attributes,true)); if(isset($_POST['cancel'])) { $this->cancel(); } $data = getUserData(); if(! $data) { return false; } logger('checkid: checkpoint1'); $q = get_pconfig(local_channel(),'openid',$realm); $attrs = array(); if($q) { $attrs = $q; } elseif(isset($_POST['attributes'])) { $attrs = array_keys($_POST['attributes']); } elseif(!isset($_POST['once']) && !isset($_POST['always'])) { return false; } $attributes = array(); foreach($attrs as $attr) { if(isset($this->attrFieldMap[$attr])) { $attributes[$attr] = $data[$this->attrFieldMap[$attr]]; } } if(isset($_POST['always'])) { set_pconfig(local_channel(),'openid',$realm,array_keys($attributes)); } return z_root() . '/id/' . $data['channel_address']; } function assoc_handle() { $channel = get_app()->get_channel(); return z_root() . '/id/' . $channel['channel_address']; } function setAssoc($handle, $data) { logger('setAssoc'); $channel = channelx_by_nick(basename($handle)); if($channel) set_pconfig($channel['channel_id'],'openid','associate',$data); } function getAssoc($handle) { logger('getAssoc: ' . $handle); $channel = channelx_by_nick(basename($handle)); if($channel) return get_pconfig($channel['channel_id'],'openid','associate'); return false; } function delAssoc($handle) { logger('delAssoc'); $channel = channelx_by_nick(basename($handle)); if($channel) return del_pconfig($channel['channel_id'],'openid','associate'); } } $op = new MysqlProvider; $op->server(); }