- $authenticatedUser: User object if credentials match a user, else null.
StartChangePassword: Before changing a password
-- $nickname: user's nickname
+- $user: user
- $oldpassword: the user's old password
- $newpassword: the desired new password
EndChangePassword: After changing a password
-- $nickname: user's nickname
+- $user: user
UserDeleteRelated: Specify additional tables to delete entries from when deleting users
- $user: User object
}
$success = false;
- if(! Event::handle('StartChangePassword', array($user->nickname, $oldpassword, $newpassword))){
+ if(! Event::handle('StartChangePassword', array($user, $oldpassword, $newpassword))){
//no handler changed the password, so change the password internally
$original = clone($user);
$this->serverError(_('Can\'t save new password.'));
return;
}
- Event::handle('EndChangePassword', array($nickname));
+ Event::handle('EndChangePassword', array($user));
}
$this->showForm(_('Password saved.'), true);
return $result;
}
- function allowed_nickname($nickname)
+ static function allowed_nickname($nickname)
{
// XXX: should already be validated for size, content, etc.
$blacklist = common_config('nickname', 'blacklist');
$profile->query('BEGIN');
+ if(!empty($email))
+ {
+ $email = common_canonical_email($email);
+ }
+
+ $nickname = common_canonical_nickname($nickname);
$profile->nickname = $nickname;
+ if(! User::allowed_nickname($nickname)){
+ common_log(LOG_WARNING, sprintf("Attempted to register a nickname that is not allowed: %s", $profile->nickname),
+ __FILE__);
+ }
$profile->profileurl = common_profile_url($nickname);
if (!empty($fullname)) {
}
}
+ if(isset($email_confirmed) && $email_confirmed) {
+ $user->email = $email;
+ }
+
// This flag is ignored but still set to 1
$user->inboxed = 1;
user_id = K
token = K
+[user_username]
+user_id = 129
+provider_name = 130
+username = 130
+created = 142
+modified = 384
+
+[user_username__keys]
+provider_name = K
+username = K
*/
function handleError($error)
{
-//error_log(print_r($error,1));
if ($error->getCode() == DB_DATAOBJECT_ERROR_NODATA) {
return;
}
}
} else {
common_ensure_syslog();
+ error_log($msg);
syslog($priority, $msg);
}
}
//should accounts be automatically created after a successful login attempt?
public $autoregistration = false;
- //can the user change their email address
- public $email_changeable=true;
-
//can the user change their email address
public $password_changeable=true;
+ //unique name for this authentication provider
+ public $provider_name;
+
//------------Auth plugin should implement some (or all) of these methods------------\\
/**
* Check if a nickname/password combination is valid
- * @param nickname
+ * @param username
* @param password
* @return boolean true if the credentials are valid, false if they are invalid.
*/
- function checkPassword($nickname, $password)
+ function checkPassword($username, $password)
{
return false;
}
/**
* Automatically register a user when they attempt to login with valid credentials.
* User::register($data) is a very useful method for this implementation
- * @param nickname
- * @return boolean true if the user was created, false if autoregistration is not allowed, null if this plugin is not responsible for this nickname
+ * @param username
+ * @return boolean true if the user was created, false if not
*/
- function autoRegister($nickname)
+ function autoRegister($username)
{
- return null;
+ $registration_data = array();
+ $registration_data['nickname'] = $username ;
+ return User::register($registration_data);
}
/**
* Change a user's password
* The old password has been verified to be valid by this plugin before this call is made
- * @param nickname
+ * @param username
* @param oldpassword
* @param newpassword
- * @return boolean true if the password was changed, false if password changing failed for some reason, null if this plugin is not responsible for this nickname
+ * @return boolean true if the password was changed, false if password changing failed for some reason
*/
- function changePassword($nickname,$oldpassword,$newpassword)
+ function changePassword($username,$oldpassword,$newpassword)
{
- return null;
- }
-
- /**
- * Can a user change this field in his own profile?
- * @param nickname
- * @param field
- * @return boolean true if the field can be changed, false if not allowed to change it, null if this plugin is not responsible for this nickname
- */
- function canUserChangeField($nickname, $field)
- {
- return null;
+ return false;
}
//------------Below are the methods that connect StatusNet to the implementing Auth plugin------------\\
- function __construct()
- {
- parent::__construct();
+ function onInitializePlugin(){
+ if(!isset($this->provider_name)){
+ throw new Exception("must specify a provider_name for this authentication provider");
+ }
}
-
+
function onStartCheckPassword($nickname, $password, &$authenticatedUser){
- if($this->password_changeable){
- $authenticated = $this->checkPassword($nickname, $password);
+ //map the nickname to a username
+ $user_username = new User_username();
+ $user_username->username=$nickname;
+ $user_username->provider_name=$this->provider_name;
+ if($user_username->find() && $user_username->fetch()){
+ $username = $user_username->username;
+ $authenticated = $this->checkPassword($username, $password);
if($authenticated){
- $authenticatedUser = User::staticGet('nickname', $nickname);
- if(!$authenticatedUser && $this->autoregistration){
- if($this->autoregister($nickname)){
+ $authenticatedUser = User::staticGet('id', $user_username->user_id);
+ return false;
+ }
+ }else{
+ $user = User::staticGet('nickname', $nickname);
+ if($user){
+ //make sure a different provider isn't handling this nickname
+ $user_username = new User_username();
+ $user_username->username=$nickname;
+ if(!$user_username->find()){
+ //no other provider claims this username, so it's safe for us to handle it
+ $authenticated = $this->checkPassword($nickname, $password);
+ if($authenticated){
$authenticatedUser = User::staticGet('nickname', $nickname);
+ $user_username = new User_username();
+ $user_username->user_id = $authenticatedUser->id;
+ $user_username->provider_name = $this->provider_name;
+ $user_username->username = $nickname;
+ $user_username->created = DB_DataObject_Cast::dateTime();
+ $user_username->insert();
+ return false;
}
}
- return false;
}else{
- if($this->authoritative){
- return false;
+ if($this->autoregistration){
+ $authenticated = $this->checkPassword($nickname, $password);
+ if($authenticated && $this->autoregister($nickname)){
+ $authenticatedUser = User::staticGet('nickname', $nickname);
+ $user_username = new User_username();
+ $user_username->user_id = $authenticatedUser->id;
+ $user_username->provider_name = $this->provider_name;
+ $user_username->username = $nickname;
+ $user_username->created = DB_DataObject_Cast::dateTime();
+ $user_username->insert();
+ return false;
+ }
}
}
- //we're not authoritative, so let other handlers try
+ }
+ if($this->authoritative){
+ return false;
}else{
- if($this->authoritative){
- //since we're authoritative, no other plugin could do this
- throw new Exception(_('Password changing is not allowed'));
- }
+ //we're not authoritative, so let other handlers try
+ return;
}
}
- function onStartChangePassword($nickname,$oldpassword,$newpassword)
+ function onStartChangePassword($user,$oldpassword,$newpassword)
{
if($this->password_changeable){
- $authenticated = $this->checkPassword($nickname, $oldpassword);
- if($authenticated){
- $result = $this->changePassword($nickname,$oldpassword,$newpassword);
- if($result){
- //stop handling of other handlers, because what was requested was done
- return false;
- }else{
- throw new Exception(_('Password changing failed'));
- }
- }else{
- if($this->authoritative){
- //since we're authoritative, no other plugin could do this
- throw new Exception(_('Password changing failed'));
+ $user_username = new User_username();
+ $user_username->user_id=$user->id;
+ $user_username->provider_name=$this->provider_name;
+ if($user_username->find() && $user_username->fetch()){
+ $authenticated = $this->checkPassword($user_username->username, $oldpassword);
+ if($authenticated){
+ $result = $this->changePassword($user_username->username,$oldpassword,$newpassword);
+ if($result){
+ //stop handling of other handlers, because what was requested was done
+ return false;
+ }else{
+ throw new Exception(_('Password changing failed'));
+ }
}else{
- //let another handler try
- return null;
+ if($this->authoritative){
+ //since we're authoritative, no other plugin could do this
+ throw new Exception(_('Password changing failed'));
+ }else{
+ //let another handler try
+ return null;
+ }
}
}
}else{
function onStartAccountSettingsPasswordMenuItem($widget)
{
if($this->authoritative && !$this->password_changeable){
- //since we're authoritative, no other plugin could change passwords, so do render the menu item
+ //since we're authoritative, no other plugin could change passwords, so do not render the menu item
+ return false;
+ }
+ }
+
+ function onAutoload($cls)
+ {
+ switch ($cls)
+ {
+ case 'User_username':
+ require_once(INSTALLDIR.'/plugins/Authentication/User_username.php');
return false;
+ default:
+ return true;
}
}
+
+ function onCheckSchema() {
+ $schema = Schema::get();
+ $schema->ensureTable('user_username',
+ array(new ColumnDef('provider_name', 'varchar',
+ '255', false, 'PRI'),
+ new ColumnDef('username', 'varchar',
+ '255', false, 'PRI'),
+ new ColumnDef('user_id', 'integer',
+ null, false),
+ new ColumnDef('created', 'datetime',
+ null, false),
+ new ColumnDef('modified', 'timestamp')));
+ return true;
+ }
+
+ function onUserDeleteRelated($user, &$tables)
+ {
+ $tables[] = 'User_username';
+ return true;
+ }
}
--- /dev/null
+<?php
+/**
+ * Table Definition for user_username
+ */
+require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
+
+class User_username extends Memcached_DataObject
+{
+ ###START_AUTOCODE
+ /* the code below is auto generated do not remove the above tag */
+
+ public $__table = 'user_username'; // table name
+ public $user_id; // int(4) not_null
+ public $provider_name; // varchar(255) primary_key not_null
+ public $username; // varchar(255) primary_key not_null
+ public $created; // datetime() not_null
+ public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
+
+ /* Static get */
+ function staticGet($k,$v=null)
+ { return Memcached_DataObject::staticGet('User_username',$k,$v); }
+
+ /* the code above is auto generated do not remove the tag below */
+ ###END_AUTOCODE
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Plugin that uses the email address as a username, and checks the password as normal
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @copyright 2009 Craig Andrews http://candrews.integralblue.com
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+class EmailAuthenticationPlugin extends Plugin
+{
+ //---interface implementation---//
+
+ function onStartCheckPassword($nickname, $password, &$authenticatedUser)
+ {
+ if(strpos($nickname, '@'))
+ {
+ $user = User::staticGet('email',$nickname);
+ if($user && isset($user->email))
+ {
+ if(common_check_user($user->nickname,$password))
+ {
+ $authenticatedUser = $user;
+ return false;
+ }
+ }
+ }
+ }
+}
+
--- /dev/null
+The Email Authentication plugin allows users to login using their email address.
+
+The provided email address is used to lookup the user's nickname, then that nickname and the provided password is checked.
+
+Installation
+============
+add "addPlugin('emailAuthentication');" to the bottom of your config.php
public $scope=null;
public $attributes=array();
- function __construct()
- {
- parent::__construct();
+ function onInitializePlugin(){
+ parent::onInitializePlugin();
+ if(!isset($this->host)){
+ throw new Exception("must specify a host");
+ }
+ if(!isset($this->basedn)){
+ throw new Exception("must specify a basedn");
+ }
+ if(!isset($this->attributes['nickname'])){
+ throw new Exception("must specify a nickname attribute");
+ }
+ if(!isset($this->attributes['username'])){
+ throw new Exception("must specify a username attribute");
+ }
}
//---interface implementation---//
- function checkPassword($nickname, $password)
+ function checkPassword($username, $password)
{
$ldap = $this->ldap_get_connection();
if(!$ldap){
return false;
}
- $entry = $this->ldap_get_user($nickname);
+ $entry = $this->ldap_get_user($username);
if(!$entry){
return false;
}else{
}
}
- function autoRegister($nickname)
+ function autoRegister($username)
{
- $entry = $this->ldap_get_user($nickname,$this->attributes);
+ $entry = $this->ldap_get_user($username,$this->attributes);
if($entry){
$registration_data = array();
foreach($this->attributes as $sn_attribute=>$ldap_attribute){
- if($sn_attribute=='email'){
- $registration_data[$sn_attribute]=common_canonical_email($entry->getValue($ldap_attribute,'single'));
- }else if($sn_attribute=='nickname'){
- $registration_data[$sn_attribute]=common_canonical_nickname($entry->getValue($ldap_attribute,'single'));
- }else{
- $registration_data[$sn_attribute]=$entry->getValue($ldap_attribute,'single');
- }
+ $registration_data[$sn_attribute]=$entry->getValue($ldap_attribute,'single');
+ }
+ if(isset($registration_data['email']) && !empty($registration_data['email'])){
+ $registration_data['email_confirmed']=true;
}
//set the database saved password to a random string.
$registration_data['password']=common_good_rand(16);
- $user = User::register($registration_data);
- return true;
+ return User::register($registration_data);
}else{
//user isn't in ldap, so we cannot register him
- return null;
+ return false;
}
}
- function changePassword($nickname,$oldpassword,$newpassword)
+ function changePassword($username,$oldpassword,$newpassword)
{
//TODO implement this
throw new Exception(_('Sorry, changing LDAP passwords is not supported at this time'));
return false;
}
-
- function canUserChangeField($nickname, $field)
- {
- switch($field)
- {
- case 'password':
- case 'nickname':
- case 'email':
- return false;
- }
- }
//---utility functions---//
function ldap_get_config(){
*/
function ldap_get_user($username,$attributes=array()){
$ldap = $this->ldap_get_connection();
- $filter = Net_LDAP2_Filter::create($this->attributes['nickname'], 'equals', $username);
+ $filter = Net_LDAP2_Filter::create($this->attributes['username'], 'equals', $username);
$options = array(
'scope' => 'sub',
'attributes' => $attributes
Settings
========
-authoritative (false): Set to true if LDAP's responses are authoritative (meaning if LDAP fails, do check the any other plugins or the internal password database).
+provider_name*: a unique name for this authentication provider.
+authoritative (false): Set to true if LDAP's responses are authoritative (meaning if LDAP fails, do check any other plugins or the internal password database).
autoregistration (false): Set to true if users should be automatically created when they attempt to login.
email_changeable (true): Are users allowed to change their email address? (true or false)
password_changeable (true): Are users allowed to change their passwords? (true or false)
scope: Default search scope. See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
attributes: an array with the key being the StatusNet user attribute name, and the value the LDAP attribute name
+ username*
nickname*
email
fullname
Here's an example of an LDAP plugin configuration that connects to Microsoft Active Directory.
addPlugin('ldapAuthentication', array(
+ 'provider_name'=>'Example',
'authoritative'=>true,
'autoregistration'=>true,
'binddn'=>'username',
--- /dev/null
+The Reverse Username Authentication plugin allows for StatusNet to handle authentication by checking if the provided password is the same as the reverse of the username.
+
+THIS PLUGIN IS FOR TESTING PURPOSES ONLY
+
+Installation
+============
+add "addPlugin('reverseUsernameAuthentication', array('setting'=>'value', 'setting2'=>'value2', ...);" to the bottom of your config.php
+
+Settings
+========
+provider_name*: a unique name for this authentication provider.
+password_changeable*: must be set to false. This plugin does not support changing passwords.
+authoritative (false): Set to true if this plugin's responses are authoritative (meaning if this fails, do check any other plugins or the internal password database).
+autoregistration (false): Set to true if users should be automatically created when they attempt to login.
+
+* required
+default values are in (parenthesis)
+
+Example
+=======
+addPlugin('reverseUsernameAuthentication', array(
+ 'provider_name'=>'Example',
+ 'password_changeable'=>false,
+ 'authoritative'=>true,
+ 'autoregistration'=>true
+));
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Plugin that checks if the password is the reverse of username
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @copyright 2009 Craig Andrews http://candrews.integralblue.com
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/plugins/Authentication/AuthenticationPlugin.php';
+
+class ReverseUsernameAuthenticationPlugin extends AuthenticationPlugin
+{
+ //---interface implementation---//
+
+ function onInitializePlugin(){
+ parent::onInitializePlugin();
+ if(!isset($this->password_changeable) && $this->password_changeable){
+ throw new Exception("password_changeable cannot be set to true. This plugin does not support changing passwords.");
+ }
+ }
+
+ function checkPassword($username, $password)
+ {
+ return $username == strrev($password);
+ }
+
+ function autoRegister($username)
+ {
+ $registration_data = array();
+ $registration_data['nickname'] = $username ;
+ return User::register($registration_data);
+ }
+}